
    <<CompilerClientCommandImpl.mesa>>
        <<Copyright  1985 by Xerox Corporation.  All rights reserved.>>
        <<Satterthwaite, October 21, 1985 5:52:55 pm PDT>>
        <<Maxwell, January 26, 1984 9:05:33 am PST>>
        <<Paul Rovner, December 4, 1983 11:57 am>>
        <<Spreitzer, August 29, 1985 2:13:50 pm PDT>>
        <<Russ Atkinson (RRA) April 3, 1985 4:02:43 pm PST>>
        <<Bob Hagmann April 24, 1986 11:01:13 am PST>>

    DIRECTORY
        Ascii USING [Lower],
        Booting USING [RegisterProcs, RollbackProc],
        Commander USING [CommandObject, Handle, Register],
        CommandTool USING [ArgumentVector, Failed, Parse, RegistrationDirectory, Run],
        CommandUtil USING [PairList, Failed, GetNth, GetRootName, ListLength, Parse, SetExtension],
        CompilerOps USING [LetterSwitches, StreamId, Transaction],
        ComputeServerClient USING [BestServerStats, RemoteSuccess, StartService],
        ComputeServerServer USING [Lookup, RegisteredProcHandle],
        FileNames USING [ConvertToSlashFormat, CurrentWorkingDirectory, GetShortName, ResolveRelativePath],
        FileParms USING [BindingProc],
        FileViewerOps USING [AttachErrorLog, ShowLog, RemoveErrorLog, WaitUntilSaved],
        FS USING [Delete, Error, ExpandName, nullOpenFile, OpenFile, StreamOpen],
        IO USING [Close, EndOfStream, GetTokenRope, IDProc, PutRope, RIS, STREAM],
        MessageWindow USING [Append, Blink, Clear],
        Process USING [GetPriority, InitializeCondition, MsecToTicks, Priority,  SetPriority],
        Pup USING [nullSocket],
        PupName USING [HisName, NameLookup],
        Rope USING [Cat, Concat, Fetch, Find, FromChar, Equal, IsEmpty, Length, ROPE, Substr],
        RopeFile USING [FromStream],
        SystemVersion USING [machineType],
        UserProfile USING [Boolean, Token];

    CompilerClientCommandImpl: MONITOR
        IMPORTS Ascii, Booting, Commander, CommandTool, CommandUtil, ComputeServerClient, ComputeServerServer, FileNames, FileViewerOps, 
        FS, IO, MessageWindow, Process, PupName, Rope, RopeFile, SystemVersion, UserProfile
        = { 

    ROPE: TYPE = Rope.ROPE;

    Outcome: TYPE = {ok, warnings, errors, aborted};

    standardDefaults: CompilerOps.LetterSwitches = DefaultSwitches[];

    directoriesToUseExistingLog: LIST OF ROPE _ NIL;

    CompilerCondition: CONDITION;


    Compile: SAFE PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] ~ TRUSTED { 
        <<Moved here from global frame by Spreitzer August 29, 1985:>>
            parms: REF CompilerOps.Transaction = NEW[CompilerOps.Transaction];
            sourceName, objectName, errorName, rootName, wDir: Rope.ROPE _ NIL;
            sourceStream, objectStream, errorStream: IO.STREAM _ NIL;
            <<>>
            useLog: BOOL;        -- use compiler.log for error reporting
            makeNewLog: BOOL _ TRUE;
            destroyLogOnSuccess: BOOL;
            createIconic: BOOL;
            blinkIfIconic: BOOL;
            viewSeparateLogs: BOOL;

        userAbort: BOOL _ FALSE;    -- set by ^DEL, STOP
        errors, warnings: BOOL _ FALSE;
        someNonSuccess: BOOL _ FALSE;
        remoteMsg: Rope.ROPE _ NIL;
        priority: Process.Priority = Process.GetPriority[];
        switchDefaults: CompilerOps.LetterSwitches;
        verboseComputeServer: BOOL;
        moduleCount: CARDINAL _ 0;
        complex: BOOL = SELECT cmd.procData.clientData FROM $Vanilla => FALSE, $Complex => TRUE, $RemoteVanilla => FALSE, ENDCASE => ERROR;
        preferRemote: BOOL = cmd.procData.clientData = $RemoteVanilla;

        compilerSwitches: Rope.ROPE _ UserProfile.Token["Compiler.Switches"];
        cmdStream: IO.STREAM;
        filesInit: BOOL _ FALSE;
        started: BOOL _ FALSE;
        Cleanup: PROC = {
            Process.SetPriority[priority];
            IF useLog THEN FileViewerOps.ShowLog[
                fileName: FS.ExpandName["Compiler.log", wDir].fullFName,
                destroyIt: ~someNonSuccess AND destroyLogOnSuccess,
                createIconic: createIconic,
                blinkIfIconic: blinkIfIconic
                ];
            };
        Finalize: PROC [userAbort: BOOL] = {
            sourceFileName: Rope.ROPE;
        IF sourceName # NIL THEN {
        <<errorName = NIL iff useLog OR no errors or warnings, under normal circumstances>>
        sourceFileName _ FS.ExpandName[sourceName, wDir].fullFName;
        IF Rope.Length[remoteMsg] > 3 THEN appendRopeToLog[Rope.Substr[remoteMsg, 3]];
        IF useLog OR ~(errors OR warnings)
         THEN FileViewerOps.RemoveErrorLog[sourceFileName]  -- removes ErrorLog button
         ELSE {
        FileViewerOps.ShowLog[fileName: sourceFileName, 
        createIconic: createIconic, blinkIfIconic: blinkIfIconic];
        IF viewSeparateLogs
        THEN {
        IF ~errorName.IsEmpty[] THEN FileViewerOps.ShowLog[fileName: errorName, createIconic: createIconic, blinkIfIconic: blinkIfIconic];
        }
        ELSE FileViewerOps.AttachErrorLog[sourceFileName];
        };
        };

            IF userAbort OR errors THEN {
                IF objectName # NIL THEN
                    DO
                        FS.Delete[name: objectName, wDir: wDir 
                            ! FS.Error => IF error.group = lock OR error.code = $unknownFile THEN EXIT];
                        ENDLOOP;
                };
            IF errorName = NIL THEN {
                errlogFileName: Rope.ROPE _ CommandUtil.SetExtension[rootName, "errlog"]; 
                DO
                    FS.Delete[name: errlogFileName, wDir: wDir 
                        ! FS.Error => IF error.group = lock OR error.code = $unknownFile THEN EXIT];
                    ENDLOOP;
                };
            };

        appendRopeToLog: SAFE PROC [logEntry: ROPE] = CHECKED {
            slashWDir: ROPE _ FileNames.ConvertToSlashFormat[wDir];
            tries: INT _ 0;
            consCurrentDirectory: BOOL _ FALSE;
            innerAppendRopeToLog: ENTRY SAFE PROC = CHECKED {
                ENABLE UNWIND => NULL;
                DO
                    openFailed: BOOL _ FALSE;
                    needNewLog: BOOL;
                    log: IO.STREAM;
                    oldLog: IO.STREAM;
                    consCurrentDirectory _ FALSE;
                    IF makeNewLog THEN {
                        needNewLog _ TRUE;
                        consCurrentDirectory _ TRUE;
                        }
                     ELSE {
                        FOR l: LIST OF ROPE _ directoriesToUseExistingLog, l.rest UNTIL l = NIL DO
                            IF Rope.Equal[l.first, slashWDir] THEN {
                                needNewLog _ FALSE;
                                EXIT;
                                };
                            REPEAT FINISHED => {
                                consCurrentDirectory _ TRUE;
                                needNewLog _ TRUE;
                                };
                            ENDLOOP;
                        };
                    IF ~needNewLog THEN oldLog _ FS.StreamOpen[fileName: "Compiler.log", accessOptions: $read ! FS.Error => {
                        IF error.group = lock THEN {
                            openFailed _ TRUE;
                            tries _ tries + 1;
                            IF tries > 10 THEN {
                                MessageWindow.Clear[];
                                MessageWindow.Append["Compiler lock failure after 10 retries for Compiler.log read"];
                                MessageWindow.Blink[];
                                };
                            CONTINUE;
                            }
                         ELSE CONTINUE;
                        };
                     ];
                    IF openFailed THEN {
                        IF tries > 10 THEN EXIT;
                        WAIT CompilerCondition;
                        LOOP;
                        };
                    log _ FS.StreamOpen[fileName: "Compiler.log", accessOptions: $create ! FS.Error => {
                        IF error.group = lock THEN {
                            openFailed _ TRUE;
                            tries _ tries + 1;
                            IF tries > 10 THEN {
                                MessageWindow.Clear[];
                                MessageWindow.Append["Compiler lock failure after 10 retries for Compiler.log create"];
                                MessageWindow.Blink[];
                                };
                            CONTINUE;
                            };
                        };
                     ];
                    IF openFailed THEN {
                        IF tries > 10 THEN EXIT;
                        WAIT CompilerCondition;
                        LOOP;
                        };
                    IF ~needNewLog AND log # NIL THEN {
                        log.PutRope[RopeFile.FromStream[oldLog]];
                        }; 
                    IF openFailed THEN {
                        IF tries > 10 THEN EXIT;
                        WAIT CompilerCondition;
                        LOOP;
                        };
                    log.PutRope[logEntry];
                    log.Close[];
                    IF consCurrentDirectory THEN directoriesToUseExistingLog _ CONS[slashWDir, directoriesToUseExistingLog];
                    EXIT;
                    ENDLOOP;
                makeNewLog _ FALSE;
                NOTIFY CompilerCondition;
                };
            innerAppendRopeToLog[];
            };

        <<get some parameters from the user's profile>>
        verboseComputeServer _ UserProfile.Boolean["Compiler.VerboseComputeServer", FALSE];
        destroyLogOnSuccess _ UserProfile.Boolean["Compiler.DestroyLogOnSuccess", TRUE];
        createIconic _ UserProfile.Boolean["Compiler.IconicLogs", FALSE];
        blinkIfIconic _ UserProfile.Boolean["Compiler.BlinkLogs", TRUE];
        viewSeparateLogs _ UserProfile.Boolean["Compiler.ViewSeparateLogs", FALSE];
        IF UserProfile.Boolean["Compiler.SeparateLogs", FALSE] 
            THEN compilerSwitches _ Rope.Cat[compilerSwitches, "~g"];
        IF compilerSwitches.Length[] # 0 THEN
            cmd.commandLine _ Rope.Cat[(IF complex THEN "/" ELSE "-"), compilerSwitches, " ", cmd.commandLine];
        cmdStream _ IO.RIS[cmd.commandLine];
        sourceName _ rootName _ objectName _ errorName _ NIL;
        parms.objectName _ NIL;

        <<do the compilation>>
        BEGIN ENABLE UNWIND => Cleanup[];

            switchDefaults _ DefaultSwitches[];

            wDir _ FileNames.CurrentWorkingDirectory[];

            DO
                first: BOOL;
                args, results: CommandUtil.PairList;
                switches: Rope.ROPE _ NIL;
                localPause: BOOL;
                sense: BOOL;

                {  -- start scope for EXITS
                cmdLine: Rope.ROPE _ NIL;
                originalSourceName: Rope.ROPE _ NIL;

                    parms.switches _ switchDefaults;
                    parms.switches['p] _ FALSE;

                    IF complex
                        THEN
                            [sourceName, args, results, switches] _ CommandUtil.Parse[cmdStream
                                ! CommandUtil.Failed => GOTO badSyntax]
                        ELSE {
                            <<use a simple syntax for the command line>>
                            token: Rope.ROPE;
                            token _ cmdStream.GetTokenRope[IO.IDProc ! IO.EndOfStream => EXIT].token;
                            IF token.Length[] > 0 THEN SELECT token.Fetch[0] FROM
                                '- => switches _ token.Substr[1, token.Length[]-1];
                                ENDCASE => sourceName _ token};
                    IF sourceName = NIL AND switches = NIL THEN EXIT;
                    IF CommandUtil.ListLength[results] > 1 THEN GOTO badSemantics;
                    IF sourceName = NIL THEN GOTO globalSwitches;
                    originalSourceName _ sourceName;
                    rootName _ CommandUtil.GetRootName[IF CommandUtil.ListLength[results] = 1
                        THEN CommandUtil.GetNth[results, 0]
                        ELSE FileNames.GetShortName[sourceName]];
                    errorName _ CommandUtil.SetExtension[rootName, "errlog"];
                    IF switches # NIL THEN {
                        sense _ TRUE;
                        FOR i: INT IN [0..switches.Length[]) DO
                            c: CHAR = switches.Fetch[i];
                            SELECT c FROM
                                '-, '~ => {sense _ ~sense; LOOP};
                                IN ['a..'z], IN ['A..'Z] =>
                                    parms.switches[Ascii.Lower[c]] _ sense;
                                IN ['1..'5] =>
                                    parms.debugPass _ c-'0;
                                ENDCASE;
                            sense _ TRUE;
                            ENDLOOP;
                        switches _ NIL;
                        };
                    sourceName _ CommandUtil.SetExtension[sourceName, "mesa"];
                    FileViewerOps.WaitUntilSaved[
                        IF Rope.Find[sourceName, ">"] < 0 AND Rope.Find[sourceName, "/"] < 0 
                            THEN FS.ExpandName[sourceName, wDir].fullFName
                            ELSE sourceName, 
                        cmd.out ! ABORTED => {userAbort _ TRUE; GOTO truncateList}];
                    parms.source.locator _ FileNames.GetShortName[sourceName];

                    IF CommandUtil.ListLength[results] # 0
                        THEN {
                            objectName _ CommandUtil.GetNth[list: results, n: 0, delete: TRUE];
                            results _ NIL;
                            }
                        ELSE objectName _ rootName;
                    objectName _ CommandUtil.SetExtension[objectName, "bcd"];
                    parms.objectName _ objectName;
                    parms.objectFile _ FS.nullOpenFile;

                    moduleCount _ moduleCount + 1;

                    first _ TRUE;
                    makeNewLog _ ~parms.switches['h];  parms.switches['h] _ FALSE;  -- set append or force new log
                    FOR c: CHAR IN ['a..'z] DO
                        sd: BOOL = (IF c = 'p THEN FALSE ELSE standardDefaults[c]);
                        IF parms.switches[c] # sd THEN {
                            IF first THEN {first _ FALSE; cmdLine _ IF complex THEN "/" ELSE "-"};
                            IF sd THEN cmdLine _ cmdLine.Concat["-"];
                            cmdLine _ cmdLine.Concat[Rope.FromChar[c]];
                            };
                        ENDLOOP;
                    cmdLine _ cmdLine.Concat[" "];
                    useLog _ parms.switches['g];  parms.switches['g] _ FALSE;
                    localPause _ parms.switches['p];  parms.switches['p] _ FALSE;

                    <<main line code>>
                    sourceName _ FileNames.GetShortName[sourceName];
                IF complex THEN {
                first: BOOL _ TRUE;
                cmdLine _ cmdLine.Cat[rootName, " _ ", originalSourceName, "["];
                FOR p: CommandUtil.PairList _ args, p.rest UNTIL p=NIL DO
                IF ~first THEN cmdLine _ cmdLine.Concat[", "];
                cmdLine _ cmdLine.Cat[p.first.key, ": ", p.first.val];
                first _ FALSE;
                ENDLOOP;
                cmdLine _ cmdLine.Concat["]"];
                }
                 ELSE cmdLine _ cmdLine.Concat[sourceName];
                    { ENABLE UNWIND => Finalize[userAbort];

                    found: BOOL _ FALSE;
                    success: ComputeServerClient.RemoteSuccess _ false;
                    serverInstance: Rope.ROPE _ NIL;


                    result _ $Blocked;
                    remoteMsg _ NIL;

                    WHILE result = $Blocked DO
                    IF SystemVersion.machineType # dorado THEN {
                    remSuccess: ComputeServerClient.RemoteSuccess;
                    selfBest: BOOL;
                    FigOfMerit: REAL;
                    [success: remSuccess, selfIsBest: selfBest, FOM: FigOfMerit] _ ComputeServerClient.BestServerStats[];
                    IF remSuccess # true OR selfBest OR FigOfMerit > 0.5 THEN {
                    result _ $TryLocal;
                    EXIT;
                    };
                    };
                    IF ~preferRemote THEN result _ $TryLocal;
                    IF result # $TryLocal THEN {
                    IF verboseComputeServer THEN cmd.out.PutRope[" -- Trying remote compile\n"];
                    IF complex THEN {
                    [found: found, success: success, remoteMsg: remoteMsg, serverInstance: serverInstance] _ ComputeServerClient.StartService[service: 
                    "RemoteComplexCompiler", cmdLine: cmdLine, in: NIL, out: cmd.out, queueService: TRUE, timeToWait: 600];
                    }
                     ELSE {
                    [found: found, success: success, remoteMsg: remoteMsg, serverInstance: serverInstance] _ ComputeServerClient.StartService[service: 
                    "RemoteCompiler", cmdLine: cmdLine, in: NIL, out: cmd.out, queueService: TRUE, timeToWait: 600];
                    };
                    SELECT TRUE FROM
                    ~found OR success = false OR success = cantImportController OR success = cantImportServer OR success = communicationFailure OR 
                    success = commandNotFound OR success = clientNotRunning => {
                    IF verboseComputeServer THEN cmd.out.PutRope[" -- Remote compile did not work; do it locally\n"];
                    result _ $TryLocal;
                    };
                    success = aborted => {
                    userAbort _ TRUE;
                    };
                    success = timeOut OR success = serverTooBusy => {
                    IF verboseComputeServer THEN cmd.out.PutRope[Rope.Cat[" -- Remote compile ", (IF success = timeOut THEN "timed out queuing" ELSE 
                    "found a server that was too busy"), "; try again\n"]];
                    LOOP;
                    };
                    found AND success = true => {
                    printServerName: PROC = {
                    serverName: ROPE _ serverInstance;
                    serverName _ PupName.HisName[PupName.NameLookup[serverInstance, Pup.nullSocket]];
                    IF ~serverName.IsEmpty[] THEN cmd.out.PutRope[Rope.Cat[" -- Compute Server used was ", serverName, "\n"]];
                    };
                    IF ~remoteMsg.IsEmpty[] THEN SELECT remoteMsg.Fetch[0] FROM
                    'F => { -- failure
                    result _ $Failure;
                    errors _ TRUE;
                    warnings _ FALSE;
                    IF verboseComputeServer THEN {
                    printServerName[];
                    }
                     ELSE {
                    IF ~serverInstance.IsEmpty[] THEN cmd.out.PutRope[Rope.Cat[" Compute Server used was ", serverInstance, "\n"]];
                    };
                    };
                    'W => { -- warnings
                    result _ $Warning;
                    errors _ FALSE;
                    warnings _ TRUE;
                    IF verboseComputeServer THEN printServerName[];
                    };
                    'S => { -- success
                    result _ $Success;
                    errorName _ NIL;
                    errors _ FALSE;
                    warnings _ FALSE;
                    IF verboseComputeServer THEN printServerName[];
                    };
                    'A => { -- aborted
                    result _ $Aborted;
                    errors _ TRUE;
                    warnings _ FALSE;
                    userAbort _ TRUE;
                    IF verboseComputeServer THEN printServerName[];
                    };
                    'B => { -- blocked
                    bestSuccess: ComputeServerClient.RemoteSuccess;
                    selfIsBest: BOOL;
                    bestFOM: REAL;
                    result _ $Blocked;
                    [success: bestSuccess, selfIsBest: selfIsBest, FOM: bestFOM] _ ComputeServerClient.BestServerStats[];
                    IF verboseComputeServer THEN {
                    cmd.out.PutRope[" -- Server tried was already busy.\n"];
                    printServerName[];
                    };
                    };
                    ENDCASE;
                    };
                    ENDCASE;
                    };
                    ENDLOOP;

                        IF result = $TryLocal THEN {
                            commandName: ROPE = IF complex THEN "RemoteComplexCompiler" ELSE "RemoteCompiler"; 
                            lookupProcData: ComputeServerServer.RegisteredProcHandle;
                            errMsg: ROPE _ NIL;
                            runError: BOOL _ FALSE;
                            lookupProcData _ ComputeServerServer.Lookup["RemoteCompiler", NIL];
                            IF verboseComputeServer THEN cmd.out.PutRope[" -- Trying to do the compile locally.\n"];
                            IF lookupProcData = NIL THEN {
                                dir: ROPE;
                                dir _ CommandTool.RegistrationDirectory[cmd];
                                IF verboseComputeServer THEN cmd.out.PutRope[Rope.Cat[" -- Trying to run CompilerServer.bcd from directory", dir, ".\n"]];
                                [errMsg: errMsg, error: runError] _ CommandTool.Run[bcdName: dir.Concat["CompilerServer.bcd"], runEvenIfAlreadyRun: FALSE, 
                                runEvenIfUnbound: FALSE];
                                lookupProcData _ ComputeServerServer.Lookup["RemoteCompiler", NIL];
                                };
                            IF lookupProcData = NIL THEN {  -- try the standard place
                                IF verboseComputeServer THEN cmd.out.PutRope[Rope.Cat[" -- Trying to run CompilerServer.bcd from directory ///Commands/\n"]];
                                [] _ CommandTool.Run[bcdName: "///Commands/CompilerServer.bcd", runEvenIfAlreadyRun: FALSE, runEvenIfUnbound: FALSE];
                                lookupProcData _ ComputeServerServer.Lookup["RemoteCompiler", NIL];
                                };
                            IF lookupProcData = NIL THEN {
                                msg _ "Failed to start up compiler (CompilerServer.bcd) on the workstation.\n";
                                IF runError AND ~errMsg.IsEmpty[] THEN msg _ msg.Cat[" Error from Run is ", errMsg];
                                appendRopeToLog[Rope.Concat[" -- ", msg]];
                                result _ $Failure;
                                }
                             ELSE {
                                myCmd: Commander.Handle;
                                myCmd _ NEW[Commander.CommandObject _ [
                                    in: cmd.in,
                                    out: cmd.out,
                                    err: cmd.err,
                                    commandLine: cmdLine,
                                    command: commandName,
                                    propertyList: cmd.propertyList,
                                    procData: cmd.procData
                                    ]];
                                result _ $Blocked;
                                WHILE result = $Blocked DO
                                    [result: result, msg: remoteMsg] _ lookupProcData.commanderProcHandle.proc[myCmd];
                                IF ~remoteMsg.IsEmpty[] THEN SELECT remoteMsg.Fetch[0] FROM
                                'F => { -- failure
                                result _ $Failure;
                                errors _ TRUE;
                                warnings _ FALSE;
                                };
                                'W => { -- warnings
                                result _ $Warning;
                                errors _ FALSE;
                                warnings _ TRUE;
                                };
                                'S => { -- success
                                result _ $Success;
                                errorName _ NIL;
                                errors _ FALSE;
                                warnings _ FALSE;
                                };
                                'A => { -- aborted
                                result _ $Aborted;
                                errors _ TRUE;
                                userAbort _ TRUE;
                                warnings _ FALSE;
                                };
                                'B => { -- blocked
                                result _ $Blocked;
                                };
                                ENDCASE;
                                ENDLOOP;

                                };
                            };
                        };  -- end ENABLE UNWIND => Finalize[];
                    IF result # $Success THEN someNonSuccess _ TRUE;
                    Finalize[userAbort];

                    EXITS
                        globalSwitches => {
                            objectName _ NIL;
                            sense _ TRUE;
                            FOR i: INT IN [0..switches.Length[]) DO
                                c: CHAR = switches.Fetch[i];
                                SELECT c FROM
                                    '-, '~ => sense _ ~sense;
                                    IN ['a..'z] => {switchDefaults[c] _ sense; sense _ TRUE};
                                    IN ['A..'Z] => {
                                        switchDefaults[VAL['a.ORD+(c.ORD-'A.ORD)]] _ sense; sense _ TRUE};
                                    ENDCASE => EXIT;
                                ENDLOOP;
                            switches _ NIL;
                            args _ NIL;
                            };
                        badSemantics => {
                            objectName _ NIL; errors _ TRUE;
                            appendRopeToLog[" -- Illegal command"];
                            args _ NIL;
                            };
                    };

                <<Here after completion of subcommand>>
                sourceName _ rootName _ objectName _ errorName _ NIL;
                parms.objectName _ NIL;
                results _ NIL;
                IF userAbort THEN {appendRopeToLog["\n... command aborted\n"];  GOTO truncateList};
                IF (errors OR warnings) AND localPause THEN GOTO truncateList;

                REPEAT
                    badSyntax => {appendRopeToLog["\n-- Illegal syntax"]; errors _ TRUE};
                    truncateList => switchDefaults['p] _ TRUE;
                ENDLOOP;
            <<Here after completion of all subcommands>>

            END;  -- end catch phrase to release the resource and reset the process priority
        Cleanup[];
        };
    <<>>
