MWCC/command_line/C++_Parser/Src/Library/Arguments.c

591 lines
14 KiB
C
Raw Permalink Normal View History

#include "parser.h"
2022-10-07 19:02:27 +00:00
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;
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_ARG && prev->text[0] == 0) {
2022-10-07 19:02:27 +00:00
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_ARG_END && (pprev->val == ATK_COMMA || pprev->val == ATK_EQUALS) && (ppprev->val != ATK_ARG || pppprev->val != ATK_OPTION)) {
2022-10-07 19:02:27 +00:00
if (parserDebug)
printf("Coalescing args with '%s'\n", Arg_GetTokenName(pprev));
val = pprev->val;
numargtoks -= 2;
} else if (pprev->val == ATK_ARG_END && ((int) val == ATK_COMMA || (int) val == ATK_EQUALS)) {
2022-10-07 19:02:27 +00:00
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;
}
2023-01-11 22:29:53 +00:00
static void Arg_SkipRespFileWS(void) {
2022-10-07 19:02:27 +00:00
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(CLPStr74, (short) err, "response ", name);
2022-10-07 19:02:27 +00:00
return 0;
} else {
respfilestart = respfile;
Arg_SkipRespFileWS();
in_response_file = 1;
return 1;
}
}
2023-01-11 22:29:53 +00:00
static void Arg_CloseRespFile(void) {
2022-10-07 19:02:27 +00:00
in_response_file = 0;
OS_FreeFileHandle(&respfilehandle);
}
2023-01-11 22:29:53 +00:00
static char *Arg_GetRespFileToken(void) {
2022-10-07 19:02:27 +00:00
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;
}
2023-01-11 22:29:53 +00:00
static unsigned char Arg_GotMore(void) {
2022-10-07 19:02:27 +00:00
if (!in_response_file)
return margind < margc;
else if (respfile[0])
return 1;
else
return margind < margc;
}
2023-01-11 22:29:53 +00:00
static void Arg_Parse(void) {
2022-10-07 19:02:27 +00:00
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_ARG_END, 0);
2022-10-07 19:02:27 +00:00
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(CLPStr2, argstart, argstart + strlen(argstart) - 15, sizeof(buffer));
2022-10-07 19:02:27 +00:00
}
*bufptr = 0;
} else {
if (isOpt) {
Arg_AddToken(ATK_OPTION, buffer);
Arg_AddToken(ATK_ARG, buffer);
2022-10-07 19:02:27 +00:00
} else {
Arg_AddToken(ATK_ARG, buffer);
2022-10-07 19:02:27 +00:00
}
Arg_AddToken(
(unsigned char) ((ch == ',') ? ATK_COMMA : (((ch == '=') || (ch == SEP3)) ? ATK_EQUALS : ATK_END)),
2022-10-07 19:02:27 +00:00
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_OPTION, buffer + (isList && strchr(MAINOPTCHAR, buffer[0])));
Arg_AddToken(ATK_ARG, buffer + (isList && strchr(MAINOPTCHAR, buffer[0])) + 1);
2022-10-07 19:02:27 +00:00
} else {
Arg_AddToken(ATK_ARG, buffer);
Arg_AddToken(ATK_ARG_END, 0);
2022-10-07 19:02:27 +00:00
}
}
if (isOpt || isList)
Arg_AddToken(ATK_ARG_END, 0);
Arg_AddToken(ATK_END, 0);
2022-10-07 19:02:27 +00:00
}
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]));
}
}
}
2023-01-11 22:29:53 +00:00
void Arg_Terminate(void) {
2022-10-07 19:02:27 +00:00
ArgToken *cur;
while (numargtoks > 0) {
cur = &argtoks[--numargtoks];
if (cur->text)
free(cur->text);
}
if (maxargtoks)
free(argtoks);
maxargtoks = 0;
}
2023-01-11 22:29:53 +00:00
void Arg_Reset(void) {
2022-10-07 19:02:27 +00:00
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_END;
2022-10-07 19:02:27 +00:00
cur->text = 0;
}
argtoks[numargtoks++].val = ATK_ARG_END;
argtoks[numargtoks++].val = ATK_END;
2022-10-07 19:02:27 +00:00
scantok = numargtoks - 2;
}
2023-01-11 22:29:53 +00:00
ArgToken *Arg_PeekToken(void) {
2022-10-07 19:02:27 +00:00
if (scantok >= numargtoks)
return 0;
else
return &argtoks[scantok];
}
2023-01-11 22:29:53 +00:00
ArgToken *Arg_UsedToken(void) {
2022-10-07 19:02:27 +00:00
if (scantok < numargtoks)
scantok++;
return Arg_PeekToken();
}
2023-01-11 22:29:53 +00:00
int Arg_IsEmpty(void) {
2022-10-07 19:02:27 +00:00
ArgToken *tok;
tok = Arg_PeekToken();
return (tok == 0 || tok->val == ATK_END);
2022-10-07 19:02:27 +00:00
}
2023-01-11 22:29:53 +00:00
ArgToken *Arg_GetToken(void) {
2022-10-07 19:02:27 +00:00
ArgToken *ret;
ret = Arg_PeekToken();
if (ret)
scantok++;
return ret;
}
2023-01-11 22:29:53 +00:00
ArgToken *Arg_UndoToken(void) {
2022-10-07 19:02:27 +00:00
if (scantok > 0) {
scantok--;
return Arg_PeekToken();
} else {
return 0;
}
}
const char *Arg_GetTokenName(ArgToken *tok) {
if ((int) tok->val == ATK_ARG)
2022-10-07 19:02:27 +00:00
return tok->text;
return
((int) tok->val == ATK_OPTION) ? "option" :
((int) tok->val == ATK_COMMA) ? "comma" :
(((int) compat == COMPAT_1 && (int) tok->val == ATK_EQUALS)) ? "colon or equals" :
(((int) compat != COMPAT_1 && (int) tok->val == ATK_EQUALS)) ? "equals" :
((int) tok->val == ATK_ARG_END) ? "end of argument" :
((int) tok->val == ATK_END) ? "end of command line" :
2022-10-07 19:02:27 +00:00
"<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_ARG || tok->val == ATK_OPTION)
2022-10-07 19:02:27 +00:00
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(CLPStr56, buffer, ptr + strlen(ptr) - ((maxlen <= 32) ? maxlen : 32), maxlen);
2022-10-07 19:02:27 +00:00
}
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_END:
2022-10-07 19:02:27 +00:00
Arg_FinishToolArgs(ta);
break;
case ATK_ARG_END:
2022-10-07 19:02:27 +00:00
if (ta->argv && ta->argv[ta->argc])
Arg_GrowArgs(ta);
break;
case ATK_ARG:
2022-10-07 19:02:27 +00:00
Arg_GrowArg(ta, toktxt);
break;
case ATK_OPTION:
2022-10-07 19:02:27 +00:00
Arg_GrowArg(ta, "-");
break;
case ATK_EQUALS:
2022-10-07 19:02:27 +00:00
Arg_GrowArg(ta, "=");
break;
case ATK_COMMA:
2022-10-07 19:02:27 +00:00
Arg_GrowArg(ta, ",");
break;
default:
2023-01-11 23:26:04 +00:00
CLPFatalError(__FILE__, 787, "Unknown token (%d)", tokval);
2022-10-07 19:02:27 +00:00
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);
}
}