MODULE ulmIO; IMPORT SYS := ulmSYSTEM, SYSTEM; CONST nl = 0AX; (* conversions *) CONST oct = 0; dec = 1; hex = 2; TYPE Basetype = SHORTINT; (* oct..hex *) (* basic IO *) VAR Done*: BOOLEAN; oldch: CHAR; readAgain: BOOLEAN; (* ==================== conversions ================================= *) PROCEDURE ConvertNumber(num, len: LONGINT; btyp: Basetype; neg: BOOLEAN; VAR str: ARRAY OF CHAR); (* conversion of a number into a string of characters *) (* num must get the absolute value of the number *) (* len is the minimal length of the generated string *) (* neg means: "the number is negative" for btyp = dec *) (*CONST NumberLen = 11;*) (* we need it as variable to change the value depending on architecture; -- noch *) VAR (*digits : ARRAY NumberLen+1 OF CHAR;*) digits : POINTER TO ARRAY OF CHAR; base : INTEGER; cnt, ix : INTEGER; maxlen : LONGINT; dig : LONGINT; NumberLen : SHORTINT; BEGIN IF SIZE(LONGINT) = 4 THEN NumberLen := 11 ELSIF SIZE(LONGINT) = 8 THEN NumberLen := 21 ELSE NumberLen := 11 (* default value, corresponds to 32 bit *) END; NEW(digits, NumberLen + 1 ); ASSERT(num >= 0); ix := 1; WHILE ix <= NumberLen DO digits[ix] := "0"; INC(ix); END; (* initialisation *) IF btyp = oct THEN base := 8; ELSIF btyp = dec THEN base := 10; ELSIF btyp = hex THEN base := 10H; END; cnt := 0; REPEAT INC(cnt); dig := num MOD base; num := num DIV base; IF dig < 10 THEN dig := dig + ORD("0"); ELSE dig := dig - 10 + ORD("A"); END; digits[cnt] := CHR(dig); UNTIL num = 0; (* (* i don't like this *) IF btyp = oct THEN cnt := 11; ELSIF btyp = hex THEN cnt := 8; ELSIF neg THEN *) IF neg THEN INC(cnt); digits[cnt] := "-"; END; maxlen := LEN(str); (* get maximal length *) IF len > maxlen THEN len := SHORT(maxlen); END; IF cnt > maxlen THEN cnt := SHORT(maxlen); END; ix := 0; WHILE len > cnt DO str[ix] := " "; INC(ix); DEC(len); END; WHILE cnt > 0 DO str[ix] := digits[cnt]; INC(ix); DEC(cnt); END; IF ix < maxlen THEN str[ix] := 0X; END; END ConvertNumber; PROCEDURE ConvertInteger(num: LONGINT; len: INTEGER; VAR str: ARRAY OF CHAR); (* conversion of an integer decimal number to a string *) BEGIN ConvertNumber(ABS(num),len,dec,num < 0,str); END ConvertInteger; (* ========================= terminal ============================ *) PROCEDURE ReadChar(VAR ch: CHAR) : BOOLEAN; CONST read = 3; (*VAR r0, r1: INTEGER;*) VAR r0, r1: LONGINT; (* in ulm system INTEGER and LONGINT have the same 4 byte size; -- noch *) BEGIN RETURN SYS.UNIXCALL(read, r0, r1, 0, SYSTEM.ADR(ch), 1) & (r0 > 0) END ReadChar; PROCEDURE WriteChar(ch: CHAR) : BOOLEAN; CONST write = 4; (*VAR r0, r1: INTEGER;*) VAR r0, r1: LONGINT; (* same here *) BEGIN RETURN SYS.UNIXCALL(write, r0, r1, 1, SYSTEM.ADR(ch), 1) END WriteChar; PROCEDURE Read*(VAR ch: CHAR); BEGIN Done := TRUE; IF readAgain THEN ch := oldch; readAgain := FALSE; ELSIF ~ReadChar(ch) THEN Done := FALSE; ch := 0X; ELSE oldch := ch; END; END Read; PROCEDURE ReadAgain*; BEGIN IF readAgain THEN Done := FALSE; ELSE Done := TRUE; readAgain := TRUE; END; END ReadAgain; PROCEDURE Write*(ch: CHAR); BEGIN Done := WriteChar(ch); END Write; PROCEDURE WriteLn*; CONST nl = 0AX; BEGIN Write(nl); END WriteLn; PROCEDURE WriteString*(s: ARRAY OF CHAR); VAR i: INTEGER; BEGIN i := 0; WHILE (i < LEN(s)) & (s[i] # 0X) DO Write(s[i]); INC(i); END; END WriteString; PROCEDURE InitIO; BEGIN readAgain := FALSE; Done := TRUE; END InitIO; PROCEDURE WriteInt*(arg: LONGINT); VAR field: ARRAY 23 OF CHAR; BEGIN (* the field size should be big enough to hold the long number. it was 12 to hold just 32 bit numbers, now it can hold 64 bit numbers; need to be more for 128bit numbers; -- noch *) ConvertInteger(arg, 1, field); WriteString(field); END WriteInt; PROCEDURE ReadInt*(VAR arg: LONGINT); VAR ch: CHAR; minus: BOOLEAN; BEGIN minus := FALSE; REPEAT Read(ch); IF ~Done THEN RETURN END; IF ch = "-" THEN minus := TRUE; ELSIF (ch # " ") & (ch # nl) & ((ch < "0") OR (ch > "9")) THEN WriteString("--- Integer expected on input"); WriteLn; END; UNTIL (ch >= "0") & (ch <= "9"); arg := ORD(ch) - ORD("0"); REPEAT Read(ch); IF ~Done THEN RETURN END; IF (ch >= "0") & (ch <= "9") THEN arg := arg*10 + (ORD(ch) - ORD("0")); END; UNTIL (ch < "0") OR (ch > "9"); ReadAgain; IF minus THEN arg := -arg; END; END ReadInt; PROCEDURE ReadLine*(VAR string: ARRAY OF CHAR); VAR index: INTEGER; ch: CHAR; ok: BOOLEAN; BEGIN index := 0; ok := TRUE; LOOP IF ~ReadChar(ch) THEN ok := FALSE; EXIT END; IF ch = nl THEN EXIT END; IF index < LEN(string) THEN string[index] := ch; INC(index); END; END; IF index < LEN(string) THEN string[index] := 0X; END; Done := ok OR (index > 0); END ReadLine; BEGIN InitIO; END ulmIO.