DIRECTORY Ascii USING [NUL], CLibraryDefs USING [cNULL, Error, exit, open], UnixDefs USING [numOpenFiles, fileInfo, openFiles], MFile USING [Error, Handle, ReadOnly], MStream USING [Handle], MLoader USING [Handle, Run], Heap USING [systemZone], Put USING [Line, LongString], Tool USING [Create, MakeTTYSW, MakeSWsProc, UnusedLogName], ToolWindow USING [TransitionProcType], TTY USING [EchoClass], TTYSW USING [SetEcho, GetLine], Window USING [Handle]; UnixImpl: PROGRAM IMPORTS MFile, MLoader, CLibraryDefs, Heap, Put, Tool, TTYSW, UnixDefs EXPORTS UnixDefs = { DataHandle: TYPE = LONG POINTER TO Data; Data: TYPE = MACHINE DEPENDENT RECORD [ ttySW(0): Window.Handle _ NIL ]; -- Variable declarations ttyWindow: PUBLIC Window.Handle; openFiles: PUBLIC ARRAY [0..UnixDefs.numOpenFiles) OF UnixDefs.fileInfo; argcT: LONG INTEGER _ 0; argvT: LONG POINTER TO LONG POINTER TO INTEGER _ NIL; argvRef: ARRAY [0..10) OF LONG POINTER TO INTEGER _ ALL[NIL]; argvRefRef: ARRAY [0..10) OF ARRAY [0..30) OF INTEGER _ ALL[ALL[0]]; p: PROCESS RETURNS []; toolData: DataHandle _ NIL; wh: Window.Handle; -- Tool's window WatchTTY: PROCEDURE = { -- Do the tasks necessary to execute a form subwindow command. -- Again, if the command will take a long time, then one might FORK a PROCESS to do it. oldEcho: TTY.EchoClass; userInput: LONG STRING _ [100]; fileName: LONG STRING _ [50]; iLine, iArg, iChar, commandLength: CARDINAL; redirect: INTEGER; commandFile: MFile.Handle; commandHandle: MLoader.Handle; Put.Line[toolData.ttySW, "Simple Shell Starting."L]; oldEcho _ TTYSW.SetEcho[ttyWindow, plain]; DO -- forever -- reset the standard input, output and error UnixDefs.openFiles[0].windowHandle _ toolData.ttySW; UnixDefs.openFiles[0].type _ window; UnixDefs.openFiles[1].windowHandle _ toolData.ttySW; UnixDefs.openFiles[1].type _ window; UnixDefs.openFiles[2].windowHandle _ toolData.ttySW; UnixDefs.openFiles[2].type _ window; -- put out the shell prompt and get a command line of input Put.LongString[toolData.ttySW, "% "L]; TTYSW.GetLine[ttyWindow, userInput]; -- parse the command line arguments userInput.text[userInput.length] _ ' ; -- blank at end iArg _ 0; iLine _ 0; argcT _ 0; WHILE iLine < userInput.length DO WHILE userInput.text[iLine] = ' DO -- skip blanks iLine _ iLine + 1; ENDLOOP; iChar _ 0; redirect _ -1; IF userInput.text[iLine] = '< THEN { redirect _ 0; iLine _ iLine + 1; } ELSE IF userInput.text[iLine] = '> THEN { redirect _ 1; iLine _ iLine + 1; }; WHILE userInput.text[iLine] # ' DO -- copy word argvRefRef[iArg][iChar] _ userInput.text[iLine]-0C; iLine _ iLine + 1; iChar _ iChar + 1; ENDLOOP; argvRefRef[iArg][iChar] _ Ascii.NUL-0C; IF iArg = 0 THEN commandLength _ iLine; SELECT redirect FROM -1 => iArg _ iArg + 1; 0, 1 => { UnixDefs.openFiles[redirect].type _ unused; IF CLibraryDefs.open[argvRef[iArg], 2] # redirect THEN CLibraryDefs.Error[ "Can't open redirected input or output file.\n"L]; }; ENDCASE => ERROR; ENDLOOP; argcT _ iArg; userInput.text[commandLength] _ '.; userInput.text[commandLength+1] _ 'b; userInput.text[commandLength+2] _ 'c; userInput.text[commandLength+3] _ 'd; userInput.length _ commandLength+4; { commandFile _ MFile.ReadOnly[userInput, [] ! MFile.Error => { GO TO BadCommand; }; ]; commandHandle _ MLoader.Run[commandFile]; EXITS BadCommand => Put.Line[toolData.ttySW, "Command not found."L]; }; userInput.length _ 0; CLibraryDefs.exit[0]; ENDLOOP; -- later we should put this back in -- MLoader.Unload[commandHandle]; }; ClientTransition: ToolWindow.TransitionProcType = { SELECT TRUE FROM old = inactive => { IF toolData = NIL THEN toolData _ Heap.systemZone.NEW[Data _ []]; argvT _ @argvRef[0]; FOR i: CARDINAL IN [0..10) DO argvRef[i] _ @argvRefRef[i][0]; ENDLOOP; }; new = inactive => IF toolData # NIL THEN { Heap.systemZone.FREE[@toolData]}; ENDCASE; }; Init: PROCEDURE = { wh _ Tool.Create[ makeSWsProc: MakeSWs, initialState: default, initialBox: [[0, 70], [500, 600]], clientTransition: ClientTransition, name: "Unix"L, tinyName1: "Unix"L]; }; MakeSWs: Tool.MakeSWsProc = { logName: STRING _ [40]; Tool.UnusedLogName[unused: logName, root: "Unix.log"L]; toolData.ttySW _ Tool.MakeTTYSW[window: window, name: logName]; ttyWindow _ toolData.ttySW; }; GetArgs: PUBLIC PROCEDURE [argc: LONG POINTER TO LONG INTEGER, argv: LONG POINTER TO LONG POINTER TO LONG POINTER TO INTEGER] = { argv^ _ argvT; argc^ _ argcT; }; -- Mainline code Init[]; FOR i: CARDINAL IN [0..UnixDefs.numOpenFiles) DO UnixDefs.openFiles[i].type _ unused; UnixDefs.openFiles[i].windowHandle _ NIL; UnixDefs.openFiles[i].streamHandle _ NIL; ENDLOOP; p _ FORK WatchTTY[]; }...