📄 cmdoptions.cpp
字号:
// $common\cmdoptions.cpp 1.5 milbo$ routines for processing command line options// Warning: this is raw research code -- expect it to be quite messy.// milbo dec05 durban#include <stdio.h>#include <stdlib.h>#include <io.h>#include <math.h>#include <stdarg.h>#include <string.h>#include "mcommon.hpp"#include "util.hpp"//-----------------------------------------------------------------------------// Get a string option from the command line.//// On entry argv should be say "-fx foo" where sFlag is "-f" and "x" is one of the// flags in sFlags. We will set the argument corresponding the position of "x"// in sFlags to "foo".//// The string can't begin with "-" because a common mistake is to leave out the string// and then the next option looks like the string.//// TODO bug: the strings have to be on the stack else this routine will overwrite variables around the strings?void __cdecl GetOptString (int *pArgc, const char ***pArgv, char cFlag, char sFlags[], int Len, char sFirst[], ...){va_list marker;va_start(marker, sFirst);char cUserFlag = (**pArgv + 1)[1]; // this corresponds to "x" in header commentchar *pOpt = sFirst;// point pOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the string // If there's an error, call Err() which will exit the program if (--(*pArgc) < 1) Err("-%c%c should be followed by a string." " Use -? for help", cFlag, cUserFlag); ++*pArgv; if ((**pArgv)[0] == '-') Err("-%c%c should be followed by a string" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); strncpy(pOpt, **pArgv, Len - 1); break; } pOpt = va_arg(marker, char *); }va_end(marker);if (!sFlags[i]) Err("-%c should be followed by %s%s (you have -%c%c). Example \"-%c%c STRING\". Use -? for help.", cFlag, (sFlags[1]? "by one of ": ""), sFlags, cFlag, cUserFlag, cFlag, sFlags[0]);}//-----------------------------------------------------------------------------// Get a bool option from the command line// On entry argv should be say "-fx 1" where sFlag is "-f" and "x" is one of the// flags in sFlags. We will set the argument corresponding the position of "x"// in sFlags to "1".void __cdecl GetOptBool (int *pArgc, const char ***pArgv, char cFlag, char sFlags[], bool *pbFirst, ...){va_list marker;va_start(marker, pbFirst);char cUserFlag = (**pArgv + 1)[1]; // this corresponds to "x" in header commentbool *pbOpt = pbFirst;// point pbOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the 0 or 1 value // If there's an error, call Err() which will exit the program (*pArgv)++; int iTemp; if (--(*pArgc) < 1 || sscanf(**pArgv, "%d", &iTemp) != 1 || (iTemp != 0 && iTemp != 1)) Err("-%c%c should be followed by 0 or 1 (you have -%c%c %s)." " Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv);// disable warning: 'int':forcing value to bool 'true' or 'false'#pragma warning(disable:4800) *pbOpt = (bool)(iTemp);// reenable the warning#pragma warning(default:4800) break; } pbOpt = va_arg(marker, bool *); }va_end(marker);if (!sFlags[i]) Err("-%c should be followed %s%s (you have -%c%c). Example \"-%c%c 0\". Use -? for help.", cFlag, (sFlags[1]? "by one of ": ""), sFlags, cFlag, cUserFlag, cFlag, sFlags[0]);}//-----------------------------------------------------------------------------// Get an integer option from the command line// On entry argv should be say "-gx 23" where sFlag is "-g" and "x" is one of the// flags in sFlags. We will set the argument corresponding the position of "x"// in sFlags to "23".// pFirst should be the first of a list of tIntOpt arguments (see below).//// This routine isn't portable (I couldn't get va_arg to work with tIntOpt).void __cdecl GetOptInt (int *pArgc, const char ***pArgv, char cFlag, char sFlags[], void *piFirst, ...){typedef struct tIntOpt {int *pi; int fHardLimit; int iMin; int iMax; } tIntOpt;char cUserFlag = (**pArgv + 1)[1]; // this corresponds to "x" in header commenttIntOpt *pOpt = (tIntOpt *)&piFirst;// point pOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the integer value // If there's an error, call Err() which will exit the program int iTemp; if (--(*pArgc) < 1) Err("-%c%c should be followed by an integer." " Use -? for help.", cFlag, cUserFlag); if (sscanf(*(++*pArgv), "%d", &iTemp) != 1) Err("-%c%c should be followed by an integer (you have -%c%c %s)." " Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); if (iTemp < pOpt->iMin || iTemp > pOpt->iMax) { if (pOpt->fHardLimit) { if (pOpt->iMin == 1) Err("-%c%c should be followed by a positive integer less than %d" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->iMax+1, cFlag, cUserFlag, **pArgv); else Err("-%c%c should be followed by an integer between %d and %d" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->iMin, pOpt->iMax, cFlag, cUserFlag, **pArgv); } else { if (pOpt->iMin == 1) Err("-%c%c should be followed by a positive integer" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); else Err("-%c%c should be followed by an integer" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); } } *(pOpt->pi) = iTemp; break; } pOpt++; // not portable: assumes stack grows up and is aligned like structures }if (!sFlags[i]) Err("-%c should be followed by %s%s (you have -%c%c). Example \"-%c%c NUMBER\". Use -? for help.", cFlag, (sFlags[1]? "by one of ": ""), sFlags, cFlag, cUserFlag, cFlag, sFlags[0]);}//-----------------------------------------------------------------------------// Same as GetOpInt but no cFlag paramvoid __cdecl GetOptInt1 (int *pArgc, const char ***pArgv, char sFlags[], void *piFirst, ...){typedef struct tIntOpt {int *pi; int fHardLimit; int iMin; int iMax; } tIntOpt;char cUserFlag = (**pArgv + 1)[0]; // this corresponds to "x" in header commenttIntOpt *pOpt = (tIntOpt *)&piFirst;// point pOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the integer value // If there's an error, call Err() which will exit the program int iTemp; if (--(*pArgc) < 1) Err("-%c should be followed by an integer." " Use -? for help.", cUserFlag); if (sscanf(*(++*pArgv), "%d", &iTemp) != 1) Err("-%c should be followed by an integer (you have -%c %s)." " Use -? for help.", cUserFlag, cUserFlag, **pArgv); if (iTemp < pOpt->iMin || iTemp > pOpt->iMax) { if (pOpt->fHardLimit) { if (pOpt->iMin == 1) Err("-%c should be followed by a positive integer less than %d" " (you have -%c %s). Use -? for help.", cUserFlag, pOpt->iMax+1, cUserFlag, **pArgv); else Err("-%c should be followed by an integer between %d and %d" " (you have -%c %s). Use -? for help.", cUserFlag, pOpt->iMin, pOpt->iMax, cUserFlag, **pArgv); } else { if (pOpt->iMin == 1) Err("-%c should be followed by a positive integer" " (you have -%c %s). Use -? for help.", cUserFlag, cUserFlag, **pArgv); else Err("-%c should be followed by an integer" " (you have -%c %s). Use -? for help.", cUserFlag, cUserFlag, **pArgv); } } *(pOpt->pi) = iTemp; break; } pOpt++; // not portable: assumes stack grows up and is aligned like structures }#if 0if (!sFlags[i]) Err("Expecting %s%s (you have -%c). Example \"-%c NUMBER\".", (sFlags[1]? "one of ": ""), sFlags, cUserFlag, sFlags[0]);#endif}//-----------------------------------------------------------------------------// Get an hex integer option from the command line// On entry argv should be say "-gx 23" where sFlag is "-g" and "x" is one of the// flags in sFlags. We will set the argument corresponding the position of "x"// in sFlags to "23".// pFirst should be the first of a list of tIntOpt arguments (see below).//// This routine isn't portable (I couldn't get va_arg to work with tIntOpt).void __cdecl GetOptHex (int *pArgc, const char ***pArgv, char cFlag, char sFlags[], void *piFirst, ...){typedef struct tHexOpt {int *pi; int fHardLimit; int iMin; int iMax; } tHexOpt;char cUserFlag = (**pArgv + 1)[1]; // this corresponds to "x" in header commenttHexOpt *pOpt = (tHexOpt *)&piFirst;// point pOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the integer value // If there's an error, call Err() which will exit the program int iTemp; if (--(*pArgc) < 1) Err("-%c%c should be followed by a hex integer." " Use -? for help.", cFlag, cUserFlag); if (sscanf(*(++*pArgv), "%x", &iTemp) != 1) Err("-%c%c should be followed by a hex integer (you have -%c%c %s)." " Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); if (iTemp < pOpt->iMin || iTemp > pOpt->iMax) { if (pOpt->fHardLimit) { if (pOpt->iMin == 1) Err("-%c%c should be followed by a positive hex integer less than %x" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->iMax+1, cFlag, cUserFlag, **pArgv); else Err("-%c%c should be followed by an hex integer between %x and %x" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->iMin, pOpt->iMax, cFlag, cUserFlag, **pArgv); } else { if (pOpt->iMin == 1) Err("-%c%c should be followed by a positive hex integer" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); else Err("-%c%c should be followed by a hex integer" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); } } *(pOpt->pi) = iTemp; break; } pOpt++; // not portable: assumes stack grows up and is aligned like structures }if (!sFlags[i]) Err("-%c should be followed by %s%s (you have -%c%c). Example \"-%c%c HEX\". Use -? for help.", cFlag, (sFlags[1]? "by one of ": ""), sFlags, cFlag, cUserFlag, cFlag, sFlags[0]);}//-----------------------------------------------------------------------------// Get a double option from the command line// On entry argv should be say "-fx 2.3" where sFlag is "-f" and "x" is one of the// flags in sFlags. We will set the argument corresponding the position of "x"// in sFlags to "2.3".// pFirst should be the first of a list of tDoubleOpt arguments (see below).//// This routine isn't portable (I couldn't get va_arg to work with tDoubleOpt).void __cdecl GetOptDouble (int *pArgc, const char ***pArgv, char cFlag, char sFlags[], void *pFirst, ...){typedef struct tDoubleOpt {double *pDouble; int fHardLimit; double Min; double Max; } tDoubleOpt;char cUserFlag = (**pArgv + 1)[1]; // this corresponds to "x" in header commenttDoubleOpt *pOpt = (tDoubleOpt *)&pFirst;// point pOpt to the function argument that matches "x"for (int i = 0; sFlags[i]; i++) { if (cUserFlag == sFlags[i]) { // Found the matching flag, now read the double value // If there's an error, call Err() which will exit the program float temp;// Microsoft doesn't provide scanf for double so use a float if (--(*pArgc) < 1) Err("-%c%c should be followed by a float." " Use -? for help.", cFlag, cUserFlag); if (sscanf(*(++*pArgv), "%.3g", &temp) != 1) Err("-%c%c should be followed by a float" " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, cFlag, cUserFlag, **pArgv); if (temp < pOpt->Min || temp > pOpt->Max) { if (pOpt->fHardLimit) Err("-%c%c should be followed by a float between %.3g and %.3g." " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->Min, pOpt->Max, cFlag, cUserFlag, **pArgv); else Err("-%c%c should be followed by a reasonable float." " (you have -%c%c %s). Use -? for help.", cFlag, cUserFlag, pOpt->Max, cFlag, cUserFlag, **pArgv); } *(pOpt->pDouble) = (double)temp; break; } pOpt++; // not portable: assumes stack grows up and is aligned like structures }if (!sFlags[i]) Err("-%c should be followed by %s%s. Example \"-%c%c FLOAT\". Use -? for help.", cFlag, (sFlags[1]? "by one of ": ""), sFlags, cFlag, sFlags[0]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -