summaryrefslogtreecommitdiff
path: root/Arguments.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Arguments.c604
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);
+ }
+}