MWCC/Arguments.c

605 lines
15 KiB
C
Raw Normal View History

2022-10-07 19:02:27 +00:00
#include "mwcc_decomp.h"
char compat;
char *MAINOPTCHAR;
char *FIRSTARGCHAR;
char *SEPOPTSTR;
char SEPOPTCHAR;
char SEP1;
char SEP2;
char SEP3;
char RESPFILECHAR;
char *RESPFILESTR;
static ArgToken *argtoks;
static int numargtoks;
static int maxargtoks;
unsigned char parserDebug;
static unsigned char in_response_file;
static int margc;
static int margind;
static char **margv;
static OSFileHandle respfilehandle;
static char *respfile;
static char *respfilestart;
static unsigned long respfilesize;
static int scantok;
anon0_50 linkargs;
anon0_50 prelinkargs;
anon0_50 postlinkargs;
// TODO move me
/*extern int OS_MakeFileSpec(const char *name, struct OSSpec *spec);
extern int OS_NewFileHandle(struct OSSpec *spec, int a, int b, OSFileHandle *fh);
extern int OS_AppendHandle(struct OSHandle *h, const void *, long);
extern int OS_LockFileHandle(OSFileHandle *fh, char **h, unsigned long *size);
extern void OS_FreeFileHandle(OSFileHandle *fh);
extern void CLPOSAlert(short code, short code2, ...);
extern void CLPReportError(short code, ...);
extern void CLPReportWarning(short code, ...);
extern void CLPFatalError(const char *format, ...);
extern int ustrncmp(const char *a, const char *b, int len);*/
// TODO move me
static void Arg_AddToken(short val, char *text);
static void Arg_Setup(int argc, char **argv);
static void Arg_SkipRespFileWS();
static unsigned char Arg_OpenRespFile(const char *name);
static void Arg_CloseRespFile();
static char *Arg_GetRespFileToken();
static char *Arg_GetNext(unsigned char allow_resp);
static unsigned char Arg_GotMore();
static void Arg_Parse();
static void Arg_GrowArgs(anon0_50 *ta);
static void Arg_GrowArg(anon0_50 *ta, char *txt);
static void Arg_AddToken(short val, char *text) {
ArgToken *cur;
ArgToken *prev;
ArgToken *pprev;
ArgToken *ppprev;
ArgToken *pppprev;
if (numargtoks > 0)
prev = &argtoks[numargtoks - 1];
else
prev = 0;
if (prev && prev->val == ATK_2 && prev->text[0] == 0) {
pppprev = ppprev = pprev = 0;
if (numargtoks > 3)
pppprev = &argtoks[numargtoks - 4];
if (numargtoks > 2)
ppprev = &argtoks[numargtoks - 3];
if (numargtoks > 1)
pprev = &argtoks[numargtoks - 2];
if (pprev) {
if ((int) val == ATK_1 && (pprev->val == ATK_5 || pprev->val == ATK_4) && (ppprev->val != ATK_2 || pppprev->val != ATK_3)) {
if (parserDebug)
printf("Coalescing args with '%s'\n", Arg_GetTokenName(pprev));
val = pprev->val;
numargtoks -= 2;
} else if (pprev->val == ATK_1 && ((int) val == ATK_5 || (int) val == ATK_4)) {
if (parserDebug)
printf("Coalescing args, removing '%s'\n", Arg_GetTokenName(pprev));
numargtoks -= 2;
}
}
}
if (numargtoks >= maxargtoks) {
argtoks = (ArgToken *) xrealloc("argument list", argtoks, sizeof(ArgToken) * (maxargtoks + 16));
maxargtoks += 16;
}
cur = &argtoks[numargtoks];
cur->val = val;
if (text)
cur->text = xstrdup(text);
else
cur->text = 0;
numargtoks++;
}
static void Arg_Setup(int argc, char **argv) {
in_response_file = 0;
respfile = 0;
margc = argc;
margv = argv;
margind = 1;
}
static void Arg_SkipRespFileWS() {
restart:
while (respfile[0] && isspace(respfile[0]))
++respfile;
if (respfile[0] == '\\' && respfile[1] == '#') {
++respfile;
return;
}
if (respfile[0] == '#') {
if ((respfile > respfilestart) ? (respfile[-1] != '\\') : 1) {
while (respfile[0] && respfile[0] != 10 && respfile[0] != 13)
++respfile;
while (respfile[0] == 13 || respfile[0] == 10)
++respfile;
goto restart;
}
}
}
static unsigned char Arg_OpenRespFile(const char *name) {
struct OSSpec spec;
int err;
if (
(err = OS_MakeFileSpec(name, &spec))
|| (err = OS_NewFileHandle(&spec, 0, 0, &respfilehandle))
|| (err = OS_AppendHandle(&respfilehandle.hand, "", 1))
|| (err = OS_LockFileHandle(&respfilehandle, &respfile, &respfilesize))
) {
CLPOSAlert(74, (short) err, "response ", name);
return 0;
} else {
respfilestart = respfile;
Arg_SkipRespFileWS();
in_response_file = 1;
return 1;
}
}
static void Arg_CloseRespFile() {
in_response_file = 0;
OS_FreeFileHandle(&respfilehandle);
}
static char *Arg_GetRespFileToken() {
char *start;
char *ptr;
int quoting;
quoting = 0;
if (respfile[0] == 0)
return 0;
start = ptr = respfile;
while (respfile[0]) {
if (!quoting && isspace(respfile[0]))
break;
if (respfile[0] == '"') {
quoting = !quoting;
respfile++;
} else if (respfile[0] == '\\' && respfile[1] == '"') {
*ptr = '"';
respfile += 2;
ptr++;
} else {
*(ptr++) = *(respfile++);
}
}
if (respfile[0])
Arg_SkipRespFileWS();
*ptr = 0;
return start;
}
static char *Arg_GetNext(unsigned char allow_resp) {
char *ret;
int rfclen;
char *rfcequ;
restart:
if (!in_response_file) {
rfclen = 1;
ret = margv[margind++];
if (ret[0] == '\\' && ret[1] == RESPFILECHAR) {
ret++;
} else if (allow_resp) {
if (ret[0] == RESPFILECHAR || (RESPFILESTR[0] && !ustrncmp(ret, RESPFILESTR, rfclen = strlen(RESPFILESTR))) && ret[rfclen]) {
rfcequ = strchr(ret + rfclen, '=');
if (rfcequ)
rfclen = (rfcequ + 1) - ret;
if (Arg_OpenRespFile(ret + rfclen))
goto restart;
ret = 0;
}
}
} else {
ret = Arg_GetRespFileToken();
if (!ret) {
Arg_CloseRespFile();
goto restart;
}
}
if (parserDebug)
fprintf(stderr, "Got arg = '%s'\n", ret ? ret : "<NULL>");
return ret;
}
static unsigned char Arg_GotMore() {
if (!in_response_file)
return margind < margc;
else if (respfile[0])
return 1;
else
return margind < margc;
}
static void Arg_Parse() {
unsigned char isOpt;
unsigned char isList;
char *arg;
char *argstart;
char buffer[4096];
char *bufptr;
char ch;
isOpt = 0;
isList = 0;
while (Arg_GotMore()) {
argstart = arg = Arg_GetNext(1);
if (!arg)
break;
bufptr = buffer;
buffer[0] = 0;
isList = 0;
if (arg[0] && arg[1] && strchr(MAINOPTCHAR, arg[0])) {
if (isOpt)
Arg_AddToken(ATK_1, 0);
buffer[0] = arg[1];
buffer[1] = 0;
isOpt = 1;
isList = 0;
bufptr++;
arg += 2;
} else {
isOpt = 0;
}
while (arg && arg[0]) {
ch = arg[0];
if (arg[0] == '\\' && (arg[1] == SEP1 || arg[1] == SEP2 || arg[1] == SEP3)) {
ch = 0x80 | *(++arg);
} else if (compat == 1 && arg[0] == ':' && arg[1] == '\\') {
ch |= 0x80;
}
if (ch != SEP1 && ch != SEP2 && ch != SEP3) {
if ((ch & 0x7F) == SEP1 || (ch & 0x7F) == SEP2 || (ch & 0x7F) == SEP3)
ch &= 0x7F;
*(bufptr++) = ch;
if (bufptr >= &buffer[sizeof(buffer)]) {
CLPReportError(2, argstart, argstart + strlen(argstart) - 15, sizeof(buffer));
}
*bufptr = 0;
} else {
if (isOpt) {
Arg_AddToken(ATK_3, buffer);
Arg_AddToken(ATK_2, buffer);
} else {
Arg_AddToken(ATK_2, buffer);
}
Arg_AddToken(
(unsigned char) ((ch == ',') ? ATK_5 : (((ch == '=') || (ch == SEP3)) ? ATK_4 : ATK_0)),
0
);
bufptr = buffer;
buffer[0] = 0;
if (ch == SEP1 || ch == SEP2 || ch == SEP3)
isOpt = 0;
isList = 1;
}
arg++;
}
// 1799C8
if (isOpt && bufptr > &buffer[0]) {
Arg_AddToken(ATK_3, buffer + (isList && strchr(MAINOPTCHAR, buffer[0])));
Arg_AddToken(ATK_2, buffer + (isList && strchr(MAINOPTCHAR, buffer[0])) + 1);
} else {
Arg_AddToken(ATK_2, buffer);
Arg_AddToken(ATK_1, 0);
}
}
if (isOpt || isList)
Arg_AddToken(ATK_1, 0);
Arg_AddToken(ATK_0, 0);
}
enum {
COMPAT_0,
COMPAT_1,
COMPAT_2
};
void Arg_Init(int theargc, char **theargv) {
int p;
int x;
maxargtoks = 0;
numargtoks = 0;
parserDebug = 0;
if (theargc > 1 && !strcmp(theargv[1], "--parser-debug")) {
parserDebug = 1;
memmove(&theargv[1], &theargv[2], sizeof(char *) * (theargc - 1));
theargc--;
}
if ((int) compat == COMPAT_0) {
MAINOPTCHAR = "-";
FIRSTARGCHAR = "=";
SEPOPTSTR = " ";
SEP1 = ',';
SEP2 = '=';
SEP3 = '=';
RESPFILECHAR = '@';
RESPFILESTR = "";
} else if ((int) compat == COMPAT_1) {
MAINOPTCHAR = "/-";
FIRSTARGCHAR = ":";
SEPOPTSTR = ":";
SEP1 = ',';
SEP2 = '=';
SEP3 = ':';
RESPFILECHAR = '@';
RESPFILESTR = "";
} else if ((int) compat == COMPAT_2) {
if (!MAINOPTCHAR)
MAINOPTCHAR = "-";
if (!FIRSTARGCHAR)
FIRSTARGCHAR = "=";
if (!SEPOPTSTR)
SEPOPTSTR = " ";
if (!SEP1)
SEP1 = ',';
if (!SEP2)
SEP2 = '=';
if (!SEP3)
SEP3 = '=';
if (!RESPFILECHAR)
RESPFILECHAR = '@';
if (!RESPFILESTR)
RESPFILESTR = "";
} else {
CLPFatalError("Unknown parser compatibility type (%d)\n", (int) compat);
}
if (parserDebug) {
printf("Incoming arguments: \n");
for (p = 0; p < theargc; p++) {
printf("[%s] ", theargv[p]);
}
printf("\n");
}
Arg_Setup(theargc, theargv);
Arg_Parse();
Arg_Reset();
if (parserDebug) {
for (x = 0; x < numargtoks; x++) {
printf("TOKEN: '%s'\n", Arg_GetTokenName(&argtoks[x]));
}
}
}
void Arg_Terminate() {
ArgToken *cur;
while (numargtoks > 0) {
cur = &argtoks[--numargtoks];
if (cur->text)
free(cur->text);
}
if (maxargtoks)
free(argtoks);
maxargtoks = 0;
}
void Arg_Reset() {
scantok = 0;
}
void Arg_Stop(ArgToken *where) {
ArgToken *cur;
while (&argtoks[numargtoks] > where) {
cur = &argtoks[--numargtoks];
if (cur->text)
free(cur->text);
cur->val = ATK_0;
cur->text = 0;
}
argtoks[numargtoks++].val = ATK_1;
argtoks[numargtoks++].val = ATK_0;
scantok = numargtoks - 2;
}
ArgToken *Arg_PeekToken() {
if (scantok >= numargtoks)
return 0;
else
return &argtoks[scantok];
}
ArgToken *Arg_UsedToken() {
if (scantok < numargtoks)
scantok++;
return Arg_PeekToken();
}
int Arg_IsEmpty() {
ArgToken *tok;
tok = Arg_PeekToken();
return (tok == 0 || tok->val == ATK_0);
}
ArgToken *Arg_GetToken() {
ArgToken *ret;
ret = Arg_PeekToken();
if (ret)
scantok++;
return ret;
}
ArgToken *Arg_UndoToken() {
if (scantok > 0) {
scantok--;
return Arg_PeekToken();
} else {
return 0;
}
}
const char *Arg_GetTokenName(ArgToken *tok) {
if ((int) tok->val == ATK_2)
return tok->text;
return
((int) tok->val == ATK_3) ? "option" :
((int) tok->val == ATK_5) ? "comma" :
(((int) compat == COMPAT_1 && (int) tok->val == ATK_4)) ? "colon or equals" :
(((int) compat != COMPAT_1 && (int) tok->val == ATK_4)) ? "equals" :
((int) tok->val == ATK_1) ? "end of argument" :
((int) tok->val == ATK_0) ? "end of command line" :
"<error>";
}
const char *Arg_GetTokenText(ArgToken *tok, char *buffer, int maxlen, unsigned char warn) {
const char *ptr;
char *bptr;
int curlen;
bptr = buffer;
curlen = 0;
if (tok->val == ATK_2 || tok->val == ATK_3)
ptr = tok->text;
else
ptr = Arg_GetTokenName(tok);
while (*ptr && curlen++ < maxlen) {
*(bptr++) = *(ptr++);
}
if (curlen < maxlen) {
bptr[0] = 0;
} else {
bptr[-1] = 0;
if (warn)
CLPReportWarning(56, buffer, ptr + strlen(ptr) - ((maxlen <= 32) ? maxlen : 32), maxlen);
}
return buffer;
}
static void Arg_GrowArgs(anon0_50 *ta) {
int len;
if (!ta->argv || (ta->argc + 1) >= ta->nargv) {
len = ta->nargv;
ta->nargv = len + 16;
ta->argv = xrealloc("argument list", ta->argv, sizeof(char *) * (ta->nargv + 1));
while (len <= ta->nargv) {
ta->argv[len++] = 0;
}
}
ta->argc++;
}
static void Arg_GrowArg(anon0_50 *ta, char *txt) {
char **ptr;
int ptrlen;
ptr = &ta->argv[ta->argc];
if (*ptr == 0) {
*ptr = xstrdup(txt);
} else {
ptrlen = strlen(*ptr);
*ptr = xrealloc("command line", *ptr, ptrlen + strlen(txt) + 1);
strcpy(*ptr + ptrlen, txt);
}
}
void Arg_InitToolArgs(anon0_50 *ta) {
ta->argc = 0;
ta->nargv = 0;
ta->argv = 0;
Arg_GrowArgs(ta);
}
void Arg_AddToToolArgs(anon0_50 *ta, short tokval, char *toktxt) {
switch (tokval) {
case ATK_0:
Arg_FinishToolArgs(ta);
break;
case ATK_1:
if (ta->argv && ta->argv[ta->argc])
Arg_GrowArgs(ta);
break;
case ATK_2:
Arg_GrowArg(ta, toktxt);
break;
case ATK_3:
Arg_GrowArg(ta, "-");
break;
case ATK_4:
Arg_GrowArg(ta, "=");
break;
case ATK_5:
Arg_GrowArg(ta, ",");
break;
default:
#line 787
CLPFatalError(__FILE__, __LINE__, "Unknown token (%d)", tokval);
break;
}
}
void Arg_FinishToolArgs(anon0_50 *ta) {
Arg_GrowArgs(ta);
ta->argv[ta->argc] = 0;
}
void Arg_ToolArgsForPlugin(anon0_50 *ta, struct CWCommandLineArgs *args) {
args->argc = 1;
args->argv = ta->argv;
while (args->argv[args->argc])
args->argc++;
args->envp = 0;
}
void Arg_FreeToolArgs(anon0_50 *ta) {
int x;
if (ta->argv) {
for (x = 1; x < ta->argc; x++) {
if (ta->argv[x])
free(ta->argv[x]);
}
free(ta->argv);
}
}