00001
00002
00003
00004 #include <stdarg.h>
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <ctype.h>
00008 #include <string.h>
00009
00010 #include "cmd.h"
00011
00012 #ifdef WIN32
00013 # define popen _popen
00014 # define pclose _pclose
00015 #endif
00016
00017 typedef struct {
00018 enum CommandType Type;
00019 const char *Name,
00020 *ArgStr;
00021 void *Val;
00022 const void *p;
00023 } Cmd_T;
00024
00025 static const Enum_T BoolEnum[] = {
00026 { "FALSE", 0 },
00027 { "TRUE", 1 },
00028 { 0, 0 }
00029 };
00030
00031 #ifdef NEEDSTRDUP
00032 char *strdup();
00033 #endif
00034
00035 #define FALSE 0
00036 #define TRUE 1
00037
00038 #define LINSIZ 10240
00039 #define MAXPARAM 256
00040
00041 static Cmd_T cmds[MAXPARAM+1];
00042 static const char *SepString = " \t\n";
00043
00045 static int get_p_int(const Cmd_T *cmd)
00046 {
00047 return *(const int *)cmd->p;
00048 }
00049
00051 static const Enum_T *get_p_enums(const Cmd_T *cmd)
00052 {
00053 return (const Enum_T *)cmd->p;
00054 }
00055
00057 static const char *get_p_char(const Cmd_T *cmd)
00058 {
00059 return (const char *)cmd->p;
00060 }
00061
00063 static const int *get_p_range(const Cmd_T *cmd)
00064 {
00065 return (const int *)cmd->p;
00066 }
00067
00069 static int *get_val_int_ptr(const Cmd_T *cmd)
00070 {
00071 return (int *)cmd->Val;
00072 }
00073
00075 static int get_val_int(const Cmd_T *cmd)
00076 {
00077 return *get_val_int_ptr(cmd);
00078 }
00079
00081 static void update_val_int(const Cmd_T *cmd, int value)
00082 {
00083 *get_val_int_ptr(cmd) = value;
00084 }
00085
00087 static double *get_val_double_ptr(const Cmd_T *cmd)
00088 {
00089 return (double *)cmd->Val;
00090 }
00091
00093 static double get_val_double(const Cmd_T *cmd)
00094 {
00095 return *get_val_double_ptr(cmd);
00096 }
00097
00099 static const char **get_val_char_ptr(const Cmd_T *cmd)
00100 {
00101 return (const char **)cmd->Val;
00102 }
00103
00105 static const char *get_val_char(const Cmd_T *cmd)
00106 {
00107 return *get_val_char_ptr(cmd);
00108 }
00109
00111 static void update_val_char(const Cmd_T *cmd, const char *s)
00112 {
00113 *get_val_char_ptr(cmd) = s;
00114 }
00115
00116 int DeclareParams(const char *ParName, ...)
00117 {
00118 va_list args;
00119 static int ParamN = 0;
00120
00121 va_start(args, ParName);
00122 for(; ParName;) {
00123 int c,
00124 j = 0;
00125 if(ParamN==MAXPARAM) {
00126 fprintf(stderr, "Too many parameters !!\n");
00127 break;
00128 }
00129 for(c=1; j<ParamN&&(c=strcmp(cmds[j].Name,ParName))<0; j++)
00130 ;
00131 if(!c) {
00132 fprintf(stderr,
00133 "Warning: parameter \"%s\" declared twice.\n",
00134 ParName);
00135 }
00136 for(c=ParamN; c>j; c--) {
00137 cmds[c] = cmds[c-1];
00138 }
00139 cmds[j].Name = ParName;
00140 cmds[j].Type = va_arg(args, enum CommandType);
00141 cmds[j].Val = va_arg(args, void *);
00142 switch(cmds[j].Type) {
00143 case CMDENUMTYPE:
00144 cmds[j].p = va_arg(args, void *);
00145 break;
00146 case CMDSUBRANGETYPE: {
00147 int *subrange = calloc(2, sizeof(int));
00148 cmds[j].p = subrange;
00149 subrange[0] = va_arg(args, int);
00150 subrange[1] = va_arg(args, int);
00151 }
00152 break;
00153 case CMDGTETYPE:
00154 case CMDLTETYPE: {
00155 int *value = calloc(1, sizeof(int));
00156 cmds[j].p = value;
00157 value[0] = va_arg(args, int);
00158 }
00159 break;
00160 case CMDSTRARRAYTYPE: {
00161 const char *s = va_arg(args, const char *);
00162 cmds[j].p = (s ? strdup(s) : NULL);
00163 }
00164 break;
00165 case CMDBOOLTYPE:
00166 cmds[j].Type = CMDENUMTYPE;
00167 cmds[j].p = BoolEnum;
00168 break;
00169 case CMDDOUBLETYPE:
00170 case CMDINTTYPE:
00171 case CMDSTRINGTYPE:
00172 break;
00173 default:
00174 fprintf(stderr, "%s: %s %d %s \"%s\"\n",
00175 "DeclareParam()", "Unknown Type",
00176 cmds[j].Type, "for parameter", cmds[j].Name);
00177 exit(1);
00178 }
00179 ParamN++;
00180 ParName = va_arg(args, const char *);
00181 }
00182 cmds[ParamN].Name = NULL;
00183 va_end(args);
00184 return 0;
00185 }
00186
00187 static char *GetLine(FILE *fp, int n, char *Line)
00188 {
00189 int offs=0;
00190
00191 for(;;) {
00192 int j, l;
00193 if(!fgets(Line+offs, n-offs, fp)) {
00194 return NULL;
00195 }
00196 if(Line[offs]=='#') continue;
00197 l = strlen(Line+offs)-1;
00198 Line[offs+l] = 0;
00199 for(j=offs; Line[j] && isspace(Line[j]); j++, l--)
00200 ;
00201 if(l<1) continue;
00202 if(j > offs) {
00203 char *s = Line+offs,
00204 *q = Line+j;
00205
00206 while((*s++=*q++))
00207 ;
00208 }
00209 if(Line[offs+l-1]=='\\') {
00210 offs += l;
00211 Line[offs-1] = ' ';
00212 } else {
00213 break;
00214 }
00215 }
00216 return Line;
00217 }
00218
00219 static void EnumError(const Cmd_T *cmd, const char *s)
00220 {
00221 const Enum_T *en;
00222
00223 fprintf(stderr,
00224 "Invalid value \"%s\" for parameter \"%s\"\n", s, cmd->Name);
00225 fprintf(stderr, "Valid values are:\n");
00226 for(en=get_p_enums(cmd); en->Name; en++) {
00227 if(*en->Name) {
00228 fprintf(stderr, " %s\n", en->Name);
00229 }
00230 }
00231 fprintf(stderr, "\n");
00232 exit(1);
00233 }
00234
00235 static void GteError(const Cmd_T *cmd, int n)
00236 {
00237 fprintf(stderr,
00238 "Value %d out of range for parameter \"%s\"\n", n, cmd->Name);
00239 fprintf(stderr, "Valid values must be greater than or equal to %d\n",
00240 get_p_int(cmd));
00241 exit(1);
00242 }
00243
00244 static void LteError(const Cmd_T *cmd, int n)
00245 {
00246 fprintf(stderr,
00247 "Value %d out of range for parameter \"%s\"\n", n, cmd->Name);
00248 fprintf(stderr, "Valid values must be less than or equal to %d\n",
00249 get_p_int(cmd));
00250 exit(1);
00251 }
00252
00253 static void SubrangeError(const Cmd_T *cmd, int n)
00254 {
00255 const int *subrange = get_p_range(cmd);
00256 fprintf(stderr,
00257 "Value %d out of range for parameter \"%s\"\n", n, cmd->Name);
00258 fprintf(stderr, "Valid values range from %d to %d\n",
00259 subrange[0], subrange[1]);
00260 exit(1);
00261 }
00262
00263 static void SetEnum(Cmd_T *cmd, const char *s)
00264 {
00265 const Enum_T *en;
00266
00267 for(en=get_p_enums(cmd); en->Name; en++) {
00268 if(*en->Name && !strcmp(s, en->Name)) {
00269 update_val_int(cmd, en->Idx);
00270 return;
00271 }
00272 }
00273 EnumError(cmd, s);
00274 }
00275
00276 static void SetSubrange(Cmd_T *cmd, const char *s)
00277 {
00278 int n;
00279 const int *subrange = get_p_range(cmd);
00280
00281 if(sscanf(s, "%d", &n)!=1) {
00282 fprintf(stderr,
00283 "Integer value required for parameter \"%s\"\n",
00284 cmd->Name);
00285 exit(1);
00286 }
00287 if(n < subrange[0] || n > subrange[1]) {
00288 SubrangeError(cmd, n);
00289 }
00290 update_val_int(cmd, n);
00291 }
00292
00293 static void SetGte(Cmd_T *cmd, const char *s)
00294 {
00295 int n;
00296
00297 if(sscanf(s, "%d", &n)!=1) {
00298 fprintf(stderr,
00299 "Integer value required for parameter \"%s\"\n",
00300 cmd->Name);
00301 exit(1);
00302 }
00303 if(n<get_p_int(cmd)) {
00304 GteError(cmd, n);
00305 }
00306 update_val_int(cmd, n);
00307 }
00308
00309 static char **str2array(const char *s, const char *sep)
00310 {
00311 const char *p;
00312 char **a;
00313 int n = 0,
00314 l;
00315
00316 if(!sep) sep = SepString;
00317 p = s += strspn(s, sep);
00318 while(*p) {
00319 p += strcspn(p, sep);
00320 p += strspn(p, sep);
00321 ++n;
00322 }
00323 a = calloc(n+1, sizeof(char *));
00324 p = s;
00325 n = 0;
00326 while(*p) {
00327 l = strcspn(p, sep);
00328 a[n] = malloc(l+1);
00329 memcpy(a[n], p, l);
00330 a[n][l] = 0;
00331 ++n;
00332 p += l;
00333 p += strspn(p, sep);
00334 }
00335 return a;
00336 }
00337
00338 static void SetStrArray(Cmd_T *cmd, const char *s)
00339 {
00340 *(char***)cmd->Val = str2array(s, get_p_char(cmd));
00341 }
00342
00343 static void SetLte(Cmd_T *cmd, const char *s)
00344 {
00345 int n;
00346
00347 if(sscanf(s, "%d", &n)!=1) {
00348 fprintf(stderr,
00349 "Integer value required for parameter \"%s\"\n",
00350 cmd->Name);
00351 exit(1);
00352 }
00353 if(n > get_p_int(cmd)) {
00354 LteError(cmd, n);
00355 }
00356 update_val_int(cmd, n);
00357 }
00358
00359 static void SetParam(Cmd_T *cmd, const char *s)
00360 {
00361 if(!*s && cmd->Type != CMDSTRINGTYPE) {
00362 fprintf(stderr,
00363 "WARNING: No value specified for parameter \"%s\"\n",
00364 cmd->Name);
00365 return;
00366 }
00367 switch(cmd->Type) {
00368 case CMDDOUBLETYPE:
00369 if(sscanf(s, "%lf", get_val_double_ptr(cmd))!=1) {
00370 fprintf(stderr,
00371 "Float value required for parameter \"%s\"\n",
00372 cmd->Name);
00373 exit(1);
00374 }
00375 break;
00376 case CMDENUMTYPE:
00377 SetEnum(cmd, s);
00378 break;
00379 case CMDINTTYPE:
00380 if(sscanf(s, "%d", get_val_int_ptr(cmd))!=1) {
00381 fprintf(stderr,
00382 "Integer value required for parameter \"%s\"\n",
00383 cmd->Name);
00384 exit(1);
00385 }
00386 break;
00387 case CMDSTRINGTYPE:
00388 update_val_char(cmd,
00389 (strcmp(s, "<NULL>") && strcmp(s, "NULL"))
00390 ? strdup(s)
00391 : 0);
00392 break;
00393 case CMDSTRARRAYTYPE:
00394 SetStrArray(cmd, s);
00395 break;
00396 case CMDGTETYPE:
00397 SetGte(cmd, s);
00398 break;
00399 case CMDLTETYPE:
00400 SetLte(cmd, s);
00401 break;
00402 case CMDSUBRANGETYPE:
00403 SetSubrange(cmd, s);
00404 break;
00405 default:
00406 fprintf(stderr, "%s: %s %d %s \"%s\"\n",
00407 "SetParam",
00408 "Unknown Type",
00409 cmd->Type,
00410 "for parameter",
00411 cmd->Name);
00412 exit(1);
00413 }
00414 cmd->ArgStr = strdup(s);
00415 }
00416
00417 static int Scan(const char *ProgName, Cmd_T *cmds, char *Line)
00418 {
00419 char *q,
00420 *p;
00421 int i,
00422 hl,
00423 HasToMatch = FALSE,
00424 c0,
00425 c;
00426
00427 p = Line+strspn(Line, SepString);
00428 hl = strcspn(p, SepString);
00429 if(!hl) {
00430 return 0;
00431 }
00432 q = strchr(p, '/');
00433 if(q && q-p<hl) {
00434 *q = 0;
00435 if(strcmp(p, ProgName)) {
00436 *q = '/';
00437 return 0;
00438 }
00439 *q = '/';
00440 HasToMatch=TRUE;
00441 p = q+1;
00442 }
00443 hl = strcspn(p, SepString);
00444 if(!hl) {
00445 return 0;
00446 }
00447 c0 = p[hl];
00448 p[hl] = 0;
00449 for(i=0, c=1; cmds[i].Name&&(c=strcmp(cmds[i].Name, p))<0; i++)
00450 ;
00451 p[hl] = c0;
00452
00453 if (c)
00454 return HasToMatch && c;
00455
00456 SetParam(cmds+i, p+hl+strspn(p+hl, SepString));
00457 return 0;
00458 }
00459
00460 static void PrintEnum(const Cmd_T *cmd, int ValFlag, FILE *fp)
00461 {
00462 const Enum_T *en;
00463
00464 fprintf(fp, "%s", cmd->Name);
00465 if(ValFlag) {
00466 for(en=get_p_enums(cmd); en->Name; en++) {
00467 if(*en->Name && en->Idx==get_val_int(cmd)) {
00468 fprintf(fp, ": %s", en->Name);
00469 }
00470 }
00471 }
00472 fprintf(fp, "\n");
00473 }
00474
00475 static void PrintStrArray(const Cmd_T *cmd, int ValFlag, FILE *fp)
00476 {
00477 char *indent,
00478 **s = *(char***)cmd->Val;
00479 int l = 4+strlen(cmd->Name);
00480
00481 fprintf(fp, "%s", cmd->Name);
00482 indent = malloc(l+2);
00483 memset(indent, ' ', l+1);
00484 indent[l+1] = 0;
00485 if(ValFlag) {
00486 fprintf(fp, ": %s", s ? (*s ? *s++ : "NULL") : "");
00487 if(s) while(*s) {
00488 fprintf(fp, "\n%s %s", indent, *s++);
00489 }
00490 }
00491 free(indent);
00492 fprintf(fp, "\n");
00493 }
00494
00495 static void PrintParam(const Cmd_T *cmd, int ValFlag, FILE *fp)
00496 {
00497 fprintf(fp, "%4s", "");
00498 switch(cmd->Type) {
00499 case CMDDOUBLETYPE:
00500 fprintf(fp, "%s", cmd->Name);
00501 if(ValFlag) fprintf(fp, ": %22.15e", get_val_double(cmd));
00502 fprintf(fp, "\n");
00503 break;
00504 case CMDENUMTYPE:
00505 PrintEnum(cmd, ValFlag, fp);
00506 break;
00507 case CMDINTTYPE:
00508 case CMDSUBRANGETYPE:
00509 case CMDGTETYPE:
00510 case CMDLTETYPE:
00511 fprintf(fp, "%s", cmd->Name);
00512 if(ValFlag) fprintf(fp, ": %d", get_val_int(cmd));
00513 fprintf(fp, "\n");
00514 break;
00515 case CMDSTRINGTYPE:
00516 fprintf(fp, "%s", cmd->Name);
00517 if(ValFlag) {
00518 const char *value = get_val_char(cmd);
00519 if(value) {
00520 fprintf(fp, ": \"%s\"", value);
00521 } else {
00522 fprintf(fp, ": %s", "NULL");
00523 }
00524 }
00525 fprintf(fp, "\n");
00526 break;
00527 case CMDSTRARRAYTYPE:
00528 PrintStrArray(cmd, ValFlag, fp);
00529 break;
00530 default:
00531 fprintf(stderr, "%s: %s %d %s \"%s\"\n",
00532 "PrintParam",
00533 "Unknown Type",
00534 cmd->Type,
00535 "for parameter",
00536 cmd->Name);
00537 exit(1);
00538 }
00539 }
00540
00541 static void PrintParams(int ValFlag, FILE *fp)
00542 {
00543 int i;
00544
00545 fflush(fp);
00546 if(ValFlag) {
00547 fprintf(fp, "Parameters Values:\n");
00548 } else {
00549 fprintf(fp, "Parameters:\n");
00550 }
00551 for(i=0; cmds[i].Name; i++) PrintParam(cmds+i, ValFlag, fp);
00552 fprintf(fp, "\n");
00553 fflush(fp);
00554 }
00555
00556 static void CmdError(const char *opt)
00557 {
00558 fprintf(stderr, "Invalid option \"%s\"\n", opt);
00559 fprintf(stderr, "This program expectes the following parameters:\n");
00560 PrintParams(FALSE, stderr);
00561 exit(0);
00562 }
00563
00564 int GetParams(int *n, char ***a, const char *CmdFileName)
00565 {
00566 char *Line,
00567 *ProgName;
00568 int argc = *n;
00569 char **argv = *a,
00570 *s;
00571 FILE *fp;
00572 int IsPipe;
00573
00574 #ifdef MSDOS
00575 #define PATHSEP '\\'
00576 char *dot = NULL;
00577 #else
00578 #define PATHSEP '/'
00579 #endif
00580
00581 if(!(Line=malloc(LINSIZ))) {
00582 fprintf(stderr, "GetParams(): Unable to alloc %d bytes\n",
00583 LINSIZ);
00584 exit(1);
00585 }
00586 if((ProgName=strrchr(*argv, PATHSEP))) {
00587 ++ProgName;
00588 } else {
00589 ProgName = *argv;
00590 }
00591 #ifdef MSDOS
00592 if(dot=strchr(ProgName, '.')) *dot = 0;
00593 #endif
00594 --argc;
00595 ++argv;
00596 for(;;) {
00597 if(argc && argv[0][0]=='-' && argv[0][1]=='=') {
00598 CmdFileName = argv[0]+2;
00599 ++argv;
00600 --argc;
00601 }
00602 if(!CmdFileName) {
00603 break;
00604 }
00605 IsPipe = !strncmp(CmdFileName, "@@", 2);
00606 fp = IsPipe
00607 ? popen(CmdFileName+2, "r")
00608 : strcmp(CmdFileName, "-")
00609 ? fopen(CmdFileName, "r")
00610 : stdin;
00611 if(!fp) {
00612 fprintf(stderr, "Unable to open command file %s\n",
00613 CmdFileName);
00614 exit(1);
00615 }
00616 while(GetLine(fp, LINSIZ, Line) && strcmp(Line, "\\End")) {
00617 if(Scan(ProgName, cmds, Line)) {
00618 CmdError(Line);
00619 }
00620 }
00621 if(fp!=stdin) {
00622 if(IsPipe) pclose(fp);
00623 else fclose(fp);
00624 }
00625 CmdFileName = NULL;
00626 }
00627 while(argc && **argv=='-' && (s=strchr(*argv, '='))) {
00628 *s = ' ';
00629 sprintf(Line, "%s/%s", ProgName, *argv+1);
00630 *s = '=';
00631 if(Scan(ProgName, cmds, Line)) CmdError(*argv);
00632 --argc;
00633 ++argv;
00634 }
00635 *n = argc;
00636 *a = argv;
00637 #ifdef MSDOS
00638 if(dot) *dot = '.';
00639 #endif
00640 free(Line);
00641 return 0;
00642 }