/************************************************************************/ /* */ /* RCPP - Resource Compiler Pre-Processor for NT system */ /* */ /* GETFLAGS.C - Parse Command Line Flags */ /* */ /* 27-Nov-90 w-BrianM Update for NT from PM SDK RCPP */ /* */ /************************************************************************/ #include #include #include #include #include "rcpptype.h" #include "getflags.h" #include "rcppdecl.h" #include "rcppext.h" /************************************************************************/ /* Define function specific macros and global vars */ /************************************************************************/ static char *ErrString; /* Store string pointer in case of error */ /************************************************************************/ /* Local Function Prototypes */ /************************************************************************/ int getnumber (char *); int isita (char *, char); void substr (struct cmdtab *, char *, int); int tailmatch (char *, char *); /************************************************************************ * crack_cmd(table, string, func, dup) * set flags determined by the string based on table. * func will get the next word. * if dup is set, any strings stored away will get pstrduped * see getflags.h for specific matching and setting operators * * for flags which take parameters, a 'char' following the flag where 'char' is * '#' : says the parameter string may be separated from the option. * ie, "-M#" accepts "-Mabc" and "-M abc" * '*' : says the parameter must be concatenated with the flag * ie, "-A*" accepts only "-Axyz" not "-A xyz" * if neither is specified a space is required between parameter and flag * ie, "-o" accepts only "-o file" and not "-ofile" * * Modified by: Dave Weil D001 * recognize '-' and '/' as equivalent on MSDOS * ************************************************************************/ int crack_cmd(struct cmdtab *tab, char *string, char *(*next)(void), int _dup) { register char *format, *str; if (!string) { return(0); } ErrString = string; for (; tab->type; tab++) /* for each format */ { format = tab->format; str = string; for (; ; ) /* scan the string */ switch (*format) { /* optional space between flag and parameter */ case '#': if ( !*str ) { substr(tab, (*next)(), _dup); } else { substr(tab, str, _dup); } return(tab->retval); break; /* no space allowed between flag and parameter */ case '*': if (*str && tailmatch(format, str)) substr(tab, str, _dup); else goto notmatch; return(tab->retval); break; /* space required between flag and parameter */ case 0: if (*str) { /* str left, no good */ goto notmatch; } else if (tab->type & TAKESARG) { /* if it takes an arg */ substr(tab, (*next)(), _dup); } else { /* doesn't want an arg */ substr(tab, (char *)0, _dup); } return(tab->retval); break; case '-': /* D001 */ if ('-' == *str) { str++; /* D001 */ format++; /* D001 */ continue; /* D001 */ } /* D001 */ else /* D001 */ goto notmatch; /* D001 */ default: if (*format++ == *str++) continue; goto notmatch; } /* sorry. we need to break out two levels of loop */ notmatch: ; } return(0); } /************************************************************************/ /* set the appropriate flag(s). called only when we know we have a match */ /************************************************************************/ void substr(struct cmdtab *tab, register char *str, int _dup) { register struct subtab *q; LIST * list; char *string = str; switch (tab->type) { case FLAG: *(int *)(tab->flag) = 1; return; case UNFLAG: *(int *)(tab->flag) = 0; return; case NOVSTR: if (*(char **)(tab->flag)) { /* before we print it out in the error message get rid of the * arg specifier (e.g. #) at the end of the format. */ string = _strdup(tab->format); string[strlen(string)-1] = '\0'; Msg_Temp = GET_MSG(1046); SET_MSG (Msg_Text, Msg_Temp, string,*(char **)(tab->flag),str); fatal(1046); return; } /* fall through */ case STRING: *(char **)(tab->flag) = (_dup ? _strdup(str) : str); return; case NUMBER: *(int *)(tab->flag) = getnumber (str); return; case PSHSTR: list = (LIST * )(tab->flag); if (list->li_top > 0) list->li_defns[--list->li_top] = (_dup ? _strdup(str) : str); else { Msg_Temp = GET_MSG(1047); SET_MSG (Msg_Text, Msg_Temp, tab->format, str); fatal(1047); } return; case SUBSTR: for ( ; *str; ++str) { /* walk the substring */ for (q = (struct subtab *)tab->flag; q->letter; q++) { /* ** for every member in the table */ if (*str == (char)q->letter) switch (q->type) { case FLAG: *(q->flag) = 1; goto got_letter; case UNFLAG: *(q->flag) = 0; goto got_letter; default: goto got_letter; } } got_letter: if (!q->letter) { Msg_Temp = GET_MSG(1048); SET_MSG (Msg_Text, Msg_Temp, *str, ErrString); fatal(1048); } } return; default: return; } } /************************************************************************/ /* Parse the string and return a number 0 <= x < 0xffff (64K) */ /************************************************************************/ int getnumber (char *str) { long i = 0; char *ptr = str; for (; isspace(*ptr); ptr++) ; if (!isdigit(*ptr) || (((i = atol(ptr)) >= 65535) || i < 0)) { Msg_Temp = GET_MSG(1049); SET_MSG (Msg_Text, Msg_Temp, str); fatal(1049); /* invalid numerical argument, 'str' */ } return ((int) i); } /************************************************************************/ /* is the letter in the string? */ /************************************************************************/ int isita (register char *str, register char let) { if (str) while (*str) if (*str++ == let) return(1); return(0); } /************************************************************************/ /* compare a tail format (as in *.c) with a string. if there is no */ /* tail, anything matches. (null strings are detected elsewhere) */ /* the current implementation only allows one wild card */ /************************************************************************/ int tailmatch (char *format, char *str) { register char *f = format; register char *s = str; if (f[1] == 0) /* wild card is the last thing in the format, it matches */ return(1); while (f[1]) /* find char in front of null in format */ f++; while (s[1]) /* find char in front of null in string to check */ s++; while (*s == *f) { /* check chars walking towards front */ s--; f--; } /* ** if we're back at the beginning of the format ** and ** the string is either at the beginning or somewhere inside ** then we have a match. ** ** ex format == "*.c", str == "file.c" ** at this point *f = '*' and *s == 'e', since we've kicked out of the above ** loop. since f==format and s>=str this is a match. ** but if format == "*.c" and str == "file.asm" then ** *f == 'c' and *s = 'm', f != format and no match. */ return((f == format) && (s >= str)); }