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[];
}...