home *** CD-ROM | disk | FTP | other *** search
- Unit UserLib;
- interface
- uses crt,dos;
- {
- Userlib is a Turbo Pascal 5.5 unit containing several useful functions
- for screen I/O, menus, etc.. Several of the routines are versions of the
- routines contained in TPIO22.ARC from the Computer Lang. Forum
- }
- type
- MenuList = Array[0..9] of String[40]; {Array of menu text choices}
-
- const
- HexChars : Array[1..16] of Char =
- ('0','1','2','3','4','5','6','7',
- '8','9','A','B','C','D','E','F');
- {keyboard constants}
- {ASCII Dec Description}
- NUL = #000; {CTRL @ Null}
- SOH = #001; {CTRL A Start of header}
- STX = #002; {CTRL B Start of text}
- ETX = #003; {CTRL C End of text}
- EOT = #004; {CTRL D End of transmission}
- ENQ = #005; {CTRL E Enquiry}
- ACK = #006; {CTRL F Acknowledge}
- BEL = #007; {CTRL G Bell}
- BS = #008; {CTRL H Backspace}
- TAB = #009; {CTRL I Horizontal tab}
- LF = #010; {CTRL J Line Feed}
- VT = #011; {CTRL K Vertical tab}
- FF = #012; {CTRL L Form feed}
- CR = #013; {CTRL M Carriage return}
- SO = #014; {CTRL N Shift out}
- SI = #015; {CTRL O Shift in}
- DLE = #016; {CTRL P Data link escape}
- DC1 = #017; {CTRL Q Dev. control 1 (XON)}
- DC2 = #018; {CTRL R Dev. control 2}
- DC3 = #019; {CTRL S Dev. control 3 (XOFF)}
- DC4 = #020; {CTRL T Dev. control 4}
- NAK = #021; {CTRL U Negative acknowledge}
- SYN = #022; {CTRL V Synchronous idle (SYNC)}
- ETB = #023; {CTRL W End of transmission block}
- CAN = #024; {CTRL X Cancel}
- EM = #025; {CTRL Y End of medium}
- SUB = #026; {CTRL Z Substitute}
- ESC = #027; {CTRL [ Escape}
- FS = #028; {CTRL \ File seperator}
- GS = #029; {CTRL ] Group seperator}
- RS = #030; {CTRL ^ Record seperator}
- US = #031; {CTRL _ Unit seperator}
- { #032 to #0126 are normal ASCII characters}
- { DEL = #127; (Delete/Rubout) }
- {translated extended codes
- codes above 127 are not generated directly from keyboard
- they are translations of the actual 2 character sequence
- (NUL xx) obtained by adding 128 to the xx character}
- F1 = #187;
- F2 = #188;
- F3 = #189;
- F4 = #190;
- F5 = #191;
- F6 = #192;
- F7 = #193;
- F8 = #194;
- F9 = #195;
- F10 = #196;
- HOMEKEY = #199;
- UPKEY = #200;
- PGUPKEY = #201;
- LEFTKEY = #203;
- RIGHTKEY = #205;
- ENDKEY = #207;
- DOWNKEY = #208;
- PGDNKEY = #209;
- INSKEY = #210;
- DELKEY = #211;
- CTRLLEFTKEY = #243;
- CTRLRIGHTKEY = #244;
-
- var
- Bgnd, {backgound text color}
- Txt : byte; {text character color}
- Field : integer; {number of current field on input screen}
-
-
- procedure Abort(msg:String);
- {display message and halt}
-
- procedure Beep;
- {sound beeper}
-
- procedure CursorType(S:char);
- {set cursor to Block, Underline or invisible}
-
- procedure ClrLine(Col,Row:byte);
- {clear line to spaces on crt}
-
- function Exists(FileName : String) : Boolean;
- { Returns True if the file FileName exists, False otherwise }
-
- function GetHex(Dval:Word):string;
- {convert word to hex string}
-
- function PadStr(S:string; L:byte; C:char; J:char):string;
- {pad string S to length L with character C justified J('R' or 'L')}
-
- function PurgeCh(InS:string; C:char):string;
- {delete all occurences of C from S}
-
- procedure Display_Int(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- I:integer; Width:byte);
- { Write an integer on screen at Col,Row with chosen colors
- in reverse video if Rev is true}
-
- procedure Display_Real(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- R:real; Width,Dec:byte);
- { Write a real number on screen}
-
- procedure Display_Str(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- S:String);
- { Write a string on screen}
-
- function KeyInp : Char;
- { Reads the next keyboard character, translates special keys }
-
- function Yes_No(Prompt:string):char;
- {print message on line 24 and wait for input}
-
- procedure Pause;
- {print message on line 24 and wait for input}
-
- procedure Message(Msg:String);
- {display msg on line 23 and pause}
-
- procedure Menu(var Items: MenuList; var Choice: integer;
- Max,Txt,Bgnd:byte);
- {display a list of items and return selection
- Parameters are Items - array of items to display
- Choice - number of item chosen
- Max - number of items
- Txt - Text Color
- Bgnd - Background Color}
-
- procedure Inp_Int(Col,Row,Txt,Bgnd:byte;
- var I:integer; Max:byte);
- {Input an integer up to max digits from screen at Col,Row}
-
- procedure Inp_Real(Col,Row,Txt,Bgnd:byte;
- var R:real; Max,Frac:byte);
- {Input a real number from screen - Max chars (including sign & decimal point)
- with up to Frac decimal places}
-
- procedure Inp_Str(Col,Row,Txt,Bgnd:byte;
- var S:String; Max:byte; Shift:char);
- {Input a string from screen at Col,Row in a reverse video box}
-
- {******************************************************************************}
- {******************************************************************************}
- implementation
-
- procedure Abort(msg:String);
- begin
- ClrScr;
- Writeln(msg);
- Halt;
- end; {Abort}
- {******************************************************************************}
- procedure Beep;
- begin
- Write(BEL);
- end; {Beep}
- {******************************************************************************}
- procedure CursorType(S:char);
-
- procedure Set_Cursor(Hi_scan_line, Low_scan_line: byte);
- var regs: registers;
- begin
- regs.ax := $0100; {ah = 01h; al = 00h}
- regs.ch := Hi_scan_line;
- regs.cl := Low_scan_line;
- intr($10,regs) {call DOS cursor services}
- end; {Set_Cursor}
-
- begin {CursorType}
- case S of
- 'B': Set_Cursor(0,7); {Block}
- 'O': Set_Cursor(15,15); {invisible}
- 'U': Set_Cursor(6,7); {Underline}
- end;
- end; {CursorType}
- {******************************************************************************}
- procedure ClrLine(Col,Row:byte);
- {clear line to spaces on crt}
- begin
- GotoXY(Col,Row);
- ClrEol;
- end; {ClrLine}
- {******************************************************************************}
- procedure Display_Int(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- I:integer; Width:byte);
- { Writes an integer in a particular location, possibly reverse video}
- begin
- if not Rev then
- begin
- TextColor(Txt);
- TextBackground(Bgnd);
- end
- else
- begin
- TextColor(Bgnd);
- TextBackground(Txt);
- end;
- GotoXY(Col,Row);
- Write(I:Width);
- end; { Display_Int }
- {******************************************************************************}
- procedure Display_Real(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- R:real; Width,Dec:byte);
- { Writes a real number in a particular location, possibly reverse video}
- begin
- if not Rev then
- begin
- TextColor(Txt);
- TextBackground(Bgnd);
- end
- else
- begin
- TextColor(Bgnd);
- TextBackground(Txt);
- end;
- GotoXY(Col,Row);
- Write(R:Width:Dec);
- end; { Display_Real }
- {******************************************************************************}
- procedure Display_Str(Col,Row,Txt,Bgnd:byte; Rev:Boolean;
- S:String);
- { Writes text in a particular location, possibly reverse video}
- begin
- if not Rev then
- begin
- TextColor(Txt);
- TextBackground(Bgnd);
- end
- else
- begin
- TextColor(Bgnd);
- TextBackground(Txt);
- end;
- GotoXY(Col,Row);
- Write(S);
- end; { Display_Str }
- {******************************************************************************}
- function Exists(FileName : String) : Boolean;
- { Returns True if the file FileName exists, False otherwise }
- var
- SR : SearchRec;
- begin
- FindFirst(FileName, ReadOnly + Hidden + SysFile, SR);
- Exists := (DosError = 0) and (Pos('?', FileName) = 0) and
- (Pos('*', FileName) = 0);
- end; { Exists }
- {******************************************************************************}
- function GetHex(Dval:Word):string;
- var
- Digit,Cntr,Divisor,Quotient:integer;
- TS:string;
- begin
- GetHex := '';
- TS := '';
- For Digit := 1 to 4 do
- begin
- Divisor := 1;
- for cntr := Digit to 3 do
- Divisor := Divisor * 16;
- Quotient := Dval DIV Divisor;
- Dval := Dval MOD Divisor;
- TS := TS+HexChars[Quotient+1];
- end;
- GetHex := TS;
- end;
- {******************************************************************************}
- function KeyInp : Char;
- { Reads the next keyboard character, handles special keys }
- var
- C : Char;
- begin
- C := ReadKey;
- repeat
- if C = NUL then
- begin {extended key}
- C := ReadKey; {get second byte of extended code}
- KeyInp := Chr(Ord(C) + 128); {translate it up}
- end
- else {normal key}
- KeyInp := C;
- until C <> NUL;
- end; { KeyInp }
- {******************************************************************************}
- function Yes_No(Prompt:string):char;
- {print message on line 24 and wait for input}
- var
- ch: char;
- begin
- ClrLine(1,24);
- Display_Str(((80-(length(Prompt)+5)) div 2),24,White,Black,True,
- Prompt+'(Y/N)');
- repeat
- ch := KeyInp;
- until ch in ['N','Y','n','y'];
- TextBackground(Bgnd);
- TextColor(Txt);
- ClrLine(1,24);
- Yes_No := Upcase(ch);
- end; {Yes_No}
- {******************************************************************************}
- procedure Pause;
- {print message on line 24 and wait for input}
- var
- ch: char;
- begin
- ClrLine(1,24);
- Display_Str(26,24,White,Black,True,'PRESS SPACE BAR TO CONTINUE');
- repeat
- ch := KeyInp;
- until ch = ' ';
- TextBackground(Bgnd);
- TextColor(Txt);
- ClrLine(1,24);
- end; {Pause}
- {******************************************************************************}
- procedure Message(Msg:String);
- {display message on line 23 and pause}
- begin
- Beep;
- ClrLine(1,23);
- Display_Str(((80-length(msg)) div 2),23,White,Black,True,Msg);
- Pause;
- ClrLine(1,23);
- end; {Message}
- {******************************************************************************}
- procedure Menu(var Items: MenuList; var Choice: integer;
- Max,Txt,Bgnd:byte);
- {display a list of items and return selection
- Parameters are Items - array of items to display
- Choice - number of item chosen
- Max - number of items
- Txt - Text Color
- Bgnd - Background Color}
- const
- Normal = False;
- var
- inp: char; i,j,l,x,y: integer; TS:string;
- begin
- TextColor(Txt); {set colors and clear screen}
- TextBackground(Bgnd);
- ClrScr;
- i := Choice; {set pointer to item to highlight first}
- Choice := -1; {set choice to invalid selection}
- y := (24-2*(Max+1)) div 2; {vertical centering}
- l := length(Items[0]); {find length of longest item including title}
- for j := 1 to Max do
- if length(Items[j]) > l then l := length(Items[j]);
- x := (80-(l+2)) div 2; {horizontal centering}
- Display_Str(x,y,Txt,Bgnd,Normal,Items[0]); {display title}
- repeat {display items, highlight current item}
- For j := 1 to Max do
- begin
- str(j:1,TS);
- TS := TS+'-'+Items[j];
- Display_Str(x,y+j*2,Txt,Bgnd,i=j,TS);
- end;
- inp := KeyInp; {get keyboard input}
- case inp of
- CR : Choice := i; {selects current item}
- ESC : Choice := 0; {skip out of menu - no selection}
- DOWNKEY : i := succ(i); {move down list}
- UPKEY : i := pred(i); {move up list}
- HOMEKEY : i := 1;
- ENDKEY : i := Max;
- '1'..'9': begin
- i := Ord(inp)-48;
- if i in [1..Max] then
- Choice := i;
- end;
- end;
- if i < 1 then i := Max; {limit movement}
- if i > Max then i := 1;
- until Choice in [0..Max]; {loop until valid choice}
- TextColor(Txt); {set colors and clear screen}
- TextBackground(Bgnd);
- ClrScr;
- end; {Do_Menu}
- {******************************************************************************}
- function PadStr(S:string; L:byte; C:char; J:char):string;
- {pad string S to length L with character C justified J('R' or 'L')}
- var TS:string;
- begin
- TS := S;
- if length(TS) < L then
- repeat
- case J of
- 'L': TS := TS+C;
- 'R': insert(C,TS,1);
- end;
- until length(TS) = L;
- PadStr := TS;
- end;
- {******************************************************************************}
- procedure Add_to_Str(var S:string; C:char; var P,Max:byte);
- {add C to S at P limited to Max length}
- begin
- if length(S) < Max then
- begin
- P := succ(P);
- insert(C,S,P);
- end;
- end; {Add_to_Str}
-
- procedure Adj_Str(var S:string; C:char; var P,Max:byte);
- {adjust position of cursor within string, delete chars, etc.}
- begin
- case C of
- LEFTKEY : if P > 0 then P := pred(P);
- RIGHTKEY: if P < length(S) then P := succ(P);
- BS : if P > 0 then
- begin
- delete(S,P,1);
- P := pred(P);
- end;
- DELKEY : if P < length(S) then delete(S,P+1,1);
- end {case}
- end; {Adj_Str}
-
- function PurgeCh(InS:string; C:char):string;
- {delete all occurences of C from S}
- var
- n: byte; OutS:string;
- begin
- OutS := '';
- for n := 1 to length(InS) do
- if InS[n] = C then
- else OutS := OutS+InS[n];
- PurgeCh := OutS;
- end; {PurgeCh}
-
- procedure StripCh(var InS:string; C:char);
- {delete leading occurences of C from S}
- begin
- while (length(InS) > 0) and (InS[1] = C) do
- delete(InS,1,1);
- end;
-
- procedure Field_Cntrl(C:char);
- begin {Field_Cntrl}
- case C of
- ESC : Field := -1;
- CR, DOWNKEY : Field := succ(Field);
- UPKEY : Field := pred(Field);
- end;
- end;
- {------------------------------------------------------------------------------}
- procedure Inp_Int(Col,Row,Txt,Bgnd:byte;
- var I:integer; Max:byte);
- {Input an integer up to max digits from screen at Col,Row}
- type
- charset = set of char;
- const
- Adjusting : charset = [BS, LEFTKEY, RIGHTKEY, DELKEY];
- Numeric : charset = ['0'..'9'];
- Terminating : charset = [ESC, CR, DOWNKEY, UPKEY];
- var
- P: byte; C:char; code:integer; S:string;
- begin
- code := 0;
- CursorType('U');
- str(I:Max,S); {convert to string}
- S := PurgeCh(S,' ');
- StripCh(S,'0');
- P := length(S);
- repeat
- Display_Str(Col,Row,Txt,Bgnd,TRUE,PadStr(S,Max,' ','L'));
- gotoXY(Col+P,Row);
- C := KeyInp;
- if C in Adjusting then Adj_Str(S,C,P,Max)
- else if C = '-' then
- begin
- if (pos('-',S) = 0) and
- (length(S) < Max) and
- (P = 0) then Add_to_Str(S,C,P,Max);
- end
- else if C in Numeric then Add_to_Str(S,C,P,Max)
- else if C in Terminating then
- begin
- Field_Cntrl(C);
- if C = ESC then S :='';
- end
- else Beep;
- until C in Terminating;
- if S = '' then I := 0
- else val(S,I,code);
- if code = 0 then Display_Int(Col,Row,Txt,Bgnd,FALSE,I,Max)
- else begin
- gotoXY(1,24);
- write('*** CONVERSION ERROR ***',BEL);
- halt;
- end;
- CursorType('O');
- end; {Inp_Int}
- {------------------------------------------------------------------------------}
- procedure Inp_Real(Col,Row,Txt,Bgnd:byte;
- var R:real; Max,Frac:byte);
- {Input a real number from screen - Max chars (including sign & decimal point)
- with up to Frac decimal places}
- type
- charset = set of char;
- const
- Adjusting : charset = [BS, LEFTKEY, RIGHTKEY, DELKEY];
- Numeric : charset = ['.','0'..'9'];
- Terminating : charset = [ESC, CR, DOWNKEY, UPKEY];
- var
- P,Pdec,Wmax,Wlen,Flen: byte; C: char; code: integer; S: string;
-
- procedure RealStrLen;
- begin {RealStrLen}
- Pdec := pos('.',S);
- if Pdec = 0 then
- begin {no decimal point}
- Wlen := length(S);
- Flen := 0;
- end
- else
- begin {decimal point present}
- Wlen := Pdec;
- Flen := length(S)-Wlen;
- end;
- end; {RealStrLen}
-
- procedure Add_to_RealStr;
- begin {Add_to_RealStr};
- Pdec := pos('.',S);
- if C = '.' then {handle decimal point}
- begin
- if (Pdec = 0) and (length(S)-P <= Frac) then Add_to_Str(S,C,P,Max);
- end
- else {digit}
- {check to see if it goes in whole part}
- if ((Pdec = 0) and (Wlen < Wmax -1)) {no decimal pt}
- or ((Pdec > 0) and (Wlen < Wmax) and (P < Pdec)) {room to fit}
- then Add_to_Str(S,C,P,Max)
- else {try frac part}
- if (Pdec <> 0) and (Flen < Frac) and (P >= Pdec) then
- Add_to_Str(S,C,P,Max);
- end; {Add_to_RealStr}
-
- begin {Inp_Real}
- code := 0;
- Wmax := Max-Frac;
- CursorType('U');
- if R <> 0.0 then str(R:Max:Frac,S) {convert to string}
- else S := '';
- S := PurgeCh(S,' ');
- StripCh(S,'0');
- P := length(S);
- repeat
- Display_Str(Col,Row,Txt,Bgnd,TRUE,PadStr(S,Max,' ','L'));
- gotoXY(Col+P,Row);
- C := KeyInp;
- RealStrLen; {compute length of parts}
- if C in Adjusting then Adj_Str(S,C,P,Max)
- else if C = '-' then
- begin
- if (pos('-',S) = 0) and (P = 0) and
- (((Pdec = 0) and (Wlen < Wmax-1)) or
- ((Pdec <> 0) and (Wlen < Wmax))) then Add_to_Str(S,C,P,Max);
- end
- else if C in Numeric then Add_to_RealStr
- else if C in Terminating then
- begin
- Field_Cntrl(C);
- if C = ESC then S := '';
- end
- else Beep
- until C in Terminating;
- {input complete - convert back to Real}
- if (S = '') or (S = '-') or (S = '.') or (S = '-.') then R := 0.0
- else val(S,R,code);
- if code = 0 then Display_Real(Col,Row,Txt,Bgnd,FALSE,R,Max,Frac)
- else begin
- gotoXY(1,24);
- write('*** CONVERSION ERROR ***',BEL);
- halt;
- end;
- CursorType('O');
- end; {Inp_Real}
- {------------------------------------------------------------------------------}
- procedure Inp_Str(Col,Row,Txt,Bgnd:byte;
- var S:String; Max:byte;Shift:char);
- {Input a string from screen at Col,Row}
- type
- charset = set of char;
- const
- Adjusting : charset = [BS, LEFTKEY, RIGHTKEY, DELKEY];
- Display : charset = [' '..'~'];
- Terminating : charset = [ESC, CR, DOWNKEY, UPKEY];
- var
- P: byte; C:char; Up:boolean;
-
- begin {Inp_Str}
- Up := UpCase(Shift) = 'U';
- CursorType('U');
- P := length(S);
- repeat
- Display_Str(Col,Row,Txt,Bgnd,TRUE,PadStr(S,Max,' ','L'));
- gotoXY(Col+P,Row);
- C := KeyInp;
- if C in Adjusting then Adj_Str(S,C,P,Max)
- else if C in Display then
- begin
- if Up then C := Upcase(C);
- Add_to_Str(S,C,P,Max);
- end
- else if C in Terminating then
- begin
- Field_Cntrl(C);
- if C = ESC then S := '';
- end
- else Beep;
- until C in Terminating;
- CursorType('O');
- Display_Str(Col,Row,Txt,Bgnd,FALSE,PadStr(S,Max,' ','L'));
- end {Inp_str};
- {******************************************************************************}
- end.
-