mirror of https://git.wuffs.org/MWCC
1160 lines
34 KiB
C
1160 lines
34 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];
|
|
|
|
extern char curparam[1024]; // check me
|
|
|
|
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) {
|
|
Option **scan;
|
|
Boolean first;
|
|
int total;
|
|
char tmp[256];
|
|
Option **next;
|
|
int slflags;
|
|
|
|
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]) {
|
|
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) {
|
|
ArgToken *tmp;
|
|
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) {
|
|
ArgToken *tmp;
|
|
|
|
if (!tok)
|
|
return 1;
|
|
if (tok->val == endingStack[level][0])
|
|
return 1;
|
|
|
|
if (endingStack[level][1] && tok->val == endingStack[level][1]) {
|
|
tmp = Arg_UsedToken();
|
|
if (tmp && tmp->val == endingStack[level][2]) {
|
|
Arg_UndoToken();
|
|
return 1;
|
|
}
|
|
Arg_UndoToken();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Boolean Option_IsEndingLevel(int level, ArgToken *tok) {
|
|
if (!tok)
|
|
return 1;
|
|
|
|
while (level > 0) {
|
|
if (Option_IsEndingThisLevel(level - 1, tok))
|
|
return 1;
|
|
level--;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum {
|
|
OFLAGS_1 = 1,
|
|
OFLAGS_2 = 2,
|
|
OFLAGS_4 = 4,
|
|
OFLAGS_8 = 8,
|
|
OFLAGS_10 = 0x10,
|
|
OFLAGS_20 = 0x20,
|
|
OFLAGS_40 = 0x40,
|
|
OFLAGS_80 = 0x80
|
|
};
|
|
enum {
|
|
PFLAGS_1 = 1,
|
|
PFLAGS_2 = 2,
|
|
PFLAGS_4 = 4,
|
|
PFLAGS_8 = 8,
|
|
PFLAGS_10 = 0x10,
|
|
PFLAGS_20 = 0x20,
|
|
PFLAGS_40 = 0x40,
|
|
PFLAGS_80 = 0x80
|
|
};
|
|
|
|
int Option_Parse(Option *opt, int oflags) {
|
|
int ret;
|
|
int pushed;
|
|
int samelevel;
|
|
int subparse;
|
|
int flags;
|
|
char errstr[1024];
|
|
Option **cscan;
|
|
Option **scan;
|
|
int goingtosubparse;
|
|
ArgToken *tok;
|
|
|
|
ret = 1;
|
|
pushed = 0;
|
|
samelevel = (opt->avail & OTF_GLOBAL) == (oflags & OFLAGS_1);
|
|
subparse = (oflags & OFLAGS_2) != 0;
|
|
flags = 0;
|
|
if (subparse) flags |= PFLAGS_4;
|
|
if (oflags & OFLAGS_8) flags |= PFLAGS_8;
|
|
if (oflags & OFLAGS_40) flags |= PFLAGS_1;
|
|
|
|
if (curopt[0]) {
|
|
pushed = 1;
|
|
Option_PushOpt(opt, curopt);
|
|
}
|
|
|
|
if (samelevel) {
|
|
if (!(flags & PFLAGS_1)) {
|
|
if ((opt->avail & OTF80000000) && (opt->avail & OTF20000)) {
|
|
Option_Warning(30);
|
|
} else if (opt->avail & OTF40000) {
|
|
cscan = opt->conflicts->list;
|
|
while (*cscan && (*cscan == opt || !((*cscan)->avail & OTF80000000))) {
|
|
++cscan;
|
|
}
|
|
|
|
if (*cscan && *cscan != opt) {
|
|
(*cscan)->avail &= ~OTF80000000;
|
|
Option_SpellList(errstr, opt->conflicts, oflags);
|
|
if (opt->conflicts->help)
|
|
Option_Warning(32, (*cscan)->names, errstr, opt->conflicts->help);
|
|
else
|
|
Option_Warning(31, (*cscan)->names, errstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Option_ThisTool() == OTF_TOOL_COMPILER && Option_ForTool(opt, OTF_TOOL_LINKER | OTF_TOOL_DISASSEMBLER)) {
|
|
flags |= PFLAGS_2;
|
|
if (!Option_ForThisTool(opt))
|
|
flags |= PFLAGS_1;
|
|
if (!subparse)
|
|
Arg_AddToToolArgs(&linkargs, ATK_1, 0);
|
|
Args_AddToToolArgs(&linkargs);
|
|
}
|
|
|
|
if (!(flags & PFLAGS_1)) {
|
|
if (opt->avail & OTF_OBSOLETE) {
|
|
if (opt->help)
|
|
Option_Error(22, opt->help);
|
|
else
|
|
Option_Error(21);
|
|
flags |= PFLAGS_1;
|
|
}
|
|
|
|
if (opt->avail & OTF_IGNORED) {
|
|
if (!(opt->avail & (OTF_WARNING | OTF_MEANINGLESS))) {
|
|
if (opt->help)
|
|
Option_Warning(27, opt->help);
|
|
else
|
|
Option_Warning(26);
|
|
}
|
|
flags |= PFLAGS_1;
|
|
} else if (opt->avail & OTF_SUBSTITUTED) {
|
|
Option_Warning(23, curopt, opt->help);
|
|
} else if (opt->avail & OTF_DEPRECATED) {
|
|
if (opt->help)
|
|
Option_Warning(25, opt->help);
|
|
else
|
|
Option_Warning(24);
|
|
}
|
|
|
|
if (opt->avail & OTF_WARNING)
|
|
Option_Warning(28, opt->help);
|
|
if (opt->avail & OTF_MEANINGLESS)
|
|
Option_Warning(29);
|
|
}
|
|
|
|
opt->avail |= OTF80000000;
|
|
if (opt->avail & OTF40000) {
|
|
scan = opt->conflicts->list;
|
|
opt->avail |= OTF40000000;
|
|
while (*scan) {
|
|
(*scan)->avail |= OTF40000000;
|
|
scan++;
|
|
}
|
|
}
|
|
} else {
|
|
flags |= PFLAGS_1;
|
|
}
|
|
|
|
goingtosubparse = opt->avail & OTF8000;
|
|
if (opt->param) {
|
|
ret = Params_Parse(opt->param, flags | (goingtosubparse ? PFLAGS_20 : 0));
|
|
} else {
|
|
tok = Arg_PeekToken();
|
|
if (tok && tok->val == ATK_4)
|
|
Arg_UsedToken();
|
|
}
|
|
|
|
if (ret && goingtosubparse) {
|
|
ret = ret && Options_Parse(
|
|
opt->sub,
|
|
(oflags & ~OFLAGS_4)
|
|
| OFLAGS_2
|
|
| ((flags & PFLAGS_1) ? OFLAGS_40 : 0)
|
|
| (subparse ? OFLAGS_10 : 0)
|
|
| ((opt->avail & OTF10000) ? OFLAGS_4 : 0)
|
|
);
|
|
}
|
|
|
|
if (pushed)
|
|
Option_PopOpt(curopt);
|
|
|
|
if (Option_ThisTool() == OTF_TOOL_COMPILER && !subparse)
|
|
Arg_AddToToolArgs(&linkargs, ATK_1, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int Option_MatchString(char *list, char *str, int flags, int *result) {
|
|
int str_len;
|
|
char cpy[64];
|
|
|
|
if (result)
|
|
*result = 0;
|
|
|
|
if (!list[0] && !str[0])
|
|
return 1;
|
|
|
|
while (*list) {
|
|
if (Utils_CompareOptionString(list, str, flags & OTF_CASED, 0))
|
|
return 1;
|
|
|
|
switch (flags & OTF_SLFLAGS_MASK) {
|
|
case OTF_SLFLAGS_8:
|
|
if (my_tolower(str[0]) == 'n' && my_tolower(str[1]) == 'o' && Utils_CompareOptionString(list, str + 2, flags & OTF_CASED, 0)) {
|
|
if (result)
|
|
*result |= 0x100000;
|
|
return 1;
|
|
}
|
|
break;
|
|
case OTF_SLFLAGS_20:
|
|
if (my_tolower(str[0]) == 'n' && my_tolower(str[1]) == 'o' && str[2] == '-' && Utils_CompareOptionString(list, str + 3, flags & OTF_CASED, 0)) {
|
|
if (result)
|
|
*result |= 0x400000;
|
|
return 1;
|
|
}
|
|
break;
|
|
case OTF_SLFLAGS_10:
|
|
str_len = strlen(str);
|
|
if (str[str_len - 1] == '-') {
|
|
strcpy(cpy, str);
|
|
cpy[str_len - 1] = 0;
|
|
if (Utils_CompareOptionString(list, cpy, flags & OTF_CASED, 0)) {
|
|
if (result)
|
|
*result |= 0x200000;
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
while (*list && *list != '|')
|
|
++list;
|
|
|
|
if (*list)
|
|
++list;
|
|
if (*list == '|')
|
|
++list;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Option *Option_Lookup(OptionList *search, int unk, int *flags) {
|
|
Option **os;
|
|
Option *stickyopt;
|
|
int stickyflags;
|
|
Boolean matched;
|
|
char *names;
|
|
|
|
os = search->list;
|
|
stickyopt = 0;
|
|
stickyflags = *flags;
|
|
|
|
if (os) {
|
|
while (*os) {
|
|
names = (*os)->names;
|
|
if (((*os)->avail & OTF2) == OTF2) {
|
|
while (*names && *names != '|')
|
|
++names;
|
|
if (*names)
|
|
++names;
|
|
if (*names == '|')
|
|
++names;
|
|
}
|
|
|
|
matched = Option_MatchString(names, curopt, (*os)->avail & (OTF_SLFLAGS_MASK | OTF_CASED), flags) && (*names || names == (*os)->names);
|
|
if (matched) {
|
|
if (!stickyopt || (*os)->names[0] == curopt[0] || strlen(curopt) > 1)
|
|
return *os;
|
|
}
|
|
|
|
if ((*os)->avail & OTF2) {
|
|
matched = Utils_CompareOptionString((*os)->names, curopt, (*os)->avail & OTF_CASED, 2);
|
|
if (matched)
|
|
stickyflags |= OTF2;
|
|
} else {
|
|
matched = 0;
|
|
}
|
|
|
|
if (matched)
|
|
stickyopt = *os;
|
|
|
|
++os;
|
|
}
|
|
}
|
|
|
|
*flags = stickyflags;
|
|
return stickyopt;
|
|
}
|
|
|
|
static int Options_DoParse(OptionList *search, int flags) {
|
|
// search: r26 *n
|
|
// flags: r28 *n
|
|
int haderrors; // r30 *n
|
|
int parsedany; // r23 *n
|
|
int failed; // r24 *n
|
|
int matchflags; // stack 0x38
|
|
int subparse; // r20 *n
|
|
ArgToken *starttok; // r0 (actually r19 i think?)
|
|
int mystery_r31; // figure out what var this actually is
|
|
ArgToken *tok; // r25 *n
|
|
ArgToken *opttok; // r27 *n
|
|
ArgToken *token_r18; // r18 MAYBE????
|
|
Option *opt; // r16 *n
|
|
Boolean isOpt; // r0
|
|
char *lptr; // r17 *n
|
|
char *optname; // r16 *n
|
|
|
|
// 915
|
|
haderrors = 0;
|
|
// 917
|
|
failed = 0;
|
|
// 918
|
|
matchflags = 0;
|
|
// 920
|
|
subparse = (flags & OFLAGS_2) != 0;
|
|
// 921
|
|
mystery_r31 = subparse && (flags & OFLAGS_10);
|
|
// 925
|
|
opttok = 0;
|
|
// 929
|
|
mystery_r31 = (subparse == 0) ? 1 : (mystery_r31 == 0) ? 2 : 3;
|
|
|
|
starttok = Arg_PeekToken(); // i think this is starttok
|
|
while ((token_r18 = Arg_PeekToken())) {
|
|
parsedany = 0;
|
|
isOpt = ((mystery_r31 == 1) && (token_r18->val == ATK_3)) || ((mystery_r31 == 2) && (token_r18->val == ATK_2) && (token_r18->text[0] || search->flags & LISTFLAGS_4)) || ((mystery_r31 == 3) && (token_r18->val == ATK_4));
|
|
// 950 17CFD4
|
|
if ((mystery_r31 == 3) && isOpt) {
|
|
token_r18 = Arg_UsedToken();
|
|
isOpt = token_r18 && (token_r18->val == ATK_2);
|
|
flags &= ~OFLAGS_4;
|
|
}
|
|
// 957 17D00C
|
|
if (isOpt) {
|
|
// 959
|
|
opt = 0;
|
|
// 960
|
|
Arg_GetTokenText(token_r18, curopt, sizeof(curopt), 0);
|
|
// 963
|
|
if (curopt[0]) {
|
|
opt = Option_Lookup(search, 0x700000, &matchflags);
|
|
if (opt) {
|
|
opttok = token_r18;
|
|
if (!(matchflags & 2)) {
|
|
// 972
|
|
if (token_r18->val == ATK_3)
|
|
Arg_UsedToken();
|
|
token_r18 = Arg_UsedToken();
|
|
} else {
|
|
lptr = opt->names;
|
|
optname = token_r18->text;
|
|
while (*lptr && *lptr != '|')
|
|
++lptr;
|
|
token_r18 = Arg_UsedToken();
|
|
|
|
if (!subparse)
|
|
strcpy(token_r18->text, optname + (lptr - opt->names));
|
|
|
|
curopt[(lptr - opt->names)] = 0;
|
|
|
|
if (!token_r18->text || !token_r18->text[0]) {
|
|
Option_PushOpt(0, curopt);
|
|
Option_ParamError(34, curopt);
|
|
Option_PopOpt(0);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1006
|
|
if (!opt) {
|
|
// 1009
|
|
if (search->flags & LISTFLAGS_4) {
|
|
char saveopt[1024]; // stack 0xBC
|
|
strcpy(saveopt, curopt);
|
|
curopt[0] = 0;
|
|
opt = Option_Lookup(search, 0, &matchflags);
|
|
strcpy(curopt, token_r18->text);
|
|
|
|
// 1019
|
|
if (opt) {
|
|
if (opt->names[0])
|
|
token_r18 = Arg_UsedToken();
|
|
if (token_r18->val == ATK_4)
|
|
Arg_UsedToken();
|
|
haderrors = Option_Parse(opt, flags) == 0;
|
|
parsedany = 1;
|
|
if (haderrors)
|
|
failed = 1;
|
|
opt = 0;
|
|
} else {
|
|
CLPFatalError("Missing default for variable list");
|
|
return 0;
|
|
}
|
|
// 1041
|
|
strcpy(curopt, saveopt);
|
|
} else if (!opt) {
|
|
// 1059
|
|
curopt[0] = 0;
|
|
// 1061
|
|
if (mystery_r31 > 1) {
|
|
if ((flags & OFLAGS_4) && token_r18 == starttok)
|
|
return haderrors == 0;
|
|
// 1072
|
|
if (search->flags & LISTFLAGS_2) {
|
|
if (!(flags & OFLAGS_1)) {
|
|
Option_SpellList(curparam, search, flags);
|
|
Option_Warning(20, token_r18->text, curparam);
|
|
}
|
|
Arg_UsedToken();
|
|
parsedany = 1;
|
|
} else {
|
|
// 1090
|
|
Option_SpellList(curparam, search, flags);
|
|
Option_Error(20, token_r18->text, curparam);
|
|
failed = 1;
|
|
haderrors++;
|
|
}
|
|
} else {
|
|
// 1099
|
|
if ((search->flags & LISTFLAGS_2) || parseopts.ignoreUnknown) {
|
|
// 1101
|
|
if (!(flags & OFLAGS_1))
|
|
Option_Warning(19, token_r18->text);
|
|
Arg_UsedToken();
|
|
Arg_GetToken();
|
|
parsedany = 1;
|
|
} else {
|
|
// 1115
|
|
Option_Error(19, token_r18->text);
|
|
failed = 1;
|
|
haderrors++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1126 - after_if_1006
|
|
if (!haderrors && !failed && opt) {
|
|
flags &= ~OFLAGS_8;
|
|
if (matchflags & 0x700000)
|
|
flags |= OFLAGS_8;
|
|
haderrors = Option_Parse(opt, flags) == 0;
|
|
if (haderrors)
|
|
failed = 1;
|
|
parsedany++;
|
|
} // else: goto 1229
|
|
} else if ((mystery_r31 == 1) && (token_r18->val == ATK_2)) {
|
|
// 1142
|
|
opttok = 0;
|
|
curopt[0] = 0;
|
|
opt = Option_Lookup(search, 0, &matchflags);
|
|
strcpy(curopt, token_r18->text);
|
|
if (!opt) {
|
|
Option_Warning(33, curopt);
|
|
failed = 1;
|
|
} else {
|
|
if (!(flags & OFLAGS_1)) {
|
|
haderrors = Option_Parse(opt, flags) == 0;
|
|
} else {
|
|
parseopts.possibleFiles++;
|
|
haderrors = 0;
|
|
}
|
|
parsedany = 1;
|
|
if (haderrors)
|
|
failed = 1;
|
|
else
|
|
Arg_UsedToken();
|
|
}
|
|
} else if ((mystery_r31 > 1) && Option_IsEndingLevel(mystery_r31, token_r18)) {
|
|
// 1193
|
|
Option *opt;
|
|
char saveopt[64]; // stack 0x7C
|
|
strcpy(saveopt, curopt);
|
|
if (!(search->flags & LISTFLAGS_4)) {
|
|
curopt[0] = 0;
|
|
opt = Option_Lookup(search, 0, &matchflags); // probably wrong result reg
|
|
} else {
|
|
opt = 0; // probably wrong reg
|
|
}
|
|
// 1203
|
|
if (!opt) {
|
|
// 1205
|
|
if (!(flags & OFLAGS_4)) {
|
|
Option_Error(34, saveopt);
|
|
failed = 1;
|
|
haderrors++;
|
|
} else {
|
|
strcpy(curopt, saveopt);
|
|
break;
|
|
}
|
|
} else {
|
|
// 1219
|
|
haderrors = Option_Parse(opt, flags) == 0;
|
|
parsedany = 1;
|
|
if (haderrors)
|
|
failed = 1;
|
|
}
|
|
// 1224
|
|
strcpy(curopt, saveopt);
|
|
}
|
|
|
|
// 1229 after_if_1126
|
|
// This is where tok comes into play.
|
|
tok = Arg_PeekToken();
|
|
// 1231
|
|
if (!failed) {
|
|
if (tok && (tok->val == ATK_2) && (matchflags & 2)) {
|
|
// 1235
|
|
ArgToken *prev; // r16
|
|
char sticky[64]; // stack 0x3C
|
|
prev = Arg_UndoToken();
|
|
tok = Arg_UsedToken();
|
|
if (tok->text[0] && prev == opttok) {
|
|
if (opttok) {
|
|
strcpy(sticky, opttok->text);
|
|
sticky[strlen(tok->text)] = 0;
|
|
Option_PushOpt(0, sticky);
|
|
Param_Error(36, Arg_GetTokenName(tok));
|
|
Option_PopOpt(0);
|
|
} else {
|
|
CLPReportError(36, Arg_GetTokenName(tok));
|
|
}
|
|
// 1251
|
|
haderrors++;
|
|
// goes to 1323
|
|
} else {
|
|
// 1256
|
|
if (!tok->text[0])
|
|
tok = Arg_UsedToken();
|
|
// 1257
|
|
if (flags & OFLAGS_1)
|
|
parseopts.possibleFiles++;
|
|
// goes to 1323
|
|
}
|
|
} else {
|
|
// 1267
|
|
if (Option_IsEndingThisLevel(mystery_r31 - 1, tok))
|
|
break;
|
|
if (Option_IsEndingThisLevel(mystery_r31 + 1, tok)) {
|
|
// 1276
|
|
ArgToken *prev = tok; // r16
|
|
tok = Arg_UsedToken();
|
|
// 1278
|
|
if ((mystery_r31 != 1) || (tok->val != ATK_3)) {
|
|
// 1280
|
|
if (opttok) {
|
|
Option_PushOpt(0, opttok->text);
|
|
if (tok->val == ATK_2)
|
|
Param_Error(36, Arg_GetTokenName(tok));
|
|
else
|
|
Param_Error(35, Arg_GetTokenName(prev));
|
|
Option_PopOpt(opttok->text);
|
|
} else if (tok->val == ATK_2) {
|
|
// 1292
|
|
CLPReportError(36, Arg_GetTokenName(tok));
|
|
} else {
|
|
// 1294
|
|
CLPReportError(35, Arg_GetTokenName(prev));
|
|
}
|
|
haderrors++;
|
|
failed++;
|
|
}
|
|
// goto 1323
|
|
} else if ((mystery_r31 < 2) && Option_IsEndingThisLevel(mystery_r31 + 2, tok)) {
|
|
// 1303
|
|
if (opttok) {
|
|
Option_PushOpt(0, opttok->text);
|
|
if (tok->val == ATK_2)
|
|
Param_Error(36, Arg_GetTokenName(tok));
|
|
else
|
|
Param_Error(35, Arg_GetTokenName(tok));
|
|
Option_PopOpt(opttok->text);
|
|
} else if (tok->val == ATK_2) {
|
|
CLPReportError(36, Arg_GetTokenName(tok));
|
|
} else {
|
|
CLPReportError(35, Arg_GetTokenName(tok));
|
|
}
|
|
haderrors++;
|
|
failed++;
|
|
}
|
|
}
|
|
} // else: 1323
|
|
|
|
if (haderrors || failed) {
|
|
while (!Option_IsEndingLevel(mystery_r31, tok))
|
|
tok = Arg_GetToken();
|
|
if (!tok)
|
|
tok = Arg_UndoToken();
|
|
#line 1335
|
|
OPTION_ASSERT(tok);
|
|
}
|
|
|
|
if (!parsedany || haderrors)
|
|
break;
|
|
|
|
if (Option_IsEndingThisLevel(mystery_r31, tok))
|
|
Arg_UsedToken();
|
|
else if (!Option_ContinuesThisLevel(mystery_r31, tok))
|
|
break;
|
|
}
|
|
|
|
return haderrors == 0;
|
|
}
|
|
|
|
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);
|
|
}
|