packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/PMOS/sources/general/numerici.mod

IMPLEMENTATION MODULE NumericIO;

	(****************************************************************)
	(*								*)
	(*		Numeric I/O using windows.			*)
	(*								*)
	(*  Programmer:		P. Moylan				*)
	(*  Last edited:	18 February 1994			*)
	(*  Status:		OK					*)
	(*								*)
	(****************************************************************)

FROM Windows IMPORT
    (* type *)	ColumnRange,
    (* proc *)	WriteChar, WriteString, ReadChar, LookaheadChar,
		ReadCharWithoutEcho, EditString, SaveCursor, SetCursor;

FROM Conversions IMPORT
    (* type *)	HexDigit, EightChar,
    (* proc *)	CardinalToString, StringToCardinal, StringToHex,
		LongCardToString, HexToChar, HexToString, LongHexToString;

FROM LowLevel IMPORT
    (* proc *)	SEGMENT, OFFSET,
		HighByte, LowByte, HighWord, LowWord,
		IANDB, RSB;

FROM Keyboard IMPORT
    (* proc *)	InKey, PutBack;

(************************************************************************)

TYPE CharSet = SET OF CHAR;

CONST Digits = CharSet {"0".."9"};

(************************************************************************)
(*				OUTPUT					*)
(************************************************************************)

PROCEDURE WriteHexDigit (w: Window;  number: BYTE);

    (* Writes a one-digit hexadecimal number.	*)

    BEGIN
	WriteChar (w, HexToChar(VAL(HexDigit, number)));
    END WriteHexDigit;

(************************************************************************)

PROCEDURE WriteHexByte (w: Window;  number: BYTE);

    (* Writes the second argument as a two-digit hexadecimal number.	*)

    BEGIN

	(* The obscure function names from LowLevel are:	*)
	(*	RSB = right shift	IANDB = logical AND	*)

	WriteHexDigit (w, RSB(number, 4));
	WriteHexDigit (w, IANDB(number,15));

    END WriteHexByte;

(************************************************************************)

PROCEDURE WriteHexWord (w: Window;  number: CARDINAL);

    (* Writes the second argument as a four-digit hexadecimal number.	*)

    BEGIN
	WriteHexByte (w, HighByte(number));
	WriteHexByte (w, LowByte(number));
    END WriteHexWord;

(************************************************************************)

PROCEDURE WriteHexLongword (w: Window;  number: LONGCARD);

    (* Writes the second argument as an eight-digit hexadecimal number.	*)

    BEGIN
	WriteHexWord (w, HighWord(number));
	WriteHexWord (w, LowWord(number));
    END WriteHexLongword;

(************************************************************************)

PROCEDURE WriteAddress (w: Window;  addr: ADDRESS);

    (* Writes a segmented address to the screen.	*)

    BEGIN
	WriteHexWord (w, SEGMENT(addr));  WriteChar (w, ":");
	WriteHexWord (w, OFFSET(addr));
    END WriteAddress;

(************************************************************************)

PROCEDURE WriteLongCard (w: Window;  number: LONGCARD);

    (* Writes the second argument as a decimal number.	*)

    VAR remainder: CARDINAL;

    BEGIN
	IF number > 9 THEN
	    WriteLongCard (w, number DIV 10);
	END (*IF*);
	remainder := CARDINAL(number MOD 10);
	WriteChar (w, CHR(remainder + ORD("0")));
    END WriteLongCard;

(************************************************************************)

PROCEDURE WriteCard (w: Window;  number: CARDINAL);

    (* Writes the second argument as a decimal number.	*)

    BEGIN
	WriteLongCard (w, VAL(LONGCARD,number));
    END WriteCard;

(************************************************************************)

PROCEDURE WriteShortCard (w: Window;  number: SHORTCARD);

    (* Writes the second argument as a decimal number.	*)

    BEGIN
	WriteLongCard (w, VAL(LONGCARD,number));
    END WriteShortCard;

(************************************************************************)

PROCEDURE WriteInt (w: Window;  number: INTEGER);

    (* Writes the second argument as a decimal number.	*)

    BEGIN
	IF number < 0 THEN
	    WriteChar (w, '-');  number := -number;
	END (*IF*);
	WriteCard (w, number);
    END WriteInt;

(************************************************************************)

PROCEDURE WriteRJLongCard (w: Window;  number: LONGCARD; fieldsize: CARDINAL);

    (* Like WriteLongCard, but the result is right justified in a field	*)
    (* of fieldsize characters.						*)

    VAR buffer: ARRAY [0..79] OF CHAR;

    BEGIN
	LongCardToString (number, buffer, fieldsize);
	buffer[fieldsize] := CHR(0);
	WriteString (w, buffer);
    END WriteRJLongCard;

(************************************************************************)

