diff options
Diffstat (limited to 'symal/cmd.cpp')
-rw-r--r-- | symal/cmd.cpp | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/symal/cmd.cpp b/symal/cmd.cpp new file mode 100644 index 000000000..76c93f490 --- /dev/null +++ b/symal/cmd.cpp @@ -0,0 +1,642 @@ + +// $Id$ + +#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"; + +/// 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; 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: /* get the pointer to Enum_T struct */ + cmds[j].p = va_arg(args, void *); + break; + case CMDSUBRANGETYPE: { /* get the two extremes */ + int *subrange = (int*) 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 = (int*) 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(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 = (char **) calloc(n+1, sizeof(char *)); + p = s; + n = 0; + while(*p) { + l = strcspn(p, sep); + a[n] = (char *) 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 = (char *) 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=(char *) 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; +} |