DIRECTORY Ascii USING [CR, NUL], CLibraryDefs USING [CChar, CInt, CString, FILE, cNULL, stderr], UnixDefs USING [GetArgs, openFiles, numOpenFiles], TTYSW USING [AppendChar, GetChar], Inline USING [LowHalf], String USING [AppendLongDecimal, AppendLongNumber], Stream USING [GetChar, PutChar, Delete, EndOfStream], Storage USING[AppendChar, AppendString, CopyString], MStream USING [Handle, Error, ReadWrite]; CLibraryImpl: PROGRAM IMPORTS UnixDefs, Inline, String, Storage, Stream, MStream, TTYSW EXPORTS CLibraryDefs = { -- System Calls chdir: PUBLIC PROC [directoryName: CLibraryDefs.CString] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["chdir not implemented."L]; RETURN [0]; }; chmod: PUBLIC PROC [fileName: CLibraryDefs.CString, fileMode: CLibraryDefs.CInt] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["chmod not implemented."L]; RETURN [0]; }; close: PUBLIC PROC [fileDescriptor: CLibraryDefs.FILE] RETURNS [returnCode: CLibraryDefs.CInt] = { file: INTEGER ← Inline.LowHalf[fileDescriptor]; IF file >= UnixDefs.numOpenFiles THEN { Error["File number too high in fclose."L]; RETURN; }; IF UnixDefs.openFiles[file].type = stream THEN { Stream.Delete[UnixDefs.openFiles[file].streamHandle]; UnixDefs.openFiles[file].type ← unused; }; }; creat: PUBLIC PROC [fileName: CLibraryDefs.CString, fileMode: CLibraryDefs.CInt] RETURNS [fileDescriptor: CLibraryDefs.FILE] = { Error["creat not implemented."L]; RETURN [CLibraryDefs.cNULL]; }; dup: PUBLIC PROC [oldFileDescriptor: CLibraryDefs.FILE] RETURNS [newFileDescriptor: CLibraryDefs.FILE] = { Error["dup not implemented."L]; RETURN [CLibraryDefs.cNULL]; }; dup2: PUBLIC PROC [fileDescriptor1, fileDescriptor2: CLibraryDefs.FILE] RETURNS [fileDescriptor: CLibraryDefs.FILE] = { Error["dup2 not implemented."L]; RETURN [CLibraryDefs.cNULL]; }; execv: PUBLIC PROC [codeFileName: CLibraryDefs.CString, argv: LONG POINTER TO CLibraryDefs.CString] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["execv not implemented."L]; RETURN [0]; }; exit: PUBLIC PROC [returnCode: CLibraryDefs.CInt] = { FOR i: CARDINAL IN [0..UnixDefs.numOpenFiles) DO fclose[LOOPHOLE[LONG[i], CLibraryDefs.FILE]]; ENDLOOP; }; fork: PUBLIC PROC [] RETURNS [processDescriptor: CLibraryDefs.CInt] = { Error["fork not implemented."L]; RETURN [0]; }; fstat: PUBLIC PROC [fileDescriptor: CLibraryDefs.FILE, buffer: LONG POINTER] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["fstat not implemented."L]; RETURN [0]; }; link: PUBLIC PROC [fileName1, fileName2: CLibraryDefs.CString] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["link not implemented."L]; RETURN [0]; }; lseek: PUBLIC PROC [fileDescriptor: CLibraryDefs.FILE, offset, whence: CLibraryDefs.CInt] RETURNS [filePosition: CLibraryDefs.CInt] = { Error["lseek not implemented."L]; RETURN [0]; }; open: PUBLIC PROC [fileName: CLibraryDefs.CString, fileMode: CLibraryDefs.CInt] RETURNS [fileDescriptor: CLibraryDefs.FILE] = { fileString: LONG STRING ← [50]; i: CARDINAL; file: INTEGER; fileDescriptor ← CLibraryDefs.cNULL; -- return value on failure -- first find an empty file slot FOR i: CARDINAL IN [0..UnixDefs.numOpenFiles) DO IF UnixDefs.openFiles[i].type = unused THEN GOTO FoundIt; REPEAT FoundIt => file ← i; FINISHED => RETURN; ENDLOOP; -- now convert the filename string from UNIX format -- (ARRAY OF INTEGER) to a Mesa string i ← 0; WHILE (fileName + i)↑ # 0 DO fileString.text[i] ← (fileName + i)↑ + 0C; i ← i + 1; ENDLOOP; fileString.length ← i; -- Now try to open the file, catching the Error signal. -- Later we should look at the access type (read, write, or -- update) and use the appropriate ReadOnly, WriteOnly, or -- ReadWrite. { UnixDefs.openFiles[file].streamHandle ← MStream.ReadWrite[fileString, [] ! MStream.Error => { GOTO BadFile; }; ]; EXITS BadFile => RETURN; }; UnixDefs.openFiles[file].type ← stream; fileDescriptor ← LONG[file]; }; pipe: PUBLIC PROC [fileDescriptorArray: LONG POINTER TO CLibraryDefs.FILE] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["pipe not implemented."L]; RETURN [0]; }; read: PUBLIC PROC [fileDescriptor: CLibraryDefs.FILE, buffer: CLibraryDefs.CString, nBytes: CLibraryDefs.CInt] RETURNS [nBytesRead: CLibraryDefs.CInt] = { Error["read not implemented."L]; RETURN [0]; }; signal: PUBLIC PROC [signalNumber: CLibraryDefs.CInt, functionToCall: LONG POINTER] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["signal not implemented."L]; RETURN [0]; }; stat: PUBLIC PROC [fileName: CLibraryDefs.CString, buffer: LONG POINTER] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["stat not implemented."L]; RETURN [0]; }; time: PUBLIC PROC [timeBuffer: LONG POINTER TO CLibraryDefs.CInt] RETURNS [timeValue: CLibraryDefs.CInt] = { Error["time not implemented."L]; RETURN [0]; }; umask: PUBLIC PROC [complementedMode: CLibraryDefs.CInt] = { Error["umask not implemented."L] }; unlink: PUBLIC PROC [fileName: CLibraryDefs.CString] RETURNS [returnCode: CLibraryDefs.CInt] = { Error["unlink not implemented."L]; RETURN [0]; }; wait: PUBLIC PROC [returnCode: LONG POINTER TO CLibraryDefs.CInt] RETURNS [processDescriptor: CLibraryDefs.CInt] = { Error["wait not implemented."L]; RETURN [0]; }; write: PUBLIC PROC [fileDescriptor: CLibraryDefs.FILE, buffer: CLibraryDefs.CString, nBytes: CLibraryDefs.CInt] RETURNS [nBytesWritten: CLibraryDefs.CInt] = { Error["write not implemented."L]; RETURN [0]; }; -- Library Functions and Procedures abs: PUBLIC PROC [i: CLibraryDefs.CInt] RETURNS [AbsI: CLibraryDefs.CInt] = { RETURN [IF i >= 0 THEN i ELSE -1]; }; atoi: PUBLIC PROC [numberPointer: CLibraryDefs.CString] RETURNS [number: CLibraryDefs.CInt] = { Error["atoi not implemented."L]; RETURN [0]; }; atol: PUBLIC PROC [numberPointer: CLibraryDefs.CString] RETURNS [number: CLibraryDefs.CInt] = { Error["atol not implemented."L]; RETURN [0]; }; ctime: PUBLIC PROC [time: LONG POINTER TO CLibraryDefs.CInt] RETURNS [timeString: CLibraryDefs.CString] = { Error["ctime not implemented."L]; RETURN [NIL]; }; fclose: PUBLIC PROC [stream: CLibraryDefs.FILE] = { junk: CLibraryDefs.CInt ← close[stream]; }; fflush: PUBLIC PROC [stream: CLibraryDefs.FILE] = { -- do nothing for now }; fgetc: PUBLIC PROC [stream: CLibraryDefs.FILE] RETURNS [char: CLibraryDefs.CChar] = { RETURN [getc[stream]]; }; fgets: PUBLIC PROC [string: CLibraryDefs.CString, length: CLibraryDefs.CInt, stream: CLibraryDefs.FILE] RETURNS [sameString: CLibraryDefs.CString] = { RETURN [gets[string]]; }; fopen: PUBLIC PROC [fileName, type: CLibraryDefs.CString] RETURNS [stream: CLibraryDefs.FILE] = { stream ← open[fileName, 644B]; }; fputc: PUBLIC PROC [char: CLibraryDefs.CChar, stream: CLibraryDefs.FILE] = { putc[char, stream]; }; fputs: PUBLIC PROC [string: CLibraryDefs.CString, stream: CLibraryDefs.FILE] = { char: CLibraryDefs.CChar; DO char ← string↑; IF char = Ascii.NUL-0C THEN EXIT; putc[char, stream]; string ← string + 1; ENDLOOP; }; fprintf: PUBLIC PROC [stream: CLibraryDefs.FILE, format: CLibraryDefs.CString, N1: LONG UNSPECIFIED ← 17777777777B, N2: LONG UNSPECIFIED ← 17777777777B, N3: LONG UNSPECIFIED ← 17777777777B, N4: LONG UNSPECIFIED ← 17777777777B, N5: LONG UNSPECIFIED ← 17777777777B, N6: LONG UNSPECIFIED ← 17777777777B, N7: LONG UNSPECIFIED ← 17777777777B, N8: LONG UNSPECIFIED ← 17777777777B] = { printf[format, N1, N2, N3, N4, N5, N6, N7, N8]; }; fread: PUBLIC PROC [buffer: LONG POINTER, sizeOfBufferItems, nItems: CLibraryDefs.CInt, stream: CLibraryDefs.FILE] RETURNS [itemsRead: CLibraryDefs.CInt] = { Error["fread not implemented."L]; RETURN [0]; }; free: PUBLIC PROC [LONG POINTER] = { Error["free not implemented."L]; }; freopen: PUBLIC PROC [fileName, type: LONG POINTER TO INTEGER, oldStream: CLibraryDefs.FILE] RETURNS [newStream: CLibraryDefs.FILE] = { -- This implementation in INCORRECT. Correct it later. RETURN [fopen[fileName, type]]; }; fscanf: PUBLIC PROC [stream: CLibraryDefs.FILE, format: CLibraryDefs.CString, N1: LONG POINTER ← NIL, N2: LONG POINTER ← NIL, N3: LONG POINTER ← NIL, N4: LONG POINTER ← NIL, N5: LONG POINTER ← NIL, N6: LONG POINTER ← NIL, N7: LONG POINTER ← NIL, N8: LONG POINTER ← NIL] = { Error["fscanf not implemented."L]; }; fseek: PUBLIC PROC [stream: CLibraryDefs.FILE, offset, ptrName: CLibraryDefs.CInt] RETURNS [itemsRead: CLibraryDefs.CInt] = { Error["fseek not implemented."L]; RETURN [0]; }; fwrite: PUBLIC PROC [buffer: LONG POINTER, sizeOfBufferItems, nItems: CLibraryDefs.CInt, stream: CLibraryDefs.FILE] RETURNS [itemsWritten: CLibraryDefs.CInt] = { Error["fwrite not implemented."L]; RETURN [0]; }; getc: PUBLIC PROC [stream: CLibraryDefs.FILE] RETURNS [char: CLibraryDefs.CChar] = { file: INTEGER ← Inline.LowHalf[stream]; char ← 0; IF file >= UnixDefs.numOpenFiles THEN { Error["File number too high in getc."L]; RETURN; }; SELECT UnixDefs.openFiles[file].type FROM unused => Error["Invalid file number in getc."L]; stream => { char ← Stream.GetChar[UnixDefs.openFiles[file].streamHandle ! Stream.EndOfStream => { char ← -1; CONTINUE}; ]-0C; }; window => { char ← TTYSW.GetChar[UnixDefs.openFiles[file].windowHandle]-0C; TTYSW.AppendChar[UnixDefs.openFiles[file].windowHandle, char + 0C]; IF char = 4 --Ascii.EOT-- THEN char ← -1; }; ENDCASE; }; getchar: PUBLIC PROC [] RETURNS [char: CLibraryDefs.CChar] = { char ← getc[0]; }; gets: PUBLIC PROC [string: CLibraryDefs.CString] RETURNS [sameString: CLibraryDefs.CString] = { char: CLibraryDefs.CChar; i: LONG INTEGER; DO char ← getchar[]; IF char < 0 THEN EXIT; string↑ ← char; string ← string + 1; IF char = Ascii.CR-0C THEN EXIT; ENDLOOP; IF char < 0 AND i = 0 THEN RETURN[NIL]; string↑ ← Ascii.NUL-0C; RETURN[string]; }; isalpha: PUBLIC PROC [char: CLibraryDefs.CChar] RETURNS [logical: CLibraryDefs.CInt] = { logical ← IF ('a-0C <= char AND char <= 'z-0C) OR ('A-0C <= char AND char <= 'Z-0C) THEN 1 ELSE 0; }; isdigit: PUBLIC PROC [char: CLibraryDefs.CChar] RETURNS [logical: CLibraryDefs.CInt] = { logical ← IF '0-0C <= char AND char <= '9-0C THEN 1 ELSE 0; }; islower: PUBLIC PROC [char: CLibraryDefs.CChar] RETURNS [logical: CLibraryDefs.CInt] = { logical ← IF ('a-0C <= char AND char <= 'z-0C) THEN 1 ELSE 0; }; isupper: PUBLIC PROC [char: CLibraryDefs.CChar] RETURNS [logical: CLibraryDefs.CInt] = { logical ← IF ('A-0C <= char AND char <= 'Z-0C) THEN 1 ELSE 0; }; malloc: PUBLIC PROC [size: CLibraryDefs.CInt] RETURNS [LONG POINTER] = { Error["malloc not implemented."L]; RETURN [NIL]; }; perror: PUBLIC PROC [string: CLibraryDefs.CString] = { Error["Perror: "L]; fprintf[CLibraryDefs.stderr, string]; }; printf: PUBLIC PROC [format: CLibraryDefs.CString, N1: LONG UNSPECIFIED ← 17777777777B, N2: LONG UNSPECIFIED ← 17777777777B, N3: LONG UNSPECIFIED ← 17777777777B, N4: LONG UNSPECIFIED ← 17777777777B, N5: LONG UNSPECIFIED ← 17777777777B, N6: LONG UNSPECIFIED ← 17777777777B, N7: LONG UNSPECIFIED ← 17777777777B, N8: LONG UNSPECIFIED ← 17777777777B] = { i: CARDINAL; outString: LONG STRING; items: ARRAY [1..8] OF LONG UNSPECIFIED; nextItem: CARDINAL ← 1; -- put the arguments into an array for easy sequential access items[1] ← N1; items[2] ← N2; items[3] ← N3; items[4] ← N4; items[5] ← N5; items[6] ← N6; items[7] ← N7; items[8] ← N8; -- scan the format string, interpreting the '% fields FOR i ← 0, i + 1 WHILE (format + i)↑ # 0 DO IF (format + i)↑ # '%-0C THEN putchar[(format + i)↑] ELSE { span: CARDINAL; i ← i + 1; -- get to the character after the '% -- read the field width (if present) IF (format + i)↑ IN ['0-0C..'9-0C] THEN { span ← (format + i)↑ - ('0-0C); DO i ← i + 1; IF (format + i)↑ NOT IN ['0-0C..'9-0C] THEN EXIT; span ← 10 * span + ((format + i)↑ - ('0-0C)); ENDLOOP; } ELSE span ← 0; -- skip past the "long" indicator if there is one IF (format + i)↑ = 'L-0C OR (format + i)↑ = 'l-0C THEN i ← i + 1; outString ← Storage.CopyString[s: ""L, longer: 64]; SELECT (format + i)↑ FROM 'd-0C => String.AppendLongDecimal[outString, LOOPHOLE[items[nextItem], LONG INTEGER]]; 'o-0C => String.AppendLongNumber[outString, LOOPHOLE[items[nextItem], LONG INTEGER], 8]; 'c-0C => { c: CHARACTER ← 0C + Inline.LowHalf[items[nextItem]]; Storage.AppendChar[@outString, c]; }; 's-0C => { i: CARDINAL; s: LONG POINTER TO INTEGER; s ← LOOPHOLE[items[nextItem], LONG POINTER TO INTEGER]; FOR i ← 0, i+1 WHILE (s+i)↑ # 0 DO Storage.AppendChar[@outString, (s+i)↑+0C]; ENDLOOP; }; ENDCASE => Storage.AppendString[@outString, "*** printf: bad % flag ***"L]; nextItem ← nextItem + 1; FOR j: CARDINAL IN [outString.length..span) DO putchar[' -0C]; ENDLOOP; FOR j: CARDINAL IN [0..outString.length) DO putchar[outString.text[j]-0C]; ENDLOOP; }; ENDLOOP; }; putc: PUBLIC PROC [char: CLibraryDefs.CChar, stream: CLibraryDefs.FILE] = { file: INTEGER ← Inline.LowHalf[stream]; IF file >= UnixDefs.numOpenFiles THEN { Error["File number too high in putc."L]; RETURN; }; SELECT UnixDefs.openFiles[file].type FROM unused => Error["Invalid file number in putc."L]; stream => Stream.PutChar[UnixDefs.openFiles[file].streamHandle, char + 0C]; window => TTYSW.AppendChar[UnixDefs.openFiles[file].windowHandle, char + 0C]; ENDCASE; }; putchar: PUBLIC PROC [char: CLibraryDefs.CChar] = { putc[char, 1]; }; puts: PUBLIC PROC [string: CLibraryDefs.CString, stream: CLibraryDefs.FILE] = { fputs[string, stream]; }; scanf: PUBLIC PROC [format: CLibraryDefs.CString, N1: LONG POINTER ← NIL, N2: LONG POINTER ← NIL, N3: LONG POINTER ← NIL, N4: LONG POINTER ← NIL, N5: LONG POINTER ← NIL, N6: LONG POINTER ← NIL, N7: LONG POINTER ← NIL, N8: LONG POINTER ← NIL] = { Error["scanf not implemented."L]; }; setbuf: PUBLIC PROC [stream: CLibraryDefs.FILE, buffer: LONG POINTER] = { -- For now just do nothing. }; strcat: PUBLIC PROC [s1, s2: CLibraryDefs.CString] RETURNS [result: CLibraryDefs.CString] = { Error["strcat not implemented."L]; RETURN [NIL]; }; strcmp: PUBLIC PROC [s1, s2: CLibraryDefs.CString] RETURNS [result: CLibraryDefs.CInt] = { Error["strcmp not implemented."L]; RETURN [0]; }; strcpy: PUBLIC PROC [s1, s2: CLibraryDefs.CString] RETURNS [result: CLibraryDefs.CString] = { Error["strcpy not implemented."L]; RETURN [NIL]; }; strlen: PUBLIC PROC [s1, s2: CLibraryDefs.CString] RETURNS [stringLength: CLibraryDefs.CInt] = { Error["strlen not implemented."L]; RETURN [0]; }; toupper: PUBLIC PROC [cin: CLibraryDefs.CChar] RETURNS [cout: CLibraryDefs.CChar] = { RETURN[IF ORD['a] <= cin AND cin <= ORD['z] THEN cin-('A-'a) ELSE cin]; }; Error: PUBLIC PROC [s: LONG STRING] = { FOR i: CARDINAL IN [0..s.length) DO putc[s.text[i]-0C, 2]; ENDLOOP; }; -- Artifacts of the simulation of Unix in Tajo GetArgs: PUBLIC PROC [argc: LONG POINTER TO LONG INTEGER, argv: LONG POINTER TO LONG POINTER TO LONG POINTER TO INTEGER] = { UnixDefs.GetArgs[argc, argv]; }; }.