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

288 lines
8.9 KiB
C

/***********************************************************************
* Microsoft (R) Windows (R) Resource Compiler
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* File Comments:
*
*
***********************************************************************/
#include "rc.h"
/************************************************************************/
/* Define function specific macros and global vars */
/************************************************************************/
static WCHAR *ErrString; /* Store string pointer in case of error */
/************************************************************************/
/* Local Function Prototypes */
/************************************************************************/
int getnumber (const wchar_t *);
int isita (const wchar_t *, const wchar_t);
void substr (struct cmdtab *, wchar_t *, int);
int tailmatch (const wchar_t *, const wchar_t *);
/************************************************************************
* 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,
WCHAR *string,
WCHAR *(*next)(void),
int _dup
)
{
const wchar_t *format;
wchar_t *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 L'#':
if ( !*str ) {
substr(tab, (*next)(), _dup);
} else {
substr(tab, str, _dup);
}
return(tab->retval);
break;
/* no space allowed between flag and parameter */
case L'*':
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, (WCHAR *)0, _dup);
}
return(tab->retval);
break;
case L'-':
if (L'-' == *str) {
str++;
format++;
continue;
} else {
goto notmatch;
}
default:
if (*format++ == *str++)
continue;
goto notmatch;
}
notmatch:
;
}
return(0);
}
/************************************************************************/
/* set the appropriate flag(s). called only when we know we have a match */
/************************************************************************/
void
substr(
struct cmdtab *tab,
wchar_t *str,
int _dup
)
{
const struct subtab *q;
LIST * list;
const wchar_t *string = str;
switch (tab->type) {
case FLAG:
*(int *)(tab->flag) = 1;
return;
case UNFLAG:
*(int *)(tab->flag) = 0;
return;
case NOVSTR:
if (*(WCHAR **)(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 = _wcsdup(tab->format);
// string[wcslen(string)-1] = L'\0';
//
// message 1046 doesn't exist and don't know what it should be
// SET_MSG(1046, string, *(WCHAR **)(tab->flag), str);
fatal(1000);
return;
}
/* fall through */
case STRING:
*(WCHAR **)(tab->flag) = (_dup ? _wcsdup(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 ? _wcsdup(str) : str);
else {
fatal(1047, tab->format, str);
}
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 == (WCHAR)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) {
fatal(1048, *str, ErrString);
}
}
return;
default:
return;
}
}
/************************************************************************/
/* Parse the string and return a number 0 <= x < 0xffff (64K) */
/************************************************************************/
int
getnumber (
const wchar_t *str
)
{
long i = 0;
const wchar_t *ptr = str;
for (; iswspace(*ptr); ptr++)
;
if (!iswdigit(*ptr) || (((i = wcstol(ptr, NULL, 10)) >= 65535) || i < 0)) {
fatal(1049, str); /* invalid numerical argument, 'str' */
}
return((int) i);
}
/************************************************************************/
/* is the letter in the string? */
/************************************************************************/
int
isita (
const wchar_t *str,
const wchar_t 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 (
const wchar_t *format,
const wchar_t *str
)
{
const wchar_t *f = format;
const wchar_t *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));
}