<<rollback>>

    RollbackRecovery: Booting.RollbackProc  = CHECKED {
        directoriesToUseExistingLog _ NIL;
        };
    <<>>
<<>>
<<new log for compiler>>

    NewCompilerLog: ENTRY SAFE PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] = CHECKED {
        ENABLE UNWIND => NULL;
        argv: CommandTool.ArgumentVector;
        dir: ROPE;
        prev: LIST OF ROPE;
    argv _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg;  CONTINUE; }];
        dir _ FileNames.ConvertToSlashFormat[IF argv.argc < 2 THEN FileNames.CurrentWorkingDirectory[] ELSE 
        FileNames.ResolveRelativePath[argv[1]]];
        FOR l: LIST OF ROPE _ directoriesToUseExistingLog, l.rest UNTIL l = NIL DO
            IF Rope.Equal[l.first, dir] THEN {
                IF l = directoriesToUseExistingLog THEN directoriesToUseExistingLog _ l.rest ELSE prev.rest _ l.rest;
                EXIT;
                };
            prev _ l;
            ENDLOOP;
        };

<<compiler inquiries>>

    DefaultSwitches: PROC RETURNS [CompilerOps.LetterSwitches] = {
        RETURN [[
            TRUE , -- A  Address fault for NIL checks
            TRUE , -- B  Bounds checking
            TRUE , -- C  compile for Cedar (special FORK)
            FALSE, -- D  call Debugger on compiler error (FALSE => just log error)
            TRUE , -- E  fixed (big Eval stack)
            TRUE , -- F  Floating point microcode
            TRUE , -- G  TRUE => log goes to compiler.log, FALSE => use foo.errlog
            FALSE, -- H  TRUE => append to compiler.log, FALSE => write new compiler.log
            FALSE, -- I  unused
            FALSE, -- J  cross-Jumping optimization
            FALSE, -- K  unused
            TRUE , -- L  allocate space for code Links
            TRUE , -- M  reference counting Microcode
            TRUE , -- N  Nil pointer checking
            FALSE, -- O  unused
            FALSE, -- P  Pause after compilation with errors
            FALSE, -- Q  unused
            FALSE, -- R  unused
            TRUE , -- S  Sort (by static frequency) global vars & entry indexes
            FALSE, -- T  unused
            FALSE, -- U  uninitialized variable checking
            FALSE, -- V  unused
            TRUE , -- W  log Warning messages
            FALSE, -- X  unused
            FALSE, -- Y  complain about KFCB
            TRUE   -- Z  FALSE => use old-style method to access ROPE & ATOM literals
            ]]};


    <<START HERE>>
    Booting.RegisterProcs[r: RollbackRecovery];
    Process.InitializeCondition[@CompilerCondition, Process.MsecToTicks[250]];
    Commander.Register["Compile", Compile, "Compile {-switches} xxx* - A simple syntax for compiling a list of cedar modules.  (See 
    'ComplexCompile' for another syntax).  Some useful switches are: 
        -b => bounds checking (default: TRUE -- don't turn this off unless you know what you are doing), 
        -d => call debugger on compiler error (else just log error), 
        -g => log goes to compiler.log (-~g => log goes to foo.errlog), 
        -j => cross-jump (default: FALSE -- don't turn this on unless you know what you are doing), 
        -n => nil checking (default: TRUE -- don't turn this off unless you know what you are doing), 
        -u => check for uninitialized variables, 
        -w => log warning messages (default: TRUE)
    Switches can be negated with '~' (i.e. '-~bj~n').  The complete list of switches is in CompilerSequencer.DefaultSwitches.  The 
    defaults can be set in your user profile with Compiler.Switches.", $Vanilla];
    Commander.Register["RCompile", Compile, "RCompile {-switches} xxx* - Same switches as Compile, but this prefers remote 
    compilation", $RemoteVanilla];
    Commander.Register["ComplexCompile", Compile, "ComplexCompile /j-b-n BcdTreeOps _ ProtoTreeOps[Literals: BcdSymbols, Symbols: 
    BcdSymbols, Tree: BcdTree] . . . - Allows a parameterized compilation.  Switches are marked with '/ and negated with '-.  (See 
    'Compile' for more on switches.)", $Complex];
    Commander.Register["NewCompilerLog", NewCompilerLog, "NewCompilerLog [directory] - Start a new Compiler.log for compiles done in 
    the current directory or the specified directory.  Useful only when the compiles are done with the g switch on "];


    }.

    <<Bob Hagmann March 21, 1986 2:06:37 pm PST>>
        <<Added "H" switch.  Wrote NewCompilerLog and RollbackRecovery to support it.>>
    <<Bob Hagmann April 15, 1986 11:49:54 am PST>>
        <<removed extraneous code from appendRopeToLog>>
        <<changes to: appendRopeToLog (local of Compile)>>
    <<Bob Hagmann April 15, 1986 11:52:43 am PST>>
        <<changes to: DIRECTORY, CompilerClientCommandImpl, appendRopeToLog (local of Compile)>>
    <<Bob Hagmann April 24, 1986 10:58:23 am PST>>
        <<changes to: DIRECTORY, CompilerClientCommandImpl, printServerName (local of Compile)>>
    <<>>
