// $Id$ #include #include #include #include #include #include "cmd.h" #ifdef WIN32 # define popen _popen # define pclose _pclose #endif typedef struct { enum CommandType Type; const char *Name, *ArgStr; void *Val; const void *p; } Cmd_T; static const Enum_T BoolEnum[] = { { "FALSE", 0 }, { "TRUE", 1 }, { 0, 0 } }; #ifdef NEEDSTRDUP char *strdup(); #endif #define FALSE 0 #define TRUE 1 #define LINSIZ 10240 #define MAXPARAM 256 static Cmd_T cmds[MAXPARAM+1]; static const char *SepString = " \t\n"; /// Return cmd->p, as an int. static int get_p_int(const Cmd_T *cmd) { return *(const int *)cmd->p; } /// Return cmd->p, as a pointer to a null-terminated array of Enum_T. static const Enum_T *get_p_enums(const Cmd_T *cmd) { return (const Enum_T *)cmd->p; } /// Return cmd->p, as a pointer to a string. static const char *get_p_char(const Cmd_T *cmd) { return (const char *)cmd->p; } /// Return cmd->p, as a pointer to an array of two ints. static const int *get_p_range(const Cmd_T *cmd) { return (const int *)cmd->p; } /// Return cmd->Val, as a pointer to int. static int *get_val_int_ptr(const Cmd_T *cmd) { return (int *)cmd->Val; } /// Return the int at which cmd->Val points. static int get_val_int(const Cmd_T *cmd) { return *get_val_int_ptr(cmd); } /// Update the int at which cmd->Val points. static void update_val_int(const Cmd_T *cmd, int value) { *get_val_int_ptr(cmd) = value; } /// Return cmd->Val, as a pointer to double. static double *get_val_double_ptr(const Cmd_T *cmd) { return (double *)cmd->Val; } /// Return the double at which cmd->Val points. static double get_val_double(const Cmd_T *cmd) { return *get_val_double_ptr(cmd); } /// Return cmd->Val as a pointer to a string pointer. static const char **get_val_char_ptr(const Cmd_T *cmd) { return (const char **)cmd->Val; } /// Return the string pointer at which cmd->Val points. static const char *get_val_char(const Cmd_T *cmd) { return *get_val_char_ptr(cmd); } /// Update the string pointer at which cmd->Val points. static void update_val_char(const Cmd_T *cmd, const char *s) { *get_val_char_ptr(cmd) = s; } int DeclareParams(const char *ParName, ...) { va_list args; static int ParamN = 0; va_start(args, ParName); for(; ParName;) { int c, j = 0; if(ParamN==MAXPARAM) { fprintf(stderr, "Too many parameters !!\n"); break; } for(c=1; jj; c--) { cmds[c] = cmds[c-1]; } cmds[j].Name = ParName; cmds[j].Type = va_arg(args, enum CommandType); cmds[j].Val = va_arg(args, void *); switch(cmds[j].Type) { case CMDENUMTYPE: /* get the pointer to Enum_T struct */ cmds[j].p = va_arg(args, void *); break; case CMDSUBRANGETYPE: { /* get the two extremes */ int *subrange = calloc(2, sizeof(int)); cmds[j].p = subrange; subrange[0] = va_arg(args, int); subrange[1] = va_arg(args, int); } break; case CMDGTETYPE: /* get lower or upper bound */ case CMDLTETYPE: { int *value = calloc(1, sizeof(int)); cmds[j].p = value; value[0] = va_arg(args, int); } break; case CMDSTRARRAYTYPE: { /* get the separators string */ const char *s = va_arg(args, const char *); cmds[j].p = (s ? strdup(s) : NULL); } break; case CMDBOOLTYPE: cmds[j].Type = CMDENUMTYPE; cmds[j].p = BoolEnum; break; case CMDDOUBLETYPE: /* nothing else is needed */ case CMDINTTYPE: case CMDSTRINGTYPE: break; default: fprintf(stderr, "%s: %s %d %s \"%s\"\n", "DeclareParam()", "Unknown Type", cmds[j].Type, "for parameter", cmds[j].Name); exit(1); } ParamN++; ParName = va_arg(args, const char *); } cmds[ParamN].Name = NULL; va_end(args); return 0; } static char *GetLine(FILE *fp, int n, char *Line) { int offs=0; for(;;) { int j, l; if(!fgets(Line+offs, n-offs, fp)) { return NULL; } if(Line[offs]=='#') continue; l = strlen(Line+offs)-1; Line[offs+l] = 0; for(j=offs; Line[j] && isspace(Line[j]); j++, l--) ; if(l<1) continue; if(j > offs) { char *s = Line+offs, *q = Line+j; while((*s++=*q++)) ; } if(Line[offs+l-1]=='\\') { offs += l; Line[offs-1] = ' '; } else { break; } } return Line; } static void EnumError(const Cmd_T *cmd, const char *s) { const Enum_T *en; fprintf(stderr, "Invalid value \"%s\" for parameter \"%s\"\n", s, cmd->Name); fprintf(stderr, "Valid values are:\n"); for(en=get_p_enums(cmd); en->Name; en++) { if(*en->Name) { fprintf(stderr, " %s\n", en->Name); } } fprintf(stderr, "\n"); exit(1); } static void GteError(const Cmd_T *cmd, int n) { fprintf(stderr, "Value %d out of range for parameter \"%s\"\n", n, cmd->Name); fprintf(stderr, "Valid values must be greater than or equal to %d\n", get_p_int(cmd)); exit(1); } static void LteError(const Cmd_T *cmd, int n) { fprintf(stderr, "Value %d out of range for parameter \"%s\"\n", n, cmd->Name); fprintf(stderr, "Valid values must be less than or equal to %d\n", get_p_int(cmd)); exit(1); } static void SubrangeError(const Cmd_T *cmd, int n) { const int *subrange = get_p_range(cmd); fprintf(stderr, "Value %d out of range for parameter \"%s\"\n", n, cmd->Name); fprintf(stderr, "Valid values range from %d to %d\n", subrange[0], subrange[1]); exit(1); } static void SetEnum(Cmd_T *cmd, const char *s) { const Enum_T *en; for(en=get_p_enums(cmd); en->Name; en++) { if(*en->Name && !strcmp(s, en->Name)) { update_val_int(cmd, en->Idx); return; } } EnumError(cmd, s); } static void SetSubrange(Cmd_T *cmd, const char *s) { int n; const int *subrange = get_p_range(cmd); if(sscanf(s, "%d", &n)!=1) { fprintf(stderr, "Integer value required for parameter \"%s\"\n", cmd->Name); exit(1); } if(n < subrange[0] || n > subrange[1]) { SubrangeError(cmd, n); } update_val_int(cmd, n); } static void SetGte(Cmd_T *cmd, const char *s) { int n; if(sscanf(s, "%d", &n)!=1) { fprintf(stderr, "Integer value required for parameter \"%s\"\n", cmd->Name); exit(1); } if(nVal = str2array(s, get_p_char(cmd)); } static void SetLte(Cmd_T *cmd, const char *s) { int n; if(sscanf(s, "%d", &n)!=1) { fprintf(stderr, "Integer value required for parameter \"%s\"\n", cmd->Name); exit(1); } if(n > get_p_int(cmd)) { LteError(cmd, n); } update_val_int(cmd, n); } static void SetParam(Cmd_T *cmd, const char *s) { if(!*s && cmd->Type != CMDSTRINGTYPE) { fprintf(stderr, "WARNING: No value specified for parameter \"%s\"\n", cmd->Name); return; } switch(cmd->Type) { case CMDDOUBLETYPE: if(sscanf(s, "%lf", get_val_double_ptr(cmd))!=1) { fprintf(stderr, "Float value required for parameter \"%s\"\n", cmd->Name); exit(1); } break; case CMDENUMTYPE: SetEnum(cmd, s); break; case CMDINTTYPE: if(sscanf(s, "%d", get_val_int_ptr(cmd))!=1) { fprintf(stderr, "Integer value required for parameter \"%s\"\n", cmd->Name); exit(1); } break; case CMDSTRINGTYPE: update_val_char(cmd, (strcmp(s, "") && strcmp(s, "NULL")) ? strdup(s) : 0); break; case CMDSTRARRAYTYPE: SetStrArray(cmd, s); break; case CMDGTETYPE: SetGte(cmd, s); break; case CMDLTETYPE: SetLte(cmd, s); break; case CMDSUBRANGETYPE: SetSubrange(cmd, s); break; default: fprintf(stderr, "%s: %s %d %s \"%s\"\n", "SetParam", "Unknown Type", cmd->Type, "for parameter", cmd->Name); exit(1); } cmd->ArgStr = strdup(s); } static int Scan(const char *ProgName, Cmd_T *cmds, char *Line) { char *q, *p; int i, hl, HasToMatch = FALSE, c0, c; p = Line+strspn(Line, SepString); hl = strcspn(p, SepString); if(!hl) { return 0; } q = strchr(p, '/'); if(q && q-pName); if(ValFlag) { for(en=get_p_enums(cmd); en->Name; en++) { if(*en->Name && en->Idx==get_val_int(cmd)) { fprintf(fp, ": %s", en->Name); } } } fprintf(fp, "\n"); } static void PrintStrArray(const Cmd_T *cmd, int ValFlag, FILE *fp) { char *indent, **s = *(char***)cmd->Val; int l = 4+strlen(cmd->Name); fprintf(fp, "%s", cmd->Name); indent = malloc(l+2); memset(indent, ' ', l+1); indent[l+1] = 0; if(ValFlag) { fprintf(fp, ": %s", s ? (*s ? *s++ : "NULL") : ""); if(s) while(*s) { fprintf(fp, "\n%s %s", indent, *s++); } } free(indent); fprintf(fp, "\n"); } static void PrintParam(const Cmd_T *cmd, int ValFlag, FILE *fp) { fprintf(fp, "%4s", ""); switch(cmd->Type) { case CMDDOUBLETYPE: fprintf(fp, "%s", cmd->Name); if(ValFlag) fprintf(fp, ": %22.15e", get_val_double(cmd)); fprintf(fp, "\n"); break; case CMDENUMTYPE: PrintEnum(cmd, ValFlag, fp); break; case CMDINTTYPE: case CMDSUBRANGETYPE: case CMDGTETYPE: case CMDLTETYPE: fprintf(fp, "%s", cmd->Name); if(ValFlag) fprintf(fp, ": %d", get_val_int(cmd)); fprintf(fp, "\n"); break; case CMDSTRINGTYPE: fprintf(fp, "%s", cmd->Name); if(ValFlag) { const char *value = get_val_char(cmd); if(value) { fprintf(fp, ": \"%s\"", value); } else { fprintf(fp, ": %s", "NULL"); } } fprintf(fp, "\n"); break; case CMDSTRARRAYTYPE: PrintStrArray(cmd, ValFlag, fp); break; default: fprintf(stderr, "%s: %s %d %s \"%s\"\n", "PrintParam", "Unknown Type", cmd->Type, "for parameter", cmd->Name); exit(1); } } static void PrintParams(int ValFlag, FILE *fp) { int i; fflush(fp); if(ValFlag) { fprintf(fp, "Parameters Values:\n"); } else { fprintf(fp, "Parameters:\n"); } for(i=0; cmds[i].Name; i++) PrintParam(cmds+i, ValFlag, fp); fprintf(fp, "\n"); fflush(fp); } static void CmdError(const char *opt) { fprintf(stderr, "Invalid option \"%s\"\n", opt); fprintf(stderr, "This program expectes the following parameters:\n"); PrintParams(FALSE, stderr); exit(0); } int GetParams(int *n, char ***a, const char *CmdFileName) { char *Line, *ProgName; int argc = *n; char **argv = *a, *s; FILE *fp; int IsPipe; #ifdef MSDOS #define PATHSEP '\\' char *dot = NULL; #else #define PATHSEP '/' #endif if(!(Line=malloc(LINSIZ))) { fprintf(stderr, "GetParams(): Unable to alloc %d bytes\n", LINSIZ); exit(1); } if((ProgName=strrchr(*argv, PATHSEP))) { ++ProgName; } else { ProgName = *argv; } #ifdef MSDOS if(dot=strchr(ProgName, '.')) *dot = 0; #endif --argc; ++argv; for(;;) { if(argc && argv[0][0]=='-' && argv[0][1]=='=') { CmdFileName = argv[0]+2; ++argv; --argc; } if(!CmdFileName) { break; } IsPipe = !strncmp(CmdFileName, "@@", 2); fp = IsPipe ? popen(CmdFileName+2, "r") : strcmp(CmdFileName, "-") ? fopen(CmdFileName, "r") : stdin; if(!fp) { fprintf(stderr, "Unable to open command file %s\n", CmdFileName); exit(1); } while(GetLine(fp, LINSIZ, Line) && strcmp(Line, "\\End")) { if(Scan(ProgName, cmds, Line)) { CmdError(Line); } } if(fp!=stdin) { if(IsPipe) pclose(fp); else fclose(fp); } CmdFileName = NULL; } while(argc && **argv=='-' && (s=strchr(*argv, '='))) { *s = ' '; sprintf(Line, "%s/%s", ProgName, *argv+1); *s = '='; if(Scan(ProgName, cmds, Line)) CmdError(*argv); --argc; ++argv; } *n = argc; *a = argv; #ifdef MSDOS if(dot) *dot = '.'; #endif free(Line); return 0; }