diff options
Diffstat (limited to '')
-rw-r--r-- | Arguments.c | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/Arguments.c b/Arguments.c new file mode 100644 index 0000000..2f66ee9 --- /dev/null +++ b/Arguments.c @@ -0,0 +1,604 @@ +#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); + } +} |