271 lines
7.5 KiB
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));
|
||
|
}
|