Windows-Server-2003/sdktools/hivepp/getflags.c

271 lines
7.5 KiB
C

/************************************************************************/
/* */
/* 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 <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#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);
if (!string) {
Msg_Temp = GET_MSG (1002);
SET_MSG (Msg_Text, Msg_Temp);
error(1002);
return;
}
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));
}