(* Copyright (C) 1990, Digital Equipment Corporation. *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* Last modified on Tue Oct 13 15:50:52 PDT 1992 by muller *) UNSAFE MODULE SmallIO; IMPORT Text, TextF, Word, Unix, Cstdio, M3toC; PROCEDURE OpenRead (t: Text.T): File = BEGIN RETURN Unix.open (M3toC.TtoS (t), Unix.O_RDONLY, 0); END OpenRead; PROCEDURE OpenWrite (t: Text.T): File = BEGIN RETURN Unix.open (M3toC.TtoS (t), Unix.O_WRONLY, Unix.Mrwrwrw); END OpenWrite; PROCEDURE Close (f: File) = BEGIN EVAL Unix.close (f); END Close; PROCEDURE EOF (f: File): BOOLEAN = BEGIN RETURN Word.And (Cstdio.iob[f].flag, Cstdio.IOEOF) # 0; END EOF; PROCEDURE GetChar (f: File): CHAR = VAR c: CHAR; BEGIN WITH ff = Cstdio.iob[f] DO DEC (ff.cnt); IF ff.cnt >= 0 THEN c := ff.ptr^; INC (ff.ptr, ADRSIZE (ff.ptr^)); ELSE c := Cstdio.filbuf (ADR (ff)); END; END; RETURN c; END GetChar; PROCEDURE UnGetChar (f: File; c: CHAR) = BEGIN Cstdio.ungetc (c, ADR (Cstdio.iob[f])); END UnGetChar; PROCEDURE PutChar (f: File; c: CHAR) = BEGIN WITH ff = Cstdio.iob[f] DO DEC (ff.cnt); IF ff.cnt >= 0 THEN ff.ptr^ := c; INC (ff.ptr, ADRSIZE (ff.ptr^)); ELSE Cstdio.flsbuf (c, ADR (ff)); END; END; END PutChar; PROCEDURE PutChars (f: File; c: UNTRACED REF CHAR; n: INTEGER) = VAR m: INTEGER; BEGIN WITH ff = Cstdio.iob[f] DO WHILE n > 0 DO m := MIN (ff.cnt, n); IF m > 0 THEN FOR j := 1 TO m DO ff.ptr^ := c^; INC (ff.ptr, BYTESIZE (ff.ptr^)); INC (c, BYTESIZE (c^)); END; DEC (ff.cnt, m); DEC (n, m); ELSE Cstdio.flsbuf (c^, ADR (ff)); INC (c, BYTESIZE (c^)); DEC (n); END; END; END; END PutChars; PROCEDURE PutInt (f: File; i: INTEGER) = VAR buf: ARRAY [0..100] OF CHAR; BEGIN PutChars (f, ADR (buf[0]), FromInt (ADR (buf[0]), i, 10, FALSE)); END PutInt; PROCEDURE PutHexa (f: File; i: INTEGER) = VAR buf: ARRAY [0..100] OF CHAR; BEGIN buf[0] := '0'; buf[1] := 'x'; PutChars (f, ADR (buf[0]), 2 + FromUnsigned (ADR (buf[2]), i, 16, FALSE)); END PutHexa; PROCEDURE PutText (f: File; t: Text.T) = BEGIN PutChars (f, ADR (t[0]), NUMBER (t^) - 1); END PutText; PROCEDURE Flush (f: File) = BEGIN Cstdio.flush (ADR (Cstdio.iob[f])); END Flush; TYPE Base = [2..16]; PROCEDURE FromInt (buf : UNTRACED REF CHAR; value : INTEGER; base : Base := 10; prefix : BOOLEAN := FALSE): INTEGER = VAR Digits := ARRAY [0..15] OF CHAR { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; nDigits : INTEGER := 0; minus : BOOLEAN := FALSE; bump : BOOLEAN := FALSE; i, j : INTEGER; c : CHAR; result : ARRAY [0..BITSIZE (INTEGER)] OF CHAR; BEGIN IF (value = 0) THEN result[0] := '0'; nDigits := 1; ELSE (* handle a non-zero number *) (* get rid of negative numbers *) IF (value < 0) THEN IF (value = FIRST (INTEGER)) THEN (* 2's complement makes FIRST(INTEGER) a special case *) bump := TRUE; INC (value); END; minus := TRUE; value := -value; <* ASSERT value > 0 *> END; (* convert the bulk of the digits *) WHILE (value > 0) DO result [nDigits] := Digits [value MOD base]; value := value DIV base; INC (nDigits); END; (* fixup FIRST (INTEGER) *) IF (bump) THEN result [nDigits] := '0'; j := 0; LOOP c := result [j]; IF (c <= '9') THEN i := ORD (c) - ORD ('0'); ELSE i := ORD (c) - ORD ('a') + 10; END; INC (i); IF (i < base) THEN result [j] := Digits [i]; EXIT END; result [j] := '0'; INC (j); END; nDigits := MAX (nDigits, j+1); END; END; (* build the result buffer *) j := 0; IF (minus) THEN buf^ := '-'; j := 1; INC (buf, BYTESIZE (buf^)); END; IF (prefix) THEN IF (base > 9) THEN buf^ := '1'; INC (j); INC (buf, BYTESIZE (buf^)); END; buf^ := Digits [base MOD 10]; INC (j); INC (buf, BYTESIZE (buf^)); buf^ := '_'; INC (j); INC (buf, BYTESIZE (buf^)); END; FOR k := nDigits-1 TO 0 BY -1 DO buf^ := result [k]; INC (j); INC (buf, BYTESIZE (buf^)); END; RETURN j; END FromInt; PROCEDURE FromUnsigned (buf : UNTRACED REF CHAR; value : INTEGER; base : Base := 10; prefix : BOOLEAN := FALSE): INTEGER = VAR Digits := ARRAY [0..15] OF CHAR { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; nDigits : INTEGER := 0; j : INTEGER; result : ARRAY [0..BITSIZE (INTEGER)] OF CHAR; BEGIN IF (value = 0) THEN result[0] := '0'; nDigits := 1; ELSE (* convert the bulk of the digits *) WHILE (value # 0) DO result [nDigits] := Digits [Word.Mod (value, base)]; value := Word.Divide (value, base); INC (nDigits); END; END; (* build the result buffer *) j := 0; IF (prefix) THEN IF (base > 9) THEN buf^ := '1'; INC (j); INC (buf, BYTESIZE (buf^)); END; buf^ := Digits [base MOD 10]; INC (j); INC (buf, BYTESIZE (buf^)); buf^ := '_'; INC (j); INC (buf, BYTESIZE (buf^)); END; FOR k := nDigits-1 TO 0 BY -1 DO buf^ := result [k]; INC (j); INC (buf, BYTESIZE (buf^)); END; RETURN j; END FromUnsigned; BEGIN END SmallIO.