| |
|
| | |
| |
|
| | #include <stdarg.h> |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <ctype.h> |
| | #include <string.h> |
| |
|
| | #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"; |
| |
|
| | |
| | static int get_p_int(const Cmd_T *cmd) |
| | { |
| | return *(const int *)cmd->p; |
| | } |
| |
|
| | |
| | static const Enum_T *get_p_enums(const Cmd_T *cmd) |
| | { |
| | return (const Enum_T *)cmd->p; |
| | } |
| |
|
| | |
| | static const char *get_p_char(const Cmd_T *cmd) |
| | { |
| | return (const char *)cmd->p; |
| | } |
| |
|
| | |
| | static const int *get_p_range(const Cmd_T *cmd) |
| | { |
| | return (const int *)cmd->p; |
| | } |
| |
|
| | |
| | static int *get_val_int_ptr(const Cmd_T *cmd) |
| | { |
| | return (int *)cmd->Val; |
| | } |
| |
|
| | |
| | static int get_val_int(const Cmd_T *cmd) |
| | { |
| | return *get_val_int_ptr(cmd); |
| | } |
| |
|
| | |
| | static void update_val_int(const Cmd_T *cmd, int value) |
| | { |
| | *get_val_int_ptr(cmd) = value; |
| | } |
| |
|
| | |
| | static double *get_val_double_ptr(const Cmd_T *cmd) |
| | { |
| | return (double *)cmd->Val; |
| | } |
| |
|
| | |
| | static double get_val_double(const Cmd_T *cmd) |
| | { |
| | return *get_val_double_ptr(cmd); |
| | } |
| |
|
| | |
| | static const char **get_val_char_ptr(const Cmd_T *cmd) |
| | { |
| | return (const char **)cmd->Val; |
| | } |
| |
|
| | |
| | static const char *get_val_char(const Cmd_T *cmd) |
| | { |
| | return *get_val_char_ptr(cmd); |
| | } |
| |
|
| | |
| | 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; j<ParamN&&(c=strcmp(cmds[j].Name,ParName))<0; j++) |
| | ; |
| | if(!c) { |
| | fprintf(stderr, |
| | "Warning: parameter \"%s\" declared twice.\n", |
| | ParName); |
| | } |
| | for(c=ParamN; c>j; 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: |
| | cmds[j].p = va_arg(args, void *); |
| | break; |
| | case CMDSUBRANGETYPE: { |
| | 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: |
| | case CMDLTETYPE: { |
| | int *value = calloc(1, sizeof(int)); |
| | cmds[j].p = value; |
| | value[0] = va_arg(args, int); |
| | } |
| | break; |
| | case CMDSTRARRAYTYPE: { |
| | 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: |
| | 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(n<get_p_int(cmd)) { |
| | GteError(cmd, n); |
| | } |
| | update_val_int(cmd, n); |
| | } |
| |
|
| | static char **str2array(const char *s, const char *sep) |
| | { |
| | const char *p; |
| | char **a; |
| | int n = 0, |
| | l; |
| |
|
| | if(!sep) sep = SepString; |
| | p = s += strspn(s, sep); |
| | while(*p) { |
| | p += strcspn(p, sep); |
| | p += strspn(p, sep); |
| | ++n; |
| | } |
| | a = calloc(n+1, sizeof(char *)); |
| | p = s; |
| | n = 0; |
| | while(*p) { |
| | l = strcspn(p, sep); |
| | a[n] = malloc(l+1); |
| | memcpy(a[n], p, l); |
| | a[n][l] = 0; |
| | ++n; |
| | p += l; |
| | p += strspn(p, sep); |
| | } |
| | return a; |
| | } |
| |
|
| | static void SetStrArray(Cmd_T *cmd, const char *s) |
| | { |
| | *(char***)cmd->Val = 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, "<NULL>") && 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-p<hl) { |
| | *q = 0; |
| | if(strcmp(p, ProgName)) { |
| | *q = '/'; |
| | return 0; |
| | } |
| | *q = '/'; |
| | HasToMatch=TRUE; |
| | p = q+1; |
| | } |
| | hl = strcspn(p, SepString); |
| | if(!hl) { |
| | return 0; |
| | } |
| | c0 = p[hl]; |
| | p[hl] = 0; |
| | for(i=0, c=1; cmds[i].Name&&(c=strcmp(cmds[i].Name, p))<0; i++) |
| | ; |
| | p[hl] = c0; |
| |
|
| | if (c) |
| | return HasToMatch && c; |
| |
|
| | SetParam(cmds+i, p+hl+strspn(p+hl, SepString)); |
| | return 0; |
| | } |
| |
|
| | static void PrintEnum(const Cmd_T *cmd, int ValFlag, FILE *fp) |
| | { |
| | const Enum_T *en; |
| |
|
| | fprintf(fp, "%s", cmd->Name); |
| | 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; |
| | } |
| |
|