home *** CD-ROM | disk | FTP | other *** search
- {$R-} {Range checking off}
- {$B-} {Boolean short circuiting off}
- {$S+} {Stack checking on}
- {$I+} {I/O checking on}
- {$N-} {No numeric coprocessor}
- {$M 65500,16384,65500}
-
- unit tp4wio;
- { -- Global I/O procedures to include in programs generally
- Much credit is due Bill Meacham who wrote the original file IO22.INC
- and released it to the public domain. Using that work this unit was
- created and added to by Gerald Rohr of Homogenized Software. As
- with Bill's work, this program is released to the Public Domain for
- all to use and modify.
- REVISION HISTORY
- ---------------------------------------------------------------------
- Ver 2.22 - Converted to a Turbo pascal V4 units. 30 Dec 87 gbr
- Ver 2.30 - Converted dates to longint types 19 Jan 88 gbr
- Ver 2.42 - Added global inv_flag for all write routines 08 Apr 88 gbr
- Ver 2.43 - Added long integer read and write routines 01 May 88 gbr
- Ver 2.43 - Added month and month/day routines 10 May 88 gbr
- Ver 3.00 - Replaced Window procedures/Reformated file 15 Jul 88 gbr
- Ver 3.10 - Moved Window error routines here 26 Aug 88 gbr
- Ver 3.20 - Added code and globals for color hi lights 27 Aug 88 gbr
- --------------------------------------------------------------------- }
-
- interface
-
- uses
- crt,dos;
-
- const
- fdslen = 29 ; { length of fulldatestring }
-
- type
- datestring = string[10] ; { 'MM/DD/YYYY' }
-
- fulldatestring = string[fdslen] ;
-
- juldate = record
- yr : integer ; { 0 .. 9999 }
- day : integer ; { 1 .. 366 }
- end ;
-
- juldatestring = string[8] ; { 'YYYY/DDD' }
-
- montharray = array [1 .. 13] of integer ;
-
- intst = string[2]; { string of an integer }
-
- var
- sys_date :longint;
- null_date :longint;
- null_date_str : datestring;
-
- fld, scrn : integer ; { For field & screen cursor control }
- macro :array[1..10] of string; { Function key macro storage }
- inv_flag :boolean; { if true all write routines inverse the screen,
- set to false by initialization. User uses
- this flag to control the screen attributes.}
- col_inv_flag :boolean; { true if color monitor, false if monochrome,
- set by initialization routine, User may change. }
- inv_color :byte; { color to use for inverse data if col_inv_flag
- is true. Defaults to green, but user may change. }
- in_window :boolean; { if true then we are in a window, used by the
- screen writing routines to high light screen
- data. NOTE high lighting can only be done when
- in_window flag is true. }
- reserv_wind :integer; { number of windows to reserve (not close) with
- endwindows procedure. Initialized to 0, use
- with multiple program files. }
-
- PROCEDURE CLRLINE (col,row : integer);
- PROCEDURE BEEP ;
- PROCEDURE DO_FLD_CTL (key : integer);
- { Adjusts global FLD based on value of key, the ordinal value
- of last key pressed }
- PROCEDURE DO_SCRN_CTL ;
- { Checks value of FLD and adjusts value of SCRN accordingly }
- PROCEDURE WRITE_STR (st:string ; col,row:integer);
- PROCEDURE WRITE_TEMP(var ln:string;tmp:string;x,y:integer);
- { writes a string using a template. the string (ln) is printed
- left justified in the template using the filler locations.
- quits when the template is complete on the screen. Fills unused
- template filler locations with space. }
- PROCEDURE WRITE_INT (i:integer ; width,col,row:integer);
- PROCEDURE WRITE_LINT(lint:longint;width,col,row:integer);
- PROCEDURE SET_BOOL (var bool : boolean);
- { Sets boolean to be undefined, neither true nor false.
- Boolean is stored as one byte:
- $80 = undefined
- $01 = true
- $00 = false.
- Note : Turbo interprets $80 as true because it is greater than zero! }
- FUNCTION DEFINED (bool : boolean) : boolean ;
- { Determines whether the boolean is defined or not }
- PROCEDURE WRITE_BOOL (bool:boolean ; col, row:integer);
- PROCEDURE WRITE_REAL (r:real ; width,frac,col,row:integer);
- FUNCTION BUILD_STR (ch : char ; n : integer) : string ;
- { returns a string of length n of the character ch }
- FUNCTION PAD (st : string ; ch : char ; i : integer) : string ;
- { Pad string with ch to length of i. }
- FUNCTION UPPER (st :string):string;
- { returns upper case of st }
- FUNCTION STRIPCH (instr:string ; inchar:char) : string ;
- {Strips leading instances of the character from the string}
- FUNCTION TRIM (st:string;len:integer):string;
- { Chops spaces from string or truncates at l length }
- FUNCTION CHOPCH (instr:string ; inchar:char) : string ;
- {Chops trailing instances of the character from the string}
- FUNCTION INTTOSTR(n:integer):intst;
- { converts integer to packed two char string }
- FUNCTION STRTOINT(s:intst):integer;
- { converts packed two char string to integer }
- PROCEDURE READ_STR (var st:string ; maxlen, col, row:integer);
- { Read String. This procedure gets input from the keyboard one
- character at a time and edits on the fly, rejecting invalid
- characters. COL and ROW tell where to begin the data input
- field, and MAXLEN is the maximum length of the string to be
- returned.
- Only use the Function keys for string input data, for other
- types of input will beep. }
- PROCEDURE READ_TEMP(var st:string;tmp:string;col, row:integer);
- { Read string with a template. This procedure gets input from
- the keyboard one character at a time and edits on the fly,
- rejecting invalid characters. tmp is a template which is filled
- in where filler characters exist, any other characters are displayed
- on the screen. Returned string does NOT have the template imbeded in
- it. COL and ROW tell where to begin the data input
- field, Max length of the string is the max length of the template.
- }
- PROCEDURE READ_INT (var int:integer ; maxlen, col, row:integer);
- { Read Integer. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field, and MAXLEN is the maximum length of the integer
- to be returned. }
- PROCEDURE READ_LINT (var lint:longint ; maxlen, col, row:integer);
- { Read LongInt. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field, and MAXLEN is the maximum length of the integer
- to be returned. }
- FUNCTION EQUAL (r1,r2 : real) : boolean ;
- { tests functional equality of two real numbers -- 4/30/85 }
- FUNCTION GREATER (r1,r2 : real) : boolean ;
- { tests functional inequality of two real numbers -- 5/1/85 }
- PROCEDURE READ_REAL (var r:real ; maxlen,frac,col,row:integer);
- { Read Real. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field; MAXLEN is the maximum length of the string
- representation of the real number, including sign and decimal
- point; FRAC is the fractional part, the number of digits to
- right of the decimal point.
-
- Note -- In Turbo the maximum number of significant digits in
- decimal (not scientific) representation is 11. In TurboBCD,
- the maximum number of significant digits is 18. It is the
- programmer's responsibility to limit input and computed output
- to the maximum significant digits. }
- PROCEDURE READ_YN (var bool:boolean; col,row:integer);
- { Inputs "Y" OR "N" to boolean at column and row specified,
- prints "YES" or "NO."
- Note -- use this when the screen control will not return
- to the question and the boolean IS NOT defined before the
- user answers the question. Does not affect global FLD. }
- PROCEDURE READ_BOOL (var bool:boolean; col,row:integer);
- { Displays boolean at column and row specified, inputs "Y"
- or "N" to set new value of boolean, prints "YES" or "NO."
- Boolean is "forced;" user cannot cursor forward past undefined
- boolean. Pressing "Y" or "N" terminates entry.
- Boolean is stored as one byte:
- $80 = undefined
- $01 = true
- $00 = false.
- Note : Turbo interprets $80 as true because it is greater
- than zero! }
- PROCEDURE PAUSE ;
- {Prints message on bottom line, waits for user response.
- Changed from line 24 to line 23 for windows gbr}
- PROCEDURE HARD_PAUSE ;
- { Like Pause, but only accepts space bar or Escape and only
- goes forward. Changed from line 24 to line 23 for windows. gbr }
- PROCEDURE SHOW_MSG (msg : string);
- { Beeps, displays message centered on line 22, pauses }
- { changed from line 23 to line 22 for windows. gbr }
- FUNCTION MK_DT_ST (dt :longint) : datestring ;
- { Makes a string out of a date -- used for printing dates }
- PROCEDURE WRITE_DATE (dt: longint ; col, row: integer);
- { Writes date at column and row specified }
- FUNCTION MK_JUL_DT_ST (jdt : juldate) : juldatestring ;
- { makes a string out of a julian date }
- PROCEDURE READ_DATE (var dt: longint ; col, row: integer);
- { Read date at column and row specified. If the user enters
- only two digits for the year, the procedure plugs the
- century as 1900 or 2000, but the user can enter all four
- digits to override the plug. }
- FUNCTION GREATER_DATE (dt1, dt2 : longint) : integer ;
- { Compares two dates, returns 0 if both equal, 1 if first is
- greater, 2 if second is greater. }
- PROCEDURE GREG_TO_JUL (dt : longint ; var jdt : juldate);
- { converts a gregorian date to a julian date }
- PROCEDURE JUL_TO_GREG (jdt : juldate ; var dt : longint);
- { converts a julian date to a gregorian date }
- PROCEDURE NEXT_DAY (var dt : longint);
- { Adds one day to the date }
- PROCEDURE PREV_DAY (var dt : longint);
- { Subtracts one day from the date }
- FUNCTION DATE_DIFF (dt1, dt2 : longint) : longint ;
- { computes the number of days between two dates }
- FUNCTION MONTH_DIFF (dt1, dt2 : longint ) : integer ;
- { Computes number of months between two dates, rounded.
- 30.4167 = 356/12, average number of days in a month. }
- FUNCTION EQUAL_DATE (dt1, dt2 : longint) : boolean ;
- { Tests whether two dates are equal }
- FUNCTION BUILD_FULL_DATE_STR (dt : longint) : fulldatestring ;
- { Build printable string of current date -- from ROS 3.4
- source code. }
- FUNCTION MONTH(dt:longint):integer;
- { returns the month portion of a date.}
- FUNCTION DAY(dt:longint):integer;
- { returns the day from the date }
- FUNCTION YEAR(dt:longint;centry:boolean):integer;
- { returns the year of a date. if the centry flag is true
- returns 4 digit year otherwise returns two digit year. }
-
- { ---- window procedures Derived from article in Computer Language
- Magazine June 1988 by James Kerr ---- }
-
- PROCEDURE OPENWINDOW(wtitle:string;x1,y1,x2,y2:byte;
- fgnd,bkgnd: byte);
- { wtitle is centered on the top border line of the window, x
- and y are the window coordinates, fgnd and bkgnd are the
- colors of the inside of the window (note the border is always
- white, if a window can not be opened, a message as to why will
- be displayed and the program exits
- }
- PROCEDURE CLOSEWINDOW;
- { closes the current open window, does nothing if no
- window to close. }
- PROCEDURE ENDWINDOWS;
- { close any open windows when exiting the windows system. Use
- as the last statment in program to insure return to
- enviroment you came from. The global reserv_wind is normally
- set to 0 allowing all windows to be closed, if using a
- multi file window program, reserv_wind can be set to the
- number of windows to be left open when a particular program
- terminates. Always set reserv_wind to 0 before the final
- program call to endwindows.
- }
-
- { ---------------------------------------------------------------- }
-
- implementation
-
- const
- { ASCII values of cursor control keys, like WordStar. }
- { Note -- Backspace and Delete are different in CP/M }
- { and PC-DOS. Proc KEYIN translates them. }
- prev_char = $13 ; { ^S }
- next_char = $04 ; { ^D }
- prev_fld = $05 ; { ^E }
- next_fld = $18 ; { ^X }
- prev_page = $12 ; { ^R }
- next_page = $03 ; { ^C }
- del_char = $07 ; { ^G }
- del_left = $08 ; { ^H (Backspace) }
- del_fld = $19 ; { ^Y }
- del = $7F ; { Delete }
- escape = $1B ;
- carr_rtn = $0D ;
- space = $20 ;
- filler = $2E ; { $2E = . $5F = _ }
-
- { The function keys return a value which is the index 201..210
- used by subtracting 200 from the value and into the user array
- of strings to insert into a field. }
- f1 = 201;
- f2 = 202;
- f3 = 203;
- f4 = 204;
- f5 = 205;
- f6 = 206;
- f7 = 207;
- f8 = 208;
- f9 = 209;
- f10= 210;
-
- monthtotal : montharray = (0,31,59,90,120,151,181,212,243,273,304,334,365);
- { used to convert julian date to gregorian and back }
-
- type
- intset = set of $00 .. $FF ;
-
- const { Turbo typed constants -- initialized variables }
- terminating : intset = [carr_rtn, next_fld, prev_fld, escape,
- next_page, prev_page] ;
- adjusting : intset = [prev_char, next_char, del_char, del_fld, del_left] ;
-
- { --------------- local definitions for the window procedures -------------- }
- const
- maxwindows = 10; { maximum # on screen windows }
- framefgnd = lightgray; { frame colors }
- framebkgnd = black;
-
- type pointer = ^integer;
- windowtype = record
- xl,yl,xr,yr :integer; { cordinates or corners }
- bufrptr :pointer; { pointer to buffer location }
- cursorx,cursory :integer; { cursor position brfore opening }
- screenattr :byte; { text attributes before opening }
- end;
-
- var
- windowstack :array[0..maxwindows] of windowtype;
- maxcols,maxrows :byte; { # rows and columns for initial video mode }
- numwindows :0..maxwindows; { # windows currently open }
- vidstart :word; { location of video memory }
- regs :registers;
- aw_fore,
- aw_back :byte; { active window fore and background colors }
-
- { ---------------------------------------------------------------- }
-
- procedure beep;
- { this procedure is called if any routine causes an error }
- begin
- sound(200); delay(100);
- sound(350); delay(100);
- sound(100); delay(100);
- nosound;
- end; { procedure beep }
-
- { ---------------------------------------------------------------- }
-
- procedure SetColor(Fore, Back : byte);
- begin
- TextColor(Fore);
- TextBackground(Back);
- end; { SetColor }
-
- { ---------------------------------------------------------------- }
-
- function Center(Len, Left, Right : integer) : integer;
- { find the location to position (x) for title }
- begin
- center := (left + ((right-left) div 2) - (len div 2));
- end;
-
- { ---------------------------------------------------------------- }
-
- procedure drawframe(wtitle:string;x1,y1,x2,y2:byte);
- { draws a rectangular frame on the screen with upper left hand corner
- at x1,y1 and lower right hand corner at x2,y2 }
- var
- k :integer;
- currentattr :byte;
- begin
- currentattr := textattr; { save the current text attributes }
- textattr := framefgnd + 16 * framebkgnd; { change attributes for frame }
- gotoxy(x1,y1);
- write(chr(201));
- for k := (x1 + 1) to (x2 -1) do { top border line }
- write(chr(205));
- write(chr(187));
- for k := (y1 + 1) to (y2 - 1) do
- begin
- gotoxy(x1,k); write(chr(186));
- gotoxy(x2,k); write(chr(186));
- end;
- gotoxy(x1,y2);
- write(chr(200));
- for k := (x1 + 1) to (x2 - 1) do
- write(chr(205));
- write(chr(188));
- { ---- put the title in the center of the window border if there is
- a title, if length(wtitle) > 0 ----- }
- if(length(wtitle) > 0) then
- begin
- if(length(wtitle) > (x2-x1-4)) then { if title too long, clip it }
- wtitle := copy(wtitle,1,(x2-x1-4));
- GotoXY(Center(Length(WTitle) + 2, X1, X2), y1);
- TextColor(White);
- Write(' ', WTitle, ' ');
- end;
- textattr := currentattr; { restore previous text attributes }
- end; { procedure drawframe }
-
- { ---------------------------------------------------------------- }
-
- procedure saveregion(x1,y1,x2,y2:byte;
- var startaddr :pointer);
- { saves the contents of the screen rectangle with coordinates x1,y1,x2,y2
- on the heap starting at address startaddr. }
- var
- tempptr, lineptr :pointer;
- k,linelength :integer;
- begin
- linelength := (x2 - x1 + 1) * 2; { # bytes per line in rectangel }
- { allocate space on heap }
- getmem(startaddr,linelength * (y2 - y1 + 1));
- tempptr := startaddr; {tempptr points to copy destination on heap }
- for k := y1 to y2 do
- begin { make lineptr point to screen position x=s1, y=k }
- lineptr := ptr(vidstart, (k -1) * maxcols * 2 + (x1 - 1) * 2);
- { move the line from screen to heap }
- move(lineptr^,tempptr^,linelength);
- { increment the screen pointer }
- tempptr := ptr(seg(tempptr^),ofs(tempptr^)+linelength);
- end;
- end; {procedure saveregion }
-
- { ---------------------------------------------------------------- }
-
- procedure recallregion(x1,y1,x2,y2 :integer;
- hpptr :pointer);
- { moves the contents of a previously saved region from the heap back
- to the screen. }
- var
- tempptr,lineptr :pointer;
- k,linelength :integer;
- begin
- linelength := (x2 - x1 + 1) * 2; { # bytes per line in rectangle }
- tempptr := hpptr; { tempptr gives the source location for copy }
- for k := y1 to y2 do
- begin { make lineptr point to screen position x=x1, y=k }
- lineptr := ptr(vidstart,(k - 1) * maxcols * 2 + (x1 -1) * 2);
- move(tempptr^,lineptr^,linelength);
- tempptr := ptr(seg(tempptr^),ofs(tempptr^)+linelength);
- end;
- end; { procedure recallregion }
-
- { ---------------------------------------------------------------- }
-
- procedure closewindow;
- var x,y :integer;
- begin
- if numwindows > 0 then
- begin
- with windowstack[numwindows] do
- begin
- recallregion(xl,yl,xr,yr,bufrptr); { restore underlying text }
- freemem(bufrptr,(xr -xl + 1) * (yr -yl + 1) * 2); { free heap }
- x := cursorx;
- y := cursory; { prepare to restore cursor position }
- textattr := screenattr; { restore screen attributes }
- end;
- { activate the underlying window }
- numwindows := numwindows -1;
- with windowstack[numwindows] do
- window(xl+1,yl+1,xr -1,yr -1);
- gotoxy(x,y); { restore cursor position }
- end;
- if numwindows = 0 then in_window := false;
- end; { procedure closewindow }
-
- { ---------------------------------------------------------------- }
-
- procedure endwindows;
- { close any open windows when exiting the windows system. Use as the
- last statment in program to insure return to enviroment you came from.
- The global variable is normally set to 0 but may be set to a reserved
- number of windows if using a multi file window system.}
- begin
- while (numwindows > reserv_wind) do
- closewindow;
- end; { procedure endwindows }
-
- { ---------------------------------------------------------------- }
-
- procedure wind_err(msg : string);
- { Beeps, displays open window error message. Can not do it right
- as the window system is broke when this is called so will just
- try to put something on the screen.
- }
- var
- i : integer ;
- ch :char;
-
- begin
- beep ;
- window(1,1,79,24); { make sure we have some screen space }
- write_str('+==========================================================+',10,10);
- for i := 1 to 9 do
- write_str('| |',10,10+i);
- write_str('+=========== Any key to exit to DOS =======================+',10,20);
- if length(msg) > 76 then msg := copy(msg,1,76);
- write_str(msg,((76-length(msg)) div 2),13);
- ch := readkey;
- reserv_wind := 0; { be sure we get them all }
- endwindows; { close them all before exit }
- end ; { wind_err }
-
- { ---------------------------------------------------------------- }
-
- procedure openwindow(wtitle :string;
- x1,y1,x2,y2 :byte;
- fgnd,bkgnd :byte
- );
- { creates a blank window with the given coordinates, and saves the contents
- of the underlying region on the heap. If an error occurs in attemping to
- open the window, a message is displayed on the screen before exiting the
- program a message is put on the screen. then the exit procedure returns
- the following error codes: 1 = too many windows, 2 = out of heap memory,
- 3 = wrong window dimensions.
- }
- var pntr :pointer;
- begin
- if(numwindows = 0) then
- begin { determine current screen parameters }
- maxcols := lo(windmax) + 1; { add 1 since numbering begins with 0 }
- maxrows := hi(windmax) + 1;
- with windowstack[0] do { windowstack[0] is the entire screen }
- begin
- xl := 0;
- yl := 0;
- xr := maxcols + 1;
- yr := maxrows + 1;
- end;
- end;
- { check for possible error conditions }
- if(numwindows = maxwindows) then
- begin
- wind_err('Sorry, too may windows requested.');
- halt(1);
- end
- else if(maxavail < (x2 - x1 + 1) * (y2 - y1 + 1) * 2) then
- begin
- wind_err('Sorry, No more Heap storage available.');
- halt(2);
- end
- else if(not ((x1 in [1..maxcols-2]) and (x2 in [3..maxcols]) and
- (x2-x1> 1) and (y1 in [1..maxrows-2]) and
- (y2 in [3..maxrows]) and (y2 - y1 > 1))) then
- begin
- wind_err('Sorry, Invalid window dimensions.');
- halt(3);
- end
- else
- begin { successful request }
- saveregion(x1,y1,x2,y2,pntr);
- numwindows := numwindows + 1;
- with windowstack[numwindows] do
- begin
- xl := x1;
- yl := y1;
- xr := x2;
- yr := y2;
- bufrptr := pntr;
- cursorx := wherex;
- cursory := wherey;
- screenattr := textattr;
- end;
- window(1,1,maxcols,maxrows); { make the whole screen a window }
- drawframe(wtitle,x1,y1,x2,y2);
- window(x1+1,y1+1,x2-1,y2-1); { create the requested window }
- textcolor(fgnd);
- textbackground(bkgnd);
- aw_back := bkgnd; { save the active window colors }
- aw_fore := fgnd;
- clrscr;
- end;
- in_window := true;
- end; { procedure openwindow }
-
- { ------- End window unit ----- }
-
- { procedure gotoxy (col,row); -- Built-in proc in Turbo to place
- cursor on screen. Upper left is (1,1) not (0,0)! }
-
- { procedure clrscr ; -- Built-in proc in Turbo to clear screen. }
-
- { procedure clreol ; -- built-in proc in Turbo to clear to end of line }
-
- { -------------------------------------------------------------------------- }
-
- procedure clrline(col,row : integer);
- begin
- gotoxy (col,row);
- clreol
- end ;
-
- { -------------------------------------------------------------------------- }
-
- procedure do_fld_ctl(key : integer);
- { Adjusts global FLD based on value of key, the ordinal value
- of last key pressed }
- { global fld : integer -- for field cursor control }
- begin
- case key of
- carr_rtn, next_fld : fld := succ(fld);
- prev_fld : fld := pred(fld);
- next_page : fld := 999 ;
- prev_page : fld := -999 ;
- escape : fld := maxint ;
- end { case }
- end ; { proc do_fld_ctl }
-
- { ------------------------------------------------------------ }
-
- procedure do_scrn_ctl ;
- { Checks value of FLD and adjusts value of SCRN accordingly }
- { Global fld, scrn : integer -- For field and screen cursor control }
- begin
- if fld < 1 then
- scrn := pred(scrn)
- else if fld = maxint then
- scrn := maxint
- else
- scrn := succ(scrn)
- end ;
-
- { ------------------------------------------------------------ }
-
- procedure write_str(st:string ; col,row:integer);
- begin
- gotoxy (col,row);
- if((in_window) and (inv_flag)) then
- begin
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- write (st);
- setcolor(aw_fore,aw_back);
- end
- else
- write(st);
- end ;
-
- { -------------------------------------------------------------------------- }
- procedure write_temp(var ln:string;tmp:string;x,y:integer);
- { writes a string using a template. the string (ln) is printed
- left justified in the template using the filler locations.
- quits when the template is complete on the screen. Fills unused
- template filler locations with space. }
- var
- p,t :integer;
- begin
- p := 1;
- t := 1;
- gotoxy(x,y);
- if((in_window) and (inv_flag)) then
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- for t := 1 to length(tmp) do
- begin
- if(tmp[t] <> chr(filler)) then
- write(tmp[t])
- else
- begin
- if(p > length(ln)) then
- write(' ')
- else
- begin
- write(ln[p]);
- p := p + 1;
- end;
- end;
- end;
- if((in_window) and (inv_flag)) then
- setcolor(aw_fore,aw_back);
- end; { procedure write_temp }
-
- { -------------------------------------------------------------------------- }
-
- procedure write_int(i:integer ; width,col,row:integer);
- begin
- gotoxy (col,row);
- if((in_window) and (inv_flag)) then
- begin
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- write(i:width);
- setcolor(aw_fore,aw_back);
- end
- else
- write (i:width)
- end ;
-
- { -------------------------------------------------------------------------- }
-
- procedure write_lint(lint:longint ; width,col,row:integer);
- begin
- gotoxy (col,row);
- if((in_window) and (inv_flag)) then
- begin
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- write (lint,width);
- setcolor(aw_fore,aw_back);
- end
- else
- write (lint:width)
- end ;
-
- { -------------------------------------------------------------------------- }
-
- procedure set_bool(var bool : boolean);
- { Sets boolean to be undefined, neither true nor false.
- Boolean is stored as one byte:
- $80 = undefined
- $01 = true
- $00 = false.
- Note : Turbo interprets $80 as true because it is greater than zero! }
-
- var
- b : byte absolute bool ;
- begin
- b := $80
- end ; { proc set_bool }
-
- { -------------------------------------------------------------------------- }
-
- function defined(bool : boolean) : boolean;
- { Determines whether the boolean is defined or not }
- var
- b : byte absolute bool ;
- begin
- defined := not (b = $80)
- end ; { function defined }
-
- { -------------------------------------------------------------------------- }
-
- procedure write_bool(bool:boolean ; col, row:integer);
- begin
- gotoxy (col,row);
- if((in_window) and (inv_flag)) then
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- if not defined(bool) then
- write ('___')
- else if bool then
- write ('YES')
- else
- write ('NO ');
- if((in_window) and (inv_flag)) then
- setcolor(aw_fore,aw_back);
- end ;
-
- { -------------------------------------------------------------------------- }
-
- procedure write_real(r:real ; width,frac,col,row:integer);
- begin
- gotoxy (col,row);
- if((in_window) and (inv_flag)) then
- begin
- if(col_inv_flag) then
- setcolor(inv_color,aw_back)
- else
- setcolor(aw_back,aw_fore);
- write (r:width:frac);
- setcolor(aw_fore,aw_back);
- end
- else
- write (r:width:frac)
- end ;
-
- { -------------------------------------------------------------------------- }
-
- { This is for IBM PC-DOS only !! not in the implimentation !!}
-
- procedure keyin (var ch:char);
- { Reads a single character from keyboard without echoing it back.
- Maps function key scan codes to single keyboard keys.
- From Turbo 3.0 manual, page 360 -- 5/29/85
- Modified for IO20 -- 2/26/86
- Modified for IO22 -- 5/24/87
- Modified to return different codes for the function keys than
- the keypad keys. Used to allow special entry for the function
- keys. 10 Dec 87 gbr.
- }
- var
- func : boolean ; { Whether function key or not }
- c : char ; { Character read }
- key : integer ; { ORD of character returned }
-
- begin
- func := false ;
- c := readkey; { Get first char }
- if(c = #0) and keypressed then { If there is a second ... }
- begin
- c := readkey; { Get 2nd char }
- func := true
- end ;
- key := ord(c);
- if func then { Translate function keys }
- case key of
- 75 : key := prev_char ; { left-arrow }
- 77 : key := next_char ; { right-arrow }
- 72 : key := prev_fld ; { up-arrow }
- 80 : key := next_fld ; { down-arrow }
- 73 : key := prev_page ; { PgUp }
- 81 : key := next_page ; { PgDn }
- 83 : key := del_char ; { DEL }
- 59 : key := f1 ; { F1 }
- 60 : key := f2 ; { F2 }
- 61 : key := f3; { F3 }
- 62 : key := f4; { F4 }
- 63 : key := f5; { F5 }
- 64 : key := f6; { F6 }
- 65 : key := f7; { F7 }
- 66 : key := f8; { F8 }
- 67 : key := f9; { F9 }
- 68 : key := f10; { F10}
- else
- key := 00 ;
- end { case }
- else { not a function key }
- case key of { CP/M-like control keys }
- $0B : key := prev_fld ; { ^K }
- $0A : key := next_fld ; { ^J }
- $0C : key := next_char ; { ^L }
- end ; { case }
- ch := chr(key) { finally, return the character }
- end ;
-
- { ------------------------------------------------------------ }
-
- function build_str(ch : char ; n : integer) : string;
- { returns a string of length n of the character ch }
- var
- st : string ;
- begin
- if n < 0 then
- n := 0 ;
- st[0] := chr(n);
- fillchar (st[1],n,ch);
- build_str := st
- end ; { function build_str);
-
- { ---------------------------------------------------------------- }
-
- FUNCTION UPPER(st :string):string;
- { make string upper case }
- var i:integer;
- begin
- if (length(st) > 0) then
- for i := 1 to length(st) do st[i] := upcase(st[i]);
- upper := st;
- end; {function upper}
-
- { -------------------------------------------------------------------------- }
-
- function pad(st : string ; ch : char ; i : integer) : string;
- { Pad string with ch to length of i }
- var
- l : integer ;
- begin
- l := length(st);
- if l > i then st := copy(st,1,i); { if too long then shorten it }
- if l < i then
- begin
- fillchar (st[l+1],i-l,ch);
- st[0] := chr(i)
- end ;
- pad := st
- end;
-
- { ------------------------------------------------------------ }
-
- procedure adjust_str (var st : string ;
- var p : integer ; { position of char to left of cursor }
- key, { ord of adjusting character }
- maxlen, col, row : integer );
- { Adjusts position of cursor within string, deletes characters, etc. }
- begin
- case key of
- prev_char :if p > 0 then
- p := pred(p);
- next_char :if p < length(st) then
- p := succ(p);
- del_left :if p > 0 then
- begin
- delete (st,p,1);
- write (^H,copy(st,p,maxlen),chr(filler));
- p := pred(p)
- end ;
- del_char :if p < length(st) then
- begin
- delete (st,p+1,1);
- write (copy(st,p+1,maxlen),chr(filler))
- end ;
- del_fld :begin
- st := '' ;
- p := 0 ;
- gotoxy(col,row);
- write(build_str(chr(filler),maxlen))
- end
- end { case }
- end ; { proc adjust_str }
-
- { -------------------------------------------------------------------------- }
-
- function purgech (instr : string ; inchar : char) : string ;
- {Purges all instances of the character from the string}
- var
- n : integer ; {Loop counter}
- outstr : string ; {Result string}
- begin
- outstr := '' ;
- for n := 1 to length (instr) do
- if not (instr[n] = inchar) then
- outstr := concat (outstr, instr[n]);
- purgech := outstr
- end ;
-
- { -------------------------------------------------------------------------- }
-
- function stripch(instr:string ; inchar:char) : string;
- {Strips leading instances of the character from the string}
- begin
- while not (length(instr) = 0) and (instr[1] = inchar) do
- delete (instr, 1, 1);
- stripch := instr
- end ;
-
- { -------------------------------------------------------------------------- }
-
- function chopch(instr:string ; inchar:char) : string;
- {Chops trailing instances of the character from the string}
- begin
- while not (length(instr) = 0) and (instr[length(instr)] = inchar) do
- delete (instr, length(instr), 1);
- chopch := instr
- end ;
-
- { -------------------------------------------------------------------------- }
-
- function inttostr(n:integer):intst;
- { converts integer to packed two char string }
- begin
- n := n + (-32768);
- inttostr := chr(hi(n)) + chr(lo(n));
- end; { function inttostr }
-
- { -------------------------------------------------------------------------- }
-
- function strtoint(s:intst):integer;
- { converts packed two char string to integer }
- begin
- strtoint := swap(ord(s[1])) + ord(s[2]) + (-32768);
- end; { function strtoint }
-
- { -------------------------------------------------------------------------- }
-
- function trim(st:string;len:integer):string;
- { trims right blanks from string and returns a string of len or less }
- var
- i :integer;
-
- begin
- if length(st) > len then trim := copy(st,1,len)
- else
- begin
- i := length(st);
- while (i >= 1) and (st[i] = ' ') do i := i - 1;
- if i = 0 then trim := ''
- else trim := copy(st,1,i);
- end;
- end; { function trim }
-
- { -------------------------------------------------------------------------- }
-
- procedure read_str(var st:string ; maxlen, col, row:integer);
-
- { Read String. This procedure gets input from the keyboard one
- character at a time and edits on the fly, rejecting invalid
- characters. COL and ROW tell where to begin the data input
- field, and MAXLEN is the maximum length of the string to be
- returned.
- Revised 6/04/85 -- WPM
- Only use the Function keys for string input data, for other
- types of input will beep.
- 10 Dec 87 gbr}
-
- var
- ch : char ; { character from keyboard }
- key, { ord(ch) }
- p : integer ; { position of char to left of cursor }
-
- procedure add_to_str ;
- begin
- if not (length(st) = maxlen) then
- begin
- p := p + 1 ;
- insert(ch,st,p);
- write (copy(st,p,maxlen))
- end
- end ; {--- of add_to_str ---}
-
- begin {--- read_str ---}
- write_str (st, col, row);
- write (build_str(chr(filler),maxlen - length(st)));
- p := length(st);
- repeat
- gotoxy (col + p, row);
- keyin (ch); {^^^^ read keyboard here ^^^^}
- key := ord(ch);
- if key in [$20 .. $7E] then { printable character }
- add_to_str
- else if key in adjusting then
- adjust_str (st,p,key,maxlen,col,row)
- else if key in terminating then
- do_fld_ctl (key)
- else if key in [201..210] then { Function key pressed }
- begin
- st := copy(macro[key-200],1,maxlen); { put macro string in st }
- key := carr_rtn; { cr to terminate entry }
- end
- else
- beep
- until key in terminating ;
- gotoxy (col + length(st), row);
- write_str(st,col,row); { rewrite for display characteristics }
- write ('':maxlen - length(st)) { delete the filler characters on screen}
- end ; {--- of read_str ---}
-
- { ------------------------------------------------------------ }
-
- function bld_tmp_str(st:string; { input string so far }
- tmp:string; { template to put it in }
- ch : char { filler character }
- ) : string ;
- { returns a string of template filled in with the input string }
- var
- i,t : integer;
- stt :string;
- begin
- stt := tmp;
- t := 1;
- for i := 1 to length(st) do
- begin
- while(stt[t] <> ch) do t := t + 1;
- stt[t] := st[i];
- end;
- bld_tmp_str := stt
- end ; { function bld_tmp_str);
-
- { -------------------------------------------------------------------------- }
- procedure read_temp(var st:string;tmp:string;col, row:integer);
- { Read string with a template. This procedure gets input from
- the keyboard one character at a time and edits on the fly,
- rejecting invalid characters. tmp is a template which is filled
- in where filler characters exist, any other characters are displayed
- on the screen. Returned string does NOT have the template imbeded in
- it. COL and ROW tell where to begin the data input
- field, Max length of the string is the max length of the template.
- }
- var
- ch : char ; { character from keyboard }
- key, { ord(ch) }
- t, { position in template }
- maxlen, { max length of the template }
- maxline, { max length of returned string }
- p,i : integer ; { position in input string }
-
- procedure add_to_str ;
- begin
- if(length(st) < maxline) then
- begin
- p := p + 1 ;
- t := t + 1;
- insert(ch,st,p);
- gotoxy(col,row);
- write(bld_tmp_str(st,tmp,chr(filler)));
- while(tmp[t] <> chr(filler)) and (t < length(tmp)) do t := succ(t);
- end
- end ; {--- of add_to_str ---}
-
- procedure adj_tmp_str;
- { Adjusts position of cursor within string using a template,
- deletes characters, etc. }
- var
- rwt_flag :boolean; { need to rewrite line }
- begin
- rwt_flag := false;
- case key of
- prev_char :if p > 0 then
- begin
- p := pred(p);
- t := pred(t);
- while(tmp[t] <> chr(filler)) and (t > 1) do t := pred(t);
- end;
- next_char :if p < length(st) then
- begin
- p := succ(p);
- t := succ(t);
- while(tmp[t] <> chr(filler)) and (t < length(tmp)) do
- t := succ(t);
- end;
- del_left :if p > 0 then
- begin
- delete (st,p,1);
- rwt_flag := true;
- p := pred(p);
- t := pred(t);
- while(tmp[t] <> chr(filler)) and (t > 1) do t := pred(t);
- end ;
- del_char :if p < length(st) then
- begin
- delete (st,p+1,1);
- rwt_flag := true;
- end ;
- del_fld :begin
- st := '' ;
- p := 0 ;
- t := 1;
- while(tmp[t] <> chr(filler)) and (t <= maxlen) do
- t := t + 1;
- rwt_flag := true;
- end
- end; { case }
- if rwt_flag then
- begin
- gotoxy(col,row);
- write(bld_tmp_str(st,tmp,chr(filler)));
- end;
- end ; { proc adj_tmp_str }
-
- begin {--- read_temp ---}
- maxlen := length(tmp);
- maxline := 0;
- for i := 1 to length(tmp) do
- if(tmp[i] = chr(filler)) then maxline := maxline + 1;
- p := length(st);
- t := 1;
- for i := 1 to p do { find the present st length + template }
- begin
- while(tmp[t] <> chr(filler)) and (t <= maxlen) do t := t + 1;
- t := t + 1;
- end; { check if the template character we are at is a template }
- while(tmp[t] <> chr(filler)) and (t <= maxlen) do t := t + 1;
- gotoxy(col,row);write(bld_tmp_str(st,tmp,chr(filler)));
- p := length(st);
- repeat
- gotoxy (col + t-1, row);
- keyin (ch); {^^^^ read keyboard here ^^^^}
- key := ord(ch);
- if key in [$20 .. $7E] then { printable character }
- add_to_str
- else if key in adjusting then
- adj_tmp_str
- else if key in terminating then
- do_fld_ctl (key)
- else if key in [201..210] then { Function key pressed }
- begin
- st := copy(macro[key-200],1,maxlen); { put macro string in st }
- key := carr_rtn; { cr to terminate entry }
- end
- else
- beep
- until key in terminating ;
- write_temp(st,tmp,col,row);
- end ; {--- of read_temp ---}
-
- { -------------------------------------------------------------------------- }
-
- procedure read_int(var int:integer ; maxlen, col, row:integer);
-
- { Read Integer. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field, and MAXLEN is the maximum length of the integer
- to be returned.
- Revised 6/04/85 -- WPM }
-
- const
- maxst : string[5] = '32767' ; { string representation of maxint }
-
- var
- ch : char ; { character from keyboard }
- key, { ord(ch) }
- p : integer ; { position of char to left of cursor }
- st : string; { string representation of integer }
- code : integer ; { result of string to integer conversion }
-
- procedure add_to_str ;
- begin
- if not (length(st) = maxlen) then
- begin
- p := p + 1 ;
- insert (ch,st,p);
- write (copy(st,p,maxlen))
- end
- end ; {--- of add_to_str---}
-
- begin {--- read_int ---}
- str (int:maxlen, st); { convert integer into string }
- st := purgech (st, ' ');
- st := stripch (st, '0');
- write_str (st, col, row);
- write (build_str(chr(filler),maxlen - length(st)));
- p := length(st);
- repeat
- gotoxy (col + p, row);
- keyin (ch);
- key := ord(ch);
- if key = $2D then { minus sign }
- begin
- if(pos('-',st) = 0) and (length(st) < maxlen)
- and (p = 0) then
- add_to_str
- end
- else if key in [$30 .. $39] then {digits 0 - 9}
- begin
- add_to_str ;
- if (length(st) = 5) and (st > maxst) then
- begin
- delete (st,p,1);
- write (^H,copy(st,p,maxlen),chr(filler));
- p := p - 1
- end
- end
- else if key in adjusting then
- adjust_str (st,p,key,maxlen,col,row)
- else if key in terminating then
- do_fld_ctl (key)
- until key in terminating ;
- if st = '' then
- begin
- int := 0 ;
- code := 0
- end
- else
- val (st, int, code); {Make string into integer}
- gotoxy (col, row);
- if code = 0 then {Conversion worked OK}
- write_int(int,maxlen,col,row)
- else
- begin
- write ('** conversion error ', code);
- halt
- end
- end ; {--- of read_int ---}
-
- { -------------------------------------------------------------------------- }
-
- procedure read_lint(var lint:longint ; maxlen, col, row:integer);
- { Read LongInt. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field, and MAXLEN is the maximum length of the long integer
- to be returned.
- }
- const
- maxst : string[10] = '2147483647' ; { string representation of maxint }
-
- var
- ch : char ; { character from keyboard }
- key, { ord(ch) }
- p : integer ; { position of char to left of cursor }
- st : string; { string representation of integer }
- code : integer ; { result of string to integer conversion }
-
- procedure add_to_str ;
- begin
- if not (length(st) = maxlen) then
- begin
- p := p + 1 ;
- insert (ch,st,p);
- write (copy(st,p,maxlen))
- end
- end ; {--- of add_to_str---}
-
- begin {--- read_int ---}
- str (lint:maxlen, st); { convert long integer into string }
- st := purgech (st, ' ');
- st := stripch (st, '0');
- write_str (st, col, row);
- write (build_str(chr(filler),maxlen - length(st)));
- p := length(st);
- repeat
- gotoxy (col + p, row);
- keyin (ch);
- key := ord(ch);
- if key = $2D then { minus sign }
- begin
- if(pos('-',st) = 0) and (length(st) < maxlen) and
- (p = 0) then
- add_to_str
- end
- else if key in [$30 .. $39] then {digits 0 - 9}
- begin
- add_to_str ;
- if (length(st) = 10) and (st > maxst) then
- begin
- delete (st,p,1);
- write (^H,copy(st,p,maxlen),chr(filler));
- p := p - 1
- end
- end
- else if key in adjusting then
- adjust_str (st,p,key,maxlen,col,row)
- else if key in terminating then
- do_fld_ctl (key)
- until key in terminating ;
- if st = '' then
- begin
- lint := 0 ;
- code := 0
- end
- else
- val (st, lint, code); {Make string into integer}
- gotoxy (col, row);
- if code = 0 then {Conversion worked OK}
- write_lint(lint,maxlen,col,row)
- else
- begin
- write ('** conversion error ', code);
- halt
- end
- end ; {--- of read_lint ---}
-
- { -------------------------------------------------------------------------- }
-
- function equal(r1,r2 : real) : boolean;
- { tests functional equality of two real numbers -- 4/30/85 }
- begin
- equal := abs(r1 - r2) < 1.0e-5
- end ; { function equal }
-
- { -------------------------------------------------------------------------- }
-
- function greater(r1,r2 : real) : boolean;
- { tests functional inequality of two real numbers -- 5/1/85 }
- begin
- greater := (r1 - r2) > 1.0e-5
- end ; { function greater }
-
- { -------------------------------------------------------------------------- }
-
- procedure read_real(var r:real ; maxlen,frac,col,row:integer);
-
- { Read Real. This procedure gets input from the keyboard
- one character at a time and edits on the fly, rejecting
- invalid characters. COL and ROW tell where to begin the data
- input field; MAXLEN is the maximum length of the string
- representation of the real number, including sign and decimal
- point; FRAC is the fractional part, the number of digits to
- right of the decimal point.
-
- Note -- In Turbo the maximum number of significant digits in
- decimal (not scientific) representation is 11. In TurboBCD,
- the maximum number of significant digits is 18. It is the
- programmer's responsibility to limit input and computed output
- to the maximum significant digits.
-
- Revised 6/04/85 -- WPM }
-
- var
- ch : char ; { Input character }
- key, { ord(ch) }
- p : integer ; { position of char to left of cursor }
- st : string; { String representation of real number -- }
- { max digits plus minus sign plus decimal point }
- code : integer ; { Result of VAL conversion }
- rlen : integer ; { Current length of st to right of dec. pt. }
- llen : integer ; { Current length to left, including dec. pt. }
- maxl : integer ; { Max allowable to left, including dec. pt. }
- posdec : integer ; { position of decimal point in string }
-
- { +++++++++++++++++++++++++++++++++++++ }
-
- procedure compute_length ;
- { Compute length of left and right portions of string }
- begin
- posdec := pos('.',st);
- if posdec = 0 then { If no dec. pt. ... }
- begin
- llen := length(st); { the whole string is Left }
- rlen := 0 { and none is Right }
- end
- else {There is a decimal point ...}
- begin
- llen := posdec ; { Left is all up to and incl. dec. pt. }
- rlen := length(st) - llen { Right is the rest }
- end
- end ; { proc compute_length }
-
- { +++++++++++++++++++++++++++++++++++++ }
-
- procedure add_to_str ;
-
- procedure add_it ;
- begin
- p := p + 1 ;
- insert (ch,st,p);
- write (copy(st,p,maxlen))
- end ;
-
- begin {add_to_str}
- posdec := pos ('.',st);
- if ch = '.' then { Decimal point; if room, add it }
- begin
- if(posdec = 0) and (length(st) - p <= frac) then
- add_it
- end
- { else it's not a decimal point }
- { see if digit fits in whole part }
- else if((posdec = 0) and (llen < maxl - 1)) or
- ((posdec > 0) and (llen < maxl) and (p < posdec)) then
- add_it { only dec. pt. allowed in pos. maxl }
- { digit is candidate for fractional part }
- else if(not(posdec = 0)) and (p >= posdec) and (rlen < frac) then
- add_it
- end ; {--- of add_to_str---}
-
- { +++++++++++++++++++++++++++++++++++++ }
-
- begin {--- read_real ---}
- {Initialize}
- maxl := maxlen - frac ;
- {Set up string representation of real and }
- {determine length of left & right portions}
- str(r:maxlen:frac,st); {Make real into string}
- st := purgech (st, ' '); {Purge all blanks}
- st := stripch (st, '0'); {Strip leading zeroes}
- if not (pos('.', st) = 0) then {If there is a dec. pt ... }
- begin
- st := chopch (st, '0'); {Chop trailing zeroes}
- st := chopch (st, '.') {and trailing dec. pt.}
- end ;
- compute_length ;
- {Write string on console}
- write_str (st, col, row);
- write (build_str(chr(filler),maxlen - length(st)));
- p := length(st);
- {Get input a character at a time & edit it}
- repeat
- gotoxy (col + p, row);
- compute_length ;
- if((posdec = 0) and (llen > maxl - 1)) or
- ((not (posdec = 0)) and (llen > maxl)) or
- (rlen > frac) then { if number is larger than }
- begin { spec then delete it all }
- key := del_fld ;
- adjust_str (st,p,key,maxlen,col,row);
- gotoxy (col,row)
- end ;
- keyin (ch);
- key := ord(ch);
- if key = $2D then { minus sign }
- begin
- if(pos('-',st) = 0) and (p = 0) and (((posdec = 0) and
- (llen < maxl - 1)) or
- ((not (posdec = 0)) and (llen < maxl))) then
- add_to_str
- end
- else if key in [$2E, $30 .. $39] then { decimal point, numeric digits }
- add_to_str
- else if key in adjusting then
- adjust_str (st,p,key,maxlen,col,row)
- else if key in terminating then
- do_fld_ctl (key);
- until key in terminating ;
- {Done getting input, now convert back to real}
- if(st = '') or (st = '.') or (st = '-') or (st = '-.') then
- begin {If null string ... }
- r := 0.0 ; {Make real zero}
- code := 0
- end
- else {Not a null string}
- val (st, r, code); {Make string into real}
- gotoxy (col, row);
- if code = 0 then {Conversion worked OK}
- write_real(r,maxlen,frac,col,row) {Write the real on screen}
- else
- begin
- write ('** conversion error ', code);
- halt
- end
- end ; {--- of read_real ---}
-
- { -------------------------------------------------------------------------- }
-
- procedure read_yn(var bool:boolean; col,row:integer);
- { Inputs "Y" OR "N" to boolean at column and row specified,
- prints "YES" or "NO."
-
- Note -- use this when the screen control will not return
- to the question and the boolean IS NOT defined before the
- user answers the question. Does not affect global FLD. }
-
- var ch:char ;
- begin
- gotoxy (col,row);
- write (' ');
- gotoxy (col,row);
- repeat
- keyin (ch)
- until (ch in ['Y', 'y', 'N', 'n']);
- if (ch = 'Y') or (ch = 'y') then
- begin
- write_str('YES',col,row);
- bool := true
- end
- else
- begin
- write_str('NO ',col,row);
- bool := false
- end
- end ; { proc read_yn }
-
- { ------------------------------------------------------------ }
-
- procedure read_bool(var bool:boolean; col,row:integer);
- { Displays boolean at column and row specified, inputs "Y"
- or "N" to set new value of boolean, prints "YES" or "NO."
- Boolean is "forced;" user cannot cursor forward past undefined
- boolean. Pressing "Y" or "N" terminates entry.
-
- Boolean is stored as one byte:
- $80 = undefined
- $01 = true
- $00 = false.
- Note : Turbo interprets $80 as true because it is greater than zero! }
-
- var
- ch : char ;
- key : integer ;
-
- begin
- write_bool (bool, col, row);
- gotoxy (col, row);
- repeat
- keyin (ch);
- key := ord(ch);
- if key in [$59,$79] then { 'Y','y' }
- begin
- bool := true ;
- key := next_fld ;
- do_fld_ctl(key)
- end
- else if key in [$4E, $6E] then { 'N','n' }
- begin
- bool := false ;
- key := next_fld ;
- do_fld_ctl(key)
- end
- else if key in terminating then
- begin
- if(not defined(bool)) and
- (key in [carr_rtn, next_fld, next_page]) then
- key := $00
- else
- do_fld_ctl (key)
- end
- until key in terminating ;
- write_bool (bool, col, row)
- end ; {--- of read_bool ---}
-
- { -------------------------------------------------------------------------- }
-
- procedure pause ;
- {Prints message on bottom line, waits for user response.
- Moved message into window in lower left corner gbr}
- var
- ch : char ;
- key : integer ;
- begin
- openwindow('',2,23,55,25,lightgray,black);
- write_str ('PRESS SPACE BAR TO CONTINUE OR UP-ARROW TO GO BACK',2,1);
- repeat
- keyin (ch);
- key := ord(ch);
- case key of
- $20 : fld := succ(fld);
- prev_fld : fld := pred(fld);
- prev_page : fld := -999 ;
- escape : fld := maxint ;
- end ;
- until key in [$20, prev_fld, prev_page, escape] ;
- closewindow;
- end ; { proc pause }
-
- { ------------------------------------------------------------ }
-
- procedure hard_pause ;
- { Like Pause, but only accepts space bar or Escape and only goes forward }
- { puts the message in a window at bottom of screen }
- var
- ch : char ;
- key : integer ;
- begin
- openwindow('',5,23,35,25,lightgray,black);
- write_str('PRESS SPACE BAR TO CONTINUE',2,1);
- repeat
- keyin (ch);
- key := ord(ch);
- case key of
- $20 : fld := succ(fld);
- escape : fld := maxint ;
- end ;
- until key in [$20, escape] ;
- closewindow;
- end ; { proc hard_pause }
-
- { ------------------------------------------------------------ }
-
- procedure show_msg(msg : string);
- { Beeps, displays message centered on line 22, pauses }
- { changed to put message in window in lower left corner. gbr }
-
- var
- savefld : integer ;
-
- begin
- savefld := fld ;
- beep ;
- openwindow('ERROR MESSAGE',2,21,79,23,lightgray,black);
- if length(msg) > 76 then msg := copy(msg,1,76);
- write_str(msg,((76-length(msg)) div 2),1);
- hard_pause ;
- closewindow;
- fld := savefld ;
- end ; { proc show_msg }
-
- { ---------------------------------------------------------------- }
-
- { -- End of Standard screen routines - Beginning of Date routines -- }
-
- function mk_dt_st(dt:longint):datestring;
- { returns a string of the dates to print }
-
- var
- yr,mo,dy,i :integer;
- result :longint;
- stmo,stdy :string[2];
- styr :string[4];
-
- begin
- if dt = 0 then mk_dt_st := null_date_str
- else
- begin
- dy := (dt mod 100);
- result := (dt - dy); { subtract the number of days }
- result := result div 100; { move to right }
- mo := (result mod 100); { get the month }
- yr := (result div 100); { get year }
- str(yr:1,styr);
- str(mo:1,stmo);
- if length(stmo) = 1 then stmo := concat('0',stmo);
- str(dy:1,stdy);
- if length(stdy) = 1 then stdy := concat('0',stdy);
- mk_dt_st := concat(stmo,'/',stdy,'/',styr);
- end;
- end; {function mk_dt_st}
-
- { ------------------------------------------------------------ }
-
- procedure write_date(dt: longint ; col, row: integer);
- { Writes date at column and row specified }
- var
- ds : datestring ;
- begin
- ds := mk_dt_st (dt);
- write_str(ds,col,row)
- end ; { --- proc write_date --- }
-
- { ------------------------------------------------------------ }
-
- function mk_jul_dt_st(jdt : juldate) : juldatestring;
- { makes a string out of a julian date }
- var
- yr_st : string[4] ;
- day_st : string[3] ;
- jdt_st : juldatestring ;
- begin
- with jdt do
- if (yr=0) and (day = 0) then
- jdt_st := 'YYYY/DDD'
- else
- begin
- str(yr:4,yr_st);
- str(day:3,day_st);
- jdt_st := concat (yr_st,'/',day_st)
- end ;
- mk_jul_dt_st := jdt_st
- end ; { function mk_jul_dt_st }
-
- { ------------------------------------------------------------ }
-
- function leapyear (yr : integer) : boolean ;
- { Whether the year is a leap year or not.
- The year is year and century, e.g. year '1984' is 1984, not 84 }
- begin
- leapyear := ((yr mod 4 = 0) and (not(yr mod 100 = 0)))
- or ( yr mod 400 = 0 )
- end ;
-
- { ------------------------------------------------------------ }
-
- procedure get_dt_val(tpdate:longint;var yr,mo,dy:integer);
- { breaks the tpdate into the global integer values }
-
- var
- result :longint;
-
- begin
- dy := (tpdate mod 100);
- result := (tpdate - dy); { subtract the number of days }
- result := result div 100; { move to right }
- mo := (result mod 100); { get the month }
- yr := (result div 100); { get year }
- end; {function get_dt_val}
-
- { ------------------------------------------------------------ }
-
- function valid_date (dt:longint) : boolean ;
- { Test whether date is valid }
- var
- bad_fld :integer ;
- yr,mo,dy :integer;
-
- begin
- get_dt_val(dt,yr,mo,dy); { puts the date in local variables }
- bad_fld := 0 ;
- if (mo = 0) and (dy = 0) and (yr = 0) then
- bad_fld := 0
- else if not (mo in [1 .. 12]) then
- bad_fld := 1
- else
- if (dy > 31) or (dy < 1) or ((mo in [4,6,9,11]) and (dy > 30)) then
- bad_fld := 2
- else
- if mo = 2 then
- begin
- if (leapyear(yr) and (dy > 29)) or
- ((not leapyear(yr)) and (dy > 28)) then
- bad_fld := 2
- end
- else
- if yr = 0 then
- bad_fld := 3;
- valid_date := (bad_fld = 0)
- end ; { function valid_date }
-
- { ------------------------------------------------------------ }
-
- procedure read_date(var dt: longint ; col, row: integer);
-
- { Read date at column and row specified. If the user enters only
- two digits for the year, the procedure plugs the century as 1900 or
- 2000, but the user can enter all four digits to override the plug. }
-
- var
- ch : char ;
- savefld,
- bad_fld,
- key,
- p : integer ;
- yr,mo,dy :integer;
- s,
- template : datestring ;
-
- { ==================== }
-
- procedure add_to_str ;
- var
- l : integer ;
- begin
- l := length(s);
- if l = 10 then
- beep
- else if (l=1) or (l=4) then
- begin
- s := concat(s,ch,'/');
- write (ch,'/')
- end
- else
- begin
- s := concat(s,ch);
- write (ch)
- end
- end ; { proc add_to_str }
-
- { ==================== }
-
- procedure adjust_dt_str ;
- var
- l : integer ;
- begin
- case key of
- del_fld :begin
- s := '' ;
- gotoxy(col,row);
- write(template);
- gotoxy (col,row)
- end ;
- del_left,
- prev_char:begin { prev_char is destructive backspace! }
- l := length(s);
- if l = 0 then
- beep
- else
- if (l=3) or (l=6) then
- begin
- write (^H,^H,chr(filler),^H);
- delete (s,l-1,2)
- end
- else
- begin
- write (^H,chr(filler),^H);
- delete (s,l,1)
- end
- end
- end { case }
- end ; { proc adjust_dt_str }
-
- { ==================== }
-
- procedure convert_date ;
- { convert the string to a date -- longint }
- var
- code :integer ;
- result :longint;
- i :byte;
-
- begin
- for i := 1 to 8 do { fill to 2 digits of year }
- begin
- if length(s) < i then s := concat(s,'0');
- if s[i] = ' ' then s[i] := '0'; { fill any spaces with 0 }
- end;
- val (copy(s,1,2),mo,code);
- if code <> 0 then
- begin
- write ('** MONTH CONVERSION ERROR ',code);
- halt
- end ;
- val (copy(s,4,2),dy,code);
- if code <> 0 then
- begin
- write ('** DAY CONVERSION ERROR ',code);
- halt
- end ;
- val (copy(s,7,4),yr,code);
- if code <> 0 then
- begin
- write ('** YEAR CONVERSION ERROR ',code);
- halt
- end ;
- if ((yr = 0) and (mo = 0) and (dy = 0)) then
- begin { default to nodate }
- dt := 0;
- end
- else
- begin { plug century }
- if yr < 80 then
- yr := 2000 + yr
- else if yr < 100 then
- yr := 1900 + yr;
- result := yr;
- result := (result * 100) + mo;
- result := (result * 100) + dy;
- dt := result;
- end;
- result := yr;
- result := (result * 100) + mo;
- result := (result * 100) + dy;
- dt := result;
- end ; { proc convert_date}
-
- { ==================== }
-
- procedure edit_date ; { Edit for valid date }
- begin
- bad_fld := 0 ;
- if (yr = 0) and (mo = 0) and (dy = 0) then
- bad_fld := 0
- else if not (mo in [1 .. 12]) then
- bad_fld := 1
- else if (dy > 31) or (dy < 1) or ((mo in [4,6,9,11]) and (dy > 30)) then
- bad_fld := 2
- else if mo = 2 then
- begin
- if (leapyear(yr) and (dy > 29)) or ((not leapyear(yr)) and
- (dy > 28)) then
- bad_fld := 2
- end
- else
- if yr = 0 then
- bad_fld := 3
- end ; { proc edit_date }
-
- { ==================== }
-
- begin { proc read_date }
- savefld := fld ;
- ch := chr(filler);
- template := concat(ch,ch,'/',ch,ch,'/',ch,ch,ch,ch);
- if (dt = 0) then
- begin
- write_str (template,col,row);
- s := '' ;
- gotoxy (col,row)
- end
- else
- begin
- s := mk_dt_st(dt);
- p := pos(' ',s);
- while p <> 0 do
- begin
- s[p] := '0' ;
- p := pos(' ',s)
- end ;
- write_str (s,col,row)
- end ;
- repeat
- keyin(ch);
- key := ord(ch);
- if ch in ['0'..'9'] then
- add_to_str
- else if key in adjusting then
- adjust_dt_str
- else if key in terminating then
- begin
- convert_date ; { uses local yr, mo, and dy }
- edit_date ;
- do_fld_ctl (key);
- if (fld < maxint) and (fld > savefld) then
- begin { edit only going forward }
- if bad_fld <> 0 then
- begin
- case bad_fld of
- 1 : show_msg ('INVALID MONTH');
- 2 : show_msg ('INVALID DAY');
- 3 : show_msg ('INVALID YEAR')
- end ; { case }
- fld := savefld
- end
- end
- end
- (* else
- beep *)
- until key in terminating ;
- write_date (dt,col,row)
- end ; { proc read_date }
-
- { ------------------------------------------------------------ }
-
- function greater_date(dt1, dt2 : longint) : integer;
- { Compares two dates, returns 0 if both equal, 1 if first is
- greater, 2 if second is greater.
- }
-
- begin
- if dt1 > dt2 then
- greater_date := 1
- else if dt2 > dt1 then
- greater_date := 2
- else { both equal }
- greater_date := 0
- end ; { --- of greater_date --- }
-
- { ------------------------------------------------------------ }
-
- procedure greg_to_jul(dt : longint ; var jdt : juldate);
- { converts a gregorian date to a julian date }
- var
- yr,mo,dy :integer;
- begin
- get_dt_val(dt,yr,mo,dy); { get the global dates }
- jdt.yr := yr ;
- if (yr = 0) and (mo = 0) and (dy = 0) then
- jdt.day := 0
- else
- begin
- if (leapyear(yr)) and (mo > 2) then
- jdt.day := 1
- else
- jdt.day := 0 ;
- jdt.day := jdt.day + monthtotal[mo] + dy
- end
- end ; { --- procedure greg_to_jul --- }
-
- { ------------------------------------------------------------ }
-
- procedure jul_to_greg(jdt : juldate ; var dt : longint);
- { converts a julian date to a gregorian date }
- var
- i, workday :integer ;
- yr,mo,dy :integer;
- begin
- yr := jdt.yr ;
- if (jdt.yr = 0) and (jdt.day = 0) then
- begin
- mo := 0 ; dy := 0
- end
- else
- begin
- workday := jdt.day ;
- if (leapyear(jdt.yr)) and (workday > 59) then
- workday := workday - 1 ; { make it look like a non-leap year }
- i := 1 ;
- repeat
- i := i + 1
- until not (workday > monthtotal[i]);
- i := i - 1 ;
- mo := i ;
- dy := workday - monthtotal[i] ;
- if leapyear(jdt.yr) and (jdt.day = 60) then
- dy := dy + 1
- end;
- { need to convert the globals back to longint }
- dt := yr;
- dt := (dt * 100) + mo;
- dt := (dt * 100) + dy;
- end ; { --- procedure jul_to_greg --- }
-
- { ------------------------------------------------------------ }
-
- procedure next_day(var dt : longint);
- { Adds one day to the date }
- var
- jdt : juldate ;
- leap : boolean ;
- yr,mo,dy :integer;
-
- begin
- get_dt_val(dt,yr,mo,dy);
- greg_to_jul (dt,jdt);
- jdt.day := jdt.day + 1 ;
- leap := leapyear (yr);
- if (leap and (jdt.day = 367)) or (not leap and (jdt.day = 366)) then
- begin
- jdt.yr := jdt.yr + 1 ;
- jdt.day := 1
- end ;
- jul_to_greg (jdt,dt)
- end ; { --- procedure next_day --- }
-
- { ------------------------------------------------------------ }
-
- procedure prev_day(var dt : longint);
- { Subtracts one day from the date }
- var
- jdt : juldate ;
- begin
- greg_to_jul (dt,jdt);
- jdt.day := jdt.day - 1 ;
- if jdt.day < 1 then
- begin
- jdt.yr := jdt.yr - 1 ;
- if leapyear (jdt.yr) then
- jdt.day := 366
- else
- jdt.day := 365
- end ;
- jul_to_greg (jdt,dt)
- end ; { --- procedure prev_day --- }
-
- { ------------------------------------------------------------ }
-
- function date_diff(dt1, dt2 : longint) : longint;
- { computes the number of days between two dates }
-
- var
- jdt1, jdt2 : juldate ;
- i, num_leap_yrs,
- yr1,mo1,dy1,
- yr2,mo2,dy2 : integer ;
-
- begin
- greg_to_jul (dt1, jdt1);
- greg_to_jul (dt2, jdt2);
- get_dt_val(dt1,yr1,mo1,dy1);
- get_dt_val(dt2,yr2,mo2,dy2);
- num_leap_yrs := 0 ; { adjust for leap years }
- if yr2 > yr1 then
- begin
- for i := yr1 to yr2 - 1 do
- if leapyear(i) then
- num_leap_yrs := num_leap_yrs + 1
- end
- else
- if yr1 > yr2 then
- begin
- for i := yr2 to yr1 - 1 do
- if leapyear(i) then
- num_leap_yrs := num_leap_yrs - 1
- end ;
-
- date_diff := jdt2.day - jdt1.day +
- ((jdt2.yr - jdt1.yr) * 365) + num_leap_yrs;
- end ;
-
- { ------------------------------------------------------------ }
-
- function month_diff(dt1, dt2 : longint ) : integer;
- { Computes number of months between two dates, rounded.
- 30.4167 = 356/12, average number of days in a month. }
- begin
- month_diff := round((date_diff(dt1, dt2) + 1) / 30.4167)
- end ;
-
- { ------------------------------------------------------------ }
-
- function equal_date(dt1, dt2 : longint) : boolean;
- { Tests whether two dates are equal }
- begin
- if (dt1 = dt2) then
- equal_date := true
- else
- equal_date := false;
- end ;
-
- { ------------------------------------------------------------ }
-
- function zeller (dt : longint) : integer ;
- { Compute the day of the week using Zeller's Congruence.
- From ROS 3.4 source code }
- var
- century: integer ;
- yr,mo,dy :integer;
-
- begin
- get_dt_val(dt,yr,mo,dy);
- if mo > 2
- then mo := mo - 2
- else
- begin
- mo := mo + 10 ;
- yr := pred(yr)
- end ;
- century := yr div 100 ;
- yr := yr mod 100 ;
- zeller := (dy - 1 + ((13 * mo - 1) div 5) + (5 * yr div 4) +
- century div 4 - 2 * century + 1) mod 7
- end ; { function zeller }
-
- { ------------------------------------------------------------ }
-
- function build_full_date_str(dt : longint) : fulldatestring;
- { Build printable string of current date -- from ROS 3.4 source code. }
- const
- day: array [0..6] of string[6] =
- ('Sun','Mon','Tues','Wednes','Thurs','Fri','Satur');
- month: array [1..12] of string[9] =
- ('January','February','March','April','May','June','July',
- 'August','September','October','November','December');
- var
- i: integer ;
- s: fulldatestring ;
- yr,mo,dy :integer;
-
- function intstr(n, w: integer): string ;
- { Return a string value of width w for the input integer n }
- var
- st: string ;
- begin
- str(n:w, st);
- st := purgech (st,' ');
- intstr := st
- end ;
-
- begin { build_full_date_str }
- get_dt_val(dt,yr,mo,dy);
- if (mo = 0) and (dy = 0) and (yr = 0) then
- s := 'No Date'
- else
- s := day[zeller(dt)] + 'day, ' +
- month[mo] + ' ' + intstr(dy, 2) + ', ' + intstr(yr, 4);
- if length (s) < fdslen then
- s := pad (s,' ',fdslen);
- build_full_date_str := s
- end ; { function build_full_date_str }
-
- { ---------------------------------------------------------------- }
-
- procedure get_date;
- { puts the system date in the sys_date date variable. }
- var
- year,month,day,dow :word;
- begin
- getdate(year,month,day,dow);
- sys_date := year;
- sys_date := (sys_date * 100) + month;
- sys_date := (sys_date * 100) + day;
- end; { procedure get_date }
-
- { ---------------------------------------------------------------- }
-
- function month(dt:longint):integer;
- { returns the month portion of a date.}
- var
- lo_date :integer;
- begin
- lo_date := dt mod 10000;
- month := (lo_date div 100);
- end; {function month }
-
- { ---------------------------------------------------------------- }
-
- function day(dt:longint):integer;
- { returns the day from the date }
- var
- lo_date :integer;
- begin
- lo_date := dt mod 10000;
- day := lo_date mod 100;
- end; { function day }
-
- { ---------------------------------------------------------------- }
-
- function year(dt:longint;centry:boolean):integer;
- { returns the year of a date. if the centry flag is true
- returns 4 digit year otherwise returns two digit year. }
- var
- hi_date,
- result :integer;
- begin
- hi_date := dt div 10000;
- if(centry) then year := hi_date
- else year := hi_date mod 100;
- end; {function year}
-
- { ----- End of Date routines ------Start of initialization ----- }
-
- begin {unit initialization}
- null_date := 0;
- null_date_str := 'MM/DD/YYYY' ;
- get_date; { put todays date in sys_date }
- inv_flag := false; { default to normal screen writes }
- inv_color := green; { default color for high lighted items if color monitor}
- numwindows := 0;
- reserv_wind := 0;
- regs.ah := 15; { prepare for dos interrupt }
- intr($10,regs); { determine current video mode }
- case regs.al of
- 0..3 :begin
- vidstart := $B800; { start of color video memory }
- col_inv_flag := true;
- end;
- 7 :begin
- vidstart := $B000; { start of mono video memory }
- col_inv_flag := false;
- end;
- else vidstart := $B000; { unknown try mono video ?? }
- end; {case}
- in_window := false; { default to not in windows }
- end. { tp4wio unit }
-