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