home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / PASCAL / UTIL / UTILITY.PAS < prev    next >
Pascal/Delphi Source File  |  1993-12-01  |  103KB  |  3,741 lines

  1. {$A+,B-,D-,E-,F-,G-,I+,L-,N-,O-,R-,S-,V-,X-}
  2. {
  3. Utility 16.1  (c) Copyright 1990, 1991 by Gemini Systems  ALL RIGHTS RESERVED
  4. ╒════════════════════════════════════════════════════════════════════════╕
  5. │                                                                        │
  6. │          This UNIT was written for TURBO PASCAL 5.0 by:                │
  7. │                                                                        │
  8. │                      GEMINI SYSTEMS                                    │
  9. │                      7748 Lake Ridge Drive                             │
  10. │                      Waterford, MI 48327                               │
  11. │                                                                        │
  12. │             Comments, Suggestions or Donations welcome.                │
  13. │                                                                        │
  14. │  To use in your programs, simply state UTILITY in your uses clause.    │
  15. │                                                                        │
  16. │  example:      PROGRAM prog_name;                                      │
  17. │                  USES utility;       (Programs must be compiled with   │
  18. │                                       the $V- Compiler Directive)      │
  19. │                                                                        │
  20. ╘════════════════════════════════════════════════════════════════════════╛
  21. }
  22.  
  23. {$I UTILITY.DOC }
  24.  
  25. IMPLEMENTATION
  26. CONST
  27.   HEXCHARS  : ARRAY [1..16] OF CHAR =
  28.               ('0','1','2','3','4','5','6','7','8','9',
  29.                'A','B','C','D','E','F');VAR
  30.   ExitSave  : pointer;
  31.   OLDVAL    : STRING;
  32.  
  33. type
  34.   EnvArray = array[0..32767] of Char;
  35.   EnvArrayPtr = ^EnvArray;
  36.   EnvRec =
  37.     record
  38.       EnvSeg : Word;              {Segment of the environment}
  39.       EnvLen : Word;              {Usable length of the environment}
  40.       EnvPtr : Pointer;           {Nil except when allocated on heap}
  41.     end;
  42.  
  43. VAR
  44.   ENV_REC        : ENVREC;
  45.   CURRENT_BORDER : INTEGER;
  46.   BLINK_IS_ON    : BOOLEAN;
  47.  
  48. FUNCTION GETHEX(DECIMAL_VALUE : WORD) : STRING;
  49. VAR
  50.   ADDRESS_DIGIT,
  51.   COUNTER,
  52.   DIVISOR,
  53.   QUOTIENT   : INTEGER;
  54.   TEMPSTRING : STRING;
  55. BEGIN
  56.   GETHEX := '';
  57.   TEMPSTRING := '';
  58.   FOR ADDRESS_DIGIT := 1 TO 4 DO
  59.     BEGIN
  60.       DIVISOR := 1;
  61.       FOR COUNTER := ADDRESS_DIGIT TO 3 DO
  62.         DIVISOR := DIVISOR * 16;
  63.         QUOTIENT := DECIMAL_VALUE DIV DIVISOR;
  64.         DECIMAL_VALUE := DECIMAL_VALUE MOD DIVISOR;
  65.         TEMPSTRING := TEMPSTRING + HEXCHARS[QUOTIENT+1];
  66.       END;
  67.   GETHEX := TEMPSTRING;
  68. END;
  69.  
  70. PROCEDURE SET_CURSOR;
  71. VAR
  72.   TOPLINE,
  73.   BOTLINE       : BYTE;
  74.   BIOSPARAM     : REGISTERS;
  75. BEGIN
  76.   CASE CURS OF
  77.           BLOCK : BEGIN
  78.                     TOPLINE := 0;
  79.                     BOTLINE := 7;
  80.                   END;
  81.      UNDERLINE  : BEGIN
  82.                     TOPLINE := 6;
  83.                     BOTLINE := 7;
  84.                   END;
  85.           NONE  : BEGIN
  86.                     TOPLINE := 32;
  87.                     BOTLINE := 0;
  88.                   END;
  89.           HALF  : BEGIN
  90.                     TOPLINE := 4;
  91.                     BOTLINE := 7;
  92.                   END;
  93.   END;
  94.   WITH BIOSPARAM DO
  95.     BEGIN
  96.       AX := 1 SHL 8 + 0;
  97.       CX := TOPLINE SHL 8 + BOTLINE;
  98.     END;
  99.   INTR($10,BIOSPARAM);
  100.   CUR := CURS;
  101. END;
  102.  
  103. {$F+}
  104. PROCEDURE EXITHANDLER;
  105. VAR
  106.   OFFSET,
  107.   SEGMENT : STRING;
  108. BEGIN
  109.   EXITPROC := EXITSAVE;
  110.   IF RESET_CURSOR THEN
  111.     SET_CURSOR(UNDERLINE);
  112.   IF (EXITCODE <> 0) AND (SHOW_ERROR) THEN
  113.     BEGIN
  114.       OFFSET    := GETHEX(OFS(ERRORADDR^));
  115.       SEGMENT   := GETHEX(SEG(ERRORADDR^));
  116.       WINDOW(1,1,80,25);
  117.       WRITELN;
  118.       ERRORADDR := NIL;
  119.       GOTOXY(1,25);
  120.       WRITELN; WRITELN; WRITELN; WRITELN; WRITELN; WRITELN; WRITELN; WRITELN;
  121.           FW(1,18,$4E,'╔═══════════════════════════════════════════════════════════════════════════╗');
  122.       IF EXITCODE = 255 THEN
  123.         BEGIN
  124.           FW(1,19,$4E,'║    Program Terminated by Operator !                                       ║');
  125.           FW(1,20,$4E,'║      Press <any key> to Continue                                          ║');
  126.           FW(1,21,$4E,'╚═══════════════════════════════════════════════════════════════════════════╝');
  127.           GOTOXY(35,20);
  128.         END
  129.       ELSE
  130.         BEGIN
  131.           FW(1,19,$4E,'║                  Program Terminated by Run-Time Error!                    ║');
  132.           FW(1,20,$4E,'║ Program       -                                                           ║');
  133.           FW(1,21,$4E,'║ Error Code    -                                                           ║');
  134.           FW(1,22,$4E,'║ Error Address -                                                           ║');
  135.           FW(1,23,$4E,'║                       Press <any key> to Continue                         ║');
  136.           FW(1,24,$4E,'╚═══════════════════════════════════════════════════════════════════════════╝');
  137.           TEXTATTR := $4F;
  138.           GOTOXY(19,20);
  139.           WRITE(PARAMSTR(0));
  140.           GOTOXY(19,21);
  141.           WRITE(EXITCODE);
  142.           GOTOXY(19,22);
  143.           WRITE(SEGMENT,':',OFFSET);
  144.           GOTOXY(52,23);
  145.         END;
  146.       CH := READKEY;
  147.       WRITELN;
  148.     END;
  149.   TEXTATTR := TEXTATTR_AT_ENTRY;
  150. END;
  151. {$F-}
  152.  
  153. FUNCTION CGA_INSTALLED : BOOLEAN;
  154. VAR
  155.   MONITOR_INFO   : BYTE   ABSOLUTE $0040:$0010;
  156. BEGIN
  157.   CGA_INSTALLED := TRUE;
  158.   IF MONITOR_INFO AND 48=48 THEN
  159.     BEGIN
  160.       CGA_INSTALLED := FALSE;
  161.       P := PTR($B000,0000);
  162.     END
  163.   ELSE
  164.     IF MONITOR_INFO AND 32=32 THEN
  165.       BEGIN
  166.         CGA_INSTALLED := TRUE;
  167.         P := PTR($B800,0000);
  168.       END;
  169. END;
  170.  
  171. PROCEDURE SAVE_SCREEN;
  172. BEGIN
  173.   MOVE(P^[1],SCREEN[1],4000);
  174. END;
  175.  
  176. PROCEDURE REBUILD_SCREEN;
  177. BEGIN
  178.   MOVE(SCREEN[1],P^[1],4000);
  179. END;
  180.  
  181. PROCEDURE UP_SOUND;
  182. VAR
  183.   I : INTEGER;
  184. BEGIN
  185.   FOR I := 2000 TO 4000 DO
  186.     SOUND(I);
  187.   NOSOUND;
  188. END;
  189.  
  190. PROCEDURE DOWN_SOUND;
  191. VAR
  192.   I : INTEGER;
  193. BEGIN
  194.   FOR I := 4000 DOWNTO 2000 DO
  195.     SOUND(I);
  196.   NOSOUND;
  197. END;
  198.  
  199. PROCEDURE CAPS_ON;
  200. VAR
  201.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  202. BEGIN
  203.   KEYBOARD:=KEYBOARD OR 64;
  204. END;
  205.  
  206. FUNCTION CAPS_ARE_ON : BOOLEAN;
  207. VAR
  208.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  209. BEGIN
  210.   CAPS_ARE_ON := KEYBOARD AND 64 = 64;
  211. END;
  212.  
  213. PROCEDURE CAPS_OFF;
  214. VAR
  215.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  216. BEGIN
  217.   KEYBOARD:=KEYBOARD AND 191;
  218. END;
  219.  
  220. PROCEDURE NUM_LOCK_ON;
  221. VAR
  222.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  223. BEGIN
  224.   KEYBOARD:=KEYBOARD OR 32;
  225. END;
  226.  
  227. FUNCTION NUM_LOCK_IS_ON : BOOLEAN;
  228. VAR
  229.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  230. BEGIN
  231.   NUM_LOCK_IS_ON := KEYBOARD AND 32 = 32;
  232. END;
  233.  
  234. PROCEDURE NUM_LOCK_OFF;
  235. VAR
  236.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  237. BEGIN
  238.   KEYBOARD:=KEYBOARD AND 223;
  239. END;
  240.  
  241. PROCEDURE SCROLL_LOCK_ON;
  242. VAR
  243.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  244. BEGIN
  245.   KEYBOARD:=KEYBOARD OR 16;
  246. END;
  247.  
  248. PROCEDURE SCROLL_LOCK_OFF;
  249. VAR
  250.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  251. BEGIN
  252.   KEYBOARD:=KEYBOARD AND 239;
  253. END;
  254.  
  255. FUNCTION SCROLL_LOCK_IS_ON : BOOLEAN;
  256. VAR
  257.   KEYBOARD       : BYTE ABSOLUTE $0040:$0017;
  258. BEGIN
  259.   SCROLL_LOCK_IS_ON := KEYBOARD AND 16 = 16;
  260. END;
  261.  
  262. PROCEDURE SHOW_VERSION;
  263. VAR
  264.   CH     : CHAR;
  265.   L      : LONGINT;
  266.   SCREEN : ARRAY [1..285] OF CHAR;
  267.   TEMP   : STRING[15];
  268. BEGIN
  269.   MOVE(P^[319],SCREEN[1],71);
  270.   MOVE(P^[479],SCREEN[72],71);
  271.   MOVE(P^[639],SCREEN[143],71);
  272.   MOVE(P^[799],SCREEN[214],71);
  273.   FW(1,3,$4F,'╒════════════════════════════════╕');
  274.   FW(1,4,$4F,'│                                │');
  275.   IF LENGTH(PARAMSTR(0)) <= 30 THEN
  276.     FW(3,4,$4F,PARAMSTR(0))
  277.   ELSE
  278.     BEGIN
  279.       FW(3,4,$4F,CHR(27)+COPY(PARAMSTR(0),LENGTH(PARAMSTR(0))-28,29));
  280.     END;
  281.   FW(1,5,$4F,'│ U16.1 RELEASE                  │');
  282.   FW(1,6,$4F,'╘════════════════════════════════╛');
  283.   IF UT.COMPILED_DATE <> '%%-%%-%%' THEN
  284.     BEGIN
  285.       FW(18,5,$4F,UT.COMPILED_DATE+' ');
  286.       IF UT.COMPILED_TIME <> '%%:%%' THEN
  287.         FW(27,5,$4F,UT.COMPILED_TIME);
  288.     END
  289.   ELSE
  290.     FW(18,5,$4F,VERSION);
  291.   GOTOXY(16,5);
  292.   START_TIMER(L);
  293.   REPEAT
  294.   UNTIL (ELAP_TIME(L) > 15) OR KEYPRESSED;
  295.   IF KEYPRESSED THEN
  296.     BEGIN
  297.       READCH(CH,FALSE);
  298.       IF CH = AF1 THEN
  299.         BEGIN
  300.           TEMP := 'LJUOUR&\\\VFMY';
  301.           UN_ENCRYPT(TEMP,15000);
  302.           FW(1,5,$4F,'│                                │');
  303.           FW(11,5,$4F,TEMP);
  304.           READCHT(CH,FALSE,30);
  305.         END;
  306.     END;
  307.   WHILE KEYPRESSED DO
  308.     CH := READKEY;
  309.   MOVE(SCREEN[1],P^[319],71);
  310.   MOVE(SCREEN[72],P^[479],71);
  311.   MOVE(SCREEN[143],P^[639],71);
  312.   MOVE(SCREEN[214],P^[799],71);
  313. END;
  314.  
  315. PROCEDURE SPECIAL_KEY(VAR CH : CHAR);
  316. BEGIN
  317.   CASE ORD(CH) OF
  318.        72  : CH:=#180; { UP ARROW    }
  319.        80  : CH:=#181; { DOWN ARROW  }
  320.        77  : CH:=#192; { RIGHT ARROW }
  321.        75  : CH:=#191; { LEFT ARROW  }
  322.        71  : CH:=#196; { HOME KEY    }    { ESC KEY RETURNS CHR(27) }
  323.        73  : CH:=#178; { PGUP KEY    }
  324.        79  : CH:=#197; { END KEY     }
  325.        81  : CH:=#179; { PGDN KEY    }
  326.        82  : CH:=#198; { INSERT KEY  }
  327.        83  : CH:=#199; { DELETE KEY  }
  328.        59  : CH:=#127; { F1 }
  329.        60  : CH:=#128; { F2 }
  330.        61  : CH:=#129; { F3 }
  331.        62  : CH:=#130; { F4 }
  332.        63  : CH:=#131; { F5 }
  333.        64  : CH:=#132; { F6 }
  334.        65  : CH:=#133; { F7 }
  335.        66  : CH:=#134; { F8 }
  336.        67  : CH:=#135; { F9 }
  337.        68  : CH:=#136; { F10 }
  338.        104 : CH:=#139; { ALT F1 }
  339.        105 : CH:=#140; { ALT F2 }
  340.        106 : CH:=#141; { ALT F3 }
  341.        107 : CH:=#142; { ALT F4 }
  342.        108 : CH:=#143; { ALT F5 }
  343.        109 : CH:=#144; { ALT F6 }
  344.        110 : CH:=#145; { ALT F7 }
  345.        111 : CH:=#146; { ALT F8 }
  346.        112 : CH:=#147; { ALT F9 }
  347.        113 : CH:=#148; { ALT F10}
  348.        30  : CH:=#151; { ALT A  }
  349.        48  : CH:=#152; { ALT B  }
  350.        46  : CH:=#153; { ALT C  }
  351.        32  : CH:=#154; { ALT D  }
  352.        18  : CH:=#155; { ALT E  }
  353.        33  : CH:=#156; { ALT F  }
  354.        34  : CH:=#157; { ALT G  }
  355.        35  : CH:=#158; { ALT H  }
  356.        23  : CH:=#159; { ALT I  }
  357.        36  : CH:=#160; { ALT J  }
  358.        37  : CH:=#161; { ALT K  }
  359.        38  : CH:=#162; { ALT L  }
  360.        50  : CH:=#163; { ALT M  }
  361.        49  : CH:=#164; { ALT N  }
  362.        24  : CH:=#165; { ALT O  }
  363.        25  : CH:=#166; { ALT P  }
  364.        16  : CH:=#167; { ALT Q  }
  365.        19  : CH:=#168; { ALT R  }
  366.        31  : CH:=#169; { ALT S  }
  367.        20  : CH:=#170; { ALT T  }
  368.        22  : CH:=#171; { ALT U  }
  369.        47  : CH:=#172; { ALT V  }
  370.        17  : CH:=#173; { ALT W  }
  371.        45  : CH:=#174; { ALT X  }
  372.        21  : CH:=#175; { ALT Y  }
  373.        44  : CH:=#176; { ALT Z  }
  374.        94  : CH:=#200; { CNTR F1 }
  375.        95  : CH:=#201;
  376.        96  : CH:=#202;
  377.        97  : CH:=#203;
  378.        98  : CH:=#204;
  379.        99  : CH:=#205;
  380.       100  : CH:=#206;
  381.       101  : CH:=#207;
  382.       102  : CH:=#208;
  383.       103  : CH:=#209;
  384.   END;
  385. END;
  386.            
  387. PROCEDURE READCH;
  388. VAR
  389.   I,
  390.   ATX, ATY : INTEGER;
  391.   LINE25   : BUF160;
  392.   HELP     : BOOLEAN;
  393.  
  394.       Procedure PROCESS_COMMAND(UserRoutine : Pointer; NA : STRING);
  395.         Procedure CallUserRoutine (NA : STRING); INLINE
  396.           ( $FF / $5E / <UserRoutine );
  397.       Begin
  398.         CallUserRoutine(NA);
  399.       End;
  400.  
  401.       PROCEDURE EVENT_HANDLER(PROCESS_ROUTINE : POINTER; MASK : STRING);
  402.       BEGIN
  403.         PROCESS_COMMAND(PROCESS_ROUTINE,'');
  404.       END;
  405.  
  406. BEGIN
  407.   ATX := WHEREX;
  408.   ATY := WHEREY;
  409.   SAVE_LINE(25,LINE25);
  410.   HELP := FALSE;
  411.   REPEAT
  412.     I := 300;
  413.     REPEAT
  414.       IF (SHIFT_KEYS('A')) AND (HELP_LINE <> '') THEN
  415.         BEGIN
  416.           FW(1,25,HELP_ATTR,PAD(HELP_LINE,80));
  417.           GOTOXY(ATX,ATY);
  418.           HELP := TRUE;
  419.         END
  420.       ELSE
  421.         IF (SHIFT_KEYS('C')) AND (HELP_LINE2 <> '') THEN
  422.           BEGIN
  423.             FW(1,25,HELP_ATTR2,PAD(HELP_LINE2,80));
  424.             GOTOXY(ATX,ATY);
  425.             HELP := TRUE;
  426.           END
  427.         ELSE
  428.           IF HELP THEN
  429.             BEGIN
  430.               REBUILD_LINE(25,LINE25);
  431.               GOTOXY(ATX,ATY);
  432.               HELP := FALSE;
  433.             END;
  434.       IF UT.TIMEX > 0 THEN
  435.         BEGIN
  436.           I := SUCC(I);
  437.           IF I > 200 THEN
  438.             BEGIN
  439.               WRITE_TIME(UT.TIMEX,UT.TIMEY,CH);
  440.               I := 0;
  441.             END;
  442.           GOTOXY43(ATX,ATY);
  443.         END;
  444.     UNTIL KEYPRESSED OR (COMMAND_BUFFER <> '');
  445.     REBUILD_LINE(25,LINE25);
  446.     HELP := FALSE;
  447.     IF COMMAND_BUFFER = '' THEN
  448.       BEGIN
  449.         CH := READKEY;
  450.         IF CH = #0 THEN
  451.           BEGIN
  452.             CH := READKEY;
  453.             SPECIAL_KEY(CH);
  454.           END;
  455.         IF (CH IN [' '..'~']) AND ECHO THEN
  456.           WRITE(CH);
  457.       END
  458.     ELSE
  459.       BEGIN
  460.         CH := COMMAND_BUFFER[1];
  461.         IF (CH IN [' '..'~']) AND ECHO THEN
  462.           WRITE(CH);
  463.         DELETE(COMMAND_BUFFER,1,1);
  464.       END;
  465.     IF CH = AF10 THEN SHOW_VERSION;
  466.     IF EventHandler <> NIL THEN
  467.       EVENT_HANDLER(EventHandler,'');
  468.   UNTIL CH <> AF10;
  469. END;       
  470.  
  471. FUNCTION PRINTER_NOT_READY : BOOLEAN;
  472. VAR
  473.   REGS         : REGISTERS;
  474. BEGIN
  475.   PRINTER_NOT_READY := TRUE;
  476.   FILLCHAR(REGS,SIZEOF(REGS),00);
  477.   WITH REGS DO
  478.     BEGIN
  479.       AX := $0200;
  480.       DX := 0;     { LPT1 = 0, LPT2 = 1 }
  481.     END;
  482.   INTR($17,REGS);
  483.   IF REGS.AX AND $4000 = 0 THEN
  484.     BEGIN
  485.       IF REGS.AX AND $1000 <> 0 THEN PRINTER_NOT_READY := FALSE;
  486.     END;
  487.   IF REGS.AX AND $8000 = 0 THEN PRINTER_NOT_READY := TRUE;
  488. END;
  489.  
  490. PROCEDURE SET_ATTR;
  491. VAR
  492.   MONITOR_INFO : BYTE ABSOLUTE $0040:$0010;
  493.   SCREEN1      : ARRAY [1..4000] OF BYTE ABSOLUTE $B800:$0000;
  494.   SCREEN2      : ARRAY [1..4000] OF BYTE ABSOLUTE $B000:$0000;
  495.   I,Z          : INTEGER;
  496. BEGIN
  497.   FOR I := 1 TO 80 DO
  498.     IF I IN X THEN
  499.       BEGIN
  500.         Z := ((Y * 160) - 160) + (I * 2);
  501.         IF MONITOR_INFO AND 48=48 THEN
  502.           SCREEN2[Z] := ATTRIB
  503.         ELSE
  504.           IF MONITOR_INFO AND 32=32 THEN
  505.             SCREEN1[Z] := ATTRIB;
  506.       END;
  507. END;
  508.  
  509. PROCEDURE SET_ATTR_BUFFER;
  510. VAR
  511.   I,Z          : INTEGER;
  512. BEGIN
  513.   FOR I := 1 TO 80 DO
  514.     IF I IN X THEN
  515.       BEGIN
  516.         Z := ((Y * 160) - 160) + (I * 2);
  517.         SC[Z] := CHAR(ATTRIB);
  518.       END;
  519. END;
  520.  
  521. PROCEDURE WRITE_TIME;
  522. VAR
  523.   IND,TEMP             : STR8;
  524.   HR, MIN, SEC, SEC100 : WORD;
  525.   C                    : CURTYPE;
  526.   SAVE_ATTR            : BYTE;
  527.   SX, SY               : INTEGER;
  528. BEGIN
  529.   GETTIME(HR,MIN,SEC,SEC100);
  530.   IND := '  ';
  531.   NOW := (HR * 60) + MIN;
  532.   IF NOT (MILITARY IN ['M','m']) THEN
  533.     BEGIN
  534.       IF HR > 12 THEN
  535.         BEGIN
  536.           HR := HR - 12;
  537.           IND := 'pm';
  538.         END
  539.       ELSE
  540.         IF HR = 12 THEN
  541.           IND := 'pm'
  542.         ELSE
  543.           IND := 'am';
  544.     END;
  545.   STR(HR:2,TIME);
  546.   IF (TIME[1] = ' ') AND (MILITARY IN ['M','n']) THEN TIME[1] := '0';
  547.   STR(MIN:2,TEMP);
  548.   IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  549.   TIME := TIME + ':' + TEMP;
  550.   IF NOT (MILITARY IN ['M','m']) THEN
  551.     TIME := TIME + ' ' + IND;
  552.   IF X <> 0 THEN
  553.     BEGIN
  554.       C := CUR;
  555.       SX := WHEREX;
  556.       SY := WHEREY;
  557.       SET_CURSOR(NONE);
  558.       SAVE_ATTR := CRT.TEXTATTR;
  559.       CRT.TEXTATTR := SCREEN_ATTR(X,Y);
  560.       GOTOXY43(X,Y);
  561.       WRITE(COPY(TIME,1,2));
  562.       IF BLINK_IS_ON THEN
  563.         CRT.TEXTATTR := CRT.TEXTATTR + BLINK;
  564.       WRITE(':');
  565.       IF BLINK_IS_ON THEN
  566.         CRT.TEXTATTR := CRT.TEXTATTR - BLINK;
  567.       WRITE(COPY(TIME,4,5));
  568.       CRT.TEXTATTR := SAVE_ATTR;
  569.       GOTOXY(SX,SY);
  570.       SET_CURSOR(C);
  571.     END;
  572. END;
  573.  
  574. PROCEDURE WRITE_DATE;
  575. VAR
  576.   TEMP         : STRING[9];
  577.   YR, MO, DAY  : WORD;
  578. BEGIN
  579.   GETDATE(YR,MO,DAY,DOW);
  580.   IF WORDS IN ['W','w','D','d'] THEN
  581.     BEGIN
  582.       CASE MO OF
  583.             1 : DATE := 'January ';
  584.             2 : DATE := 'February ';
  585.             3 : DATE := 'March ';
  586.             4 : DATE := 'April ';
  587.             5 : DATE := 'May ';
  588.             6 : DATE := 'June ';
  589.             7 : DATE := 'July ';
  590.             8 : DATE := 'August ';
  591.             9 : DATE := 'September ';
  592.            10 : DATE := 'October ';
  593.            11 : DATE := 'November ';
  594.            12 : DATE := 'December ';
  595.       END;
  596.       STR(DAY:2,TEMP);
  597.       DATE := DATE + TEMP;
  598.       STR(YR:4,TEMP);
  599.       DATE := DATE + ', '+TEMP;
  600.       IF WORDS IN ['D','d'] THEN
  601.         BEGIN
  602.           CASE DOW OF
  603.               0 : TEMP := 'Sunday';
  604.               1 : TEMP := 'Monday';
  605.               2 : TEMP := 'Tuesday';
  606.               3 : TEMP := 'Wednesday';
  607.               4 : TEMP := 'Thursday';
  608.               5 : TEMP := 'Friday';
  609.               6 : TEMP := 'Saturday';
  610.           END;
  611.           DATE := TEMP + ' ' + DATE;
  612.         END;
  613.     END
  614.       ELSE
  615.         BEGIN
  616.           IF YR > 2000 THEN
  617.             YR := YR - 2000
  618.           ELSE
  619.             YR := YR - 1900;
  620.           STR(MO:2,DATE);
  621.           IF DATE[1] = ' ' THEN DATE[1] := '0';
  622.           STR(DAY:2,TEMP);
  623.           IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  624.           DATE := DATE + '-' + TEMP + '-';
  625.           STR(YR:2,TEMP);
  626.           IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  627.           DATE := DATE + TEMP;
  628.         END;
  629.   IF X <> 0 THEN
  630.     FW(X,Y,SCREEN_ATTR(X,Y),DATE);
  631. END;
  632.  
  633. PROCEDURE FW(X,Y : INTEGER; ATTR : BYTE; LINE : STR80);
  634. VAR
  635.   I,J,
  636.   Z : INTEGER;
  637. BEGIN
  638.   Z := (((Y * 160) - 160) + (X * 2)) - 1;
  639.   I := 1;
  640.   J := 1;
  641.   REPEAT
  642.     P^[Z+J-1] := LINE[I];
  643.     P^[Z+J]   := CHR(ATTR);
  644.     I := I + 1;
  645.     J := J + 2;
  646.   UNTIL I > LENGTH(LINE);
  647. END;
  648.  
  649. FUNCTION WHOAMI;
  650. BEGIN
  651.   WHOAMI := PARAMSTR(0);
  652. END;
  653.  
  654. PROCEDURE START_TIMER;
  655. VAR
  656.   TIME1,
  657.   TIME2     : DATETIME;
  658.   SEC100,
  659.   DAYOFWEEK : WORD;
  660. BEGIN
  661.   WITH TIME1 DO
  662.     GETDATE(YEAR,MONTH,DAY,DAYOFWEEK);
  663.   WITH TIME1 DO
  664.     GETTIME(HOUR,MIN,SEC,SEC100);
  665.   PACKTIME(TIME1,T);
  666. END;
  667.  
  668. FUNCTION ELAP_TIME;
  669. VAR
  670.   TIME1,
  671.   TIME2     : DATETIME;
  672.   SEC100,
  673.   DAYOFWEEK : WORD;
  674.   L,M,N     : LONGINT;
  675.   R         : REAL;
  676.  
  677.        FUNCTION JULIAN(T : DATETIME) : REAL;
  678.        VAR
  679.           TEMP : REAL;
  680.        BEGIN
  681.           TEMP   := INT((T.MONTH - 14.0) / 12.0);
  682.           JULIAN := T.DAY - 32075.0 +
  683.                     INT(1461.0 * (T.YEAR + 4800.0 + TEMP) / 4.0) +
  684.                     INT(367.0 * (T.MONTH - 2.0 - TEMP * 12.0) / 12.0) -
  685.                     INT(3.0 * INT((T.YEAR + 4900.0 + TEMP) / 100.0) / 4.0)
  686.        END;
  687. BEGIN
  688.   WITH TIME1 DO
  689.     GETDATE(YEAR,MONTH,DAY,DAYOFWEEK);
  690.   WITH TIME1 DO
  691.     GETTIME(HOUR,MIN,SEC,SEC100);
  692.   UNPACKTIME(T,TIME2);
  693.   R := JULIAN(TIME1)-JULIAN(TIME2);
  694.   L := TRUNC(R * 864.0 * 100.0);
  695.   M := TIME1.HOUR * 60;
  696.   M := (M + TIME1.MIN) * 60;
  697.   M := M + TIME1.SEC;
  698.   N := TIME2.HOUR * 60;
  699.   N := (N + TIME2.MIN) * 60;
  700.   N := N + TIME2.SEC;
  701.   ELAP_TIME := L + M - N;
  702. END;
  703.  
  704. FUNCTION ELAP_TIME_STR;
  705. VAR
  706.   D,H,M,S : LONGINT;
  707.   T       : LONGINT;
  708.   ST      : STRING;
  709. BEGIN
  710.   T  := ELAP_TIME(TIM);
  711.   D  := T DIV 86400;
  712.   T  := T MOD 86400;
  713.   H  := T DIV 3600;
  714.   T  := T MOD 3600;
  715.   M  := T DIV 60;
  716.   S  := T MOD 60;
  717.   IF D > 0 THEN
  718.     BEGIN
  719.       ST := LONGINT_STR(D,1);
  720.       IF D = 1 THEN
  721.         ST := ST + ' day, '
  722.       ELSE
  723.         ST := ST + ' days, ';
  724.     END
  725.   ELSE
  726.     ST := '';
  727.   IF (D > 0) OR (H > 0) THEN
  728.     BEGIN
  729.       ST := ST + LONGINT_STR(H,2);
  730.       IF H = 1 THEN
  731.         ST := ST + ' hour, '
  732.       ELSE
  733.         ST := ST + ' hours, ';
  734.     END;
  735.   IF (D > 0) OR (H > 0) OR (M > 0) THEN
  736.     ST := ST + LONGINT_STR(M,2) + ' min, ';
  737.   ST := ST + LONGINT_STR(S,2) + ' sec';
  738.   ELAP_TIME_STR := PAD(ST,35);
  739. END;
  740.  
  741. FUNCTION PAD;
  742. VAR
  743.   I : INTEGER;
  744. BEGIN
  745.   I := 1;
  746.   IF LENGTH(S) < LEN THEN
  747.     S := S + SPACES(LEN - LENGTH(S));
  748.   IF LENGTH(S) > LEN THEN
  749.     S[0] := CHR(LEN);
  750.   WHILE POS(#0,S) > 0 DO
  751.     S[POS(#0,S)] := ' ';
  752.   PAD := S;
  753. END;
  754.  
  755. FUNCTION PAD_LEFT;
  756. VAR
  757.   I : INTEGER;
  758. BEGIN
  759.   I := 1;
  760.   IF LENGTH(S) < LEN THEN
  761.     S := SPACES(LEN - LENGTH(S)) + S;
  762.   IF LENGTH(S) > LEN THEN
  763.     S[0] := CHR(LEN);
  764.   PAD_LEFT := S;
  765. END;
  766.  
  767. FUNCTION PAD_CH;
  768. VAR
  769.   I : INTEGER;
  770. BEGIN
  771.   I := 1;
  772.   IF LENGTH(S) < LEN THEN
  773.     S := S + DUP(CH,LEN - LENGTH(S));
  774.   IF LENGTH(S) > LEN THEN
  775.     S[0] := CHR(LEN);
  776.   PAD_CH := S;
  777. END;
  778.  
  779. FUNCTION SPACES;
  780. VAR
  781.   S : STRING;
  782. BEGIN
  783.   S[0] := CHR(NUM);
  784.   FILLCHAR(S[1], NUM, ' ');
  785.   SPACES := S;
  786. END;
  787.  
  788. FUNCTION UPPERCASE;
  789. VAR
  790.   COUNTER : WORD;
  791. BEGIN
  792.   FOR COUNTER := 1 TO LENGTH(S) DO
  793.     S[COUNTER] := UPCASE(S[COUNTER]);
  794.   UPPERCASE := S;
  795. END;
  796.  
  797. FUNCTION EGA_INSTALLED : BOOLEAN;
  798. VAR
  799.   REG : REGISTERS;
  800. BEGIN
  801.   REG.AX := $1200;
  802.   REG.BX := $0010;
  803.   REG.CX := $FFFF;
  804.   INTR($10, REG);
  805.   EGA_INSTALLED := REG.CX <> $FFFF;
  806. END;
  807.  
  808. FUNCTION VGA_INSTALLED : BOOLEAN;
  809. VAR
  810.   REGS : REGISTERS;
  811. BEGIN
  812.   REGS.AX := $1A00;
  813.   INTR($10,REGS);
  814.   VGA_INSTALLED := (REGS.AL = $1A);
  815. END;
  816.  
  817. PROCEDURE LINES43;
  818. BEGIN
  819.   IF EGA_PRESENT THEN
  820.     TEXTMODE(CO80 + FONT8X8);
  821. END;
  822.  
  823. PROCEDURE GOTOXY43;
  824. VAR
  825.   I : INTEGER;
  826.   C : CURTYPE;
  827. BEGIN
  828.   C := CUR;
  829.   IF Y < 26 THEN
  830.     GOTOXY(X,Y)
  831.   ELSE
  832.     IF LASTMODE = 259 THEN
  833.       BEGIN
  834.         I := 25;
  835.         SET_CURSOR(NONE);
  836.         GOTOXY(X,25);
  837.         WHILE I < Y DO
  838.           BEGIN
  839.             WRITE(CHR(10));
  840.             I := SUCC(I);
  841.           END;
  842.         SET_CURSOR(C);
  843.       END;
  844. END;
  845.  
  846. PROCEDURE LINES25;
  847. BEGIN
  848.   TEXTMODE(CO80);
  849. END;
  850.  
  851. PROCEDURE READCHTIME;
  852. VAR
  853.   I,
  854.   ATX, ATY : INTEGER;
  855.   HELP     : BOOLEAN;
  856.   LINE25   : BUF160;
  857. BEGIN
  858.   ATX := WHEREX;
  859.   ATY := WHEREY;
  860.   HELP := FALSE;
  861.   SAVE_LINE(25,LINE25);
  862.   I := 300;
  863.   REPEAT
  864.     I := SUCC(I);
  865.     IF (SHIFT_KEYS('A')) AND (HELP_LINE <> '') THEN
  866.       BEGIN
  867.         FW(1,25,HELP_ATTR,PAD(HELP_LINE,80));
  868.         GOTOXY(ATX,ATY);
  869.         HELP := TRUE;
  870.       END
  871.     ELSE
  872.       IF (SHIFT_KEYS('C')) AND (HELP_LINE2 <> '') THEN
  873.         BEGIN
  874.           FW(1,25,HELP_ATTR2,PAD(HELP_LINE2,80));
  875.           GOTOXY(ATX,ATY);
  876.           HELP := TRUE;
  877.         END
  878.       ELSE
  879.         IF HELP THEN
  880.           BEGIN
  881.             REBUILD_LINE(25,LINE25);
  882.             GOTOXY(ATX,ATY);
  883.             HELP := FALSE;
  884.           END;
  885.     IF I > 200 THEN
  886.       BEGIN
  887.         WRITE_TIME(X,Y,CH);
  888.         I := 0;
  889.       END;
  890.     GOTOXY43(ATX,ATY);
  891.   UNTIL KEYPRESSED OR (COMMAND_BUFFER <> '');
  892.   REBUILD_LINE(25,LINE25);
  893.   READCH(CH,ECHO);
  894. END;
  895.  
  896. PROCEDURE READSTR;
  897. VAR
  898.   I,
  899.   START  : INTEGER;
  900.   CAPIT,
  901.   CAPWO,
  902.   INSON  : BOOLEAN;
  903.   SAVECH : CHAR;
  904.  
  905.        FUNCTION EDIT_ALL : BOOLEAN;
  906.        VAR
  907.          I : INTEGER;
  908.        BEGIN
  909.          EDIT_ALL := TRUE;
  910.          FOR I := 1 TO LEN DO
  911.            IF NOT (I IN CANEDIT) THEN
  912.              EDIT_ALL := FALSE;
  913.        END;
  914.  
  915. BEGIN
  916.   OLDVAL := INSTRING;
  917.   INSON := FALSE;
  918.   IF YLOC > 199 THEN
  919.     BEGIN
  920.       CAPIT := TRUE;
  921.       YLOC := YLOC - 200;
  922.     END
  923.   ELSE
  924.     BEGIN
  925.       CAPIT := FALSE;
  926.       IF YLOC > 99 THEN
  927.         BEGIN
  928.           YLOC := YLOC - 100;
  929.           CAPWO := TRUE;
  930.         END
  931.       ELSE
  932.         CAPWO := FALSE;
  933.     END;
  934.   IF CLEAR IN EXITCH THEN
  935.     INSTRING := SPACES(LEN)
  936.   ELSE
  937.     INSTRING := PAD(INSTRING,LEN);
  938.   FW(X,Y,PATTR,PROMPT);
  939.   START := X + LENGTH(PROMPT);
  940.   X := X_IN;
  941.   FW(START,Y,IATTR,INSTRING);
  942.   WHILE (NOT (X IN CANEDIT)) AND
  943.         (X <= LEN + START) DO
  944.     X := SUCC(X);
  945.   IF XLOC > 99 THEN
  946.     BEGIN
  947.       X := LEN;
  948.       XLOC := XLOC - 100;
  949.     END;
  950.   WHILE NOT (X IN CANEDIT) DO
  951.     X := PRED(X);
  952.   SET_CURSOR(UNDERLINE);
  953.   IF NOT (DISPLAY IN EXITCH) THEN
  954.     REPEAT
  955.       GOTOXY(START+X-1,Y);
  956.       CH := CH1;
  957.       READCHTIME(CH,FALSE,XLOC,YLOC);
  958.       SAVECH := CH;
  959.       CASE CH OF
  960.           HOMEKEY : BEGIN
  961.                       X := 1;
  962.                       WHILE (NOT (X IN CANEDIT)) AND
  963.                             (X <= LEN + START) DO
  964.                         X := SUCC(X);
  965.                     END;
  966.            ENDKEY : BEGIN
  967.                       X := LEN;
  968.                       WHILE (X > 2) AND (INSTRING[X-1] = ' ') DO
  969.                         X := PRED(X);
  970.                       WHILE (NOT (X IN CANEDIT)) AND
  971.                             (X <= LEN) DO
  972.                         X := SUCC(X);
  973.                       WHILE NOT (X IN CANEDIT) DO
  974.                         X := PRED(X);
  975.                       IF X < 1 THEN
  976.                         X := 1
  977.                       ELSE
  978.                         IF (X = 2) AND (INSTRING[1] = ' ') AND
  979.                            (1 IN CANEDIT) THEN
  980.                           X := 1;
  981.                     END;
  982.                #8 : IF (X > 1) AND EDIT_ALL THEN
  983.                       BEGIN
  984.                         DELETE(INSTRING,X-1,1);
  985.                         INSTRING := INSTRING + ' ';
  986.                         FW(START,Y,IATTR,INSTRING);
  987.                         X := PRED(X);
  988.                         WHILE (NOT (X IN CANEDIT)) AND
  989.                               (X > 1) DO
  990.                           X := PRED(X);
  991.                         WHILE NOT (X IN CANEDIT) DO
  992.                           X := SUCC(X);
  993.                       END
  994.                     ELSE
  995.                       IF X > 1 THEN
  996.                         BEGIN
  997.                           X := PRED(X);
  998.                           WHILE (NOT (X IN CANEDIT)) AND
  999.                                 (X > 1) DO
  1000.                             X := PRED(X);
  1001.                           WHILE NOT (X IN CANEDIT) DO
  1002.                             X := SUCC(X);
  1003.                         END
  1004.                       ELSE
  1005.                         BEGIN
  1006.                           SAVECH := CH;
  1007.                           IF NOCONV IN EXITCH THEN
  1008.                             CH := NOCONV
  1009.                           ELSE
  1010.                             CH := UP;
  1011.                         END;
  1012.             RIGHT : IF X < LEN THEN
  1013.                       BEGIN
  1014.                         X := SUCC(X);
  1015.                         WHILE (NOT (X IN CANEDIT)) AND
  1016.                               (X <= LEN + START) DO
  1017.                           X := SUCC(X);
  1018.                         IF NOT (X IN CANEDIT) THEN
  1019.                           IF NOCONV IN EXITCH THEN
  1020.                             BEGIN
  1021.                               SAVECH := RIGHT;
  1022.                               CH := NOCONV;
  1023.                             END
  1024.                           ELSE
  1025.                             CH := DOWN;
  1026.                         WHILE NOT (X IN CANEDIT) DO
  1027.                           X := PRED(X);
  1028.                       END
  1029.                     ELSE
  1030.                       BEGIN
  1031.                         SAVECH := CH;
  1032.                         IF NOCONV IN EXITCH THEN
  1033.                           CH := NOCONV
  1034.                         ELSE
  1035.                           CH := DOWN;
  1036.                       END;
  1037.              LEFT : IF X > 1 THEN
  1038.                       BEGIN
  1039.                         X := PRED(X);
  1040.                         WHILE (NOT (X IN CANEDIT)) AND
  1041.                               (X > 1) DO
  1042.                           X := PRED(X);
  1043.                         IF NOT (X IN CANEDIT) THEN
  1044.                           IF NOCONV IN EXITCH THEN
  1045.                             BEGIN
  1046.                               SAVECH := LEFT;
  1047.                               CH := NOCONV;
  1048.                             END
  1049.                           ELSE
  1050.                             CH := UP;
  1051.                         WHILE NOT (X IN CANEDIT) DO
  1052.                           X := SUCC(X);
  1053.                       END
  1054.                     ELSE
  1055.                       BEGIN
  1056.                         SAVECH := CH;
  1057.                         IF NOCONV IN EXITCH THEN
  1058.                           CH := NOCONV
  1059.                         ELSE
  1060.                           CH := UP;
  1061.                       END;
  1062.          ' '..'~' : IF CH IN VALID THEN
  1063.                       IF INSON THEN
  1064.                         BEGIN
  1065.                           DELETE(INSTRING,LENGTH(INSTRING),1);
  1066.                           IF (CAPWO AND ((X = 1) OR (INSTRING[X-1] = ' '))) OR
  1067.                              CAPIT THEN
  1068.                             CH := UPCASE(CH);
  1069.                           INSERT(CH,INSTRING,X);
  1070.                           X := SUCC(X);
  1071.                           IF X > LEN THEN
  1072.                             CH := DOWN;
  1073.                           WHILE (NOT (X IN CANEDIT)) AND
  1074.                                 (X <= LEN + START) DO
  1075.                             X := SUCC(X);
  1076.                           WHILE NOT (X IN CANEDIT) DO
  1077.                             X := PRED(X);
  1078.                           FW(START,Y,IATTR,INSTRING);
  1079.                         END
  1080.                       ELSE
  1081.                         BEGIN
  1082.                           IF (CAPWO AND ((X = 1) OR (INSTRING[X-1] = ' '))) OR
  1083.                              CAPIT THEN
  1084.                             CH := UPCASE(CH);
  1085.                           INSTRING[X] := CH;
  1086.                           FW(START+X-1,Y,IATTR,CH);
  1087.                           X := SUCC(X);
  1088.                           IF X > LEN THEN
  1089.                             BEGIN
  1090.                               SAVECH := RIGHT;
  1091.                               IF NOCONV IN EXITCH THEN
  1092.                                 CH := NOCONV
  1093.                               ELSE
  1094.                                 CH := DOWN;
  1095.                             END;
  1096.                           WHILE (NOT (X IN CANEDIT)) AND
  1097.                                 (X <= LEN + START) DO
  1098.                             X := SUCC(X);
  1099.                           IF NOT (X IN CANEDIT) THEN
  1100.                             IF NOCONV IN EXITCH THEN
  1101.                               BEGIN
  1102.                                 SAVECH := RIGHT;
  1103.                                 CH := NOCONV;
  1104.                               END
  1105.                             ELSE
  1106.                               CH := DOWN;
  1107.                           WHILE NOT (X IN CANEDIT) DO
  1108.                             X := PRED(X);
  1109.                         END;
  1110.            INSKEY : BEGIN
  1111.                       INSON := NOT INSON;
  1112.                       IF INSON AND (EDIT_ALL) THEN
  1113.                         SET_CURSOR(BLOCK)
  1114.                       ELSE
  1115.                         BEGIN
  1116.                           SET_CURSOR(UNDERLINE);
  1117.                           INSON := FALSE;
  1118.                         END;
  1119.                     END;
  1120.            DELKEY : IF EDIT_ALL THEN
  1121.                       BEGIN
  1122.                         DELETE(INSTRING,X,1);
  1123.                         INSTRING := INSTRING + ' ';
  1124.                         GOTOXY(START,Y);
  1125.                         FW(START,Y,IATTR,INSTRING);
  1126.                       END;
  1127.             ALT_C : BEGIN
  1128.                       FOR I := 1 TO LEN DO
  1129.                         IF I IN CANEDIT THEN
  1130.                           INSTRING[I] := ' ';
  1131.                       X := 1;
  1132.                       FW(START,Y,IATTR,INSTRING);
  1133.                       WHILE (NOT (X IN CANEDIT)) AND
  1134.                             (X <= LEN + START) DO
  1135.                         X := SUCC(X);
  1136.                     END;
  1137.       END;
  1138.       IF X > LEN THEN X := LEN;
  1139.     UNTIL (CH = #27) OR (CH IN EXITCH);
  1140.   IF NOCONV IN EXITCH THEN
  1141.     CH := SAVECH;
  1142.   X_OUT := X;
  1143.   X_IN  := 1;
  1144.   SET_CURSOR(UNDERLINE);
  1145.   CHANGED := INSTRING <> OLDVAL;
  1146. END;
  1147.  
  1148. PROCEDURE READ_STR;
  1149. VAR
  1150.   I,
  1151.   LEN,
  1152.   START   : INTEGER;
  1153.   CAPWO,
  1154.   VALID,
  1155.   EDITALL,
  1156.   INSON   : BOOLEAN;
  1157.   SAVECH  : CHAR;
  1158.   OLDATTR : BYTE;
  1159.   OLDCUR  : CURTYPE;
  1160.  
  1161.          FUNCTION CANEDIT(INCHAR : CHAR) : BOOLEAN;
  1162.          BEGIN
  1163.            IF ((INCHAR = ' ') OR
  1164.                (INCHAR = 'c') OR
  1165.                (INCHAR = 'y') OR
  1166.                (INCHAR = 'A') OR
  1167.                (INCHAR = '0') OR
  1168.                (INCHAR = '1') OR
  1169.                (INCHAR = '.') OR
  1170.                (INCHAR = '!') OR
  1171.                (INCHAR = '+')) THEN
  1172.              CANEDIT := TRUE
  1173.            ELSE
  1174.              CANEDIT := FALSE;
  1175.          END;
  1176.  
  1177.  
  1178. BEGIN                           
  1179.   INSTRING := PAD(INSTRING,LENGTH(MASK));
  1180.   OLDVAL := INSTRING;
  1181.   INSON := FALSE;
  1182.   SAVECH := #0;
  1183.   CAPWO := FALSE;
  1184.   EDITALL := TRUE;
  1185.   OLDCUR := CUR;
  1186.   TEXTATTR := UT.INPUT_ATTR;
  1187.   LEN := LENGTH(INSTRING);
  1188.   FOR I := 1 TO LENGTH(INSTRING) DO
  1189.     BEGIN
  1190.       IF MASK[I] = 'c' THEN
  1191.         CAPWO := TRUE
  1192.       ELSE
  1193.         IF (NOT CANEDIT(MASK[I])) THEN
  1194.           BEGIN
  1195.             IF MASK[I] <> 'x' THEN
  1196.               INSTRING[I] := MASK[I];
  1197.             EDITALL := FALSE;
  1198.           END;
  1199.       IF EDITALL THEN
  1200.         BEGIN
  1201.           IF (POS('y',MASK) > 0) AND (MASK <> DUP('y',LENGTH(MASK))) THEN
  1202.             EDITALL := FALSE;
  1203.           IF (POS('y',MASK) > 0) AND (MASK <> DUP('y',LENGTH(MASK))) THEN
  1204.             EDITALL := FALSE;
  1205.           IF (POS('A',MASK) > 0) AND (MASK <> DUP('A',LENGTH(MASK))) THEN
  1206.             EDITALL := FALSE;
  1207.           IF (POS('0',MASK) > 0) AND (MASK <> DUP('0',LENGTH(MASK))) THEN
  1208.             EDITALL := FALSE;
  1209.           IF (POS('1',MASK) > 0) AND (MASK <> DUP('1',LENGTH(MASK))) THEN
  1210.             EDITALL := FALSE;
  1211.           IF (POS('.',MASK) > 0) AND (MASK <> DUP('.',LENGTH(MASK))) THEN
  1212.             EDITALL := FALSE;
  1213.           IF (POS('!',MASK) > 0) AND (MASK <> DUP('!',LENGTH(MASK))) THEN
  1214.             EDITALL := FALSE;
  1215.           IF (POS('+',MASK) > 0) AND (MASK <> DUP('+',LENGTH(MASK))) THEN
  1216.             EDITALL := FALSE;
  1217.         END;
  1218.     END;
  1219.   IF X > 99 THEN
  1220.     BEGIN
  1221.       X := X - 100;
  1222.       START := X;
  1223.       X := LEN;
  1224.       WHILE (X > 2) AND (NOT CANEDIT(MASK[X])) DO
  1225.         X := X - 1;
  1226.     END
  1227.   ELSE
  1228.     BEGIN
  1229.       START := X;
  1230.       X := X_IN;
  1231.     END;
  1232.   OLDATTR := SCREEN_ATTR(START,Y);
  1233.   GOTOXY(START,Y);
  1234.   WRITE(INSTRING);
  1235.   SET_CURSOR(UNDERLINE);
  1236.   WHILE (NOT CANEDIT(MASK[X])) AND (X <= LEN) DO
  1237.     X := X + 1;
  1238.   REPEAT
  1239.     GOTOXY(START+X-1,Y);
  1240.     READCH(CH,FALSE);
  1241.     CASE CH OF
  1242.         HOMEKEY : BEGIN
  1243.                     X := 1;
  1244.                     WHILE (NOT CANEDIT(MASK[X])) AND
  1245.                           (X <= LEN + START) DO
  1246.                       X := SUCC(X);
  1247.                   END;
  1248.          ENDKEY : BEGIN
  1249.                     X := LEN;
  1250.                     WHILE (X > 2) AND (INSTRING[X-1] = ' ') DO
  1251.                       X := PRED(X);
  1252.                     WHILE (NOT CANEDIT(MASK[X])) AND
  1253.                           (X <= LEN) DO
  1254.                       X := SUCC(X);
  1255.                     WHILE NOT CANEDIT(MASK[X]) DO
  1256.                       X := PRED(X);
  1257.                     IF X < 1 THEN
  1258.                       X := 1
  1259.                     ELSE
  1260.                       IF (X = 2) AND (INSTRING[1] = ' ') AND
  1261.                          (CANEDIT(MASK[1])) THEN
  1262.                         X := 1;
  1263.                   END;
  1264.              #8 : IF (X > 1) AND EDITALL THEN
  1265.                     BEGIN
  1266.                       DELETE(INSTRING,X-1,1);
  1267.                       INSTRING := INSTRING + ' ';
  1268.                       GOTOXY(START,Y);
  1269.                       WRITE(INSTRING);
  1270.                       X := PRED(X);
  1271.                       WHILE (NOT CANEDIT(MASK[X])) AND
  1272.                             (X > 1) DO
  1273.                         X := PRED(X);
  1274.                       WHILE NOT CANEDIT(MASK[X]) DO
  1275.                         X := SUCC(X);
  1276.                     END
  1277.                   ELSE
  1278.                     IF X > 1 THEN
  1279.                       BEGIN
  1280.                         X := PRED(X);
  1281.                         WHILE (NOT CANEDIT(MASK[X])) AND
  1282.                               (X > 1) DO
  1283.                           X := PRED(X);
  1284.                         WHILE NOT CANEDIT(MASK[X]) DO
  1285.                           X := SUCC(X);
  1286.                       END
  1287.                     ELSE
  1288.                       BEGIN
  1289.                         IF UT.NOCONV THEN
  1290.                           SAVECH := LEFT
  1291.                         ELSE
  1292.                           CH := UP;
  1293.                       END;
  1294.           RIGHT : IF X < LEN THEN
  1295.                     BEGIN
  1296.                       X := SUCC(X);
  1297.                       WHILE (NOT CANEDIT(MASK[X])) AND
  1298.                             (X <= LEN + START) DO
  1299.                         X := SUCC(X);
  1300.                       IF NOT CANEDIT(MASK[X]) THEN
  1301.                         IF UT.NOCONV THEN
  1302.                           SAVECH := RIGHT
  1303.                         ELSE
  1304.                           CH := DOWN;
  1305.                       WHILE NOT CANEDIT(MASK[X]) DO
  1306.                         X := PRED(X);
  1307.                     END
  1308.                   ELSE
  1309.                     BEGIN
  1310.                       IF UT.NOCONV THEN
  1311.                         SAVECH := CH
  1312.                       ELSE
  1313.                         CH := DOWN;
  1314.                     END;
  1315.            LEFT : IF X > 1 THEN
  1316.                     BEGIN
  1317.                       X := PRED(X);
  1318.                       WHILE (NOT CANEDIT(MASK[X])) AND
  1319.                             (X > 1) DO
  1320.                         X := PRED(X);
  1321.                       IF NOT CANEDIT(MASK[X]) THEN
  1322.                         IF UT.NOCONV THEN
  1323.                           SAVECH := LEFT
  1324.                         ELSE
  1325.                           CH := UP;
  1326.                       WHILE NOT CANEDIT(MASK[X]) DO
  1327.                         X := SUCC(X);
  1328.                     END
  1329.                   ELSE
  1330.                     BEGIN
  1331.                       IF UT.NOCONV THEN
  1332.                         SAVECH := LEFT
  1333.                       ELSE
  1334.                         CH := UP;
  1335.                     END;
  1336.        ' '..'~' : BEGIN
  1337.                     VALID := FALSE;
  1338.                     CASE MASK[X] OF
  1339.                         ' ',
  1340.                         'c'  : VALID := TRUE;
  1341.                         'A'  : BEGIN
  1342.                                  VALID := TRUE;
  1343.                                  CH := UPCASE(CH);
  1344.                                END;
  1345.                         'y'  : BEGIN
  1346.                                  CH := UPCASE(CH);
  1347.                                  IF CH IN ['Y','N'] THEN
  1348.                                    VALID := TRUE;
  1349.                                END;
  1350.                         '0'  : IF CH IN ['0'..'9'] THEN
  1351.                                  VALID := TRUE;
  1352.                         '1'  : IF CH IN ['0'..'9',' '] THEN
  1353.                                  VALID := TRUE;
  1354.                         '.'  : IF CH IN ['0'..'9','.'] THEN
  1355.                                  VALID := TRUE;
  1356.                         '!'  : IF CH IN ['0'..'9','.',' '] THEN
  1357.                                  VALID := TRUE;
  1358.                         '+'  : IF CH IN ['0'..'9','.',' ','+','-'] THEN
  1359.                                  VALID := TRUE;
  1360.                     END;
  1361.                     IF VALID THEN
  1362.                       BEGIN
  1363.                         IF (CAPWO) AND ((X = 1) OR
  1364.                            (INSTRING[X-1] = ' ')) THEN
  1365.                           CH := UPCASE(CH);
  1366.                         IF INSON THEN
  1367.                           BEGIN
  1368.                             DELETE(INSTRING,LENGTH(INSTRING),1);
  1369.                             INSERT(CH,INSTRING,X);
  1370.                             GOTOXY(START,Y);
  1371.                             WRITE(INSTRING);
  1372.                           END
  1373.                         ELSE
  1374.                           BEGIN
  1375.                             INSTRING[X] := CH;
  1376.                             GOTOXY(START+X-1,Y);
  1377.                             WRITE(CH);
  1378.                           END;
  1379.                         X := SUCC(X);
  1380.                         IF X > LEN THEN
  1381.                           BEGIN
  1382.                             IF UT.NOCONV THEN
  1383.                               SAVECH := RIGHT
  1384.                             ELSE
  1385.                               CH := DOWN;
  1386.                           END
  1387.                         ELSE
  1388.                           BEGIN
  1389.                             WHILE (NOT CANEDIT(MASK[X])) AND
  1390.                                   (X <= LEN + START) DO
  1391.                               X := SUCC(X);
  1392.                             IF NOT CANEDIT(MASK[X]) THEN
  1393.                               IF UT.NOCONV THEN
  1394.                                 SAVECH := RIGHT
  1395.                               ELSE
  1396.                                 CH := DOWN;
  1397.                             WHILE NOT CANEDIT(MASK[X]) DO
  1398.                               X := PRED(X);
  1399.                           END;
  1400.                       END;
  1401.                   END;
  1402.          INSKEY : BEGIN
  1403.                     INSON := NOT INSON;
  1404.                     IF INSON AND (EDITALL) THEN
  1405.                       SET_CURSOR(BLOCK)
  1406.                     ELSE
  1407.                       BEGIN
  1408.                         SET_CURSOR(UNDERLINE);
  1409.                         INSON := FALSE;
  1410.                       END;
  1411.                   END;
  1412.          DELKEY : IF EDITALL THEN
  1413.                     BEGIN
  1414.                       DELETE(INSTRING,X,1);
  1415.                       INSTRING := INSTRING + ' ';
  1416.                       GOTOXY(START,Y);
  1417.                       WRITE(INSTRING);
  1418.                     END;
  1419.           ALT_C : BEGIN
  1420.                     FOR I := 1 TO LEN DO
  1421.                       IF CANEDIT(MASK[I]) THEN
  1422.                         INSTRING[I] := ' ';
  1423.                     X := 1;
  1424.                     GOTOXY(START,Y);
  1425.                     WRITE(INSTRING);
  1426.                     WHILE (NOT CANEDIT(MASK[X])) AND
  1427.                           (X <= LEN) DO
  1428.                       X := SUCC(X);
  1429.                   END;
  1430.     END;
  1431.     IF X > LEN THEN X := LEN;
  1432.   UNTIL (CH = #27) OR (UT.EXITCH[ORD(CH)]) OR (SAVECH <> #0);
  1433.   IF SAVECH <> #0 THEN
  1434.     CH := SAVECH;
  1435.   X_OUT := X;
  1436.   X_IN  := 1;
  1437.   SET_CURSOR(UNDERLINE);
  1438.   TEXTATTR := OLDATTR;
  1439.   GOTOXY(START,Y);
  1440.   WRITE(INSTRING);
  1441.   TEXTATTR := UT.DEFAULT_ATTR;
  1442.   SET_CURSOR(OLDCUR);
  1443.   CHANGED := INSTRING <> OLDVAL;
  1444. END;
  1445.  
  1446. PROCEDURE READ_ONLY(NAME : STRING);
  1447. VAR
  1448.   F    : FILE;
  1449.   ATTR : WORD;
  1450. BEGIN
  1451.   ASSIGN(F,NAME);
  1452.   GETFATTR(F,ATTR);
  1453.   ATTR := ATTR OR 1;
  1454.   SETFATTR(F,ATTR);
  1455. END;
  1456.  
  1457. PROCEDURE READ_WRITE(NAME : STRING);
  1458. VAR
  1459.   F    : FILE;
  1460.   ATTR : WORD;
  1461. BEGIN
  1462.   ASSIGN(F,NAME);
  1463.   GETFATTR(F,ATTR);
  1464.   IF ODD(ATTR) THEN
  1465.     ATTR := ATTR - 1;
  1466.   SETFATTR(F,ATTR);
  1467. END;
  1468.  
  1469. PROCEDURE READ_REAL(X,Y,LEN  : INTEGER;
  1470.                     PATTR    : INTEGER;
  1471.                     PROMPT   : STR80;
  1472.                     IATTR    : INTEGER;
  1473.                     VAR R    : REAL;
  1474.                     DPLACES  : INTEGER;
  1475.                     LOW,HIGH : REAL;
  1476.                     EXITCH   : ETYPE;
  1477.                     ICOMA    : BOOLEAN;
  1478.                     TX, TY   : INTEGER;
  1479.                     CH       : CHAR);
  1480. VAR
  1481.   RESULT : INTEGER;
  1482.   TEMP   : STRING[40];
  1483.   T      : ETYPE;
  1484.   S      : BUF160;
  1485.   SAT    : INTEGER;
  1486. BEGIN
  1487.   IF ICOMA THEN
  1488.     TEMP := COMMA(R,0,DPLACES,RNUM)
  1489.   ELSE
  1490.     STR(R:0:DPLACES,TEMP);
  1491.   IF (R = 0.0) OR (CLEAR IN EXITCH) THEN
  1492.     BEGIN
  1493.       TEMP := '0';
  1494.       TEMP := PAD(TEMP,LEN);
  1495.       EXITCH := EXITCH - [CLEAR];
  1496.     END;
  1497.   T := [' ','0'..'9','-',','];
  1498.   IF DPLACES > 0 THEN
  1499.     T := T + ['.'];
  1500.   REPEAT
  1501.     WHILE LENGTH(TEMP) < LEN DO
  1502.       TEMP := TEMP + ' ';
  1503.     READSTR(X,Y,LEN,PATTR,PROMPT,IATTR,TEMP,T,[1..LEN],EXITCH,TX,TY,CH);
  1504.     WHILE (TEMP[1] = ' ') AND (LENGTH(TEMP) > 0) DO
  1505.       DELETE(TEMP,1,1);
  1506.     WHILE (TEMP[LENGTH(TEMP)] = ' ') AND (LENGTH(TEMP) > 0) DO
  1507.       DELETE(TEMP,LENGTH(TEMP),1);
  1508.     IF TEMP[LENGTH(TEMP)] = '.' THEN
  1509.       DELETE(TEMP,LENGTH(TEMP),1);
  1510.     WHILE (POS(',',TEMP) > 0) AND (LENGTH(TEMP) > 0) DO
  1511.       DELETE(TEMP,POS(',',TEMP),1);
  1512.     IF TEMP[1] = '.' THEN
  1513.       TEMP := '0' + TEMP;
  1514.     VAL(TEMP,R,RESULT);
  1515.     IF (RESULT = 0) AND ((R < LOW) OR (R > HIGH)) THEN
  1516.       RESULT := 1;
  1517.     IF RESULT <> 0 THEN
  1518.       BEGIN
  1519.         SAT := TEXTATTR;
  1520.         SAVE_LINE(Y+1,S);
  1521.         TEXTATTR := $4F;
  1522.         IF X > 30 THEN
  1523.           GOTOXY(30,Y+1)
  1524.         ELSE
  1525.           GOTOXY(X,Y+1);
  1526.         WRITE(' Range: ',LOW:0:DPLACES,' to ',HIGH:0:DPLACES,'  Press <any key> ',CHR(8));
  1527.         READCH(CH,FALSE);
  1528.         REBUILD_LINE(Y+1,S);
  1529.         TEXTATTR := SAT;
  1530.       END;
  1531.   UNTIL RESULT = 0;
  1532.   WHILE LENGTH(TEMP) < LEN DO
  1533.     TEMP := ' ' + TEMP;
  1534.   IF ICOMA THEN
  1535.     FW(X+LENGTH(PROMPT),Y,IATTR,COMMA(R,LEN,DPLACES,RNUM))
  1536.   ELSE
  1537.     FW(X+LENGTH(PROMPT),Y,IATTR,TEMP);
  1538. END;
  1539.  
  1540. PROCEDURE READ_INT(X,Y,LEN   : INTEGER;
  1541.                     PATTR    : INTEGER;
  1542.                     PROMPT   : STR80;
  1543.                     IATTR    : INTEGER;
  1544.                     VAR R    : INTEGER;
  1545.                     LOW,HIGH : INTEGER;
  1546.                     EXITCH   : ETYPE;
  1547.                     ICOMA    : BOOLEAN;
  1548.                     TX, TY   : INTEGER;
  1549.                     CH       : CHAR);
  1550. VAR
  1551.   RESULT : INTEGER;
  1552.   TEMP   : STRING;
  1553.   T      : ETYPE;
  1554.   S      : BUF160;
  1555.   SAT    : INTEGER;
  1556. BEGIN
  1557.   IF (R = 0) OR (CLEAR IN EXITCH) THEN
  1558.     BEGIN
  1559.       TEMP := '0';
  1560.       EXITCH := EXITCH - [CLEAR];
  1561.     END
  1562.   ELSE
  1563.     IF ICOMA THEN
  1564.       TEMP := COMMA(R,0,0,INUM)
  1565.     ELSE
  1566.       STR(R,TEMP);
  1567.   WHILE LENGTH(TEMP) < LEN DO
  1568.     TEMP := TEMP + ' ';
  1569.   T := [' ','0'..'9','-',','];
  1570.   REPEAT
  1571.     WHILE LENGTH(TEMP) < LEN DO
  1572.       TEMP := TEMP + ' ';
  1573.     READSTR(X,Y,LEN,PATTR,PROMPT,IATTR,TEMP,T,[1..LEN],EXITCH,TX,TY,CH);
  1574.     WHILE (TEMP[1] = ' ') AND (LENGTH(TEMP) > 0) DO
  1575.       DELETE(TEMP,1,1);
  1576.     WHILE (TEMP[LENGTH(TEMP)] = ' ') AND (LENGTH(TEMP) > 0) DO
  1577.       DELETE(TEMP,LENGTH(TEMP),1);
  1578.     WHILE (POS(',',TEMP) > 0) AND (LENGTH(TEMP) > 0) DO
  1579.       DELETE(TEMP,POS(',',TEMP),1);
  1580.     IF _LONGINT(TEMP) <= 32767 THEN
  1581.       VAL(TEMP,R,RESULT)
  1582.     ELSE
  1583.       RESULT := 1;
  1584.     IF (RESULT = 0) AND ((R < LOW) OR (R > HIGH)) THEN
  1585.       RESULT := 1;
  1586.     IF RESULT <> 0 THEN
  1587.       BEGIN
  1588.         SAVE_LINE(Y+1,S);
  1589.         SAT := TEXTATTR;
  1590.         TEXTATTR := $4F;
  1591.         IF X > 39 THEN
  1592.           GOTOXY(39,Y+1)
  1593.         ELSE
  1594.           GOTOXY(X,Y+1);
  1595.         WRITE(' Range: ',LOW,' to ',HIGH,'  Press <any key> ',CHR(8));
  1596.         READCH(CH,FALSE);
  1597.         REBUILD_LINE(Y+1,S);
  1598.         TEXTATTR := SAT;
  1599.       END;
  1600.   UNTIL RESULT = 0;
  1601.   WHILE LENGTH(TEMP) < LEN DO
  1602.     TEMP := ' ' + TEMP;
  1603.   IF ICOMA THEN
  1604.     FW(X+LENGTH(PROMPT),Y,IATTR,COMMA(R,LEN,0,INUM))
  1605.   ELSE
  1606.     FW(X+LENGTH(PROMPT),Y,IATTR,TEMP);
  1607. END;
  1608.  
  1609. FUNCTION DRIVE_READY(DRIVE : CHAR) : BOOLEAN;
  1610. BEGIN
  1611.   DRIVE_READY := DISKSIZE(ORD(DRIVE)-64) <> -1;
  1612. END;
  1613.  
  1614. FUNCTION _REAL(INSTRING : STRING) : REAL;
  1615. VAR
  1616.   R      : REAL;
  1617.   RESULT : INTEGER;
  1618. BEGIN
  1619.   WHILE POS(' ',INSTRING) > 0 DO
  1620.     DELETE(INSTRING,POS(' ',INSTRING),1);
  1621.   VAL(INSTRING,R,RESULT);
  1622.   _REAL := R;
  1623. END;
  1624.  
  1625. FUNCTION _INTEGER(INSTRING : STRING) : INTEGER;
  1626. VAR
  1627.   I,
  1628.   RESULT : INTEGER;
  1629. BEGIN
  1630.   WHILE POS(' ',INSTRING) > 0 DO
  1631.     DELETE(INSTRING,POS(' ',INSTRING),1);
  1632.   IF POS('.',INSTRING) > 0 THEN
  1633.     INSTRING := COPY(INSTRING,1,POS('.',INSTRING)-1);
  1634.   IF (LENGTH(INSTRING) >= 5) AND (INSTRING > '32767') THEN
  1635.     BEGIN
  1636.       _INTEGER := 0;
  1637.       EXIT;
  1638.     END;
  1639.   VAL(INSTRING,I,RESULT);
  1640.   _INTEGER := I;
  1641. END;
  1642.  
  1643. FUNCTION _LONGINT(INSTRING : STRING) : LONGINT;
  1644. VAR
  1645.   SIGN,
  1646.   LEN,
  1647.   I      : INTEGER;
  1648.   TENS,
  1649.   NUMBER : LONGINT;
  1650. BEGIN
  1651.   TENS := 1;
  1652.   NUMBER := 0;
  1653.   SIGN := 1;
  1654.   _LONGINT := 0;
  1655.   WHILE POS(' ',INSTRING) > 0 DO
  1656.     DELETE(INSTRING,POS(' ',INSTRING),1);
  1657.   IF POS('.',INSTRING) > 0 THEN
  1658.     INSTRING := COPY(INSTRING,1,POS('.',INSTRING)-1);
  1659.   IF (LENGTH(INSTRING) >= 10) AND (INSTRING > '2147483648') THEN
  1660.     EXIT;
  1661.   LEN := LENGTH(INSTRING);
  1662.   IF INSTRING[1] = '-' THEN
  1663.     BEGIN
  1664.       IF LEN = 1 THEN
  1665.         EXIT;
  1666.       SIGN := -1;
  1667.     END;
  1668.   FOR I := LEN DOWNTO 1 DO
  1669.     IF (INSTRING[I] < '0') OR (INSTRING[I] > '9') THEN
  1670.     ELSE
  1671.       BEGIN
  1672.         NUMBER := NUMBER + (ORD(INSTRING[I]) - ORD('0')) * TENS;
  1673.         TENS := TENS * 10;
  1674.       END;
  1675.   NUMBER := NUMBER * SIGN;
  1676.   _LONGINT := NUMBER;
  1677. END;
  1678.  
  1679. FUNCTION _WORD(INSTRING : STRING) : WORD;
  1680. VAR
  1681.   SIGN,
  1682.   LEN,
  1683.   I      : INTEGER;
  1684.   TENS   : LONGINT;
  1685.   NUMBER : WORD;
  1686. BEGIN
  1687.   TENS := 1;
  1688.   NUMBER := 0;
  1689.   SIGN := 1;
  1690.   _WORD := 0;
  1691.   WHILE POS(' ',INSTRING) > 0 DO
  1692.     DELETE(INSTRING,POS(' ',INSTRING),1);
  1693.   IF POS('.',INSTRING) > 0 THEN
  1694.     INSTRING := COPY(INSTRING,1,POS('.',INSTRING)-1);
  1695.   IF (LENGTH(INSTRING) >= 5) AND (INSTRING > '65535') THEN
  1696.     EXIT;
  1697.   LEN := LENGTH(INSTRING);
  1698.   IF INSTRING[1] = '-' THEN
  1699.     BEGIN
  1700.       IF LEN = 1 THEN
  1701.         EXIT;
  1702.       SIGN := -1;
  1703.     END;
  1704.   FOR I := LEN DOWNTO 1 DO
  1705.     IF (INSTRING[I] < '0') OR (INSTRING[I] > '9') THEN
  1706.       EXIT
  1707.     ELSE
  1708.       BEGIN
  1709.         NUMBER := NUMBER + (ORD(INSTRING[I]) - ORD('0')) * TENS;
  1710.         TENS := TENS * 10;
  1711.       END;
  1712.   NUMBER := NUMBER * SIGN;
  1713.   _WORD := NUMBER;
  1714. END;
  1715.  
  1716. FUNCTION GET_FILE_NAME(MASK : STRING; DEL : BOOLEAN) : STRING;
  1717. TYPE
  1718.   STR12     = STRING[12];
  1719. VAR
  1720.   I,J,
  1721.   FM,
  1722.   TOP,
  1723.   SEL,
  1724.   INDEX     : INTEGER;
  1725.   TEMP      : STR12;
  1726.   DIRINFO   : SEARCHREC;
  1727.   SAVENAME  : ARRAY [1..500] OF STRING[12];
  1728.   F         : FILE;
  1729.   C         : CURTYPE;
  1730.   SAVE_ATTR : INTEGER;
  1731.  
  1732.       PROCEDURE WRITE_PAGE;
  1733.       VAR
  1734.         I : INTEGER;
  1735.       BEGIN
  1736.         J := 10;
  1737.         WINDOW(36,10,50,17);
  1738.         CLRSCR;
  1739.         WINDOW(1,1,80,25);
  1740.         FOR I := TOP TO TOP+7 DO
  1741.           IF I <= INDEX THEN
  1742.             BEGIN
  1743.               FW(38,J,$0E,SAVENAME[I]);
  1744.               J := SUCC(J);
  1745.             END;
  1746.       END;
  1747.  
  1748. BEGIN
  1749.   C := CUR;
  1750.   SAVE_ATTR := TEXTATTR;
  1751.   SET_CURSOR(NONE);
  1752.   TEXTBACKGROUND(BLACK);
  1753.   FM := FILEMODE;
  1754.   FILEMODE := 0;
  1755.   INDEX := 1;
  1756.   FILLCHAR(SAVENAME,SIZEOF(SAVENAME),0);
  1757.   FINDFIRST(MASK,READONLY+ARCHIVE,DIRINFO);
  1758.   WHILE DOSERROR = 0 DO
  1759.     BEGIN
  1760.       SAVENAME[INDEX] := DIRINFO.NAME;
  1761.       INDEX := SUCC(INDEX);
  1762.       FINDNEXT(DIRINFO);
  1763.     END;
  1764.   INDEX := PRED(INDEX);
  1765.   FOR I := 1 TO INDEX DO
  1766.     FOR J := I+1 TO INDEX DO
  1767.       IF SAVENAME[I] > SAVENAME[J] THEN
  1768.         BEGIN
  1769.           TEMP := SAVENAME[I];
  1770.           SAVENAME[I] := SAVENAME[J];
  1771.           SAVENAME[J] := TEMP;
  1772.         END;
  1773.   FW(35, 8,$0E,'╔═ Select File ═╗');
  1774.   FW(35, 9,$0E,'║               ║');
  1775.   FW(35,10,$0E,'║               ║');
  1776.   FW(35,11,$0E,'║               ║');
  1777.   FW(35,12,$0E,'║               ║');
  1778.   FW(35,13,$0E,'║               ║');
  1779.   FW(35,14,$0E,'║               ║');
  1780.   FW(35,15,$0E,'║               ║');
  1781.   FW(35,16,$0E,'║               ║');
  1782.   FW(35,17,$0E,'║               ║');
  1783.   FW(35,18,$0E,'║               ║');
  1784.   FW(35,19,$0E,'║               ║');
  1785.   FW(35,20,$0E,'║               ║');
  1786.   FW(35,21,$0E,'╚═══════════════╝');
  1787.   FW(39,19,$0F,CHR(24)+' '+CHR(25)+'   '+ENTER_KEY);
  1788.   FW(38,20,$0F,'PgUp   PgDn');
  1789.   IF DEL THEN
  1790.     BEGIN
  1791.       FW(35,21,$0E,'║  <DEL> Delete ║');
  1792.       FW(35,22,$0E,'╚═══════════════╝');
  1793.       SET_ATTR([36..49],21,$0F);
  1794.     END;
  1795.   SET_CURSOR(NONE);
  1796.   TOP := 1;
  1797.   SEL := 1;
  1798.   FOR I := 1 TO 8 DO
  1799.     IF I <= INDEX THEN
  1800.       FW(38,I+9,$0E,SAVENAME[I]);
  1801.   REPEAT
  1802.     SET_ATTR([37..49],SEL+9,$70);
  1803.     READCH(CH,FALSE);
  1804.     CH := UPCASE(CH);
  1805.     SET_ATTR([37..49],SEL+9,$0E);
  1806.     CASE CH OF
  1807.        '0'..'9',
  1808.        'A'..'Z' : BEGIN
  1809.                     TOP := 1;
  1810.                     WHILE (TOP < 500) AND (SAVENAME[TOP][1] < CH) DO
  1811.                       TOP := SUCC(TOP);
  1812.                     SEL := 1;
  1813.                     WHILE (TOP > 1) AND (LENGTH(SAVENAME[TOP]) = 0) DO
  1814.                       TOP := PRED(TOP);
  1815.                     WRITE_PAGE;
  1816.                   END;
  1817.              UP : IF SEL > 1 THEN
  1818.                     SEL := PRED(SEL)
  1819.                   ELSE
  1820.                     IF TOP > 1 THEN
  1821.                       BEGIN
  1822.                         WINDOW(36,10,50,17);
  1823.                         INSLINE;
  1824.                         WINDOW(1,1,80,25);
  1825.                         TOP := PRED(TOP);
  1826.                         FW(38,10,$0E,SAVENAME[TOP]);
  1827.                       END;
  1828.            DOWN : IF (SEL < 8) AND (TOP+SEL-1 < INDEX) THEN
  1829.                     SEL := SUCC(SEL)
  1830.                   ELSE
  1831.                     IF TOP+SEL < INDEX THEN
  1832.                       BEGIN
  1833.                         WINDOW(36,10,50,17);
  1834.                         GOTOXY(1,8);
  1835.                         WRITELN;
  1836.                         WINDOW(1,1,80,25);
  1837.                         TOP := SUCC(TOP);
  1838.                         FW(38,17,$0E,SAVENAME[TOP+SEL-1]);
  1839.                       END;
  1840.            PGDN : IF TOP + 8 <= INDEX THEN
  1841.                     BEGIN
  1842.                       SEL := 1;
  1843.                       TOP := TOP + 8;
  1844.                       WRITE_PAGE;
  1845.                     END;
  1846.            PGUP : IF TOP > 1 THEN
  1847.                     BEGIN
  1848.                       SEL := 1;
  1849.                       TOP := TOP - 8;
  1850.                       IF TOP < 1 THEN TOP := 1;
  1851.                       WRITE_PAGE;
  1852.                     END;
  1853.          DELKEY : IF DEL THEN
  1854.                     BEGIN
  1855.                       SET_ATTR([37..49],SEL+9,$70);
  1856.                       FW(36,21,$8E,' Are You Sure? ');
  1857.                       SET_CURSOR(UNDERLINE);
  1858.                       REPEAT
  1859.                         GOTOXY(50,21);
  1860.                         READCH(CH,FALSE);
  1861.                         CH := UPCASE(CH);
  1862.                       UNTIL CH IN ['Y','N'];
  1863.                       SET_CURSOR(NONE);
  1864.                       IF CH = 'Y' THEN
  1865.                         BEGIN
  1866.                           ASSIGN(F,SAVENAME[TOP+SEL-1]);
  1867.                           {$I-}
  1868.                             ERASE(F);
  1869.                           {$I+}
  1870.                           IF IORESULT = 0 THEN
  1871.                             BEGIN
  1872.                               FOR I := TOP+SEL-1 TO INDEX-1 DO
  1873.                                 SAVENAME[I] := SAVENAME[I+1];
  1874.                               INDEX := PRED(INDEX);
  1875.                               WRITE_PAGE;
  1876.                             END;
  1877.                         END;
  1878.                       FW(37,21,$0F,' <DEL> Delete ');
  1879.                     END;
  1880.     END;
  1881.   UNTIL (CH = RETURN) OR (CH = ESCAPE);
  1882.   IF CH = RETURN THEN
  1883.     GET_FILE_NAME := SAVENAME[TOP+SEL-1]
  1884.   ELSE
  1885.     GET_FILE_NAME := '';
  1886.   CH := 'X';
  1887.   SET_CURSOR(CUR);
  1888.   FILEMODE := FM;
  1889.   TEXTATTR := SAVE_ATTR;
  1890. END;
  1891.  
  1892. PROCEDURE PATHEXEC(COMMAND : PATHSTR; PARMS : STRING);
  1893. VAR
  1894.   P,
  1895.   DIRSTR    : STRING;
  1896.   AllocError: Integer;
  1897.   Regs      : Registers;
  1898.  
  1899.         {
  1900.         Procedure ShrinkAllocation;
  1901.         Begin
  1902.            If Ofs(FreePtr^)<>0 Then
  1903.            Begin
  1904.               AllocError := -1;
  1905.               Exit;
  1906.            End;
  1907.            Regs.AH := $4A;
  1908.            Regs.ES := Prefixseg;
  1909.            Regs.BX := Seg(HeapPtr^)-PrefixSeg;
  1910.            MsDos(Regs);
  1911.            If (Regs.Flags And Fcarry)=Fcarry Then
  1912.               AllocError := Regs.AX
  1913.            Else
  1914.               AllocError := 0;
  1915.         End;
  1916.  
  1917.         Procedure RestoreAllocation;
  1918.         Begin
  1919.            If Ofs(FreePtr^)<>0 Then
  1920.            Begin
  1921.               AllocError := -1;
  1922.               Exit;
  1923.            End;
  1924.            Regs.AH := $4A;
  1925.            Regs.ES := Prefixseg;
  1926.            Regs.BX := Seg(FreePtr^)+$1000-PrefixSeg;
  1927.            MsDos(Regs);
  1928.            If (Regs.Flags And Fcarry)=Fcarry Then
  1929.               AllocError := Regs.AX
  1930.            Else
  1931.               AllocError := 0;
  1932.         End;
  1933.         }
  1934.  
  1935. BEGIN
  1936.   DIRSTR := GETENV('PATH');
  1937.   P := FSEARCH(COMMAND,DIRSTR);
  1938.   IF P <> '' THEN
  1939.     BEGIN
  1940.       {
  1941.       IF DYNAMIC_PATHEXEC THEN
  1942.         ShrinkAllocation
  1943.       ELSE
  1944.         ALLOCERROR := 0;
  1945.       IF ALLOCERROR = 0 THEN
  1946.         BEGIN
  1947.       }
  1948.           SWAPVECTORS;
  1949.           EXEC(P,PARMS);
  1950.           SWAPVECTORS;
  1951.       {
  1952.           IF DYNAMIC_PATHEXEC THEN
  1953.             RestoreAllocation;
  1954.         END
  1955.       ELSE
  1956.         DOSERROR := 8;
  1957.       }
  1958.     END
  1959.   ELSE
  1960.     DOSERROR := 2;
  1961. END;
  1962.  
  1963. FUNCTION  COMMA(VAR VALUE; FIELDWIDTH, PLACES : INTEGER; NTYPE : TYPEN) : STRING;
  1964. VAR
  1965.   TEMP           : STRING;
  1966.   I,
  1967.   COMMAPOS,
  1968.   COMMASINSERTED : INTEGER;
  1969.   RNUMBER        : REAL ABSOLUTE VALUE;
  1970.   LNUMBER        : LONGINT ABSOLUTE VALUE;
  1971.   INUMBER        : INTEGER ABSOLUTE VALUE;
  1972. BEGIN
  1973.   IF FIELDWIDTH < 0 THEN FIELDWIDTH := 0;
  1974.   IF PLACES < 0 THEN PLACES := 0;
  1975.   CASE NTYPE OF
  1976.       RNUM : STR(RNUMBER:FIELDWIDTH:PLACES,TEMP);
  1977.       LNUM : BEGIN
  1978.                STR(LNUMBER:FIELDWIDTH,TEMP);
  1979.                PLACES := 0;
  1980.              END;
  1981.       INUM : BEGIN
  1982.                STR(INUMBER:FIELDWIDTH,TEMP);
  1983.                PLACES := 0;
  1984.              END;
  1985.   END;
  1986.   IF PLACES = 0 THEN
  1987.     COMMAPOS := LENGTH(TEMP)-2
  1988.   ELSE
  1989.     COMMAPOS := LENGTH(TEMP)-PLACES-3;
  1990.   COMMASINSERTED := 0;
  1991.   WHILE (COMMAPOS > 1) AND (TEMP[COMMAPOS-1] IN ['0'..'9']) DO
  1992.     BEGIN
  1993.       INSERT(',',TEMP,COMMAPOS);
  1994.       COMMASINSERTED := SUCC(COMMASINSERTED);
  1995.       COMMAPOS := COMMAPOS - 3;
  1996.     END;
  1997.   FOR I := 1 TO COMMASINSERTED DO
  1998.     IF TEMP[1] = ' ' THEN
  1999.       DELETE(TEMP,1,1);
  2000.   COMMA := TEMP;
  2001. END;
  2002.  
  2003. FUNCTION READ_SCREEN(X,Y : INTEGER) : CHAR;
  2004. VAR
  2005.   Z : INTEGER;
  2006. BEGIN
  2007.   Z := (((Y * 160) - 160) + (X * 2)) - 1;
  2008.   READ_SCREEN := P^[Z];
  2009. END;
  2010.  
  2011. FUNCTION SCREEN_ATTR(X,Y : INTEGER) : BYTE;
  2012. VAR
  2013.   Z : INTEGER;
  2014. BEGIN
  2015.   Z := (((Y * 160) - 160) + (X * 2));
  2016.   SCREEN_ATTR := ORD(P^[Z]);
  2017. END;
  2018.  
  2019. PROCEDURE BIN_LED(L : BYTE);
  2020. VAR
  2021.   SHIFTBYTE : BYTE ABSOLUTE $0000:$0417;
  2022. BEGIN
  2023.   IF L IN [0..7] THEN
  2024.     SHIFTBYTE := L SHL 4;
  2025. END;
  2026.  
  2027. PROCEDURE READCHT(VAR CH : CHAR; ECHO : BOOLEAN; TOO : LONGINT);
  2028. VAR
  2029.   T      : LONGINT;
  2030.   HELP   : BOOLEAN;
  2031.   ATX,
  2032.   ATY    : INTEGER;
  2033.   LINE25 : BUF160;
  2034. BEGIN
  2035.   ATX := WHEREX;
  2036.   ATY := WHEREY;
  2037.   START_TIMER(T);
  2038.   HELP := FALSE;
  2039.   SAVE_LINE(25,LINE25);
  2040.   REPEAT
  2041.     IF (SHIFT_KEYS('A')) AND (HELP_LINE <> '') THEN
  2042.       BEGIN
  2043.         FW(1,25,HELP_ATTR,PAD(HELP_LINE,80));
  2044.         GOTOXY(ATX,ATY);
  2045.         HELP := TRUE;
  2046.       END
  2047.     ELSE
  2048.       IF (SHIFT_KEYS('C')) AND (HELP_LINE2 <> '') THEN
  2049.         BEGIN
  2050.           FW(1,25,HELP_ATTR2,PAD(HELP_LINE2,80));
  2051.           GOTOXY(ATX,ATY);
  2052.           HELP := TRUE;
  2053.         END
  2054.       ELSE
  2055.         IF HELP THEN
  2056.           BEGIN
  2057.             REBUILD_LINE(25,LINE25);
  2058.             GOTOXY(ATX,ATY);
  2059.             HELP := FALSE;
  2060.           END;
  2061.   UNTIL KEYPRESSED OR (ELAP_TIME(T) >= TOO) OR (COMMAND_BUFFER <> '');
  2062.   REBUILD_LINE(25,LINE25);
  2063.   IF KEYPRESSED THEN
  2064.     READCH(CH,ECHO);
  2065. END;
  2066.  
  2067. PROCEDURE PRINT_SCREEN(X1,Y1,X2,Y2 : INTEGER; EXT : BOOLEAN);
  2068. VAR
  2069.   CH   : CHAR;
  2070.   I,J  : INTEGER;
  2071. BEGIN
  2072.   IF NOT PRINTER_READY THEN EXIT;
  2073.   FOR I := Y1 TO Y2 DO
  2074.     BEGIN
  2075.       FOR J := X1 TO X2 DO
  2076.         BEGIN
  2077.           CH := READ_SCREEN(J,I);
  2078.           IF (CH IN [' '..'~']) OR EXT THEN
  2079.             WRITE(LST,CH)
  2080.           ELSE
  2081.             WRITE(LST,' ');
  2082.         END;
  2083.       WRITELN(LST);
  2084.     END;
  2085. END;
  2086.  
  2087. FUNCTION PRINTER_READY : BOOLEAN;
  2088. VAR
  2089.   SC : BUFFER;
  2090. BEGIN
  2091.   IF PRINTER_NOT_READY THEN
  2092.     BEGIN
  2093.       SAVE_SCREEN(SC);
  2094.       POP_WINDOW(30,10,57,14,2,$4F);
  2095.       FW(34,11,$CF,'PRINTER NOT READY !!');
  2096.       FW(33,13,$4F,'Ready Printer, or <ESC>');
  2097.       CH := 'X';
  2098.       GOTOXY(56,13);
  2099.       WHILE (CH <> ESCAPE) AND PRINTER_NOT_READY DO
  2100.         IF KEYPRESSED THEN
  2101.           READCH(CH,FALSE);
  2102.       IF CH = ESCAPE THEN
  2103.         PRINTER_READY := FALSE
  2104.       ELSE
  2105.         PRINTER_READY := TRUE;
  2106.       CH := 'X';
  2107.       REBUILD_SCREEN(SC);
  2108.     END
  2109.   ELSE
  2110.     PRINTER_READY := TRUE;
  2111. END;
  2112.  
  2113. FUNCTION COMBINE(S1, S2 : STRING;
  2114.                     MAX : INTEGER;
  2115.            INSERT_COMMA : BOOLEAN) : STRING;
  2116. BEGIN
  2117.   WHILE (S1[LENGTH(S1)] = ' ') AND (LENGTH(S1) > 0) DO
  2118.     DELETE(S1,LENGTH(S1),1);
  2119.   IF INSERT_COMMA THEN
  2120.     S1 := S1 + ', ' + S2
  2121.   ELSE
  2122.     S1 := S1 + ' ' + S2;
  2123.   IF LENGTH(S1) > MAX THEN
  2124.     S1 := COPY(S1,1,MAX)
  2125.   ELSE
  2126.     WHILE LENGTH(S1) < MAX DO
  2127.       S1 := S1 + ' ';
  2128.   COMBINE := S1;
  2129. END;
  2130.  
  2131. PROCEDURE ENCRYPT(VAR LINE : STRING; I : INTEGER);
  2132. BEGIN
  2133.   RANDSEED := I;
  2134.   FOR I := 1 TO LENGTH(LINE) DO
  2135.     LINE[I] := CHR(ORD(LINE[I]) + RANDOM(10));
  2136. END;
  2137.  
  2138. PROCEDURE UN_ENCRYPT(VAR LINE : STRING; I : INTEGER);
  2139. BEGIN
  2140.   RANDSEED := I;
  2141.   FOR I := 1 TO LENGTH(LINE) DO
  2142.     LINE[I] := CHR(ORD(LINE[I]) - RANDOM(10));
  2143. END;
  2144.  
  2145. PROCEDURE CENTER(Y, ATTRIB : INTEGER; LINE : STRING);
  2146. VAR
  2147.   TEMP      : STRING;
  2148. BEGIN
  2149.   TEMP := STRIP(LINE,FALSE);
  2150.   FW(40 - (LENGTH(TEMP) DIV 2),Y,ATTRIB,TEMP);
  2151. END;
  2152.  
  2153. PROCEDURE SET_ATTR_BOX(X1,Y1,X2,Y2,ATT : INTEGER);
  2154. VAR
  2155.   I : INTEGER;
  2156. BEGIN
  2157.   FOR I := Y1 TO Y2 DO
  2158.     SET_ATTR([X1..X2],I,ATT);
  2159. END;
  2160.  
  2161. FUNCTION FILE_OPEN(VAR F) : BOOLEAN;
  2162. VAR
  2163.   FILE_INFO : FILEREC ABSOLUTE F;
  2164. BEGIN
  2165.   FILE_OPEN := FILE_INFO.MODE <> FMCLOSED;
  2166. END;
  2167.  
  2168. PROCEDURE WRITE_X80_Y25(CH : CHAR; ATTRIB : INTEGER);
  2169. BEGIN
  2170.   FW(80,25,ATTRIB,CH);
  2171. END;
  2172.  
  2173. PROCEDURE GET_DOS_VER;
  2174. VAR
  2175.   VER   : WORD;
  2176.   TEMP,
  2177.   TEMP2 : STRING[4];
  2178. BEGIN
  2179.   VER := DOSVERSION;
  2180.   STR(LO(VER),TEMP);
  2181.   STR(HI(VER),TEMP2);
  2182.   DOS_VER := TEMP + '.' + TEMP2;
  2183. END;
  2184.  
  2185. FUNCTION RANDOM_NUMBER(LOW, HIGH : INTEGER) : INTEGER;
  2186. VAR
  2187.   H,M,S,S100 : WORD;
  2188. BEGIN
  2189.   IF (LOW < 0) OR (HIGH > 99) THEN
  2190.     BEGIN
  2191.       RANDOM_NUMBER := 0;
  2192.       EXIT;
  2193.     END;
  2194.   REPEAT
  2195.     GETTIME(H,M,S,S100);
  2196.   UNTIL (S100 >= LOW) AND (S100 <= HIGH);
  2197.   RANDOM_NUMBER := S100;
  2198. END;
  2199.  
  2200. FUNCTION FILE_EXIST(FILENAME : STRING) : BOOLEAN;
  2201. VAR
  2202.   INF : SEARCHREC;
  2203. BEGIN
  2204.   FINDFIRST(FILENAME,ANYFILE-DIRECTORY,INF);
  2205.   FILE_EXIST := (DOSERROR = 0);
  2206. END;
  2207.  
  2208. PROCEDURE BEEP;
  2209. BEGIN
  2210.   SOUND(400);
  2211.   DELAY(150);
  2212.   SOUND(300);
  2213.   DELAY(100);
  2214.   NOSOUND;
  2215. END;
  2216.  
  2217. PROCEDURE READSTR_BIG(X,Y,LEN : INTEGER;
  2218.                         PATTR : INTEGER;
  2219.                        PROMPT : STR80;
  2220.                         IATTR : INTEGER;
  2221.                  VAR INSTRING : STRING;
  2222.                         VALID : ETYPE;
  2223.                       CANEDIT : CTYPE;
  2224.                        EXITCH : ETYPE;
  2225.                        XLOC,
  2226.                        YLOC   : INTEGER;
  2227.                        CH1    : CHAR;
  2228.                        WIN    : INTEGER);
  2229. VAR
  2230.   I,
  2231.   XX,
  2232.   START,
  2233.   OFS    : INTEGER;
  2234.   CAPIT,
  2235.   CAPWO,
  2236.   INSON  : BOOLEAN;
  2237.   SAVECH : CHAR;
  2238.  
  2239. BEGIN
  2240.   OLDVAL := INSTRING;
  2241.   INSON := FALSE;
  2242.   IF X_IN > LEN THEN
  2243.     X_IN := LEN;
  2244.   IF X_IN > WIN THEN
  2245.     OFS   := X_IN
  2246.   ELSE
  2247.     OFS   := 1;                
  2248.   IF OFS + WIN > LEN THEN
  2249.     OFS := LEN - WIN + 1;
  2250.   IF YLOC > 199 THEN
  2251.     BEGIN
  2252.       CAPIT := TRUE;
  2253.       YLOC := YLOC - 200;
  2254.     END
  2255.   ELSE
  2256.     BEGIN
  2257.       CAPIT := FALSE;
  2258.       IF YLOC > 99 THEN
  2259.         BEGIN
  2260.           YLOC := YLOC - 100;
  2261.           CAPWO := TRUE;
  2262.         END
  2263.       ELSE
  2264.         CAPWO := FALSE;
  2265.     END;
  2266.   IF CLEAR IN EXITCH THEN
  2267.     INSTRING := SPACES(LEN)
  2268.   ELSE
  2269.     INSTRING := PAD(INSTRING,LEN);
  2270.   FW(X,Y,PATTR,PROMPT);
  2271.   START := X + LENGTH(PROMPT);
  2272.   IF X_IN > WIN THEN
  2273.     X := X_IN - OFS + 1
  2274.   ELSE
  2275.     X := X_IN;
  2276.   FW(START,Y,IATTR,COPY(INSTRING,OFS,WIN));
  2277.   IF XLOC > 99 THEN
  2278.     BEGIN
  2279.       X := LEN;
  2280.       XLOC := XLOC - 100;
  2281.     END;                
  2282.  
  2283.   SET_CURSOR(UNDERLINE);
  2284.   IF NOT (DISPLAY IN EXITCH) THEN
  2285.     REPEAT
  2286.  
  2287.       FW(START,Y,IATTR,COPY(INSTRING,OFS,WIN));
  2288.  
  2289.       GOTOXY(START+X-1,Y);
  2290.       CH := CH1;
  2291.       READCHTIME(CH,FALSE,XLOC,YLOC);
  2292.       SAVECH := CH;
  2293.       CASE CH OF
  2294.           HOMEKEY : BEGIN
  2295.                       OFS := 1;
  2296.                       X := 1;
  2297.                     END;
  2298.            ENDKEY : BEGIN
  2299.                       X := LEN;
  2300.                       WHILE (X > 2) AND (INSTRING[X-1] = ' ') DO
  2301.                         X := PRED(X);
  2302.                       IF (X = 1) AND (INSTRING[1] = ' ') THEN
  2303.                         X := 1;
  2304.                       OFS := X - (WIN - 2);
  2305.                       IF OFS < 1 THEN OFS := 1;
  2306.                       X := WIN;
  2307.                       WHILE (X > 1) AND (INSTRING[X+OFS-2] = ' ') DO
  2308.                         X := PRED(X);
  2309.                       IF X + OFS > LEN THEN
  2310.                         OFS := PRED(OFS);
  2311.                     END;
  2312.                #8 : IF (X > 1) THEN
  2313.                       BEGIN
  2314.                         DELETE(INSTRING,X-1+OFS-1,1);
  2315.                         INSTRING := INSTRING + ' ';
  2316.                         X := PRED(X);
  2317.                       END
  2318.                     ELSE
  2319.                       IF X > 1 THEN
  2320.                         X := PRED(X)
  2321.                       ELSE
  2322.                         BEGIN
  2323.                           SAVECH := CH;
  2324.                           IF NOCONV IN EXITCH THEN
  2325.                             CH := NOCONV
  2326.                           ELSE
  2327.                             CH := UP;
  2328.                         END;
  2329.             RIGHT : IF X < WIN THEN
  2330.                       X := SUCC(X)
  2331.                     ELSE
  2332.                       IF OFS + WIN <= LEN THEN
  2333.                         OFS := SUCC(OFS)
  2334.                       ELSE
  2335.                         BEGIN
  2336.                           SAVECH := CH;
  2337.                           IF NOCONV IN EXITCH THEN
  2338.                             CH := NOCONV
  2339.                           ELSE
  2340.                             CH := DOWN;
  2341.                         END;
  2342.              LEFT : IF X > 1 THEN
  2343.                       X := PRED(X)
  2344.                     ELSE
  2345.                       IF OFS > 1 THEN
  2346.                         OFS := PRED(OFS)
  2347.                       ELSE
  2348.                         BEGIN
  2349.                           SAVECH := CH;
  2350.                           IF NOCONV IN EXITCH THEN
  2351.                             CH := NOCONV
  2352.                           ELSE
  2353.                             CH := UP;
  2354.                         END;
  2355.          ' '..'~' : IF CH IN VALID THEN
  2356.                       IF INSON THEN
  2357.                         BEGIN
  2358.                           IF INSTRING[LEN] = ' ' THEN
  2359.                             BEGIN
  2360.                               DELETE(INSTRING,LENGTH(INSTRING),1);
  2361.                               IF (CAPWO AND ((X = 1) OR (INSTRING[X+OFS-2] = ' '))) OR
  2362.                                  CAPIT THEN
  2363.                                 CH := UPCASE(CH);
  2364.                               INSERT(CH,INSTRING,X+OFS-1);
  2365.                               IF X < WIN THEN
  2366.                                 X := SUCC(X)
  2367.                               ELSE
  2368.                                 IF OFS + WIN <= LEN THEN
  2369.                                   OFS := SUCC(OFS)
  2370.                                 ELSE
  2371.                                   BEGIN
  2372.                                     SAVECH := RIGHT;
  2373.                                     IF NOCONV IN EXITCH THEN
  2374.                                       CH := NOCONV
  2375.                                     ELSE
  2376.                                       CH := DOWN;
  2377.                                   END;
  2378.                             END
  2379.                           ELSE
  2380.                             BEEP;
  2381.                         END
  2382.                       ELSE
  2383.                         BEGIN
  2384.                           IF (CAPWO AND ((X = 1) OR (INSTRING[X+OFS-2] = ' '))) OR
  2385.                              CAPIT THEN
  2386.                             CH := UPCASE(CH);
  2387.                           INSTRING[X+OFS-1] := CH;
  2388.                           IF X < WIN THEN
  2389.                             X := SUCC(X)
  2390.                           ELSE
  2391.                             IF OFS + WIN <= LEN THEN
  2392.                               OFS := SUCC(OFS)
  2393.                             ELSE
  2394.                               BEGIN
  2395.                                 SAVECH := RIGHT;
  2396.                                 IF NOCONV IN EXITCH THEN
  2397.                                   CH := NOCONV
  2398.                                 ELSE
  2399.                                   CH := DOWN;
  2400.                               END;
  2401.                         END;
  2402.            INSKEY : BEGIN
  2403.                       INSON := NOT INSON;
  2404.                       IF INSON THEN
  2405.                         SET_CURSOR(BLOCK)
  2406.                       ELSE
  2407.                         BEGIN
  2408.                           SET_CURSOR(UNDERLINE);
  2409.                           INSON := FALSE;
  2410.                         END;
  2411.                     END;
  2412.            DELKEY : BEGIN
  2413.                       DELETE(INSTRING,X+OFS-1,1);
  2414.                       INSTRING := INSTRING + ' ';
  2415.                       GOTOXY(START,Y);
  2416.                     END;
  2417.             ALT_C : BEGIN
  2418.                       FOR I := 1 TO LEN DO
  2419.                         INSTRING[I] := ' ';
  2420.                       X := 1;
  2421.                       OFS := 1;
  2422.                     END;
  2423.       END;
  2424.       FW(START,Y,IATTR,COPY(INSTRING,OFS,WIN));
  2425.       IF X > LEN THEN X := LEN;
  2426.     UNTIL (CH = #27) OR (CH IN EXITCH);
  2427.   IF NOCONV IN EXITCH THEN
  2428.     CH := SAVECH;
  2429.   X_IN := 1;
  2430.   X_OUT := X+OFS-1;
  2431.   SET_CURSOR(UNDERLINE);
  2432.   CHANGED := INSTRING <> OLDVAL;
  2433. END;
  2434.  
  2435.  
  2436. FUNCTION CHECK_KEYBOARD : CHAR;
  2437. VAR
  2438.   CH : CHAR;
  2439. BEGIN
  2440.   IF KEYPRESSED OR (COMMAND_BUFFER <> '') THEN
  2441.     BEGIN
  2442.       READCH(CH,FALSE);
  2443.       CHECK_KEYBOARD := CH;
  2444.     END
  2445.   ELSE
  2446.     CHECK_KEYBOARD := #0;
  2447. END;
  2448.  
  2449. PROCEDURE CENTER_PRINT(LINE     : STRING;
  2450.                         LEN     : INTEGER;
  2451.                     VAR NEXTPOS : INTEGER;
  2452.                         CR      : BOOLEAN);
  2453. BEGIN
  2454.   NEXTPOS := ((LEN DIV 2) + (LENGTH(LINE) DIV 2)) + 1;
  2455.   IF CR THEN
  2456.     WRITELN(LST,LINE:NEXTPOS-1)
  2457.   ELSE
  2458.     WRITE(LST,LINE:NEXTPOS-1);
  2459. END;
  2460.  
  2461. PROCEDURE DISP_NOPROMPT_MESSAGE(X,Y,LEN,ATTR : INTEGER; MESS : STR80);
  2462. BEGIN
  2463.   FW(X,Y,ATTR,PAD(MESS,LEN));
  2464.   GOTOXY(X+LEN-1,Y);
  2465. END;
  2466.  
  2467. PROCEDURE DISP_MESSAGE(X,Y,LEN,ATTR : INTEGER; MESS : STR80);
  2468. BEGIN
  2469.   FW(X,Y,ATTR,PAD(MESS,LEN));
  2470.   GOTOXY(X+LEN-1,Y);
  2471.   READCH(CH,FALSE);
  2472. END;
  2473.  
  2474. PROCEDURE CLEAR_BUFFER(VAR SCREEN : BUFFER;
  2475.                          ATTR : INTEGER);
  2476. VAR
  2477.   I : INTEGER;
  2478. BEGIN
  2479.   I := 1;
  2480.   REPEAT
  2481.     SCREEN[I] := ' ';
  2482.     SCREEN[I+1] := CHAR(ATTR);
  2483.     I := I + 2;
  2484.   UNTIL I > 3999;
  2485. END;
  2486.  
  2487. PROCEDURE FWB(VAR SCREEN : BUFFER;
  2488.                 X,Y,ATTR : INTEGER;
  2489.                 INSTRING : STR80);
  2490. VAR
  2491.   I,Z : INTEGER;
  2492. BEGIN
  2493.   Z := (((Y * 160) - 160) + (X * 2)) - 1;
  2494.   FOR I := 1 TO LENGTH(INSTRING) DO
  2495.     IF Z < 4000 THEN
  2496.       BEGIN
  2497.         SCREEN[Z] := INSTRING[I];
  2498.         SCREEN[Z+1] := CHR(ATTR);
  2499.         Z := Z + 2;
  2500.       END;
  2501. END;
  2502.  
  2503. FUNCTION CREATE_NEW_FILE(FILENAME, MESS : STR80) : BOOLEAN;
  2504. VAR
  2505.   CH : CHAR;
  2506.   SC : BUFFER;
  2507. BEGIN
  2508.   SAVE_SCREEN(SC);
  2509.   FW(10,15,$04,'╒══════════════════════════════════════════════════╕');
  2510.   FW(10,16,$04,'│               FILE NOT FOUND !!                  │');
  2511.   FW(10,17,$04,'│                                                  │');
  2512.   FW(10,18,$04,'│                                                  │');
  2513.   FW(10,19,$04,'│                                                  │');
  2514.   FW(10,20,$04,'│   Contact:                                       │');
  2515.   FW(10,21,$04,'│                                                  │');
  2516.   FW(10,22,$04,'│        Press <any Key> to Abort Program          │');
  2517.   FW(10,23,$04,'╘══════════════════════════════════════════════════╛');
  2518.   FW(28,18,$0F,FILENAME);
  2519.   FW(23,20,$0F,MESS);
  2520.   GOTOXY(52,22);
  2521.   WHILE KEYPRESSED DO
  2522.     CH := READKEY;
  2523.   READCH(CH,FALSE);
  2524.   CREATE_NEW_FILE := CH = AF1;
  2525.   REBUILD_SCREEN(SC);
  2526. END;
  2527.  
  2528. FUNCTION INT_STR(I,LEN : INTEGER) : STR80;
  2529. VAR
  2530.   TEMP   : STR80;
  2531. BEGIN
  2532.   STR(I:LEN,TEMP);
  2533.   INT_STR := TEMP;
  2534. END;
  2535.  
  2536. FUNCTION REAL_STR(R : REAL; LEN, PLACES : INTEGER) : STR80;
  2537. VAR
  2538.   TEMP   : STR80;
  2539. BEGIN
  2540.   STR(R:LEN:PLACES,TEMP);
  2541.   REAL_STR := TEMP;
  2542. END;
  2543.  
  2544. FUNCTION LONGINT_STR(I : LONGINT; LEN : INTEGER) : STR80;
  2545. VAR
  2546.   TEMP   : STR80;
  2547. BEGIN
  2548.   STR(I:LEN,TEMP);
  2549.   LONGINT_STR := TEMP;
  2550. END;
  2551.  
  2552. FUNCTION DATE_TIME_KEY : STR16;
  2553. VAR
  2554.   YEAR, MON, DAY, DOW,
  2555.   HOUR, MIN, SEC, SEC100 : WORD;
  2556.   TEMP1,
  2557.   TEMP2                  : STR16;
  2558. BEGIN
  2559.   GETDATE(YEAR,MON,DAY,DOW);
  2560.   GETTIME(HOUR,MIN,SEC,SEC100);
  2561.   STR(YEAR:4,TEMP1);
  2562.   STR(MON:2,TEMP2);
  2563.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2564.   TEMP1 := TEMP1 + TEMP2;
  2565.   STR(DAY:2,TEMP2);
  2566.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2567.   TEMP1 := TEMP1 + TEMP2;
  2568.   STR(HOUR:2,TEMP2);
  2569.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2570.   TEMP1 := TEMP1 + TEMP2;
  2571.   STR(MIN:2,TEMP2);
  2572.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2573.   TEMP1 := TEMP1 + TEMP2;
  2574.   STR(SEC:2,TEMP2);
  2575.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2576.   TEMP1 := TEMP1 + TEMP2;
  2577.   STR(SEC100:2,TEMP2);
  2578.   IF TEMP2[1] = ' ' THEN TEMP2[1] := '0';
  2579.   TEMP1 := TEMP1 + TEMP2;
  2580.   DATE_TIME_KEY := TEMP1;
  2581. END;
  2582.  
  2583. FUNCTION STRIP(ST : STRING; IMBED : BOOLEAN) : STRING;
  2584. BEGIN
  2585.   WHILE (LENGTH(ST) > 0) AND (ST[1] = ' ') DO
  2586.     DELETE(ST,1,1);
  2587.   WHILE (LENGTH(ST) > 0) AND (ST[LENGTH(ST)] = ' ') DO
  2588.     DELETE(ST,LENGTH(ST),1);
  2589.   IF IMBED THEN
  2590.     WHILE POS('  ',ST) > 0 DO
  2591.       DELETE(ST,POS('  ',ST),1);
  2592.   STRIP := ST;
  2593. END;
  2594.  
  2595. FUNCTION KEY_TO_DATE(ST : STRING) : STRING;
  2596. VAR
  2597.   INT : INTEGER;
  2598.   IND : STRING[2];
  2599.   TMP : STRING[2];
  2600. BEGIN
  2601.   INT := _INTEGER(COPY(ST,9,2));
  2602.   IF INT > 11 THEN
  2603.     IND := 'pm'
  2604.   ELSE
  2605.     IND := 'am';
  2606.   IF INT > 12 THEN
  2607.     INT := INT - 12;
  2608.   TMP := INT_STR(INT,2);
  2609.   IF TMP[1] = ' ' THEN TMP[1] := '0';
  2610.   KEY_TO_DATE := COPY(ST,5,2)+'-'+COPY(ST,7,2)+'-'+COPY(ST,1,4)+'   '+
  2611.                   TMP+':'+COPY(ST,11,2)+' '+IND;
  2612. END;
  2613.  
  2614. function Julian(DT : STR8) : longint;
  2615. var
  2616.    Temp, Y, M, D  : longint;
  2617.    Year, Mon, Day : integer;
  2618. begin
  2619.    YEAR := _INTEGER(COPY(DT,7,2));
  2620.    MON  := _INTEGER(COPY(DT,1,2));
  2621.    DAY  := _INTEGER(COPY(DT,4,2));
  2622.    if (Year < 0) or (Mon < 1) or (Mon > 12)             {Mod. #1}
  2623.                  or (Day < 1) or (Day > 31) then
  2624.       begin
  2625.          Julian := -1;
  2626.          exit
  2627.       end;
  2628.    Y := Year;  M := Mon;  D := Day;
  2629.    if Y < 100 then Y := Y + 1900;                       {Mod. #1}
  2630.    Temp   := (M - 14) div 12;
  2631.    Julian := D - 32075 +
  2632.              (1461 * (Y + 4800 + Temp) div 4) +
  2633.              (367 * (M - 2 - Temp * 12) div 12) -
  2634.              (3 * ((Y + 4900 + Temp) div 100) div 4)
  2635. end;
  2636.  
  2637. FUNCTION JulToMDY(JulianDay: longint) : STR8;
  2638. var
  2639.    TempA, TempB, TempC : longint;
  2640.    MON, YEAR, DAY      : INTEGER;
  2641.    TEMP                : STRING[10];
  2642. begin
  2643.    TempA := JulianDay + 68569;
  2644.    TempB := 4 * TempA div 146097;
  2645.    TempA := TempA - (146097 * TempB + 3) div 4;
  2646.    Year  := 4000 * (TempA + 1) div 1461001;
  2647.    TempC := Year;
  2648.    TempA := TempA - (1461 * TempC div 4) + 31;
  2649.    Mon   := 80 * TempA div 2447;
  2650.    TempC := Mon;
  2651.    Day   := TempA - (2447 * TempC div 80);
  2652.    TempA := Mon div 11;
  2653.    Mon   := Mon + 2 - (12 * TempA);
  2654.    Year  := 100 * (TempB - 49) + Year + TempA;
  2655.    TEMP := INT_STR(MON,2) + '-' + INT_STR(DAY,2) + '-' + INT_STR(YEAR,4);
  2656.    IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  2657.    IF TEMP[4] = ' ' THEN TEMP[4] := '0';
  2658.    DELETE(TEMP,7,2);
  2659.    JULTOMDY := TEMP;
  2660. end;
  2661.  
  2662. procedure DayWeek(DT : STR8; var DayNum: integer;
  2663.                   var DayName: Str3);
  2664. VAR
  2665.   CENTURY,
  2666.   Tmp      : Integer;
  2667.   YEAR,
  2668.   MONTH,
  2669.   DAY      : WORD;
  2670. Begin
  2671.   VAL(COPY(DT,7,2),YEAR,TMP);
  2672.   VAL(COPY(DT,1,2),MONTH,TMP);
  2673.   VAL(COPY(DT,4,2),DAY,TMP);
  2674.   If Year < 1900 then
  2675.      Inc(Year,1900);
  2676.   If Month < 3 then
  2677.      Inc(Month, 10)
  2678.   else
  2679.      Dec(Month, 2);
  2680.   If Month > 10 then
  2681.      Dec(Year);
  2682.   Century := Year div 100;
  2683.   Year := Year mod 100;
  2684.   Tmp := Trunc((2.6 * Month - 0.2) + Day + Year + (Year div 4) +
  2685.      (Century div 4) - (2 * Century));
  2686.   DAYNUM := (Tmp + 777) mod 7;
  2687.   CASE DAYNUM OF
  2688.       0 : DAYNAME := 'Sun';
  2689.       1 : DAYNAME := 'Mon';
  2690.       2 : DAYNAME := 'Tue';
  2691.       3 : DAYNAME := 'Wed';
  2692.       4 : DAYNAME := 'Thu';
  2693.       5 : DAYNAME := 'Fri';
  2694.       6 : DAYNAME := 'Sat';
  2695.   END;
  2696. End;
  2697.  
  2698. FUNCTION DUP(MASK : CHAR; N : INTEGER) : STRING;
  2699. VAR
  2700.   ST : STRING;
  2701. BEGIN
  2702.   FILLCHAR(ST,SIZEOF(ST),MASK);
  2703.   IF (N < 256) AND (N > 0) THEN
  2704.     ST[0] := CHR(N)
  2705.   ELSE
  2706.     ST[0] := CHR(0);
  2707.   DUP := ST;
  2708. END;
  2709.  
  2710. PROCEDURE POP_WINDOW(X1,Y1,X2,Y2 : INTEGER; STYLE : INTEGER; ATTR : BYTE);
  2711. VAR
  2712.   I,
  2713.   SHADOW       : BYTE;
  2714.   URCORNER,
  2715.   ULCORNER,
  2716.   LRCORNER,
  2717.   LLCORNER,
  2718.   VERTICAL,
  2719.   HORIZONTAL   : CHAR;
  2720. BEGIN
  2721.   CASE STYLE OF
  2722.      0,
  2723.     10 : BEGIN
  2724.            URCORNER   := ' ';
  2725.            ULCORNER   := ' ';
  2726.            LRCORNER   := ' ';
  2727.            LLCORNER   := ' ';
  2728.            VERTICAL   := ' ';
  2729.            HORIZONTAL := ' ';
  2730.          END;
  2731.      1,
  2732.     11  : BEGIN
  2733.            URCORNER   := '┐';
  2734.            ULCORNER   := '┌';
  2735.            LRCORNER   := '┘';
  2736.            LLCORNER   := '└';
  2737.            VERTICAL   := '│';
  2738.            HORIZONTAL := '─';
  2739.          END;
  2740.     ELSE BEGIN
  2741.            URCORNER   := '╗';
  2742.            ULCORNER   := '╔';
  2743.            LRCORNER   := '╝';
  2744.            LLCORNER   := '╚';
  2745.            VERTICAL   := '║';
  2746.            HORIZONTAL := '═';
  2747.          END;
  2748.   END;
  2749.   FW(X1,Y1,ATTR,ULCORNER+DUP(HORIZONTAL,X2-X1-1)+URCORNER);
  2750.   FOR I := Y1 + 1 TO Y2 - 1 DO
  2751.     FW(X1,I,ATTR,VERTICAL+DUP(' ',X2-X1-1)+VERTICAL);
  2752.   FW(X1,Y2,ATTR,LLCORNER+DUP(HORIZONTAL,X2-X1-1)+LRCORNER);
  2753.  
  2754.   IF STYLE < 10 THEN
  2755.     IF (X2 < 80) AND (Y2 < 25) THEN
  2756.       BEGIN
  2757.         SHADOW := $07;
  2758.         IF Y2 < 25 THEN
  2759.           SET_ATTR([X1+2..X2+2],Y2+1,SHADOW);
  2760.         FOR I := Y1 + 1 TO Y2 + 1 DO
  2761.           IF I <= 25 THEN
  2762.             SET_ATTR([X2+1,X2+2],I,SHADOW);
  2763.       END;
  2764. END;
  2765.  
  2766. FUNCTION GET_FILE_INFO(FILENAME : STRING) : STR80;
  2767. VAR
  2768.   F         : FILE OF BYTE;
  2769.   SAVE_MODE : BYTE;
  2770.   DT        : DATETIME;
  2771.   DATE,
  2772.   SIZE      : LONGINT;
  2773.                                  
  2774.        FUNCTION CONVERT_DATE : STRING;
  2775.        VAR
  2776.          IND         : CHAR;
  2777.          TEMP, TEMP2 : STRING;
  2778.        BEGIN
  2779.          UNPACKTIME(DATE,DT);
  2780.          STR(DT.MONTH:2,TEMP2);
  2781.          STR(DT.DAY:2,TEMP);
  2782.          IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  2783.          TEMP2 := TEMP2 + '-' + TEMP;
  2784.          STR(DT.YEAR:4,TEMP);
  2785.          TEMP2 := TEMP2 + '-' + COPY(TEMP,3,2);
  2786.          IF DT.HOUR >= 12 THEN
  2787.            BEGIN
  2788.              IND := 'p';
  2789.              IF DT.HOUR > 12 THEN
  2790.                DT.HOUR := DT.HOUR - 12;
  2791.            END
  2792.          ELSE
  2793.            IND := 'a';
  2794.          STR(DT.HOUR:2,TEMP);
  2795.          TEMP2 := TEMP2 + ' ' + TEMP + ':';
  2796.          STR(DT.MIN:2,TEMP);
  2797.          IF TEMP[1] = ' ' THEN TEMP[1] := '0';
  2798.          TEMP2 := TEMP2 + TEMP + IND;
  2799.          IF (DT.HOUR=0) AND (DT.MIN=0) AND (DT.SEC=0) THEN
  2800.            BEGIN
  2801.              TEMP2 := COPY(TEMP2,1,10);
  2802.              TEMP2 := TEMP2 + SPACES(5);
  2803.            END;
  2804.          CONVERT_DATE := TEMP2;
  2805.        END;
  2806.  
  2807. BEGIN
  2808.   SAVE_MODE := FILEMODE;
  2809.   FILEMODE  := 0;
  2810.   ASSIGN(F,FILENAME);
  2811.   {$I-}
  2812.     RESET(F);
  2813.   {$I+}
  2814.   IF IORESULT = 0 THEN
  2815.     BEGIN
  2816.       SIZE := FILESIZE(F);
  2817.       GETFTIME(F,DATE);
  2818.       CLOSE(F);
  2819.       GET_FILE_INFO := LONGINT_STR(SIZE,9)+' '+CONVERT_DATE;
  2820.     END
  2821.   ELSE
  2822.     GET_FILE_INFO := '';
  2823.   FILEMODE := SAVE_MODE;
  2824. END;
  2825.  
  2826. PROCEDURE SAVE_LINE(Y : INTEGER; VAR STR : BUF160);
  2827. VAR
  2828.   Z : INTEGER;
  2829. BEGIN
  2830.   Z := (((Y * 160) - 160) + 2) - 1;
  2831.   MOVE(P^[Z],STR,160);
  2832. END;
  2833.  
  2834. PROCEDURE REBUILD_LINE(Y : INTEGER; STR : BUF160);
  2835. VAR
  2836.   Z : INTEGER;
  2837. BEGIN
  2838.   Z := (((Y * 160) - 160) + 2) - 1;
  2839.   MOVE(STR,P^[Z],160);
  2840. END;
  2841.  
  2842. PROCEDURE FILL_SCREEN(X1,Y1,X2,Y2 : INTEGER; CH : CHAR; ATTR : INTEGER);
  2843. VAR
  2844.   X,Y,
  2845.   Z   : INTEGER;
  2846.   SC  : BUFFER;
  2847. BEGIN
  2848.   SAVE_SCREEN(SC);
  2849.   FOR Y := Y1 TO Y2 DO
  2850.     FOR X := X1 TO X2 DO
  2851.       BEGIN
  2852.         Z := (((Y * 160) - 160) + (X * 2)) - 1;
  2853.         SC[Z] := CH;
  2854.         SC[Z+1] := CHR(ATTR);
  2855.       END;
  2856.   REBUILD_SCREEN(SC);
  2857. END;
  2858.  
  2859. FUNCTION PROGRAM_LOCATION : STRING;
  2860. VAR
  2861.   TEMP,
  2862.   DIR,
  2863.   NAME,
  2864.   EXT    : STRING;
  2865. BEGIN
  2866.   TEMP := PARAMSTR(0);
  2867.   FSPLIT(TEMP,DIR,NAME,EXT);
  2868.   PROGRAM_LOCATION := DIR;
  2869. END;
  2870.  
  2871. PROCEDURE REBOOT;
  2872. BEGIN
  2873. INLINE(
  2874.   $B8/$40/$00/
  2875.   $8E/$D8/
  2876.   $C7/$06/$72/$00/$34/$12/
  2877.   $EA/$00/$00/$FF/$FF);
  2878. END;
  2879.  
  2880. procedure SetBlink(On : Boolean);
  2881.   {-Enable text mode attribute blinking if On is True}
  2882. const
  2883.   PortVal : array[0..4] of Byte = ($0C, $08, $0D, $09, $09);
  2884. var
  2885.   PortNum : Word;
  2886.   Index : Byte;
  2887.   PVal : Byte;
  2888. begin
  2889.   IF EGA_PRESENT THEN
  2890.     begin
  2891.         inline(
  2892.           $8A/$5E/<On/     {mov bl,[bp+<On]}
  2893.           $B8/$03/$10/     {mov ax,$1003}
  2894.           $CD/$10);        {int $10}
  2895.         Exit;
  2896.     end
  2897.   ELSE
  2898.     IF CGA_PRESENT THEN
  2899.       begin
  2900.         PortNum := $3D8;
  2901.         case LastMode of
  2902.           0..3 : Index := LastMode;
  2903.           else Exit;
  2904.         end;
  2905.       end
  2906.     ELSE
  2907.       begin
  2908.         PortNum := $3B8;
  2909.         Index := 4;
  2910.       end;
  2911.   PVal := PortVal[Index];
  2912.   if On then
  2913.     PVal := PVal or $20;
  2914.   Port[PortNum] := PVal;
  2915. end;
  2916.  
  2917. PROCEDURE BLINK_OFF;
  2918. BEGIN
  2919.   SetBlink(False);
  2920.   BLINK_IS_ON := FALSE;
  2921. END;
  2922.  
  2923. PROCEDURE BLINK_ON;
  2924. BEGIN
  2925.   SetBlink(True);
  2926.   BLINK_IS_ON := TRUE;
  2927. END;                       
  2928.  
  2929. PROCEDURE SET_BORDER(COLOR : INTEGER);
  2930. VAR
  2931.   REGS         : REGISTERS;
  2932.   MONITOR_INFO : BYTE ABSOLUTE $0040:$0010;
  2933. BEGIN                         
  2934.   CURRENT_BORDER := COLOR;
  2935.   IF (EGA_PRESENT) OR (VGA_PRESENT) THEN
  2936.     BEGIN
  2937.       REGS.AH := $10;
  2938.       REGS.AL := 1;
  2939.       REGS.BH := COLOR;
  2940.       INTR($10,REGS);
  2941.     END
  2942.   ELSE
  2943.     PORT[$03D9]:=15 AND COLOR;
  2944. END;
  2945.  
  2946. PROCEDURE SCREEN_ON;
  2947. VAR
  2948.   REGS         : REGISTERS;
  2949.   MONITOR_INFO : BYTE ABSOLUTE $0040:$0010;
  2950. BEGIN
  2951.   IF EGA_PRESENT OR VGA_PRESENT THEN
  2952.     BEGIN
  2953.       REGS.AH := $12;
  2954.       REGS.AL := 0;
  2955.       REGS.BL := $36;
  2956.       INTR($10,REGS);
  2957.     END
  2958.   ELSE
  2959.     BEGIN         
  2960.       IF MONITOR_INFO AND 48 = 48 THEN
  2961.         PORT[952]:=255
  2962.       ELSE
  2963.         PORT[984]:=41;
  2964.     END;
  2965.   SET_BORDER(CURRENT_BORDER);
  2966. END;
  2967.  
  2968. PROCEDURE SCREEN_OFF;
  2969. VAR
  2970.   REGS         : REGISTERS;
  2971.   MONITOR_INFO : BYTE ABSOLUTE $0040:$0010;
  2972. BEGIN
  2973.   IF EGA_PRESENT OR VGA_PRESENT THEN
  2974.     BEGIN
  2975.       REGS.AH := $12;
  2976.       REGS.AL := 1;
  2977.       REGS.BL := $36;
  2978.       INTR($10,REGS);
  2979.     END
  2980.   ELSE
  2981.     BEGIN
  2982.       IF MONITOR_INFO AND 48 = 48 THEN
  2983.         PORT[952]:=1
  2984.       ELSE
  2985.         PORT[984]:=1;
  2986.     END;
  2987.   IF (EGA_PRESENT) OR (VGA_PRESENT) THEN
  2988.     BEGIN
  2989.       REGS.AH := $10;
  2990.       REGS.AL := 1;
  2991.       REGS.BH := 0;
  2992.       INTR($10,REGS);
  2993.     END
  2994.   ELSE
  2995.     PORT[$03D9]:=15 AND 0;
  2996. END;
  2997.  
  2998. PROCEDURE POP_MESSAGE(X,Y : INTEGER; BORDER, ATTR : BYTE;
  2999.                          MATTR : BYTE; MESSAGE : STR80);
  3000. BEGIN
  3001.   IF X = 0 THEN
  3002.     X := 40 - ((LENGTH(MESSAGE) + 3) DIV 2);
  3003.   POP_WINDOW(X,Y,X+LENGTH(MESSAGE)+3,Y+2,BORDER,ATTR);
  3004.   FW(X+2,Y+1,MATTR,MESSAGE);
  3005.   GOTOXY(X+LENGTH(MESSAGE)+2,Y+1);
  3006. END;
  3007.  
  3008. PROCEDURE POP_WINDOW_TITLE(   X,Y,X1,Y1 : INTEGER;
  3009.                            BORDER, ATTR : BYTE;
  3010.                                   TATTR,
  3011.                                      TY : BYTE;
  3012.                                   TITLE : STR80);
  3013. BEGIN
  3014.   POP_WINDOW(X,Y,X1,Y1,BORDER,ATTR);
  3015.   FW((X+((X1-X) DIV 2) - (LENGTH(TITLE) DIV 2)),TY,TATTR,+' '+TITLE+' ');
  3016. END;
  3017.  
  3018. FUNCTION SHIFT_KEYS(KEY : CHAR) : BOOLEAN;
  3019.  { KEY = 'R' for Right, 'L' for Left, 'C' for Control, 'A' for Alt }
  3020. VAR
  3021.   KEYBOARD : BYTE ABSOLUTE $0040:$0017;
  3022. BEGIN
  3023.   CASE UPCASE(KEY) OF
  3024.      'R' : SHIFT_KEYS := KEYBOARD AND 1 = 1;
  3025.      'L' : SHIFT_KEYS := KEYBOARD AND 2 = 2;
  3026.      'C' : SHIFT_KEYS := KEYBOARD AND 4 = 4;
  3027.      'A' : SHIFT_KEYS := KEYBOARD AND 8 = 8;
  3028.   END;
  3029. END;
  3030.  
  3031. procedure MasterEnv;
  3032.   {-Return master environment record}
  3033. var
  3034.   Owner : Word;
  3035.   Mcb : Word;
  3036.   Eseg : Word;
  3037.   Done : Boolean;
  3038. begin
  3039.   with Env_Rec do begin
  3040.     FillChar(Env_Rec, SizeOf(Env_Rec), 0);
  3041.  
  3042.     {Interrupt $2E points into COMMAND.COM}
  3043.     Owner := MemW[0:(2+4*$2E)];
  3044.  
  3045.     {Mcb points to memory control block for COMMAND}
  3046.     Mcb := Owner-1;
  3047.     if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  3048.       Exit;
  3049.  
  3050.     {Read segment of environment from PSP of COMMAND}
  3051.     Eseg := MemW[Owner:$2C];
  3052.  
  3053.     {Earlier versions of DOS don't store environment segment there}
  3054.     if Eseg = 0 then begin
  3055.       {Master environment is next block past COMMAND}
  3056.       Mcb := Owner+MemW[Mcb:3];
  3057.       if (Mem[Mcb:0] <> Byte('M')) or (MemW[Mcb:1] <> Owner) then
  3058.         {Not the right memory control block}
  3059.         Exit;
  3060.       Eseg := Mcb+1;
  3061.     end else
  3062.       Mcb := Eseg-1;
  3063.  
  3064.     {Return segment and length of environment}
  3065.     EnvSeg := Eseg;
  3066.     EnvLen := MemW[Mcb:3] shl 4;
  3067.   end;
  3068. end;
  3069.  
  3070. procedure SkipAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word);
  3071.   {-Skip to end of current AsciiZ string}
  3072. begin
  3073.   while EPtr^[EOfs] <> #0 do
  3074.     Inc(EOfs);
  3075. end;
  3076.  
  3077. function EnvNext(EPtr : EnvArrayPtr) : Word;
  3078.   {-Return the next available location in environment at EPtr^}
  3079. var
  3080.   EOfs : Word;
  3081. begin
  3082.   EOfs := 0;
  3083.   if EPtr <> nil then begin
  3084.     while EPtr^[EOfs] <> #0 do begin
  3085.       SkipAsciiZ(EPtr, EOfs);
  3086.       Inc(EOfs);
  3087.     end;
  3088.   end;
  3089.   EnvNext := EOfs;
  3090. end;
  3091.  
  3092. function StUpcase(S : string) : string;
  3093.   {-Uppercase a string}
  3094. var
  3095.   SLen : byte absolute S;
  3096.   I : Integer;
  3097. begin
  3098.   for I := 1 to SLen do
  3099.     S[I] := UpCase(S[I]);
  3100.   StUpcase := S;
  3101. end;
  3102.  
  3103. function SearchEnv(EPtr : EnvArrayPtr;
  3104.                    var Search : string) : Word;
  3105.   {-Return the position of Search in environment, or $FFFF if not found.
  3106.     Prior to calling SearchEnv, assure that
  3107.       EPtr is not nil,
  3108.       Search is not empty
  3109.   }
  3110. var
  3111.   SLen : Byte absolute Search;
  3112.   EOfs : Word;
  3113.   MOfs : Word;
  3114.   SOfs : Word;
  3115.   Match : Boolean;
  3116. begin
  3117.   {Force upper case search}
  3118.   Search := StUpcase(Search);
  3119.  
  3120.   {Assure search string ends in =}
  3121.   if Search[SLen] <> '=' then begin
  3122.     Inc(SLen);
  3123.     Search[SLen] := '=';
  3124.   end;
  3125.  
  3126.   EOfs := 0;
  3127.   while EPtr^[EOfs] <> #0 do begin
  3128.     {At the start of a new environment element}
  3129.     SOfs := 1;
  3130.     MOfs := EOfs;
  3131.     repeat
  3132.       Match := (EPtr^[EOfs] = Search[SOfs]);
  3133.       if Match then begin
  3134.         Inc(EOfs);
  3135.         Inc(SOfs);
  3136.       end;
  3137.     until not Match or (SOfs > SLen);
  3138.  
  3139.     if Match then begin
  3140.       {Found a match, return index of start of match}
  3141.       SearchEnv := MOfs;
  3142.       Exit;
  3143.     end;
  3144.  
  3145.     {Skip to end of this environment string}
  3146.     SkipAsciiZ(EPtr, EOfs);
  3147.  
  3148.     {Skip to start of next environment string}
  3149.     Inc(EOfs);
  3150.   end;
  3151.  
  3152.   {No match}
  3153.   SearchEnv := $FFFF;
  3154. end;
  3155.  
  3156. procedure GetAsciiZ(EPtr : EnvArrayPtr; var EOfs : Word; var EStr : string);
  3157.   {-Collect AsciiZ string starting at EPtr^[EOfs]}
  3158. var
  3159.   ELen : Byte absolute EStr;
  3160. begin
  3161.   ELen := 0;
  3162.   while (EPtr^[EOfs] <> #0) and (ELen < 255) do begin
  3163.     Inc(ELen);
  3164.     EStr[ELen] := EPtr^[EOfs];
  3165.     Inc(EOfs);
  3166.   end;
  3167. end;
  3168.  
  3169. function SetEnv(Name, Value : string) : Boolean;
  3170.   {-Set environment string, returning true if successful}
  3171. var
  3172.   SLen : Byte absolute Name;
  3173.   VLen : Byte absolute Value;
  3174.   EPtr : EnvArrayPtr;
  3175.   ENext : Word;
  3176.   EOfs : Word;
  3177.   MOfs : Word;
  3178.   OldLen : Word;
  3179.   NewLen : Word;
  3180.   NulLen : Word;
  3181. begin
  3182.   with Env_Rec do begin
  3183.     SetEnv := False;
  3184.     if (EnvSeg = 0) or (SLen = 0) then
  3185.       Exit;
  3186.     EPtr := Ptr(EnvSeg, 0);
  3187.  
  3188.     {Find the search string}
  3189.     EOfs := SearchEnv(EPtr, Name);
  3190.  
  3191.     {Get the index of the next available environment location}
  3192.     ENext := EnvNext(EPtr);
  3193.  
  3194.     {Get total length of new environment string}
  3195.     NewLen := SLen+VLen;
  3196.  
  3197.     if EOfs <> $FFFF then begin
  3198.       {Search string exists}
  3199.       MOfs := EOfs+SLen;
  3200.       {Scan to end of string}
  3201.       SkipAsciiZ(EPtr, MOfs);
  3202.       OldLen := MOfs-EOfs;
  3203.       {No extra nulls to add}
  3204.       NulLen := 0;
  3205.     end else begin
  3206.       OldLen := 0;
  3207.       {One extra null to add}
  3208.       NulLen := 1;
  3209.     end;
  3210.  
  3211.     if VLen <> 0 then
  3212.       {Not a pure deletion}
  3213.       if ENext+NewLen+NulLen >= EnvLen+OldLen then
  3214.         {New string won't fit}
  3215.         Exit;
  3216.  
  3217.     if OldLen <> 0 then begin
  3218.       {Overwrite previous environment string}
  3219.       Move(EPtr^[MOfs+1], EPtr^[EOfs], ENext-MOfs-1);
  3220.       {More space free now}
  3221.       Dec(ENext, OldLen+1);
  3222.     end;
  3223.  
  3224.     {Append new string}
  3225.     if VLen <> 0 then begin
  3226.       Move(Name[1], EPtr^[ENext], SLen);
  3227.       Inc(ENext, SLen);
  3228.       Move(Value[1], EPtr^[ENext], VLen);
  3229.       Inc(ENext, VLen);
  3230.     end;
  3231.  
  3232.     {Clear out the rest of the environment}
  3233.     FillChar(EPtr^[ENext], EnvLen-ENext, 0);
  3234.  
  3235.     SetEnv := True;
  3236.   end;
  3237. end;
  3238.  
  3239. PROCEDURE READ_R(     X,Y : INTEGER;
  3240.                     VAR R : REAL;
  3241.                       MIN,
  3242.                       MAX : REAL;
  3243.                    PLACES : INTEGER;
  3244.                RIGHT_JUST : INTEGER;
  3245.                    ICOMMA : BOOLEAN);
  3246. var
  3247.   temp : string[80];
  3248.   len  : integer;
  3249.   SAT  : BYTE;
  3250.   S    : BUF160;
  3251. begin
  3252.   str(max:0:places,temp); 
  3253.   LEN := LENGTH(TEMP);
  3254.   str(r:0:places,temp);
  3255.   sat := screen_attr(x,y);
  3256.   textattr := sat;
  3257.   FW(X,Y,SAT,SPACES(RIGHT_JUST));
  3258.   IF MIN < 0.0 THEN
  3259.     BEGIN
  3260.       len := LEN + 1;                   { +1 FOR MINUS SIGN }
  3261.       REPEAT
  3262.         read_str(x,y,temp,dup('+',len));
  3263.        IF (_REAL(TEMP) < MIN) OR (_REAL(TEMP) > MAX) THEN
  3264.          BEGIN
  3265.            SAVE_LINE(Y+1,S);
  3266.            TEXTATTR := $4F;
  3267.            IF X > 30 THEN
  3268.              GOTOXY(30,Y+1)
  3269.            ELSE
  3270.              GOTOXY(X,Y+1);
  3271.            WRITE(' Range: ',MIN:0:PLACES,' to ',MAX:0:PLACES,'  Press <any key> ',CHR(8));
  3272.            READCH(CH,FALSE);
  3273.            REBUILD_LINE(Y+1,S);
  3274.            TEXTATTR := SAT;
  3275.          END;
  3276.       UNTIL (_REAL(TEMP) >= MIN) AND (_REAL(TEMP) <= MAX);
  3277.     END
  3278.   ELSE
  3279.     REPEAT
  3280.       READ_STR(X,Y,TEMP,DUP('.',LEN));
  3281.       IF (_REAL(TEMP) < MIN) OR (_REAL(TEMP) > MAX) THEN
  3282.         BEGIN
  3283.           SAVE_LINE(Y+1,S);
  3284.           TEXTATTR := $4F;
  3285.           IF X > 30 THEN
  3286.             GOTOXY(30,Y+1)
  3287.           ELSE
  3288.             GOTOXY(X,Y+1);
  3289.           WRITE(' Range: ',MIN:0:PLACES,' to ',MAX:0:PLACES,'  Press <any key> ',CHR(8));
  3290.           READCH(CH,FALSE);
  3291.           REBUILD_LINE(Y+1,S);
  3292.           TEXTATTR := SAT;
  3293.         END;
  3294.     UNTIL (_REAL(TEMP) >= MIN) AND (_REAL(TEMP) <= MAX);
  3295.   r := _real(temp);
  3296.   str(r:0:places,temp);               { THIS TRUNCATES ANYTHING }
  3297.   r := _real(temp);                   { PAST PLACES             }
  3298.   textattr := screen_attr(x,y);
  3299.   gotoxy(x,y);
  3300.   IF ICOMMA THEN
  3301.     write(comma(r,RIGHT_JUST,places,RNUM))
  3302.   ELSE
  3303.     WRITE(R:RIGHT_JUST:PLACES);
  3304. end;
  3305.  
  3306. PROCEDURE READ_I(     X,Y : INTEGER;
  3307.                     VAR R : INTEGER;
  3308.                       MIN,
  3309.                       MAX : INTEGER;
  3310.                RIGHT_JUST : INTEGER;
  3311.                    ICOMMA : BOOLEAN);
  3312. var
  3313.   temp : string[80];
  3314.   len  : integer;
  3315.   SAT  : BYTE;
  3316.   S    : BUF160;
  3317. begin
  3318.   str(max:0,temp);
  3319.   LEN := LENGTH(TEMP);
  3320.   str(r:0,temp);
  3321.   sat := screen_attr(x,y);
  3322.   textattr := sat;
  3323.   GOTOXY(X,Y);
  3324.   WRITE(' ':RIGHT_JUST);
  3325.   IF MIN < 0.0 THEN
  3326.     BEGIN
  3327.       len := LEN + 1;                   { +1 FOR MINUS SIGN }
  3328.       REPEAT
  3329.         read_str(x,y,temp,dup('+',len));
  3330.        IF (_INTEGER(TEMP) < MIN) OR (_INTEGER(TEMP) > MAX) THEN
  3331.          BEGIN
  3332.            SAVE_LINE(Y+1,S);
  3333.            TEXTATTR := $4F;
  3334.            IF X > 30 THEN
  3335.              GOTOXY(30,Y+1)
  3336.            ELSE
  3337.              GOTOXY(X,Y+1);
  3338.            WRITE(' Range: ',MIN:0,' to ',MAX:0,'  Press <any key> ',CHR(8));
  3339.            READCH(CH,FALSE);
  3340.            REBUILD_LINE(Y+1,S);
  3341.            TEXTATTR := SAT;
  3342.          END;
  3343.       UNTIL (_INTEGER(TEMP) >= MIN) AND (_INTEGER(TEMP) <= MAX);
  3344.     END
  3345.   ELSE
  3346.     REPEAT
  3347.       READ_STR(X,Y,TEMP,DUP('.',LEN));
  3348.       IF (_INTEGER(TEMP) < MIN) OR (_INTEGER(TEMP) > MAX) THEN
  3349.         BEGIN
  3350.           SAVE_LINE(Y+1,S);
  3351.           TEXTATTR := $4F;
  3352.           IF X > 30 THEN
  3353.             GOTOXY(30,Y+1)
  3354.           ELSE
  3355.             GOTOXY(X,Y+1);
  3356.           WRITE(' Range: ',MIN:0,' to ',MAX:0,'  Press <any key> ',CHR(8));
  3357.           READCH(CH,FALSE);
  3358.           REBUILD_LINE(Y+1,S);
  3359.           TEXTATTR := SAT;
  3360.         END;
  3361.     UNTIL (_INTEGER(TEMP) >= MIN) AND (_INTEGER(TEMP) <= MAX);
  3362.   r := _INTEGER(temp);
  3363.   str(r:0,temp);               { THIS TRUNCATES ANYTHING }
  3364.   r := _INTEGER(temp);                   { PAST PLACES             }
  3365.   textattr := screen_attr(x,y);
  3366.   gotoxy(x,y);
  3367.   IF ICOMMA THEN
  3368.     write(comma(r,RIGHT_JUST,0,INUM))
  3369.   ELSE
  3370.     WRITE(R:RIGHT_JUST);
  3371. end;
  3372.  
  3373. PROCEDURE READ_L(     X,Y : INTEGER;
  3374.                     VAR R : LONGINT;
  3375.                       MIN,
  3376.                       MAX : LONGINT;
  3377.                RIGHT_JUST : LONGINT;
  3378.                    ICOMMA : BOOLEAN);
  3379. var
  3380.   temp : string[80];
  3381.   len  : integer;
  3382.   SAT  : BYTE;
  3383.   S    : BUF160;
  3384. begin
  3385.   str(max:0,temp);
  3386.   LEN := LENGTH(TEMP);
  3387.   str(r:0,temp);
  3388.   sat := screen_attr(x,y);
  3389.   textattr := sat;
  3390.   GOTOXY(X,Y);
  3391.   WRITE(' ':RIGHT_JUST);
  3392.   IF MIN < 0.0 THEN
  3393.     BEGIN
  3394.       len := LEN + 1;                   { +1 FOR MINUS SIGN }
  3395.       REPEAT
  3396.         read_str(x,y,temp,dup('+',len));
  3397.        IF (_LONGINT(TEMP) < MIN) OR (_LONGINT(TEMP) > MAX) THEN
  3398.          BEGIN
  3399.            SAVE_LINE(Y+1,S);
  3400.            TEXTATTR := $4F;
  3401.            IF X > 30 THEN
  3402.              GOTOXY(30,Y+1)
  3403.            ELSE
  3404.              GOTOXY(X,Y+1);
  3405.            WRITE(' Range: ',MIN:0,' to ',MAX:0,'  Press <any key> ',CHR(8));
  3406.            READCH(CH,FALSE);
  3407.            REBUILD_LINE(Y+1,S);
  3408.            TEXTATTR := SAT;
  3409.          END;
  3410.       UNTIL (_LONGINT(TEMP) >= MIN) AND (_LONGINT(TEMP) <= MAX);
  3411.     END
  3412.   ELSE
  3413.     REPEAT
  3414.       READ_STR(X,Y,TEMP,DUP('.',LEN));
  3415.       IF (_LONGINT(TEMP) < MIN) OR (_LONGINT(TEMP) > MAX) THEN
  3416.         BEGIN
  3417.           SAVE_LINE(Y+1,S);
  3418.           TEXTATTR := $4F;
  3419.           IF X > 30 THEN
  3420.             GOTOXY(30,Y+1)
  3421.           ELSE
  3422.             GOTOXY(X,Y+1);
  3423.           WRITE(' Range: ',MIN:0,' to ',MAX:0,'  Press <any key> ',CHR(8));
  3424.           READCH(CH,FALSE);
  3425.           REBUILD_LINE(Y+1,S);
  3426.           TEXTATTR := SAT;
  3427.         END;
  3428.     UNTIL (_LONGINT(TEMP) >= MIN) AND (_LONGINT(TEMP) <= MAX);
  3429.   r := _LONGINT(temp);
  3430.   str(r:0,temp);               { THIS TRUNCATES ANYTHING }
  3431.   r := _LONGINT(temp);                   { PAST PLACES             }
  3432.   textattr := screen_attr(x,y);
  3433.   gotoxy(x,y);
  3434.   IF ICOMMA THEN
  3435.     write(comma(r,RIGHT_JUST,0,LNUM))
  3436.   ELSE
  3437.     WRITE(R:RIGHT_JUST);
  3438. end;
  3439.  
  3440. PROCEDURE READ_MONEY(X,Y : INTEGER;
  3441.                    VAR R : REAL;
  3442.                  DPLACES : INTEGER;
  3443.               RIGHT_JUST : INTEGER;
  3444.                LOW, HIGH : REAL);
  3445. VAR
  3446.   I         : INTEGER;
  3447.   TEMP      : STRING[15];
  3448.   OLDATTR   : BYTE;
  3449.   LEN       : INTEGER;
  3450.   VALID_SET : SET OF CHAR;
  3451.   FACTOR    : REAL;
  3452.   OLD_CUR   : CURTYPE;
  3453. BEGIN
  3454.   OLD_CUR := CUR;
  3455.   SET_CURSOR(UNDERLINE);
  3456.   FACTOR := 1;
  3457.   FOR I := 1 TO DPLACES DO
  3458.     FACTOR := FACTOR * 10;
  3459.   VALID_SET := ['0'..'9',#8];
  3460.   IF R > HIGH THEN R := HIGH;
  3461.   IF R < LOW  THEN R := LOW;
  3462.   OLDATTR := SCREEN_ATTR(X,Y);
  3463.   TEXTATTR := UT.INPUT_ATTR;
  3464.   LEN := LENGTH(COMMA(HIGH,0,DPLACES,RNUM));
  3465.   IF LOW < 0.0 THEN
  3466.     BEGIN                          
  3467.       VALID_SET := VALID_SET + ['-'];
  3468.       IF LENGTH(COMMA(LOW,0,DPLACES,RNUM)) > LEN THEN
  3469.         LEN := LENGTH(COMMA(LOW,0,DPLACES,RNUM));
  3470.     END;
  3471.   CHANGED := FALSE;
  3472.   TEMP := COMMA(R,LEN,DPLACES,RNUM);
  3473.   GOTOXY(X+RIGHT_JUST-LEN,Y);
  3474.   WRITE(TEMP);
  3475.   TEMP := '';
  3476.   REPEAT
  3477.     GOTOXY(X+RIGHT_JUST-1,Y);
  3478.     READCH(CH,FALSE);
  3479.     IF CH IN VALID_SET THEN
  3480.       BEGIN
  3481.         VALID_SET := VALID_SET - ['-'];
  3482.         CHANGED := TRUE;
  3483.         IF CH = #8 THEN
  3484.           DELETE(TEMP,LENGTH(TEMP),1)
  3485.         ELSE
  3486.           IF (_REAL(TEMP+CH) > 0.0) THEN
  3487.             IF (LENGTH(TEMP) < LEN) AND
  3488.                ((_REAL(TEMP+CH) / FACTOR) <= HIGH) THEN
  3489.               TEMP := TEMP + CH
  3490.             ELSE
  3491.           ELSE
  3492.             IF (LENGTH(TEMP) < LEN) AND
  3493.                ((_REAL(TEMP+CH) / FACTOR) >= LOW) THEN
  3494.               TEMP := TEMP + CH;
  3495.         R := _REAL(TEMP) / FACTOR;
  3496.         GOTOXY(X+RIGHT_JUST-LEN,Y);
  3497.         WRITE(COMMA(R,LEN,DPLACES,RNUM));
  3498.         IF CH = '-' THEN
  3499.           BEGIN
  3500.             GOTOXY(X+RIGHT_JUST-LEN,Y);
  3501.             WRITE('-');
  3502.           END;
  3503.       END;
  3504.   UNTIL (CH = #27) OR (UT.EXITCH[ORD(CH)]);
  3505.   TEXTATTR := OLDATTR;
  3506.   GOTOXY(X,Y);
  3507.   WRITE(COMMA(R,RIGHT_JUST,DPLACES,RNUM));
  3508.   TEXTATTR := UT.DEFAULT_ATTR;
  3509.   SET_CURSOR(OLD_CUR);
  3510. END;
  3511.  
  3512. PROCEDURE READ_DIGIT(    X,Y : INTEGER;
  3513.                    VAR VALUE;          
  3514.                   RIGHT_JUST : INTEGER;
  3515.                    LOW, HIGH : LONGINT;
  3516.                        NTYPE : TYPEN);
  3517. VAR
  3518.   TEMP      : STRING[15];
  3519.   OLDATTR   : BYTE;
  3520.   LNUMBER   : LONGINT ABSOLUTE VALUE;
  3521.   INUMBER   : INTEGER ABSOLUTE VALUE;
  3522.   LEN       : INTEGER;
  3523.   VALID_SET : SET OF CHAR;
  3524.   OLD_CUR   : CURTYPE;
  3525. BEGIN
  3526.   OLD_CUR := CUR;
  3527.   SET_CURSOR(UNDERLINE);
  3528.   VALID_SET := ['0'..'9',#8];
  3529.   LEN := LENGTH(COMMA(HIGH,0,0,LNUM));
  3530.   IF LOW < 0 THEN
  3531.     BEGIN
  3532.       VALID_SET := VALID_SET + ['-'];
  3533.       IF LENGTH(COMMA(LOW,0,0,LNUM)) > LEN THEN
  3534.         LEN := LENGTH(COMMA(LOW,0,0,LNUM));
  3535.     END;
  3536.   CASE NTYPE OF
  3537.       LNUM : BEGIN
  3538.                IF LNUMBER > HIGH THEN LNUMBER := HIGH;
  3539.                IF LNUMBER < LOW  THEN LNUMBER := LOW;
  3540.                TEMP := COMMA(LNUMBER,LEN,0,LNUM);
  3541.              END;
  3542.       INUM : BEGIN
  3543.                IF INUMBER > HIGH THEN INUMBER := HIGH;
  3544.                IF INUMBER < LOW  THEN INUMBER := LOW;
  3545.                TEMP := COMMA(INUMBER,LEN,0,INUM);
  3546.              END;
  3547.       ELSE   EXIT;
  3548.   END;
  3549.   OLDATTR := SCREEN_ATTR(X,Y);
  3550.   TEXTATTR := UT.INPUT_ATTR;
  3551.   CHANGED := FALSE;
  3552.   GOTOXY(X+RIGHT_JUST-LEN,Y);
  3553.   WRITE(TEMP);
  3554.   TEMP := '';
  3555.   REPEAT        
  3556.     GOTOXY(X+RIGHT_JUST-1,Y);
  3557.     READCH(CH,FALSE);
  3558.     IF CH IN VALID_SET THEN
  3559.       BEGIN
  3560.         VALID_SET := VALID_SET - ['-'];
  3561.         CHANGED := TRUE;
  3562.         IF CH = #8 THEN
  3563.           DELETE(TEMP,LENGTH(TEMP),1)
  3564.         ELSE
  3565.           CASE NTYPE OF
  3566.              LNUM : IF _LONGINT(TEMP+CH) > 0 THEN
  3567.                       IF (LENGTH(TEMP) < LEN) AND
  3568.                          ((_LONGINT(TEMP+CH) <= HIGH)) THEN
  3569.                         TEMP := TEMP + CH
  3570.                       ELSE
  3571.                     ELSE
  3572.                       IF (LENGTH(TEMP) < LEN) AND
  3573.                          ((_LONGINT(TEMP+CH) >= LOW)) THEN
  3574.                         TEMP := TEMP + CH;
  3575.              INUM : IF _INTEGER(TEMP+CH) > 0 THEN
  3576.                       IF (LENGTH(TEMP) < LEN) AND
  3577.                          ((_INTEGER(TEMP+CH) <= HIGH)) THEN
  3578.                         TEMP := TEMP + CH
  3579.                       ELSE
  3580.                     ELSE
  3581.                       IF (LENGTH(TEMP) < LEN) AND
  3582.                          ((_INTEGER(TEMP+CH) >= LOW)) THEN
  3583.                         TEMP := TEMP+CH;
  3584.           END;
  3585.         GOTOXY(X+RIGHT_JUST-LEN,Y);
  3586.         CASE NTYPE OF
  3587.             LNUM : BEGIN
  3588.                      LNUMBER := _LONGINT(TEMP);
  3589.                      WRITE(COMMA(LNUMBER,LEN,0,LNUM));
  3590.                    END;
  3591.             INUM : BEGIN
  3592.                      INUMBER := _INTEGER(TEMP);
  3593.                      WRITE(COMMA(INUMBER,LEN,0,INUM));
  3594.                    END;
  3595.         END;
  3596.         IF CH = '-' THEN
  3597.           BEGIN
  3598.             GOTOXY(X+RIGHT_JUST-LEN,Y);
  3599.             WRITE('-');
  3600.           END;
  3601.       END;
  3602.   UNTIL (CH = #27) OR (UT.EXITCH[ORD(CH)]);
  3603.   TEXTATTR := OLDATTR;
  3604.   GOTOXY(X+RIGHT_JUST-LEN,Y);
  3605.   CASE NTYPE OF
  3606.       LNUM : BEGIN
  3607.                IF CHANGED THEN
  3608.                  LNUMBER := _LONGINT(TEMP);
  3609.                WRITE(COMMA(LNUMBER,LEN,0,LNUM));
  3610.              END;
  3611.       INUM : BEGIN
  3612.                IF CHANGED THEN
  3613.                  INUMBER := _INTEGER(TEMP);
  3614.                WRITE(COMMA(INUMBER,LEN,0,INUM));
  3615.              END;
  3616.   END;
  3617.   TEXTATTR := UT.DEFAULT_ATTR;
  3618.   SET_CURSOR(OLD_CUR);
  3619. END;
  3620.  
  3621. FUNCTION BLANKS(INSTRING : STRING) : BOOLEAN;
  3622. BEGIN
  3623.   BLANKS := PAD(' ',LENGTH(INSTRING)) = INSTRING;
  3624. END;
  3625.  
  3626. Function PackKey(Dte, Tme : str8) : longint;
  3627. var
  3628.   Dow,
  3629.   sec100 : word;
  3630.   dt     : DateTime;
  3631.   Tlong  : longint;
  3632. begin
  3633.   if Dte = '' then
  3634.     begin
  3635.       GetDate(Dt.Year,Dt.Month,Dt.Day,Dow);
  3636.       GetTime(Dt.Hour,Dt.Min,Dt.Sec,Sec100);
  3637.     end
  3638.   else
  3639.     begin
  3640.       if copy(Dte,7,2) < '80' then
  3641.         Dt.Year  := 2000 + _word(copy(Dte,7,2))
  3642.       else
  3643.         Dt.Year  := 1900 + _word(copy(Dte,7,2));
  3644.       Dt.Month := _word(copy(Dte,1,2));
  3645.       Dt.Day   := _word(copy(Dte,4,2));
  3646.       Dt.Hour  := _word(copy(Tme,1,2));
  3647.       Dt.Min   := _word(copy(Tme,4,2));
  3648.       Dt.Sec   := _word(copy(Tme,7,2));
  3649.     end;
  3650.   PackTime(Dt, Tlong);
  3651.   PackKey := Tlong;
  3652. end;
  3653.  
  3654. Function UnPackKey(PK : longint) : str20;
  3655. var
  3656.   Temp : str20;
  3657.   Dt   : DateTime;
  3658. begin
  3659.   UnPackTime(PK, Dt);
  3660.   temp := longint_str(Dt.Month,2) + '-' +
  3661.           longint_str(Dt.Day,2)   + '-' +
  3662.           longint_str(Dt.Year,2)  + ' ' +
  3663.           longint_str(Dt.Hour,2)  + ':' +
  3664.           longint_str(Dt.Min,2)   + ':' +
  3665.           longint_str(Dt.Sec,2);
  3666.   delete(temp,7,2);
  3667.   if temp[1] = ' ' then temp[1] := '0';
  3668.   if temp[4] = ' ' then temp[4] := '0';
  3669.   if temp[7] = ' ' then temp[7] := '0';
  3670.   if temp[10] = ' ' then temp[10] := '0';
  3671.   if temp[13] = ' ' then temp[13] := '0';
  3672.   if temp[16] = ' ' then temp[16] := '0';
  3673.   UnPackKey := Temp;
  3674. end;
  3675.  
  3676. PROCEDURE StuffBuffer(S : STR16);
  3677. CONST
  3678.   KbStart = $1E;
  3679. VAR
  3680.   N,MAX : BYTE;
  3681.   KbHead : WORD ABSOLUTE $40:$1A;
  3682.   KbTail : WORD ABSOLUTE $40:$1C;
  3683.   KbBuff : ARRAY [0..15] OF WORD ABSOLUTE $40:KbStart;
  3684. BEGIN
  3685.   MAX := 15;
  3686.   IF LENGTH(S) < MAX THEN
  3687.     MAX := LENGTH(S);
  3688.   ASM CLI END;
  3689.   KbHead := KbStart;
  3690.   KbTail := KbStart + 2*MAX;
  3691.   FOR N := 1 TO MAX DO
  3692.     KbBuff[PRED(N)] := WORD(S[N]);
  3693.   ASM STI END;
  3694. END;
  3695.  
  3696. BEGIN
  3697.   SHOW_ERROR := TRUE;
  3698.   EXITSAVE := EXITPROC;
  3699.   EXITPROC := @EXITHANDLER;
  3700.   TEXTATTR_AT_ENTRY := TEXTATTR;
  3701.   GEMINI_SYSTEMS := 'Ngmmwp![~{zkpt';
  3702.   UN_ENCRYPT(GEMINI_SYSTEMS,69);
  3703.  
  3704.   UT.TIMEX         := 0;
  3705.   UT.TIMEY         := 2;
  3706.   UT.TIME_TYPE     := 'N';
  3707.   UT.DATEX         := 0;
  3708.   UT.DATEY         := 2;
  3709.   UT.DATE_TYPE     := ' ';   { D,W,else }
  3710.   UT.INPUT_ATTR    := $70;
  3711.   UT.DEFAULT_ATTR  := $02;
  3712.   UT.COMPILED_DATE := '%%-%%-%%';
  3713.   UT.COMPILED_TIME := '%%:%%';
  3714.   UT.NOCONV        := FALSE;
  3715.   FILLCHAR(UT.EXITCH,SIZEOF(UT.EXITCH),1);
  3716.   FILLCHAR(UT.EXITCH[32],95,0);
  3717.   UT.EXITCH[191] := FALSE;
  3718.   UT.EXITCH[192] := FALSE;
  3719.   UT.EXITCH[8] := FALSE;
  3720.   UT.EXITCH[196] := FALSE;
  3721.   UT.EXITCH[197] := FALSE;
  3722.   UT.EXITCH[198] := FALSE;
  3723.   UT.EXITCH[199] := FALSE;
  3724.   SET_CURSOR(UNDERLINE);
  3725.   BLINK_ON;
  3726.   CGA_PRESENT := CGA_INSTALLED;
  3727.   EGA_PRESENT := EGA_INSTALLED;
  3728.   VGA_PRESENT := VGA_INSTALLED;
  3729.   DYNAMIC_PATHEXEC := FALSE;
  3730.   CURRENT_BORDER   := 0;
  3731.   GET_DOS_VER;
  3732.   WRITE_TIME(0,1,'N');
  3733.   WRITE_DATE(0,1,'N');
  3734.   DISPLAY := #255;
  3735.   NOCONV  := #254;
  3736.   CLEAR   := #253;
  3737.   X_IN    := 1;
  3738.   X_OUT   := 1;
  3739.   MASTERENV;
  3740.   START_TIMER(TIM);
  3741. END.