mirror of https://git.wuffs.org/MWCC
631 lines
16 KiB
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);
|
|
}
|