PROCEDURE WriteRJCard (w: Window;  number, fieldsize: CARDINAL);

    (* Like WriteCard, but the result is right justified in a field	*)
    (* of fieldsize characters.						*)

    VAR buffer: ARRAY [0..79] OF CHAR;

    BEGIN
	CardinalToString (number, buffer, fieldsize);
	buffer[fieldsize] := CHR(0);
	WriteString (w, buffer);
    END WriteRJCard;

(************************************************************************)

PROCEDURE WriteRJShortCard (w: Window;  number: SHORTCARD;
					fieldsize: CARDINAL);

    (* Like WriteShortCard, but the result is right justified in a	*)
    (* field of fieldsize characters.					*)

    BEGIN
	WriteRJCard (w, CARDINAL(number), fieldsize);
    END WriteRJShortCard;

(************************************************************************)
(*			CHECK FOR Esc KEY				*)
(************************************************************************)

PROCEDURE EditOK (): BOOLEAN;

    (* Returns TRUE unless the Esc key was pressed.	*)

    CONST Esc = CHR(27);

    VAR ch: CHAR;

    BEGIN
	ch := InKey();  PutBack(ch);
	RETURN ch <> Esc;
    END EditOK;

(************************************************************************)
(*			  HEXADECIMAL INPUT				*)
(************************************************************************)

PROCEDURE EditHexByte (w: Window;  VAR (*INOUT*) value: BYTE);

    (* Screen editing of a 2-digit hexadecimal value *)

    VAR buffer: ARRAY [0..1] OF CHAR;

    BEGIN
	HexToString (CARDINAL(value), buffer);
	EditString (w, buffer, 2);
	IF EditOK() THEN
	    value := BYTE (StringToHex (buffer));
	END (*IF*);
    END EditHexByte;

(************************************************************************)

PROCEDURE EditHexWord (w: Window;  VAR (*INOUT*) value: CARDINAL);

    (* Screen editing of a 4-digit hexadecimal value *)

    VAR buffer: ARRAY [0..3] OF CHAR;

    BEGIN
	HexToString (value, buffer);
	EditString (w, buffer, 4);
	IF EditOK() THEN
	    value := CARDINAL (StringToHex (buffer));
	END (*IF*);
    END EditHexWord;

(************************************************************************)

PROCEDURE EditHexLongword (w: Window;  VAR (*INOUT*) value: LONGCARD);

    (* Screen editing of an 8-digit hexadecimal value *)

    VAR buffer: EightChar;

    BEGIN
	LongHexToString (value, buffer);
	EditString (w, buffer, 8);
	IF EditOK() THEN
	    value := StringToHex (buffer);
	END (*IF*);
    END EditHexLongword;

(************************************************************************)
(*			    DECIMAL INPUT				*)
(************************************************************************)

PROCEDURE ReadCard (w: Window;  VAR (*OUT*) number: CARDINAL);

    (* Reads a decimal number, skipping over all non-numeric input.	*)

    VAR ch: CHAR;

    BEGIN
	number := 0;

	(* Skip over any leading non-numeric input.	*)

	WHILE NOT (LookaheadChar(w) IN Digits) DO
	    ReadCharWithoutEcho (w, ch);
	END (*WHILE*);

	(* Now read and convert the desired input.	*)

	WHILE LookaheadChar(w) IN Digits DO
	    ReadChar (w, ch);
	    number := 10*number + ORD(ch) - ORD("0");
	END (*WHILE*);
    END ReadCard;

(*************************************************************************)

PROCEDURE ReadBufferedCardinal (w: Window;  fieldsize: CARDINAL): CARDINAL;

    (* Reads a decimal number.  The difference between this and		*)
    (* ReadCard is that the user is given a reverse-video field of a	*)
    (* fixed width to work in, and is able to use the cursor control	*)
    (* keys to edit within that field.					*)

    VAR buffer: ARRAY ColumnRange OF CHAR;
	result: CARDINAL;  row, column: CARDINAL;

    BEGIN
	SaveCursor (w, row, column);
	buffer := "";
	EditString (w, buffer, fieldsize);
	result := StringToCardinal (buffer);
	SetCursor (w, row, column);
	WriteRJCard (w, result, fieldsize);
	RETURN result;
    END ReadBufferedCardinal;

(*************************************************************************)

PROCEDURE EditCardinal (w: Window;  VAR (*INOUT*) value: CARDINAL;
						fieldsize: CARDINAL);

    (* Screen editing of a decimal number. *)

    VAR buffer: ARRAY ColumnRange OF CHAR;
	row, column: CARDINAL;

    BEGIN
	SaveCursor (w, row, column);
	CardinalToString (value, buffer, fieldsize);
	EditString (w, buffer, fieldsize);
	IF EditOK() THEN
	    value := StringToCardinal (buffer);
	END (*IF*);
	SetCursor (w, row, column);
	WriteRJCard (w, value, fieldsize);
    END EditCardinal;

(*************************************************************************)

END NumericIO.