Chris@66: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@66: /* Chris@66: Copyright (c) 2020 Queen Mary, University of London Chris@66: Chris@66: Permission is hereby granted, free of charge, to any person Chris@66: obtaining a copy of this software and associated documentation Chris@66: files (the "Software"), to deal in the Software without Chris@66: restriction, including without limitation the rights to use, copy, Chris@66: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@66: of the Software, and to permit persons to whom the Software is Chris@66: furnished to do so, subject to the following conditions: Chris@66: Chris@66: The above copyright notice and this permission notice shall be Chris@66: included in all copies or substantial portions of the Software. Chris@66: Chris@66: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@66: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@66: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@66: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY Chris@66: CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@66: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@66: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@66: Chris@66: Except as contained in this notice, the names of the Centre for Chris@66: Digital Music and Queen Mary, University of London shall not be Chris@66: used in advertising or otherwise to promote the sale, use or other Chris@66: dealings in this Software without prior written authorization. Chris@66: */ Chris@66: Chris@66: #include Chris@66: Chris@66: // Undocumented internal API Chris@66: #include Chris@66: Chris@67: #ifdef _WIN32 Chris@67: #include Chris@67: #include Chris@67: #include Chris@67: #else Chris@67: #include Chris@67: #endif Chris@67: Chris@67: #include Chris@67: Chris@66: #include Chris@66: #include Chris@66: Chris@66: using namespace std; Chris@66: Chris@66: void usage(const char *me) Chris@66: { Chris@66: cerr << endl; Chris@66: cerr << "Usage: " << me << " " << endl; Chris@66: cerr << endl; Chris@66: cerr << "Loads the Vamp plugin library found in and lists\n" Chris@66: << "the plugin versions found therein. Plugins are listed one per\n" Chris@66: << "line, with the plugin id and version number separated by a colon." Chris@66: << endl; Chris@66: cerr << endl; Chris@66: cerr << "Note that must be the path to a plugin library, not\n" Chris@66: << "merely the name of the library. That is, no search path is used.\n" Chris@66: << "The file path should be UTF-8 encoded (on all platforms)." Chris@66: << endl; Chris@66: cerr << endl; Chris@66: cerr << "The return code is 0 if the plugin library was successfully\n" Chris@66: << "loaded, otherwise 1. An error message may be printed to stderr\n" Chris@66: << "in the latter case." << endl; Chris@66: cerr << endl; Chris@66: exit(2); Chris@66: } Chris@66: Chris@67: // We write our output to stdout, but want to ensure that the plugin Chris@67: // doesn't write anything itself. To do this we open a null file Chris@67: // descriptor and dup2() it into place of stdout in the gaps between Chris@67: // our own output activity. Chris@67: Chris@67: static int normalFd = -1; Chris@67: static int suspendedFd = -1; Chris@67: Chris@67: static void initFds() Chris@67: { Chris@67: #ifdef _WIN32 Chris@67: normalFd = _dup(1); Chris@67: suspendedFd = _open("NUL", _O_WRONLY); Chris@67: #else Chris@67: normalFd = dup(1); Chris@67: suspendedFd = open("/dev/null", O_WRONLY); Chris@67: #endif Chris@67: Chris@67: if (normalFd < 0 || suspendedFd < 0) { Chris@67: throw std::runtime_error Chris@67: ("Failed to initialise fds for stdio suspend/resume"); Chris@67: } Chris@67: } Chris@67: Chris@67: static void suspendOutput() Chris@67: { Chris@67: #ifdef _WIN32 Chris@67: _dup2(suspendedFd, 1); Chris@67: #else Chris@67: dup2(suspendedFd, 1); Chris@67: #endif Chris@67: } Chris@67: Chris@67: static void resumeOutput() Chris@67: { Chris@67: fflush(stdout); Chris@67: #ifdef _WIN32 Chris@67: _dup2(normalFd, 1); Chris@67: #else Chris@67: dup2(normalFd, 1); Chris@67: #endif Chris@67: } Chris@67: Chris@66: int main(int argc, char **argv) Chris@66: { Chris@66: char *scooter = argv[0]; Chris@66: char *name = 0; Chris@66: while (scooter && *scooter) { Chris@66: if (*scooter == '/' || *scooter == '\\') name = ++scooter; Chris@66: else ++scooter; Chris@66: } Chris@66: if (!name || !*name) name = argv[0]; Chris@66: Chris@66: if (argc != 2) usage(name); Chris@66: if (string(argv[1]) == string("-?")) usage(name); Chris@66: Chris@67: initFds(); Chris@67: suspendOutput(); Chris@67: Chris@66: string libraryPath(argv[1]); Chris@66: Chris@66: void *handle = Files::loadLibrary(libraryPath); Chris@66: if (!handle) { Chris@66: cerr << "Unable to load library " << libraryPath << endl; Chris@66: return 1; Chris@66: } Chris@66: Chris@66: VampGetPluginDescriptorFunction fn = Chris@66: (VampGetPluginDescriptorFunction)Files::lookupInLibrary Chris@66: (handle, "vampGetPluginDescriptor"); Chris@66: Chris@66: if (!fn) { Chris@66: cerr << "No vampGetPluginDescriptor function found in library \"" Chris@66: << libraryPath << "\"" << endl; Chris@66: Files::unloadLibrary(handle); Chris@66: return 1; Chris@66: } Chris@66: Chris@66: int index = 0; Chris@66: const VampPluginDescriptor *descriptor = 0; Chris@66: Chris@66: while ((descriptor = fn(VAMP_API_VERSION, index))) { Chris@67: resumeOutput(); Chris@66: cout << descriptor->identifier << ":" Chris@66: << descriptor->pluginVersion << endl; Chris@67: suspendOutput(); Chris@66: ++index; Chris@66: } Chris@66: Chris@66: Files::unloadLibrary(handle); Chris@66: Chris@66: return 0; Chris@66: }