MWCC/command_line/CmdLine/Src/CLMain.c

650 lines
18 KiB
C

#include "mwcc_decomp.h"
jmp_buf exit_program;
int numPlugins;
CLPluginInfo *pluginInfo;
int numPanels;
char **panelNames;
CWCommandLineArgs *panel_args;
CWCommandLineArgs *plugin_args;
Project mainProj;
Target *gTarg;
PCmdLine optsCmdLine;
PCmdLineEnvir optsEnvir;
PCmdLineCompiler optsCompiler;
PCmdLineLinker optsLinker;
CLState clState;
char cmdline_build_date[32];
char cmdline_build_time[32];
Project *gProj = &mainProj;
static SInt16 CLT_dummymain(void *context) {
return 0;
}
static SInt16 CLT_GetDropInFlags(const DropInFlags **flags, SInt32 *flagsSize) {
static const DropInFlags sFlags = {
kCurrentDropInFlagsVersion,
CWFOURCHAR('c','l','d','r'),
7,
0,
0,
12
};
*flags = &sFlags;
*flagsSize = sizeof(sFlags);
return 0;
}
static SInt16 CLT_GetDropInName(const char **dropinName) {
static const char *sDropInName = "Command-Line Driver";
*dropinName = sDropInName;
return 0;
}
static SInt16 CLT_GetDisplayName(const char **displayName) {
static const char *sDisplayName = "Command-Line Driver";
*displayName = sDisplayName;
return 0;
}
static SInt16 CLT_GetPanelList(const CWPanelList **panelList) {
static const char *sPanelNames[4];
static CWPanelList sPanelList = {
kCurrentCWPanelListVersion,
4,
sPanelNames
};
if (clState.plugintype == CWDROPINCOMPILERTYPE) {
sPanelNames[0] = "CmdLine Panel";
sPanelNames[1] = "CmdLine Compiler Panel";
sPanelNames[2] = "CmdLine Linker Panel";
sPanelList.count = 3;
} else {
sPanelNames[0] = "CmdLine Panel";
sPanelNames[1] = "CmdLine Linker Panel";
sPanelList.count = 2;
}
*panelList = &sPanelList;
return 0;
}
static SInt16 CLT_GetTargetList(const CWTargetList **targetList) {
static FourCharCode sCPU = targetCPUAny;
static FourCharCode sOS = targetOSAny;
static CWTargetList sTargetList = {
kCurrentCWTargetListVersion,
1,
&sCPU,
1,
&sOS
};
*targetList = &sTargetList;
return 0;
}
static SInt16 CLT_GetVersionInfo(const VersionInfo **versioninfo) {
static const VersionInfo vi = {
3, 0, 0, 0
};
*versioninfo = &vi;
return 0;
}
static SInt16 CLT_GetFileTypeMappings(const OSFileTypeMappingList **mappinglist) {
static const OSFileTypeMapping ftmes[2] = {
{CWFOURCHAR('B','r','w','s'), "DubL", 4, 0, 0},
{CWFOURCHAR('M','M','P','r'), "looc", 4, 0, 0}
};
static const OSFileTypeMappingList ftml = {
2,
ftmes
};
*mappinglist = &ftml;
return 0;
}
static BasePluginCallbacks clcb = {
CLT_dummymain,
CLT_GetDropInFlags,
CLT_GetDisplayName,
CLT_GetDropInName,
CLT_GetPanelList,
0,
0,
CLT_GetVersionInfo,
CLT_GetFileTypeMappings
};
static int RegisterStaticCmdLinePlugin() {
return RegisterStaticPlugin(&clcb);
}
#include "command_line/CmdLine/Project/Resources/CLErrors.r"
static int RegisterCmdLineResources() {
return RegisterResource("Command-line strings", 12000, STR12000);
}
static Boolean special_debug(Boolean pre, char *) {
if (pre) {
SetupDebuggingTraps();
return 1;
} else {
return 0;
}
}
static Boolean special_plugin_debug(Boolean pre, char *) {
if (pre) {
clState.pluginDebug = 1;
return 1;
} else {
return clState.pluginDebug;
}
}
static Boolean special_stdout_base(Boolean pre, char *) {
if (pre) {
return 1;
} else {
return clState.stdout_base != 0;
}
}
struct SpecialOption {
const char *optname;
char **argp;
Boolean (*func)(Boolean a, char *b);
};
static struct SpecialOption special_options[3] = {
{"", 0, special_debug},
{"--plugin-debug", 0, special_plugin_debug},
{"--stdout", &clState.stdout_base, special_stdout_base}
};
void Main_PreParse(int *argc, char ***argv) {
int idx;
struct SpecialOption *so;
if (*argc > 1) {
do {
idx = 0;
so = special_options;
do {
if (!strcmp(so->optname, (*argv)[1])) {
if (so->argp) {
*so->argp = (*argv)[2];
so->func(1, *so->argp);
(*argv)[1] = (*argv)[0];
(*argc)--;
(*argv)++;
(*argv)[1] = (*argv)[0];
(*argc)--;
(*argv)++;
} else {
so->func(1, 0);
(*argv)[1] = (*argv)[0];
(*argc)--;
(*argv)++;
}
break;
}
idx++;
so++;
} while (idx < 3);
} while (*argc > 1 && idx < 3);
}
}
void Main_PassSpecialArgs(int *argc, char ***argv) {
int idx;
struct SpecialOption *so;
idx = 0;
so = special_options;
do {
if (so->func(0, 0)) {
AppendArgumentList(argc, argv, so->optname);
if (so->argp)
AppendArgumentList(argc, argv, (*so->argp) ? *so->argp : "");
}
idx++;
so++;
} while (idx < 3);
}
static int MainInitialized;
int Main_Initialize(int argc, char **argv) {
static char secret[8];
char exename[256];
OS_InitProgram(&argc, &argv);
memset(&clState, 0, sizeof(CLState));
special_options[0].optname = secret;
secret[7] = 0;
secret[4] = 'b';
secret[1] = '-';
secret[5] = 'u';
secret[2] = 'd';
secret[0] = '-';
secret[3] = 'e';
secret[6] = 'g';
Main_PreParse(&argc, &argv);
clState.argc = argc;
clState.argv = argv;
strcpyn(exename, argv[0], strlen(argv[0]), 256);
exename[255] = 0;
IO_Initialize();
if (!RegisterCmdLineResources())
CLFatalError("Could not initialize resource strings");
if (!OS_IsFullPath(argv[0])) {
clState.programName = argv[0];
} else {
clState.programName = OS_GetFileNamePtr(argv[0]);
}
if (OS_FindProgram(exename, &clState.programSpec))
CLReportError(2, exename);
Plugins_Init();
if (!RegisterStaticCmdLinePlugin())
CLFatalError("Could not initialize built-in plugins");
Proj_Initialize(gProj);
SystemInitResources(&clState.programSpec);
License_Initialize();
MainInitialized = 1;
return 0;
}
int Main_Terminate(int exitcode) {
if (MainInitialized) {
Plugins_Term();
License_Terminate();
Proj_Terminate(gProj);
IO_Terminate();
MainInitialized = 0;
}
return exitcode;
}
enum {
ResultCode_0 = 0,
ResultCode_1 = 1,
ResultCode_2 = 2
};
static int Main_ParseCommandLine() {
Plugin *parser;
CWCommandLineArgs myargs;
int x, y;
FourCharCode vislang;
if (
!Plugins_GetPluginList(0, &numPlugins, &pluginInfo)
|| !Plugins_GetPrefPanelUnion(0, &numPanels, &panelNames)
|| !(panel_args = xcalloc(0, numPanels * sizeof(CWCommandLineArgs)))
|| !(plugin_args = xcalloc(0, numPlugins * sizeof(CWCommandLineArgs)))
) {
CLFatalError("Out of memory during init\n");
}
parser = Plugins_GetParserForPlugin(0, clState.parserstyle, numPlugins, pluginInfo, gTarg->cpu, gTarg->os, numPanels, panelNames);
if (!parser)
CLFatalError("Could not find a command-line parser!");
myargs.argc = clState.argc;
myargs.argv = clState.argv;
myargs.envp = 0;
if (!SendParserRequest(parser, gTarg, &myargs, gTarg->cpu, gTarg->os, numPlugins, pluginInfo, numPanels, panelNames, plugin_args, panel_args, cmdline_build_date, cmdline_build_time, Plugin_GetToolVersionInfo())) {
return CheckForUserBreak() ? ResultCode_2 : ResultCode_1;
}
if (clState.pluginDebug) {
for (y = 0; y < numPanels; y++) {
CLPrintErr("Outgoing args for '%s': ", panelNames[y]);
for (x = 0; x < panel_args[y].argc; x++) {
CLPrintErr("%s ", panel_args[y].argv[x]);
}
CLPrintErr("\n");
}
for (x = 0; x < numPlugins; x++) {
vislang = pluginInfo[x].language ? pluginInfo[x].language : CWFOURCHAR('-','-','-','-');
CLPrintErr(
"Outgoing args for '%c%c%c%c/%c%c%c%c': ",
(pluginInfo[x].plugintype & 0xFF000000) >> 24,
(pluginInfo[x].plugintype & 0x00FF0000) >> 16,
(pluginInfo[x].plugintype & 0x0000FF00) >> 8,
(pluginInfo[x].plugintype & 0x000000FF),
(vislang & 0xFF000000) >> 24,
(vislang & 0x00FF0000) >> 16,
(vislang & 0x0000FF00) >> 8,
(vislang & 0x000000FF)
);
for (y = 1; y < plugin_args[x].argc; y++) {
CLPrintErr("%s ", plugin_args[x].argv[y]);
}
CLPrintErr("\n");
}
}
return ResultCode_0;
}
static int Main_SetupParamBlock() {
PrefPanelsChangedCallback(0);
if (optsCompiler.outMakefile[0]) {
int err = OS_MakeFileSpec(optsCompiler.outMakefile, &clState.makefileSpec);
if (err) {
CLReportOSError(8, err, optsCompiler.outMakefile);
return 1;
}
OS_Delete(&clState.makefileSpec);
}
if (optsCompiler.sbmPath[0]) {
int err = OS_MakePathSpec(0, optsCompiler.sbmPath, &clState.sbmPathSpec);
if (err) {
CLReportOSError(23, err, optsCompiler.sbmPath);
return 1;
}
} else {
OS_GetCWD(&clState.sbmPathSpec);
}
return 0;
}
static int Main_ResolveProject() {
SInt32 startTime;
SInt32 endTime;
int err;
if (optsCmdLine.state == OptsCmdLineState_0 || optsCmdLine.state == OptsCmdLineState_1)
return 0;
startTime = LMGetTicks();
err = CompileFilesInProject();
if (err)
return err;
if (optsCmdLine.state == OptsCmdLineState_3) {
err = LinkProject();
if (err)
return err;
}
if (!DeleteTemporaries())
return 1;
endTime = LMGetTicks();
if (optsCmdLine.timeWorking) {
CLReport(24, (endTime - startTime) / 60.0, "resolve", "", "project", "");
}
return 0;
}
static int UpdatePCmdLineFromVersion(PCmdLine *given, PCmdLine *target) {
static Boolean warned;
SInt16 version = given->version;
*target = *given;
if (clState.pluginDebug && version < 0x1002 && !warned) {
CLReportWarning(104, "CmdLine Panel");
warned = 1;
}
if (version == 0x1000) {
target->stderr2stdout = 0;
version++;
}
if (version == 0x1001) {
target->noCmdLineWarnings = 0;
version++;
}
if (version < 0x1000 || version > 0x1002) {
CLReportError(104, "CmdLine Panel");
return 0;
} else {
target->version = 0x1002;
return 1;
}
}
static int UpdatePCmdLineEnvirFromVersion(PCmdLineEnvir *given, PCmdLineEnvir *target) {
SInt16 version = given->version;
*target = *given;
if ((clState.pluginDebug && version < 0x1000) || version > 0x1000) {
CLReportError(104, "CmdLine Environment");
return 0;
} else {
target->version = 0x1000;
return 1;
}
}
static int UpdatePCmdLineCompilerFromVersion(PCmdLineCompiler *given, PCmdLineCompiler *target) {
static Boolean warned;
SInt16 version = given->version;
*target = *given;
if (clState.pluginDebug && version < 0x1005 && !warned) {
CLReportWarning(104, "CmdLine Compiler Panel");
warned = 1;
}
if (version == 0x1001) {
target->ignoreMissingFiles = 0;
target->printHeaderNames = 0;
version++;
}
if (version == 0x1002) {
target->sbmState = 0;
target->sbmPath[0] = 0;
version++;
}
if (version == 0x1003) {
target->canonicalIncludes = 0;
version++;
}
if (version == 0x1004) {
target->keepObjects = 0;
version++;
}
if (version <= 0x1000 || version > 0x1005) {
CLReportError(104, "CmdLine Compiler Panel");
return 0;
} else {
target->version = 0x1005;
return 1;
}
}
static int UpdatePCmdLineLinkerFromVersion(PCmdLineLinker *given, PCmdLineLinker *target) {
static Boolean warned;
SInt16 version = given->version;
*target = *given;
if (clState.pluginDebug && version < 0x1002 && !warned) {
CLReportWarning(104, "CmdLine Linker Panel");
warned = 1;
}
if (version == 0x1000) {
target->callPreLinker = 1;
target->callPostLinker = 1;
target->keepLinkerOutput = 1;
version++;
}
if (version == 0x1001) {
target->callLinker = 1;
version++;
}
if (version < 0x1000 || version > 0x1002) {
CLReportError(104, "CmdLine Linker Panel");
return 0;
} else {
target->version = 0x1002;
return 1;
}
}
static int UpdatePrefPanels(const char *name) {
PrefPanel *panel;
Handle h;
if (!name || !ustrcmp(name, "CmdLine Panel")) {
if ((panel = Prefs_FindPanel("CmdLine Panel")) && (h = PrefPanel_GetHandle(panel))) {
if (name) {
if (!UpdatePCmdLineFromVersion((PCmdLine *) *h, &optsCmdLine))
return 0;
}
} else {
CLReportError(91, "CmdLine Panel");
return 0;
}
}
if (!name || !ustrcmp(name, "CmdLine Environment")) {
if ((panel = Prefs_FindPanel("CmdLine Environment")) && (h = PrefPanel_GetHandle(panel))) {
if (name) {
if (!UpdatePCmdLineEnvirFromVersion((PCmdLineEnvir *) *h, &optsEnvir))
return 0;
}
} else {
CLReportError(91, "CmdLine Environment");
return 0;
}
}
if (!name || !ustrcmp(name, "CmdLine Compiler Panel")) {
if ((panel = Prefs_FindPanel("CmdLine Compiler Panel")) && (h = PrefPanel_GetHandle(panel))) {
if (name) {
if (!UpdatePCmdLineCompilerFromVersion((PCmdLineCompiler *) *h, &optsCompiler))
return 0;
}
} else {
CLReportError(91, "CmdLine Compiler Panel");
return 0;
}
}
if (!name || !ustrcmp(name, "CmdLine Linker Panel")) {
if ((panel = Prefs_FindPanel("CmdLine Linker Panel")) && (h = PrefPanel_GetHandle(panel))) {
if (name) {
if (!UpdatePCmdLineLinkerFromVersion((PCmdLineLinker *) *h, &optsLinker))
return 0;
}
} else {
CLReportError(91, "CmdLine Linker Panel");
return 0;
}
}
return 1;
}
static int SetupCmdLinePrefPanels() {
int ret;
PrefPanelsChangedCallback = UpdatePrefPanels;
ret = Prefs_AddPanel(
PrefPanel_New("CmdLine Environment", &optsEnvir, sizeof(PCmdLineEnvir))
);
ret |= (
Prefs_AddPanel(PrefPanel_New("CmdLine Panel", 0, sizeof(PCmdLine)))
&& Prefs_AddPanel(PrefPanel_New("CmdLine Compiler Panel", 0, sizeof(PCmdLineCompiler)))
&& Prefs_AddPanel(PrefPanel_New("CmdLine Linker Panel", 0, sizeof(PCmdLineLinker)))
);
return ret;
}
static int Main_SetupContext() {
gTarg = Target_New("default", clState.cpu, clState.os, clState.language);
Target_Add(&gProj->targets, gTarg);
Plugins_AddFileTypeMappingsForTarget(0, 0, gTarg->cpu, gTarg->os);
gTarg->linker = Plugins_GetLinker(0, gTarg->cpu, gTarg->os);
if (gTarg->linker) {
gTarg->linkerDropinFlags = Plugin_GetDropInFlags(gTarg->linker)->dropinflags;
} else {
if (Plugins_GetLinker(0, CWFOURCHAR('*','*','*','*'), CWFOURCHAR('*','*','*','*')))
CLFatalError("A linker is compiled in, but does not match the static target!\n");
gTarg->linkerDropinFlags = 0;
}
gTarg->preLinker = Plugins_GetPreLinker(0, gTarg->cpu, gTarg->os);
if (gTarg->preLinker) {
gTarg->preLinkerDropinFlags = Plugin_GetDropInFlags(gTarg->preLinker)->dropinflags;
} else {
if (Plugins_GetPreLinker(0, CWFOURCHAR('*','*','*','*'), CWFOURCHAR('*','*','*','*')))
CLFatalError("A pre-linker is compiled in, but does not match the static target!\n");
gTarg->preLinkerDropinFlags = 0;
}
gTarg->postLinker = Plugins_GetPostLinker(0, gTarg->cpu, gTarg->os);
if (gTarg->postLinker) {
gTarg->postLinkerDropinFlags = Plugin_GetDropInFlags(gTarg->postLinker)->dropinflags;
} else {
if (Plugins_GetPostLinker(0, CWFOURCHAR('*','*','*','*'), CWFOURCHAR('*','*','*','*')))
CLFatalError("A post-linker is compiled in, but does not match the static target!\n");
gTarg->postLinkerDropinFlags = 0;
}
if (clState.plugintype == CWDROPINLINKERTYPE) {
if (!gTarg->preLinker && !gTarg->linker && !gTarg->postLinker)
CLFatalError("The linker plugin was not found!");
}
gTarg->linkmodel = 0;
Framework_GetEnvInfo();
return 1;
}
int Main_Driver() {
volatile int result;
result = setjmp(exit_program);
if (!result) {
if (!SetupCmdLinePrefPanels())
CLFatalError("Could not initialize preferences");
Main_SetupContext();
if (!(result = Main_ParseCommandLine())) {
if (!(result = Main_SetupParamBlock()))
result = Main_ResolveProject();
}
} else {
result = 1;
}
return result;
}