📄 getopt.cpp
字号:
// Input:// option:// The option the user typed (without the leading "--", but with// any trailing argument attached by an '=')//// Returns:// A pointer to the corresponding GetOpt::Option// NULL if no option matched// If more than one option might match, calls reportError and then// returns NULL.const GetOpt::Option* GetOpt::findLongOption(const char* option){ const Option* op = optionList; const Option* possibleMatch = NULL; bool ambiguous = false; while (op->shortName || op->longName) { if (op->longName) { bool partial = false; const char* u = option; const char* o = op->longName; for (;;) { if (!*u || *u == '=') { // Reached end of user entry if (*o || partial) { if (possibleMatch) ambiguous = true; // 2 possible matches possibleMatch = op; break; // Found possible match, keep going } else return op; // Exact match! } else if (!*o) { break; // Not a match } else if (*u == *o) { ++u; ++o; } else if (*u == '-') { partial = true; while (*(++o)) if (*o == '-') break; } else break; // Not a match } // end forever } // end if option has a longName ++op; } // end while more options // We didn't find an exact match, what about a possible one? if (possibleMatch) { if (ambiguous) { // More than one possible match found reportError(argv[argi], " is ambiguous"); return NULL; } return possibleMatch; // Found just one possible match } // end if possibleMatch return NULL; // Found no matches at all} // end GetOpt::findLongOption//--------------------------------------------------------------------// Determine what Option a short option refers to://// Input:// option: The option to look for//// Returns:// A pointer to the corresponding GetOpt::Option// NULL if no option matchedconst GetOpt::Option* GetOpt::findShortOption(char option) const{ const Option* op = optionList; while (op->shortName || op->longName) { if (op->shortName == option) return op; ++op; } return NULL;} // end GetOpt::findShortOption//--------------------------------------------------------------------// Find the next argument to process://// If returningAll is not NULL, this returns all arguments in order.// Otherwise, the options (and their arguments) are moved before the// non-option arguments, but this function still returns all arguments.//// Output:// option: Points to the option (after any option start characters)// type: The type of option found// optArg: Normal argument (not an option)// optLong: A long option// optShort: A single-character option// posArg: The index of a possible argument for this option// 0 means use argi+1//// Returns:// true: Found an option or normal argument to be returned// false: No more arguments (option & type are undefined in this case)bool GetOpt::nextOption(const char*& option, Type& type, int& posArg){ posArg = 0; if (chari) { if (argv[argi][++chari]) { option = argv[argi] + chari; type = optShort; return true; } chari = 0; // We've reached the end of a short option bundle } // end if processing a short option bundle if (++argi >= argc) return false; // No more options const char* arg = argv[argi]; if (!normalOnly) { if (*arg && strchr(optionStart, *arg)) { foundOptionStart: if (!strncmp(longOptionStart, arg, sizeof(longOptionStart)-1)) { option = arg+2; type = optLong; return true; } if (arg[1]) { chari = 1; option = arg+1; type = optShort; return true; } } // end if arg begins with option start character if (!returningAll) { // Look for another option argument for (int i = argi+1; i < argc; ++i) { if (argv[i][0] && strchr(optionStart, argv[i][0])) { // We found another option, move it before the other args: posArg = i + 1; arg = argv[i]; while (--i >= argi) argv[i+1] = argv[i]; argv[argi] = arg; goto foundOptionStart; } // end if we found another option argument } // end for remaining arguments normalOnly = true; // There are no more option arguments } // end if not returning all arguments in order } // end if still looking for options option = arg; type = optArg; return true;} // end GetOpt::nextOption//--------------------------------------------------------------------// Return the next argument to process://// If returningAll is not NULL, this returns all arguments in order.// Otherwise, it returns only the options, which are moved before the// non-option arguments, and returns false when it runs out of options.//// Output:// option: Points to the GetOpt::Option selected by the user// asEntered: The actual text the user typed//// Returns:// true: Found an option or normal argument to be returned// false: No more arguments match the option listbool GetOpt::nextOption(const Option*& option, const char*& asEntered){ const char* arg; Type type; int posArg; nextArg: if (!nextOption(arg, type, posArg)) return false; if (type == optLong && !*arg) { normalOnly = true; goto nextArg; } // end if "--" by itself (no more options) if (type == optShort) { shortOptionBuf[0] = argv[argi][0]; shortOptionBuf[1] = *arg; shortOptionBuf[2] = 0; asEntered = shortOptionBuf; option = findShortOption(*arg); } else { asEntered = argv[argi]; if (type == optArg) option = returningAll; else option = findLongOption(arg); } if (!option) { if ((type != optArg) && !error) reportError(asEntered, " is not a recognized option"); return false; } if (option->found && *option->found && !(option->flag & GetOpt::repeatable)) { reportError(asEntered, " cannot be repeated"); return false; } Found found = noArg; if (option->function) { int usedChars = -1; int* mayUseChars = NULL; Connection connect = nextArg; if (!posArg) posArg = argi + 1; if (type != optArg) { if ((type == optShort) && argv[argi][chari+1]) { mayUseChars = &usedChars; arg = argv[argi] + chari + 1; if (*arg == '=') { ++arg; connect = withEquals; } else connect = adjacent; } else if ((type == optLong) && (arg = strchr(arg, '='))) { ++arg; // Skip over equals connect = withEquals; } else if (posArg < argc) arg = argv[posArg]; else if (option->flag & GetOpt::needArg) { reportError(asEntered, " requires an argument"); return false; } else arg = NULL; } // end if option (not normal argument) if ((*(option->function))(this, option, asEntered, connect, arg, mayUseChars)) { found = withArg; if (usedChars >= 0) chari += usedChars; else { chari = 0; if ((type != optArg) && (connect == nextArg) && arg) { ++argi; // If we moved the option, we need to move the argument: while (--posArg >= argi) argv[posArg+1] = argv[posArg]; argv[argi] = arg; } // end if used next argument } // end else didn't use just some of the characters in a bundle } // end if found option else if ((option->flag & GetOpt::needArg) && !error) { reportError(asEntered, " requires an argument"); return false; } } // end if option has function to call if (option->found) *(option->found) = found; return true;} // end GetOpt::nextOption//--------------------------------------------------------------------// Report (and possibly print) an error://// This sets error to true and then calls the errorOutput function (if// that is not NULL). The errorOutput function (normally printError)// is expected to print both its arguments (see printError).//// Your callback functios should call reportError to report any errors// they encounter. If printing error messages to stderr is not// appropriate for your application, then set errorOutput to a// suitable function, or to NULL to suppress error messages// altogether.//// Input:// option: The option that caused a problem// message: The problem that was encounteredvoid GetOpt::reportError(const char* option, const char* message){ error = true; if (errorOutput) (*errorOutput)(option, message);} // end GetOpt::reportError//--------------------------------------------------------------------// Process a command line://// This is the standard entry point for GetOpt. Most programs will// just call the constructor to set up the option list and then call// process, relying on callbacks to store the results.//// Input:// theArgc:// The number of elements in theArgv// theArgv:// The program name & command line arguments.// theArgv[0] (the program name) is not used and may be NULL.// This array is not copied, and must exist as long as the GetOpt// object is in use.//// Returns:// The index (into theArgv) of the first argument that was not// processed by GetOpt. If this is >= theArgc, then all arguments// were processed. (This is the same value that would be returned// by currentArg().)int GetOpt::process(int theArgc, const char** theArgv){ const Option* option; const char* asEntered; init(theArgc, theArgv); while (nextOption(option, asEntered)) ; return argi;} // end GetOpt::process
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -