MWCC/Option.c

631 lines
16 KiB
C

#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);
}