summaryrefslogtreecommitdiff
path: root/Option.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2022-10-07 20:02:27 +0100
committerAsh Wolf <ninji@wuffs.org>2022-10-07 20:02:27 +0100
commit97f6a2438df1eaeb4128ce36f29346ea38a3db4a (patch)
tree78260f8f0f2b84fc70fadb1e50e7fc104390eee4 /Option.c
downloadMWCC-97f6a2438df1eaeb4128ce36f29346ea38a3db4a.tar.gz
MWCC-97f6a2438df1eaeb4128ce36f29346ea38a3db4a.zip
first very unfinished commit lol
Diffstat (limited to '')
-rw-r--r--Option.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/Option.c b/Option.c
new file mode 100644
index 0000000..4a09705
--- /dev/null
+++ b/Option.c
@@ -0,0 +1,630 @@
+#include "mwcc_decomp.h"
+
+#define OPTION_ASSERT(cond) do { if (!(cond)) { printf("%s:%u: failed assertion\n", __FILE__, __LINE__); abort(); } } while(0)
+
+#define MAXSTACK 8
+
+int oStackPtr;
+Opt48 oStack[8];
+char curopt[1024];
+int maxlegalset;
+int numlegalset;
+int numinternalset;
+static OptionList legalset;
+static OptionList internalset;
+int numoptionlists;
+static OptionList *optionlists[32];
+
+enum {
+ ARGFLAG_1 = 1,
+ ARGFLAG_2 = 2,
+ ARGFLAG_4 = 4,
+ ARGFLAG_8 = 8,
+ ARGFLAG_10 = 0x10,
+ ARGFLAG_20 = 0x20,
+ ARGFLAG_40 = 0x40,
+ ARGFLAG_80 = 0x80
+};
+
+enum {
+ ARGSPELLFLAG_1 = 1,
+ ARGSPELLFLAG_2 = 2,
+ ARGSPELLFLAG_4 = 4,
+ ARGSPELLFLAG_8 = 8,
+ ARGSPELLFLAG_10 = 0x10,
+ ARGSPELLFLAG_20 = 0x20,
+ ARGSPELLFLAG_40 = 0x40,
+ ARGSPELLFLAG_80 = 0x80
+};
+
+enum {
+ OPTSPELLFLAG_1 = 1,
+ OPTSPELLFLAG_2 = 2,
+ OPTSPELLFLAG_4 = 4,
+ OPTSPELLFLAG_8 = 8,
+ OPTSPELLFLAG_10 = 0x10,
+ OPTSPELLFLAG_20 = 0x20,
+ OPTSPELLFLAG_40 = 0x40,
+ OPTSPELLFLAG_80 = 0x80
+};
+
+static void Option_PushList(OptionList *lst) {
+ Args_Push(1, lst, 0);
+}
+
+static void Option_PushOpt(Option *opt, const char *optname) {
+ char *cpy;
+ short flags = ARGFLAG_2;
+ if (opt && (opt->avail & OTF2)) {
+ if (Utils_CompareOptionString(opt->names, optname, opt->avail & OTF_CASED, OTF2)) {
+ flags |= ARGFLAG_80;
+ }
+ }
+ cpy = xstrdup(optname);
+ Args_Push(flags, opt, cpy);
+}
+
+static void Option_PopOpt(char *optname) {
+ Opt48 *os = Args_Pop(ARGFLAG_2);
+ if (optname)
+ strcpy(optname, os->e.o.curopt);
+ free(os->e.o.curopt);
+}
+
+static void Option_PopList() {
+ Args_Pop(ARGFLAG_1);
+}
+
+void Args_InitStack() {
+ oStackPtr = 0;
+}
+int Args_StackSize() {
+ return oStackPtr;
+}
+
+void Args_Push(short flags, void *first, void *second) {
+#line 104
+ OPTION_ASSERT(oStackPtr<MAXSTACK);
+ if (oStackPtr > 0)
+ {
+ short prev =
+ (flags & ARGFLAG_1) ? ARGFLAG_2 :
+ (flags & ARGFLAG_2) ? ARGFLAG_1 :
+ (flags & ARGFLAG_4) ? ARGFLAG_2 : -1;
+ OPTION_ASSERT(oStack[oStackPtr-1].flags & prev);
+ }
+
+ oStack[oStackPtr].e.v.first = first;
+ oStack[oStackPtr].e.v.second = second;
+ oStack[oStackPtr].flags = flags;
+ oStackPtr++;
+}
+
+Opt48 *Args_Pop(short flags)
+{
+ OPTION_ASSERT(oStackPtr>0);
+ --oStackPtr;
+ OPTION_ASSERT(oStack[oStackPtr].flags & flags);
+ return &oStack[oStackPtr];
+}
+
+void Args_SpellStack(char *buffer, short flags) {
+ char *bptr;
+ Opt48 *os;
+ int sp;
+ int level;
+
+ bptr = buffer;
+ sp = 0;
+ level = 0;
+ os = &oStack[sp];
+
+ while (sp < oStackPtr) {
+ if (!flags || !(os->flags & ARGFLAG_20)) {
+ if (os->flags & ARGFLAG_4) {
+ Opt48 *po = os - 1;
+ if (!(os[-1].flags & ARGFLAG_40)) {
+ if ((level == 1 || level == 2) && !(po->flags & ARGFLAG_80))
+ *(bptr++) = (flags & ARGSPELLFLAG_20) ? '\n' : ' ';
+ os[-1].flags |= ARGFLAG_40;
+ } else if (level == 2) {
+ *(bptr++) = ',';
+ } else if (level == 3) {
+ *(bptr++) = '=';
+ }
+ strcpy(bptr, os->e.param);
+ bptr += strlen(bptr);
+ } else if (os->flags & ARGFLAG_2) {
+ if (level == 1) {
+ *(bptr++) = MAINOPTCHAR[0];
+ } else if (level == 2) {
+ Opt48 *po = os - 2;
+ if (!(os[-1].flags & ARGFLAG_40) && !(po->flags & ARGFLAG_80))
+ *(bptr++) = (flags & ARGSPELLFLAG_20) ? '\n' : ' ';
+ }
+
+ if (os[-1].flags & ARGFLAG_40) {
+ if (level == 2) {
+ if (flags & ARGSPELLFLAG_20)
+ *(bptr++) = ',';
+ else
+ *(bptr++) = ' ';
+ }
+ } else {
+ if (level == 3) {
+ *(bptr++) = '=';
+ }
+ }
+
+ os[-1].flags |= ARGFLAG_40;
+ strcpy(bptr, os->e.o.curopt);
+ bptr += strlen(bptr);
+ }
+
+ if (flags & ARGSPELLFLAG_20)
+ os->flags |= ARGFLAG_20;
+ }
+
+ if (os->flags & ARGFLAG_1)
+ level++;
+
+ ++sp;
+ ++os;
+ }
+}
+
+void Args_AddToToolArgs(anon0_50 *ta) {
+ char buffer[4096];
+ char *nptr;
+
+ Args_SpellStack(buffer, ARGSPELLFLAG_20);
+ nptr = strchr(buffer, '\n');
+ if (nptr) {
+ *(nptr++) = 0;
+ Arg_AddToToolArgs(ta, 2, buffer);
+ Arg_AddToToolArgs(ta, 1, 0);
+ } else {
+ nptr = buffer;
+ }
+ Arg_AddToToolArgs(ta, 2, nptr);
+}
+
+void Options_Init() {
+ numoptionlists = 0;
+ maxlegalset = 0;
+ numlegalset = 0;
+ numinternalset = 0;
+
+ if (legalset.list)
+ free(legalset.list);
+ if (internalset.list)
+ free(internalset.list);
+
+ legalset.list = 0;
+ legalset.flags =
+ ((Option_ThisTool() & OTF_TOOL_COMPILER) ? LISTFLAGS_COMPILER : 0) |
+ ((Option_ThisTool() & OTF_TOOL_LINKER) ? LISTFLAGS_LINKER : 0) |
+ ((Option_ThisTool() & OTF_TOOL_DISASSEMBLER) ? LISTFLAGS_DISASSEMBLER : 0);
+ internalset.list = 0;
+ internalset.flags =
+ ((Option_ThisTool() & OTF_TOOL_COMPILER) ? LISTFLAGS_COMPILER : 0) |
+ ((Option_ThisTool() & OTF_TOOL_LINKER) ? LISTFLAGS_LINKER : 0) |
+ ((Option_ThisTool() & OTF_TOOL_DISASSEMBLER) ? LISTFLAGS_DISASSEMBLER : 0);
+
+ Args_InitStack();
+}
+
+OptionList *Options_GetOptions() {
+ return &legalset;
+}
+
+void Options_SortOptions() {
+ int r;
+
+ if (numinternalset > 0) {
+ legalset.list = (Option **) xrealloc("options", legalset.list, sizeof(Option *) * (numinternalset + 1));
+ for (r = 0; r < numinternalset; r++) {
+ if (internalset.list[r]->avail & (OTF2 | OTF_CASED))
+ legalset.list[numlegalset++] = internalset.list[r];
+ }
+ for (r = 0; r < numinternalset; r++) {
+ if (!(internalset.list[r]->avail & (OTF2 | OTF_CASED)))
+ legalset.list[numlegalset++] = internalset.list[r];
+ }
+ legalset.list[numlegalset] = 0;
+
+ if (internalset.list)
+ free(internalset.list);
+ internalset.list = 0;
+ numinternalset = 0;
+ }
+}
+
+static void Options_AddOption(Option *opt) {
+ if (numinternalset >= maxlegalset) {
+ maxlegalset += 32;
+ internalset.list = (Option **) xrealloc("options", internalset.list, sizeof(Option *) * (maxlegalset + 1));
+ }
+
+ internalset.list[numinternalset++] = opt;
+ internalset.list[numinternalset] = 0;
+}
+
+int Options_AddList(OptionList *optlst) {
+ Option **ptr;
+
+ if (numoptionlists >= 32)
+ CLPFatalError("Too many option lists defined!");
+
+ optionlists[numoptionlists++] = optlst;
+ for (ptr = optlst->list; *ptr; ptr++)
+ Options_AddOption(*ptr);
+
+ return 1;
+}
+
+int Options_AddLists(OptionList **optlst) {
+ int ret = 1;
+ OptionList **ptr;
+
+ for (ptr = optlst; *ptr; ptr++) {
+ ret = Options_AddList(*ptr);
+ if (!ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void Options_Reset(OptionList *optlst) {
+ Option **os;
+
+ os = optlst->list;
+ if (os) {
+ for (; *os; os++) {
+ (*os)->avail &= ~(OTF80000000 | OTF40000000);
+ }
+ }
+}
+
+static void Option_SpellList(char *buffer, OptionList *conflicts, int flags) {
+ // r25: buffer
+ // r0: conflicts
+ // r26: flags
+
+ Option **scan; // r30
+ Boolean first; // r29
+ int total; // r28
+ char tmp[256]; // stack 0x58
+ Option **next; // r27
+ int slflags; // r6
+
+ scan = conflicts->list;
+ first = 1;
+ total = 0;
+ while (*scan) {
+ next = scan + 1;
+ if (!((*scan)->avail & (((parseopts.helpFlags & HELPFLAGS_SECRET) ? 0 : OTF_SECRET) | ((parseopts.helpFlags & HELPFLAGS_DEPRECATED) ? 0 : OTF_DEPRECATED) | OTF_SUBSTITUTED)) && (*scan)->names[0]) {
+ // 17C1BC
+ if (!first)
+ buffer += sprintf(buffer, ", ");
+ if (first)
+ first = 0;
+
+ if (total > 1) {
+ while (*next && (((*next)->avail & (((parseopts.helpFlags & HELPFLAGS_SECRET) ? 0 : OTF_SECRET) | ((parseopts.helpFlags & HELPFLAGS_DEPRECATED) ? 0 : OTF_DEPRECATED) | OTF_SUBSTITUTED)) || !(*next)->names[0])) {
+ ++next;
+ }
+
+ if (!*next)
+ buffer += sprintf(buffer, "or ");
+ }
+
+ slflags = (flags & OPTSPELLFLAG_2) ? SLFLAGS_2 : SLFLAGS_1;
+ switch ((*scan)->avail & OTF_SLFLAGS_MASK) {
+ case OTF_SLFLAGS_8:
+ slflags |= SLFLAGS_8;
+ break;
+ case OTF_SLFLAGS_20:
+ slflags |= SLFLAGS_20;
+ break;
+ case OTF_SLFLAGS_10:
+ slflags |= SLFLAGS_10;
+ break;
+ }
+
+ Utils_SpellList((*scan)->names, tmp, slflags);
+ total++;
+ buffer += sprintf(buffer, "%s", tmp);
+
+ if ((*scan)->avail & OTF8000)
+ buffer += sprintf(buffer, " ...");
+ }
+ scan++;
+ }
+}
+
+int Option_ForTool(Option *opt, int which) {
+ return !which || (opt->avail & which);
+}
+
+int Option_ThisTool() {
+ return (pTool->TYPE == CWDROPINCOMPILERTYPE) ? OTF_TOOL_COMPILER : OTF_TOOL_LINKER;
+}
+
+int Option_ForThisTool(Option *opt) {
+ return !Option_ForTool(opt, OTF_TOOL_MASK) || Option_ForTool(opt, Option_ThisTool());
+}
+
+int Option_AlsoPassedToTool(Option *opt, int which) {
+ return Option_ForThisTool(opt) && Option_ForTool(opt, which);
+}
+
+int Option_AlsoPassedFromThisTool(Option *opt) {
+ return Option_ForThisTool(opt) && Option_ForTool(opt, ~Option_ThisTool() & OTF_TOOL_MASK);
+}
+
+static Boolean Option_ContinuesThisLevel(int level, ArgToken *tok) {
+ // tok: r30
+ ArgToken *tmp; // r0
+ int ret; // not in stabs but i think this exists
+
+ if (level == 1) {
+ return (tok->val == ATK_1) || (tok->val == ATK_3) || (tok->val == ATK_2);
+ } else if (level == 2) {
+ tmp = Arg_UsedToken();
+ ret = (tok->val == ATK_5 && tmp->val != ATK_3) || (tok->val == ATK_2 && tmp->val != ATK_1);
+ Arg_UndoToken();
+ return ret;
+ } else if (level == 3) {
+ return (tok->val == ATK_4) || (tok->val == ATK_2);
+ } else {
+ return 0;
+ }
+}
+
+static short endingStack[5][3];
+static Boolean Option_IsEndingThisLevel(int level, ArgToken *tok) {
+ // level, tok: r0
+ ArgToken *tmp; // r0
+
+ if (!tok)
+ return 0;
+ // todo
+}
+
+static Boolean Option_IsEndingLevel(int level, ArgToken *tok) {
+ // level: r30
+ // tok: r31
+}
+
+int Option_Parse(Option *opt, int oflags) {
+ // opt: r24
+ // oflags: r25
+ int ret; // r29
+ int pushed; // r28
+ int samelevel; // r30
+ int subparse; // r27
+ int flags; // r26
+ char errstr[1024]; // stack 0x3C
+ Option **cscan; // r30
+ Option **scan; // r5
+ int goingtosubparse; // r30
+ ArgToken *tok; // r0
+}
+
+static int Option_MatchString(char *list, char *str, int flags, int *result) {
+ // list: r26
+ // str: r27
+ // flags: r0
+ // result: r28
+ int str_len; // r0
+ char cpy[64]; // stack 0x3C
+}
+
+static Option *Option_Lookup(OptionList *search, int unk, int *flags) {
+ // search: r0
+ // flags: r25
+ Option **os; // r29
+ Option *stickyopt; // r28
+ int stickyflags; // r27
+ Boolean matched; // r0
+ char *names; // r26
+}
+
+static int Options_DoParse(OptionList *search, int flags) {
+ // search: r26
+ // flags: r28
+ int haderrors; // r30
+ int parsedany; // r23
+ int failed; // r24
+ int matchflags; // stack 0x3C
+ int subparse; // r20
+ ArgToken *starttok; // r0
+ ArgToken *tok; // r25
+ ArgToken *opttok; // r27
+ Option *opt; // r16
+ Boolean isOpt; // r0
+ char *lptr; // r17
+ char *optname; // r16
+ char saveopt[1024]; // stack 0xBC
+ // Option *opt; // r3
+ // char saveopt[64]; // stack 0x7C
+ // ArgToken *prev; // r0
+ // char sticky[64]; // stack 0x3C
+ // ArgToken *prev; // r16
+}
+
+int Options_Parse(OptionList *options, int flags) {
+ // options: r30
+ // flags: r31
+ int ret; // r31
+ char savecuropt[64]; // stack 0x3C
+
+ Options_Reset(options);
+ Option_PushList(options);
+
+ if (!(flags & 2)) {
+ ret = Options_DoParse(options, flags);
+ if (Option_ThisTool() == OTF_TOOL_COMPILER)
+ Arg_AddToToolArgs(&linkargs, 1, 0);
+ } else {
+ strcpy(savecuropt, curopt);
+ ret = Options_DoParse(options, flags);
+ strcpy(curopt, savecuropt);
+ }
+
+ Option_PopList();
+ return ret;
+}
+
+int Option_ParseDefaultOption(OptionList *options) {
+ // options: r31
+ int ret; // r31
+ Option *dopt; // r0
+ int matchflags; // 0x3C
+
+ Options_Reset(options);
+ Option_PushList(options);
+
+ strcpy(curopt, "defaultoptions");
+ dopt = Option_Lookup(options, 0, &matchflags);
+ if (!dopt) {
+ CLPFatalError("Default options not defined");
+ ret = 1;
+ } else {
+ ret = Option_Parse(dopt, 0);
+ }
+
+ Option_PopList();
+ return ret;
+}
+
+void Option_ParamError(short id, va_list ap) {
+ char buf[4096];
+
+ CLPGetErrorString(id, buf);
+ sprintf(&buf[strlen(buf)], "\nwhile parsing option '");
+ Args_SpellStack(&buf[strlen(buf)], 0);
+ sprintf(&buf[strlen(buf)], "'");
+ CLPReportError_V(buf, ap);
+}
+
+void Option_ParamWarning(short id, va_list ap) {
+ char buf[1024];
+
+ CLPGetErrorString(id, buf);
+ sprintf(&buf[strlen(buf)], "\nwhile parsing option '");
+ Args_SpellStack(&buf[strlen(buf)], 0);
+ sprintf(&buf[strlen(buf)], "'");
+ CLPReportWarning_V(buf, ap);
+}
+
+void Option_OptionError(short id, va_list ap) {
+ char buf[1024];
+
+ CLPGetErrorString(id, buf);
+ if (Args_StackSize() >= 2) {
+ sprintf(&buf[strlen(buf)], "\nwhile parsing option '");
+ Args_SpellStack(&buf[strlen(buf)], 0);
+ sprintf(&buf[strlen(buf)], "'");
+ }
+ CLPReportError_V(buf, ap);
+}
+
+void Option_OptionWarning(short id, va_list ap) {
+ char buf[1024];
+
+ CLPGetErrorString(id, buf);
+ if (Args_StackSize() >= 2) {
+ sprintf(&buf[strlen(buf)], "\nwhile parsing option '");
+ Args_SpellStack(&buf[strlen(buf)], 0);
+ sprintf(&buf[strlen(buf)], "'");
+ }
+ CLPReportWarning_V(buf, ap);
+}
+
+void Option_Error(short id, ...) {
+ va_list va;
+ va_start(va, id);
+ Option_OptionError(id, va);
+ va_end(va);
+}
+
+void Option_Warning(short id, ...) {
+ va_list va;
+ va_start(va, id);
+ Option_OptionWarning(id, va);
+ va_end(va);
+}
+
+int Options_Help(const char *keyword) {
+ // keyword: r31
+ int scan; // r26
+ OptionList *lst; // r25
+
+ Help_Init();
+
+ if (parseopts.helpFlags & HELPFLAGS_USAGE) {
+ ShowVersion(1);
+ Help_Line('=');
+ Help_Usage();
+ } else {
+ ShowVersion(1);
+ for (scan = 0; scan < numoptionlists; scan++) {
+ if ((lst = optionlists[scan])) {
+ if (parseopts.helpFlags & HELPFLAGS_8000) {
+ if (keyword && keyword[0] && lst->help && strstr(lst->help, keyword))
+ Help_Options(lst, 0, "");
+ } else {
+ Help_Options(lst, 0, keyword);
+ }
+ }
+ }
+ }
+
+ Help_Term();
+ return 1;
+}
+
+int Option_Help(const char *opt) {
+ // opt: r31
+ Option *find; // r29
+ int matchflags; // stack 0x3C
+ int ret; // r29
+
+ find = 0;
+ Option_PushList(Options_GetOptions());
+ Option_PushOpt(0, "help");
+ if (opt[0] == MAINOPTCHAR[0])
+ strcpy(curopt, opt + 1);
+ else
+ strcpy(curopt, opt);
+
+ if (!curopt[1])
+ find = Option_Lookup(Options_GetOptions(), 0x700002, &matchflags);
+ if (!find)
+ find = Option_Lookup(Options_GetOptions(), 0x700000, &matchflags);
+
+ if (find) {
+ Help_Init();
+ if (!Help_Option(Options_GetOptions(), find, 0, ""))
+ CLPReportWarning(38, opt);
+ Help_Term();
+ ret = 1;
+ } else {
+ Option_Error(19, opt);
+ ret = 0;
+ }
+
+ Option_PopOpt(curopt);
+ Option_PopList();
+ return ret;
+}
+
+int Options_DisplayHelp() {
+ if (parseopts.helpFlags & HELPFLAGS_1)
+ Option_Help(parseopts.helpKey);
+ else
+ Options_Help(parseopts.helpKey);
+}