/****************************************************************************** IrstLM: IRST Language Model Toolkit Copyright (C) 2006 Marcello Federico, ITC-irst Trento, Italy This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ #include #include #include #include #include "cmd.h" static 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 char *GetLine(), **str2array(); static int Scan(), SetParam(), SetEnum(), SetSubrange(), SetStrArray(), SetGte(), SetLte(), CmdError(), EnumError(), SubrangeError(), GteError(), LteError(), PrintParam(), PrintEnum(), PrintStrArray(); static Cmd_T cmds[MAXPARAM+1]; static char *SepString = " \t\n"; #if defined(__STDC__) #include int DeclareParams(char *ParName, ...) #else #include int DeclareParams(ParName, va_alist) char *ParName; va_dcl #endif { va_list args; static int ParamN = 0; int j, c; char *s; #if defined(__STDC__) va_start(args, ParName); #else va_start(args); #endif for(;ParName;) { if(ParamN==MAXPARAM) { fprintf(stderr, "Too many parameters !!\n"); break; } for(j=0,c=1; jj; c--) { cmds[c] = cmds[c-1]; } cmds[j].Name = ParName; cmds[j].Type = va_arg(args, int); 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 */ cmds[j].p = (void*) calloc(2, sizeof(int)); ((int*)cmds[j].p)[0] = va_arg(args, int); ((int*)cmds[j].p)[1] = va_arg(args, int); break; case CMDGTETYPE: /* get lower or upper bound */ case CMDLTETYPE: cmds[j].p = (void*) calloc(1, sizeof(int)); ((int*)cmds[j].p)[0] = va_arg(args, int); break; case CMDSTRARRAYTYPE: /* get the separators string */ cmds[j].p = (s=va_arg(args, char*)) ? (void*)strdup(s) : 0; 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, char *); } cmds[ParamN].Name = NULL; va_end(args); return 0; } int GetParams(n, a, CmdFileName) int *n; char ***a; 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; } int PrintParams(ValFlag, fp) 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); return 0; } int SPrintParams(a, pfx) char ***a, *pfx; { int l, n; Cmd_T *cmd; if(!pfx) pfx=""; l = strlen(pfx); for(n=0, cmd=cmds; cmd->Name; cmd++) n += !!cmd->ArgStr; a[0] = calloc(n, sizeof(char*)); for(n=0, cmd=cmds; cmd->Name; cmd++) { if(!cmd->ArgStr) continue; a[0][n] = malloc(strlen(cmd->Name)+strlen(cmd->ArgStr)+l+2); sprintf(a[0][n], "%s%s=%s", pfx, cmd->Name, cmd->ArgStr); ++n; } return n; } static int CmdError(opt) char *opt; { fprintf(stderr, "Invalid option \"%s\"\n", opt); fprintf(stderr, "This program expectes the following parameters:\n"); PrintParams(FALSE, stderr); exit(0); } static int PrintParam(cmd, ValFlag, fp) 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", *(double *)cmd->Val); 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", *(int *)cmd->Val); fprintf(fp, "\n"); break; case CMDSTRINGTYPE: fprintf(fp, "%s", cmd->Name); if(ValFlag) { if(*(char **)cmd->Val) { fprintf(fp, ": \"%s\"", *(char **)cmd->Val); } 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); } return 0; } static char *GetLine(fp, n, Line) FILE *fp; int n; char *Line; { int j, l, offs=0; for(;;) { 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 int Scan(ProgName, cmds, Line) char *ProgName, *Line; Cmd_T *cmds; { char *q, *p; int i, hl, HasToMatch = FALSE, c0, c; p = Line+strspn(Line, SepString); if(!(hl=strcspn(p, SepString))) { return 0; } if((q=strchr(p, '/')) && q-pType != CMDSTRINGTYPE) { fprintf(stderr, "WARNING: No value specified for parameter \"%s\"\n", cmd->Name); return 0; } switch(cmd->Type) { case CMDDOUBLETYPE: if(sscanf(s, "%lf", (double*)cmd->Val)!=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", (int*)cmd->Val)!=1) { fprintf(stderr, "Integer value required for parameter \"%s\"\n", cmd->Name); exit(1); } break; case CMDSTRINGTYPE: *(char **)cmd->Val = (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); return 0; } static int SetEnum(cmd, s) Cmd_T *cmd; char *s; { Enum_T *en; for(en=(Enum_T *)cmd->p; en->Name; en++) { if(*en->Name && !strcmp(s, en->Name)) { *(int *) cmd->Val = en->Idx; return 0; } } return EnumError(cmd, s); } static int SetSubrange(cmd, s) Cmd_T *cmd; 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 < *(int *)cmd->p || n > *((int *)cmd->p+1)) { return SubrangeError(cmd, n); } *(int *)cmd->Val = n; return 0; } static int SetGte(cmd, s) Cmd_T *cmd; 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<*(int *)cmd->p) { return GteError(cmd, n); } *(int *)cmd->Val = n; return 0; } static int SetStrArray(cmd, s) Cmd_T *cmd; char *s; { *(char***)cmd->Val = str2array(s, (char*)cmd->p); return 0; } static int SetLte(cmd, s) Cmd_T *cmd; 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 > *(int *)cmd->p) { return LteError(cmd, n); } *(int *)cmd->Val = n; return 0; } static int EnumError(cmd, s) Cmd_T *cmd; char *s; { Enum_T *en; fprintf(stderr, "Invalid value \"%s\" for parameter \"%s\"\n", s, cmd->Name); fprintf(stderr, "Valid values are:\n"); for(en=(Enum_T *)cmd->p; en->Name; en++) { if(*en->Name) { fprintf(stderr, " %s\n", en->Name); } } fprintf(stderr, "\n"); exit(1); } static int GteError(cmd, n) 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", *(int *)cmd->p); exit(1); } static int LteError(cmd, n) 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", *(int *)cmd->p); exit(1); } static int SubrangeError(cmd, n) Cmd_T *cmd; int n; { fprintf(stderr, "Value %d out of range for parameter \"%s\"\n", n, cmd->Name); fprintf(stderr, "Valid values range from %d to %d\n", *(int *)cmd->p, *((int *)cmd->p+1)); exit(1); } static int PrintEnum(cmd, ValFlag, fp) Cmd_T *cmd; int ValFlag; FILE *fp; { Enum_T *en; fprintf(fp, "%s", cmd->Name); if(ValFlag) { for(en=(Enum_T *)cmd->p; en->Name; en++) { if(*en->Name && en->Idx==*(int *)cmd->Val) { fprintf(fp, ": %s", en->Name); } } } fprintf(fp, "\n"); return 0; } static int PrintStrArray(cmd, ValFlag, fp) 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"); return 0; } static char **str2array(s, sep) char *s, *sep; { char *p, **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; }