home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / asm / wasm / io.asm < prev    next >
Assembly Source File  |  1987-11-20  |  48KB  |  1,862 lines

  1.  List-
  2.  
  3. ;=============================================================================
  4. ; Basic I/O Procedures
  5. ;
  6. ; These routines provide methods to manipulate strings and processes simple
  7. ; I/O.  The procedures are completely MS/PC DOS compatible, the hardware or
  8. ; BIOS is never directly accessed (except for SOUND_SPK_P).
  9. ;
  10. ; All parameters are passed on the stack unless specified otherwise. All
  11. ; string addresses consist of a segment and offset (they are 32-bit). The
  12. ; offset should always be pushed on the stack first. If more than one string
  13. ; address is required, the destination string (the string to be modified)
  14. ; should be pushed on the stack first. Note that data may be returned on the
  15. ; stack as specified and should be removed by the programmer before, for
  16. ; instance, returning from a routine. Parameters will be returned even if an
  17. ; error occurs, though the data may not be valid.
  18. ;
  19. ; If a new string is created (for instance the time string), it will exist in
  20. ; a local buffer and the address that is returned on the stack will point to
  21. ; that buffer.  Local buffers should never be written to, only read from.
  22. ;
  23. ; All registers are preserved (unless they are used to pass parameters). The
  24. ; flags are not explicitly preserved.  Note particularly that the direction
  25. ; flag (DF) may be cleared. If an error is detected, the carry flag will be
  26. ; set and generally the operation will not be carried out.
  27. ;
  28. ; Strings are defined as any sequence of 0 to 255 characters preceded by a
  29. ; length byte, except for file names, which must be a sequence of characters
  30. ; terminated by a byte 00. These two string types are not interchangeable, the
  31. ; only routines that require the latter type are the routines that open,
  32. ; create, or delete files (OPEN_FIL_P, CREATE_FIL_P, and DELETE_FIL_P).
  33. ;
  34. ; The stack is used extensively and should have about 200 bytes free before
  35. ; pushing any parameters and calling the routines.
  36. ;
  37. ; String manipulation:
  38. ;
  39. ;   CLEAR_STR_P                 clear a string
  40. ;   TRUNCATE_STR_P              truncate a string
  41. ;   COPY_STR_P                  copy a string from one location to another
  42. ;   APPEND_STR_P                append a string to another
  43. ;   APPEND_CHRS_P               append characters to a string
  44. ;   FORMAT_RGT_P                append a string to another after formatting
  45. ;   JUSTIFY_RGT_P               append a string to another right justified
  46. ;   LOWER_CHR_P                 make a character lower-case
  47. ;   UPPER_CHR_P                 make a character upper-case
  48. ;   MAKE_BIN_P                  translate a string to a binary number
  49. ;   MAKE_DEC_P                  translate a binary number to a string
  50. ;   DAY_STR_P                   get the string representing the day
  51. ;   MONTH_STR_P                 get the string representing the month
  52. ;   TIME_STR_P                  get the string representing the time
  53. ;   MAKE_NAM_P                  translate a string into the file name format
  54. ;   MAKE_STR_P                  translate a file string into normal format
  55. ;
  56. ; Keyboard:
  57. ;
  58. ;   INPUT_STA_P                 return input status
  59. ;   INPUT_CHR_P                 input a character
  60. ;   INPUT_HID_P                 input a character without screen echo
  61. ;   INPUT_STR_P                 input a string
  62. ;
  63. ; Display:
  64. ;
  65. ;   HOME_CUR_P                  move the cursor home (1)
  66. ;   LEFT_CUR_P                  move the cursor left (1)
  67. ;   RIGHT_CUR_P                 move the cursor right (1)
  68. ;   UP_CUR_P                    move the cursor up (1)
  69. ;   DOWN_CUR_P                  move the cursor down (1)
  70. ;   SAVE_CUR_P                  save the cursor position (1)
  71. ;   RESTORE_CUR_P               restore the cursor position (1)
  72. ;   LOCATE_CUR_P                move the cursor to a location (1)
  73. ;   NORMAL_ATR_P                change the attribute to normal (1)
  74. ;   BOLD_ATR_P                  change the attribute to bold (1)
  75. ;   UNDERLINE_ATR_P             change the attribute to underline (1)
  76. ;   BLINK_ATR_P                 change the attribute to blinking (1)
  77. ;   REVERSE_ATR_P               change the attribute to reverse video (1)
  78. ;   CLEAR_SCR_P                 clear the screen and home the cursor (1)
  79. ;   DISPLAY_CHR_P               display a character
  80. ;   LINE_P                      start a new display line
  81. ;   DISPLAY_STR_P               display a string
  82. ;   DISPLAY_LIN_P               display a string and start a new line
  83. ;
  84. ; Speaker:
  85. ;
  86. ;   SOUND_BEL_P                 beep the speaker
  87. ;   SOUND_SPK_P                 sound the speaker at freq. for duration (2)
  88. ;
  89. ; File:
  90. ;
  91. ;   OPEN_FIL_P                  open a file
  92. ;   CREATE_FIL_P                create or truncate a file
  93. ;   DELETE_FIL_P                delete a file
  94. ;   READ_FIL_P                  read from a file
  95. ;   WRITE_FIL_P                 write to a file
  96. ;   SEEK_FIL_P                  move a file read write pointer
  97. ;   SIZE_FIL_P                  get the size of a file
  98. ;   CLOSE_FIL_P                 close a file
  99. ;   FREE_DSK_P                  return free disk space
  100. ;
  101. ; (1) Requires that ANSI.SYS or compatible device driver be installed.
  102. ; (2) Hardware specific, duration is dependent on a 4.77 MHz computer.
  103.  
  104. ;================================================
  105. ; This creates a library header so this file can
  106. ; read by the dispatcher code in DISPATCH.ASM.
  107. ; The next two source lines vary depending
  108. ; whether or not the file is being included into
  109. ; the source file directly, or is being
  110. ; assembled separately as a runtime library.
  111.  
  112. ;presently set up to be included directly
  113.  If 0                           ;set to 1 if external library,
  114.                                 ;0 if included directly
  115. ;Include 'E:Library.Asm'        ;add this line (remove semi-colon) if external
  116.                                 ;library, remove line (turn it into comment
  117.                                 ;by adding semi-colon) if included directly
  118.  
  119.  Dw Offset Clear_Str_P
  120.  Dw Offset Truncate_Str_P
  121.  Dw Offset Copy_Str_P
  122.  Dw Offset Append_Str_P
  123.  Dw Offset Append_Chrs_P
  124.  Dw Offset Format_Rgt_P
  125.  Dw Offset Justify_Rgt_P
  126.  Dw Offset Lower_Chr_P
  127.  Dw Offset Upper_Chr_P
  128.  Dw Offset Make_Bin_P
  129.  Dw Offset Make_Dec_P
  130.  Dw Offset Day_Str_P
  131.  Dw Offset Month_Str_P
  132.  Dw Offset Time_Str_P
  133.  Dw Offset Make_Nam_P
  134.  Dw Offset Make_Str_P
  135.  Dw Offset Input_Sta_P
  136.  Dw Offset Input_Chr_P
  137.  Dw Offset Input_Hid_P
  138.  Dw Offset Input_Str_P
  139.  Dw Offset Home_Cur_P
  140.  Dw Offset Left_Cur_P
  141.  Dw Offset Right_Cur_P
  142.  Dw Offset Up_Cur_P
  143.  Dw Offset Down_Cur_P
  144.  Dw Offset Locate_Cur_P
  145.  Dw Offset Normal_Atr_P
  146.  Dw Offset Bold_Atr_P
  147.  Dw Offset Underline_Atr_P
  148.  Dw Offset Blink_Atr_P
  149.  Dw Offset Reverse_Atr_P
  150.  Dw Offset Clear_Scr_P
  151.  Dw Offset Display_Chr_P
  152.  Dw Offset Sound_Bel_P
  153.  Dw Offset Line_P
  154.  Dw Offset Display_Str_P
  155.  Dw Offset Display_Lin_P
  156.  Dw Offset Open_Fil_P
  157.  Dw Offset Create_Fil_P
  158.  Dw Offset Delete_Fil_P
  159.  Dw Offset Read_Fil_P
  160.  Dw Offset Write_Fil_P
  161.  Dw Offset Seek_Fil_P
  162.  Dw Offset Size_Fil_P
  163.  Dw Offset Close_Fil_P
  164.  Dw Offset Free_Dsk_P
  165.  Dw Offset Sound_Spk_P
  166.  Dw Offset Save_Cur_P
  167.  Dw Offset Restore_Cur_P
  168.  Endif
  169.  
  170. ;================================================
  171. ; Set the length of the destination string to
  172. ; zero. The string address is returned on the
  173. ; stack.
  174.  
  175. Clear_Str_P Proc Near
  176.  Push Si
  177.  Push Ds
  178.  Push Bp                ;save registers
  179.  
  180.  Mov Bp, Sp
  181.  Mov Si, [Bp+10]        ;get source offset
  182.  Mov Ds, [Bp+8]         ;get source segment
  183.  
  184.  Mov Byte [Si], 0       ;zero length
  185.  
  186.  Pop Bp
  187.  Pop Ds
  188.  Pop Si
  189.  Clc                    ;no error
  190.  Ret
  191.  Endp                   ;Clear_Str_P
  192.  
  193. ;================================================
  194. ; Set the length of the destination string to
  195. ; the specifed length. The length must in the
  196. ; low byte of the last word pushed on the
  197. ; stack. The string address is returned on the
  198. ; stack and also the flags are set by a
  199. ; comparision of the new and previous lengths.
  200.  
  201. Truncate_Str_P Proc Near
  202.  Push Ax
  203.  Push Si
  204.  Push Ds
  205.  Push Bp                ;save registers
  206.  
  207.  Mov Bp, Sp
  208.  Mov Si, [Bp+14]        ;get source offset
  209.  Mov Ds, [Bp+12]        ;get source segment
  210.  Mov Al, [Bp+10]        ;get new length
  211.  Mov Ah, Al
  212.  Xchg Al, [Si]          ;set new length and get old
  213.  
  214.  Cmp Al, Ah             ;compare sizes, set flags
  215.  
  216.  Pop Bp
  217.  Pop Ds
  218.  Pop Si
  219.  Pop Ax
  220.  Ret 2
  221.  Endp                   ;Truncate_Str_P
  222.  
  223. ;================================================
  224. ; Copy the source string to the destination.
  225. ; The destination string address is returned on
  226. ; the stack.
  227.  
  228. Copy_Str_P Proc Near
  229.  Push Cx
  230.  Push Di
  231.  Push Si
  232.  Push Ds
  233.  Push Es
  234.  Push Bp                ;save registers
  235.  Cld                    ;clear direction
  236.  
  237.  Mov Bp, Sp
  238.  Mov Di, [Bp+20]        ;get destination offset
  239.  Mov Es, [Bp+18]        ;get destination segment
  240.  Mov Si, [Bp+16]        ;get source offset
  241.  Mov Ds, [Bp+14]        ;get source segment
  242.  
  243.  Mov Cl, [Si]           ;length
  244.  Sub Ch, Ch
  245.  Inc Cx                 ;include length byte
  246.  Rep
  247.  Movsb                  ;move string
  248.  
  249.  Pop Bp
  250.  Pop Es
  251.  Pop Ds
  252.  Pop Si
  253.  Pop Di
  254.  Pop Cx                 ;restore registers
  255.  Clc                    ;no error
  256.  Ret 4
  257.  Endp                   ;Copy_Str_P
  258.  
  259. ;================================================
  260. ; Append the source string to the destination
  261. ; string. The destination string address is
  262. ; returned on the stack. The carry is set if
  263. ; the string would be too long.
  264.  
  265. Append_Str_P Proc Near
  266.  Push Ax
  267.  Push Bx
  268.  Push Cx
  269.  Push Di
  270.  Push Si
  271.  Push Ds
  272.  Push Es
  273.  Push Bp                ;save registers
  274.  Cld                    ;clear direction
  275.  
  276.  Mov Bp, Sp
  277.  Mov Di, [Bp+24]        ;get destination offset
  278.  Mov Es, [Bp+22]        ;get destination segment
  279.  Mov Si, [Bp+20]        ;get source offset
  280.  Mov Ds, [Bp+18]        ;get source segment
  281.  
  282.  Seg Es
  283.  Mov Al, [Di]           ;destination length
  284.  Mov Cl, [Si]           ;source length
  285.  Sub Ah, Ah
  286.  Mov Ch, Ah
  287.  
  288.  Mov Bx, Ax
  289.  Add Al, Cl             ;new total length
  290.  Jc AppendStrError      ;jump if too big
  291.  
  292.  Seg Es
  293.  Mov [Di], Al           ;save new length
  294.  
  295.  Add Di, Bx             ;destination pointer to end
  296.  Inc Di                 ;don't forget length byte
  297.  Inc Si                 ;... and source
  298.  
  299.  Rep
  300.  Movsb                  ;move string
  301.  Clc                    ;no error
  302.  
  303. AppendStrError
  304.  Pop Bp
  305.  Pop Es
  306.  Pop Ds
  307.  Pop Si
  308.  Pop Di
  309.  Pop Cx
  310.  Pop Bx
  311.  Pop Ax                 ;restore registers
  312.  Ret 4
  313.  Endp                   ;Append_Str_P
  314.  
  315. ;================================================
  316. ; Append some number of characters to the
  317. ; destination string.  The character to append
  318. ; must be in the high byte of the last word
  319. ; pushed on the stack and the byte count must
  320. ; be in the low byte. The string address is
  321. ; returned on the stack. The carry is set if
  322. ; the string would be too long.
  323.  
  324. Append_Chrs_P Proc Near
  325.  Push Ax
  326.  Push Bx
  327.  Push Cx
  328.  Push Di
  329.  Push Es
  330.  Push Bp                ;save registers
  331.  Cld                    ;clear direction
  332.  
  333.  Mov Bp, Sp
  334.  Mov Di, [Bp+18]        ;get destination offset
  335.  Mov Es, [Bp+16]        ;get destination segment
  336.  Mov Cl, [Bp+14]        ;get number of characters to append
  337.  
  338.  Seg Es
  339.  Mov Al, [Di]           ;destination length
  340.  Sub Ah, Ah
  341.  Mov Ch, Ah
  342.  
  343.  Mov Bx, Ax
  344.  Add Al, Cl             ;new total length
  345.  Jc AppendChrError      ;jump if too big
  346.  
  347.  Seg Es
  348.  Mov [Di], Al           ;save new length
  349.  
  350.  Add Di, Bx             ;pointer to end
  351.  Inc Di                 ;length byte
  352.  
  353.  Mov Al, [Bp+15]        ;get character
  354.  Rep
  355.  Stosb                  ;store
  356.  Clc                    ;no error
  357.  
  358. AppendChrError
  359.  Pop Bp
  360.  Pop Es
  361.  Pop Di
  362.  Pop Cx
  363.  Pop Bx
  364.  Pop Ax                 ;restore registers
  365.  Ret 2
  366.  Endp                   ;Append_Chrs_P
  367.  
  368. ;================================================
  369. ; Append a right justified source string to the
  370. ; destination string. Note that the source
  371. ; string is justified itself before it is
  372. ; appended. The character to use in justifing
  373. ; must be in the high byte of the last word
  374. ; pushed on the stack and the final source
  375. ; string size must be in the low byte. The
  376. ; destination string address is returned on the
  377. ; stack. The carry is set if the final string
  378. ; would be too long or could not be formatted.
  379.  
  380. Format_Rgt_P Proc Near
  381.  Push Ax
  382.  Push Bx
  383.  Push Cx
  384.  Push Di
  385.  Push Si
  386.  Push Ds
  387.  Push Es
  388.  Push Bp                ;save registers
  389.  Cld                    ;clear direction
  390.  
  391.  Mov Bp, Sp
  392.  Mov Di, [Bp+26]        ;get destination offset
  393.  Mov Es, [Bp+24]        ;get destination segment
  394.  Mov Si, [Bp+22]        ;get source offset
  395.  Mov Ds, [Bp+20]        ;get source segment
  396.  
  397. ;--- add the justifing characters
  398.  
  399.  Seg Es
  400.  Mov Al, [Di]           ;destination length
  401.  Mov Bh, [Si]           ;source length
  402.  Add Al, Bh             ;length of two strings
  403.  Jc FormatRgtError      ;jump if too big
  404.  Mov Bl, [Bp+18]        ;get final source size
  405.  Sub Bl, Bh             ;calculate amount of justify
  406.  Jc FormatRgtError      ;jump if too small
  407.  Add Al, Bl             ;final total length
  408.  Jc FormatRgtError      ;jump if too big
  409.  Mov Bh, [Bp+19]        ;get character to justify with
  410.  
  411.  Push Di
  412.  Push Es
  413.  Push Bx
  414.  Call Append_Chrs_P     ;append characters
  415.  Add Sp, 4              ;throw away address, not needed
  416.  
  417. ;--- append the string
  418.  
  419.  Seg Es
  420.  Mov Al, [Di]           ;destination length
  421.  Mov Cl, [Si]           ;source length
  422.  Sub Ah, Ah
  423.  Mov Ch, Ah             ;clear high bytes of sizes
  424.  
  425.  Mov Bx, Ax
  426.  Add Al, Cl             ;new total length
  427.  
  428.  Seg Es
  429.  Mov [Di], Al           ;save new length
  430.  
  431.  Add Di, Bx             ;destination pointer to end
  432.  Inc Di                 ;don't forget length byte
  433.  Inc Si                 ;... and source
  434.  
  435.  Rep
  436.  Movsb                  ;move string
  437.  Clc                    ;no error
  438.  
  439. FormatRgtError
  440.  Pop Bp
  441.  Pop Es
  442.  Pop Ds
  443.  Pop Si
  444.  Pop Di
  445.  Pop Cx
  446.  Pop Bx
  447.  Pop Ax                 ;restore registers
  448.  Ret 6
  449.  Endp                   ;Format_Rgt_P
  450.  
  451. ;================================================
  452. ; Append the source string to the destination
  453. ; string right justified. The character to use
  454. ; in justifing must be in the high byte of the
  455. ; last word pushed on the stack and the final
  456. ; string size must be in the low byte. The
  457. ; destination string address is returned on the
  458. ; stack. The carry is set if the final string
  459. ; would be too long or could not be justified.
  460.  
  461. Justify_Rgt_P Proc Near
  462.  Push Ax
  463.  Push Bx
  464.  Push Cx
  465.  Push Di
  466.  Push Si
  467.  Push Ds
  468.  Push Es
  469.  Push Bp                ;save registers
  470.  Cld                    ;clear direction
  471.  
  472.  Mov Bp, Sp
  473.  Mov Di, [Bp+26]        ;get destination offset
  474.  Mov Es, [Bp+24]        ;get destination segment
  475.  Mov Si, [Bp+22]        ;get source offset
  476.  Mov Ds, [Bp+20]        ;get source segment
  477.  
  478.  Seg Es
  479.  Mov Al, [Di]           ;destination length
  480.  Mov Cl, [Si]           ;source length
  481.  
  482. ;--- add the justifing characters
  483.  
  484.  Mov Bh, Al
  485.  Add Bh, Cl             ;length of both strings in BL
  486.  Jc Badjustify          ;jump if too big
  487.  Mov Bl, [Bp+18]        ;get final size
  488.  Sub Bl, Bh             ;calculate amount of justify
  489.  Jc Badjustify          ;jump if final size too small
  490.  Mov Bh, [Bp+19]        ;get character to justify with
  491.  
  492.  Push Di
  493.  Push Es
  494.  Push Bx
  495.  Call Append_Chrs_P     ;append characters
  496.  Add Sp, 4              ;throw away address, not needed
  497.  
  498. ;--- append the string
  499.  
  500.  Sub Ah, Ah
  501.  Mov Bh, Ah
  502.  Mov Ch, Bh             ;clear high bytes of sizes
  503.  
  504.  Add Ax, Bx             ;add for new characters
  505.  Mov Bx, Ax
  506.  Add Al, Cl             ;new total length
  507.  
  508.  Seg Es
  509.  Mov [Di], Al           ;save new length
  510.  
  511.  Add Di, Bx             ;destination pointer to end
  512.  Inc Di                 ;don't forget length byte
  513.  Inc Si                 ;... and source
  514.  
  515.  Rep
  516.  Movsb                  ;move string
  517.  Clc                    ;no error
  518.  
  519. BadJustify
  520.  Pop Bp
  521.  Pop Es
  522.  Pop Ds
  523.  Pop Si
  524.  Pop Di
  525.  Pop Cx
  526.  Pop Bx
  527.  Pop Ax                 ;restore registers
  528.  Ret 6
  529.  Endp                   ;Justify_Rgt_P
  530.  
  531. ;================================================
  532. ; Convert character in AL to lower-case. AL not
  533. ; preserved.
  534.  
  535. Lower_Chr_P Proc Near
  536.  Cmp Al, 'A'            ;lower limit
  537.  Jb NotLowerChr
  538.  Cmp Al, 'Z'            ;upper limit
  539.  Ja NotLowerChr
  540.  Add Al ,'a'-'A'        ;make lower
  541. NotLowerChr Ret
  542.  Endp                   ;Lower_Chr_P
  543.  
  544. ;================================================
  545. ; Convert character in AL to upper-case. AL not
  546. ; preserved.
  547.  
  548. Upper_Chr_P Proc Near
  549.  Cmp Al, 'a'            ;lower limit
  550.  Jb NotUpperChr
  551.  Cmp Al, 'z'            ;upper limit
  552.  Ja NotUpperChr
  553.  Sub Al ,'a'-'A'        ;make upper
  554. NotUpperChr Ret
  555.  Endp                   ;Upper_Chr_P
  556.  
  557. ;================================================
  558. ; Translate the destination string into a 32-
  559. ; bit number.  The number is returned on the
  560. ; stack in place of the string address (the
  561. ; high 16 bits should be popped first). If
  562. ; there is an error the carry is set and a
  563. ; particular value is returned in the low word
  564. ; of the value: 0000 means the source was a nul
  565. ; string, 0001 means overflow, and 0002  means
  566. ; there  was a bad character in the string.
  567.  
  568. Make_Bin_P Proc Near
  569.  Push Ax
  570.  Push Bx
  571.  Push Cx
  572.  Push Dx
  573.  Push Di
  574.  Push Si
  575.  Push Ds
  576.  Push Bp                ;save registers
  577.  Cld                    ;clear direction
  578.  
  579.  Mov Bp, Sp
  580.  Mov Si, [Bp+20]        ;get source offset
  581.  Mov Ds, [Bp+18]        ;get source segment
  582.  
  583.  Cmp Byte [Si], 0       ;check if nul string
  584.  Je MakeBinNul          ;jump if so
  585.  
  586.  Mov Bx, 10             ;base ten
  587.  Lodsb                  ;load length
  588.  Mov Cl, Al
  589.  Sub Ch, Ch             ;CX has length
  590.  
  591.  Sub Dx, Dx
  592.  Mov Di, Dx             ;expects value in DX.DI
  593.  Jmp MakeBinStart       ;jump to start, skip value x 10
  594.  
  595. ;--- loop for each digit
  596.  
  597. ;--- multiply total times ten
  598.  
  599. MakeBinLoop
  600.  Mov Ax, [Bp+18]        ;high word of value
  601.  Mul Ax, Bx             ;multply, AX has high word result
  602.  Jc MakeBinOver         ;jump if overflow
  603.  Mov Di, Ax             ;save high word
  604.  
  605.  Mov Ax, [Bp+20]        ;low word of value
  606.  Mul Ax, Bx             ;multiply, DX.AX has result
  607.  
  608.  Add Dx, Di             ;add high result
  609.  Jc MakeBinOver         ;jump if overflow
  610.  
  611.  Mov Di, Ax             ;save low word, new value is in DX.DI
  612.  
  613. ;--- add in next digit
  614.  
  615. MakeBinStart
  616.  Lodsb                  ;load next digit
  617.  Sub Al, '0'            ;get value
  618.  Cmp Al, 9              ;check value
  619.  Ja MakeBinBad          ;jump if illegal character
  620.  
  621.  Sub Ah, Ah
  622.  Add Di, Ax             ;add in new value
  623.  Jnc MakeBinNohi        ;jump if no carry to high word
  624.  
  625.  Inc Dx                 ;increment high word
  626.  Jz MakeBinOver         ;jump if overflow
  627.  
  628. MakeBinNohi
  629.  Mov [Bp+20], Di        ;save low word
  630.  Mov [Bp+18], Dx        ;save high word
  631.  Loop MakeBinLoop       ;loop back for next digit
  632.  
  633. ;--- number successfully converted
  634.  
  635.  Clc
  636.  
  637. MakeBinDone
  638.  Pop Bp
  639.  Pop Ds
  640.  Pop Si
  641.  Pop Di
  642.  Pop Dx
  643.  Pop Cx
  644.  Pop Bx
  645.  Pop Ax                 ;restore registers
  646.  Ret
  647.  
  648. ;--- nul string
  649.  
  650. MakeBinNul
  651.  Mov Word [Bp+20], 0000 ;error code
  652.  Mov Word [Bp+18], 0000
  653.  Stc
  654.  Jmps MakeBinDone
  655.  
  656. ;--- overflow
  657.  
  658. MakeBinOver
  659.  Mov Word [Bp+20], 0001 ;error code
  660.  Mov Word [Bp+18], 0000
  661.  Stc
  662.  Jmps MakeBinDone
  663.  
  664. ;--- illegal character
  665.  
  666. MakeBinBad
  667.  Mov Word [Bp+20], 0002 ;error code
  668.  Mov Word [Bp+18], 0000
  669.  Stc
  670.  Jmps MakeBinDone
  671.  Endp                   ;Make_Bin_P
  672.  
  673. ;================================================
  674. ; Translate the 32-bit number into a decimal
  675. ; ASCII string.  The low word of the number
  676. ; must be pushed onto the stack first. The
  677. ; local string address is returned on the stack.
  678.  
  679. Make_Dec_P Proc Near
  680.  Push Ax
  681.  Push Bx
  682.  Push Cx
  683.  Push Dx
  684.  Push Di
  685.  Push Si
  686.  Push Ds
  687.  Push Es
  688.  Push Bp                ;save registers
  689.  Cld                    ;clear direction
  690.  
  691.  Mov Ax, Cs
  692.  Mov Ds, Ax
  693.  Mov Es, Ax             ;set data segments
  694.  
  695.  Mov Bx, 10             ;number base
  696.  Sub Cx, Cx             ;CX counts digits
  697.  Mov Di, Offset MakeDecBuff ;number buffer location
  698.  Mov Si, Di
  699.  Inc Di
  700.  Mov Bp, Sp             ;pointer to value
  701.  
  702. ;--- loop for each digit, at least one 0
  703.  
  704. MakeDecLoop
  705.  Mov Ax, [Bp+20]        ;high word of value
  706.  Sub Dx, Dx             ;clear for divide
  707.  Div Ax, Bx             ;divide, DX gets remainder
  708.  Mov [Bp+20], Ax        ;save quotient (high word)
  709.  
  710.  Mov Ax, [Bp+22]        ;low word of value
  711.  Div Ax, Bx             ;divide, DX gets remainder (the digit)
  712.  Mov [Bp+22], Ax        ;save quotient (low word)
  713.  
  714.  Add Dl, '0'            ;make ASCII
  715.  Mov Al, Dl
  716.  Stosb                  ;store
  717.  Inc Cx                 ;another digit
  718.  
  719.  Cmp Word [Bp+22], 0    ;check if low word zero
  720.  Jne MakeDecLoop        ;jump if not
  721.  Cmp Word [Bp+20], 0    ;check if high word zero
  722.  Jne MakeDecLoop        ;jump if not
  723.  
  724. ;--- done with number
  725.  
  726.  Mov [Si], Cl           ;save length
  727.  Shr Cx                 ;CX/2
  728.  Jz MakeDecDone         ;jump if nothing to switch
  729.  Dec Di                 ;last digit
  730.  Inc Si                 ;first digit
  731.  Xchg Si, Di            ;SI points to end, DI points to beginning
  732.  
  733. ;--- reverse digits
  734.  
  735. MakeDecRLoop
  736.  Seg Es
  737.  Mov Al, [Di]           ;load front character
  738.  Xchg Al, [Si]          ;swap with end character
  739.  Stosb                  ;store new front character
  740.  Dec Si                 ;back up
  741.  Loop MakeDecRLoop      ;loop back for each digit
  742.  
  743. ;--- finished
  744.  
  745. MakeDecDone
  746.  Mov Word [Bp+22], Offset MakeDecBuff ;save offset
  747.  Mov [Bp+20], Ds        ;save segment
  748.  
  749.  Clc
  750.  Pop Bp
  751.  Pop Es
  752.  Pop Ds
  753.  Pop Si
  754.  Pop Di
  755.  Pop Dx
  756.  Pop Cx
  757.  Pop Bx
  758.  Pop Ax                 ;restore registers
  759.  Ret
  760.  
  761. ;--- data
  762.  
  763. MakeDecBuff Label Byte  ;string buffer
  764.  Ds 11
  765.  Endp                   ;Make_Dec_P
  766.  
  767. ;================================================
  768. ; Get the string representing the present day.
  769. ; The day index (Sunday=0, etc.) must be in the
  770. ; low byte of the word pushed on the stack. The
  771. ; local string address is returned on the
  772. ; stack.
  773.  
  774. Day_Str_P Proc Near
  775.  Sub Sp, 2              ;room for return data
  776.  Push Bx
  777.  Push Ds
  778.  Push Bp
  779.  
  780.  Mov Bp, Sp
  781.  Mov Bx, [Bp+8]
  782.  Mov [Bp+6], Bx         ;move return address
  783.  
  784.  Mov Bx, Cs
  785.  Mov Ds, Bx             ;load data segment
  786.  Mov Bl, [Bp+10]        ;get day index
  787.  Sub Bh, Bh             ;clear high part of index
  788.  Shl Bx                 ;times two (two bytes per entry)
  789.  Add Bx, Offset DayStrList ;offset of string location
  790.  Mov Bx, [Bx]           ;get string location
  791.  
  792.  Mov [Bp+10], Bx        ;save offset
  793.  Mov [Bp+8], Ds         ;save segment
  794.  
  795.  Pop Bp
  796.  Pop Ds
  797.  Pop Bx
  798.  Ret
  799.  
  800. ;--- table of day strings
  801.  
  802. DayStrList Label Word
  803.  Dw Offset DayStr01, Offset DayStr02, Offset DayStr03, Offset DayStr04
  804.  Dw Offset DayStr05, Offset DayStr06, Offset DayStr07
  805.  
  806. ;--- day strings
  807.  
  808. DayStr01 Db 6,'Sunday'
  809. DayStr02 Db 6,'Monday'
  810. DayStr03 Db 7,'Tuesday'
  811. DayStr04 Db 9,'Wednesday'
  812. DayStr05 Db 8,'Thursday'
  813. DayStr06 Db 6,'Friday'
  814. DayStr07 Db 8,'Saturday'
  815.  Endp                   ;Day_Str_P
  816.  
  817. ;================================================
  818. ; Get the string representing the present
  819. ; month. The month index (January=0, etc.) must
  820. ; be in the low byte of the word pushed on the
  821. ; stack. The local string address is returned
  822. ; on the stack.
  823.  
  824. Month_Str_P Proc Near
  825.  Sub Sp, 2              ;room for return data
  826.  Push Bx
  827.  Push Ds
  828.  Push Bp
  829.  
  830.  Mov Bp, Sp
  831.  Mov Bx, [Bp+8]
  832.  Mov [Bp+6], Bx         ;move return address
  833.  
  834.  Mov Bx, Cs
  835.  Mov Ds, Bx             ;load data segment
  836.  Mov Bl, [Bp+10]        ;get day index
  837.  Sub Bh, Bh             ;clear high part of index
  838.  Shl Bx                 ;times two (two bytes per entry)
  839.  Add Bx, Offset MonthStrList ;offset of string location
  840.  Mov Bx, [Bx]           ;get string location
  841.  
  842.  Mov [Bp+10], Bx        ;save offset
  843.  Mov [Bp+8], Ds         ;save segment
  844.  
  845.  Pop Bp
  846.  Pop Ds
  847.  Pop Bx
  848.  Ret
  849.  
  850. ;--- table of month strings
  851.  
  852. MonthStrList Label Word
  853.  Dw Offset MonthStr01, Offset MonthStr02, Offset MonthStr03
  854.  Dw Offset MonthStr04, Offset MonthStr05, Offset MonthStr06
  855.  Dw Offset MonthStr07, Offset MonthStr08, Offset MonthStr09
  856.  Dw Offset MonthStr10, Offset MonthStr11, Offset MonthStr12
  857.  
  858. ;--- month strings
  859.  
  860. MonthStr01 Db 7,'January'
  861. MonthStr02 Db 8,'February'
  862. MonthStr03 Db 5,'March'
  863. MonthStr04 Db 5,'April'
  864. MonthStr05 Db 3,'May'
  865. MonthStr06 Db 4,'June'
  866. MonthStr07 Db 4,'July'
  867. MonthStr08 Db 6,'August'
  868. MonthStr09 Db 9,'September'
  869. MonthStr10 Db 7,'October'
  870. MonthStr11 Db 8,'November'
  871. MonthStr12 Db 8,'December'
  872.  Endp                   ;Month_Str_P
  873.  
  874. ;================================================
  875. ; Get the string representing the time the in
  876. ; XX:XX am/pm format (e.g. 3:27 pm). The hours
  877. ; must be in the high byte of the word on the
  878. ; stack and the minutes must be in the low
  879. ; byte. The local string address is returned on
  880. ; the stack.
  881.  
  882. Time_Str_P Proc Near
  883.  Sub Sp, 2              ;room for return data
  884.  Push Ax
  885.  Push Ds
  886.  Push Bp
  887.  
  888.  Mov Bp, Sp
  889.  Mov Bx, [Bp+8]
  890.  Mov [Bp+6], Bx         ;move return address
  891.  
  892.  Mov Ax, Cs
  893.  Mov Ds, Ax             ;set segment registers
  894.  
  895.  Mov Ax, Offset TimeStrBuff ;storage
  896.  Push Ax
  897.  Push Ds
  898.  Call Clear_Str_P       ;initialize string
  899.  
  900. ;--- hours
  901.  
  902.  Mov Al, [Bp+11]        ;get hours
  903.  Or Al, Al              ;check if 12am to 12:59am
  904.  Jnz TimeStrHour1       ;jump if not
  905.  Mov Al, 12             ;set to 12
  906.  
  907. TimeStrHour1
  908.  Cmp Al, 13             ;check if next half
  909.  Jb TimeStrHour2        ;jump if not
  910.  Sub Al, 12             ;reset half
  911.  
  912. TimeStrHour2
  913.  Sub Ah, Ah
  914.  Push Ax
  915.  Sub Ax, Ax             ;high word of number is zero
  916.  Push Ax
  917.  Call Make_Dec_P        ;create number string
  918.  Call Copy_Str_P        ;copy string to buffer
  919.  
  920.  Mov Ah, ':'            ;colon
  921.  Mov Al, 1              ;count
  922.  Push Ax
  923.  Call Append_Chrs_P     ;append character
  924.  
  925. ;--- minutes
  926.  
  927.  Mov Al,[Bp+10]         ;get minutes
  928.  Sub Ah, Ah
  929.  Push Ax
  930.  Sub Ax, Ax             ;high word of number is zero
  931.  Push Ax
  932.  Call Make_Dec_P        ;create number string
  933.  Mov Al, 2              ;string size
  934.  Mov Ah, '0'            ;justify character
  935.  Push Ax
  936.  Call Format_Rgt_P      ;append string to buffer
  937.  
  938. ;--- am/pm
  939.  
  940.  Mov Ax, Offset TimeStrPm
  941.  Cmp Byte [Bp+11], 12   ;check after noon
  942.  Jae TimeStrAmPm        ;jump if so
  943.  Mov Ax, Offset TimeStrAm
  944.  
  945. TimeStrAmPm
  946.  Push Ax
  947.  Push Ds
  948.  Call Append_Str_P     ;append string
  949.  
  950. ;--- set return data
  951.  
  952.  Pop Ax                 ;return segment
  953.  Mov [Bp+8], Ax         ;save
  954.  Pop Ax                 ;return offset
  955.  Mov [Bp+10], Ax        ;save
  956.  
  957.  Pop Bp
  958.  Pop Ds
  959.  Pop Ax
  960.  Ret
  961.  
  962. ;--- data
  963.  
  964. TimeStrPm Db 3,' pm'
  965. TimeStrAm Db 3,' am'
  966.  
  967. TimeStrBuff Label Byte
  968.  Db ?,'??:?? ??'
  969.  Endp                   ;Time_Str_P
  970.  
  971. ;================================================
  972. ; Translate string format into a name format
  973. ; (a sequence of characters terminated by byte
  974. ; 00). The local string address is returned on
  975. ; the stack.
  976.  
  977. Make_Nam_P Proc Near
  978.  Push Cx
  979.  Push Di
  980.  Push Si
  981.  Push Ds
  982.  Push Es
  983.  Push Bp                ;save registers
  984.  
  985.  Mov Bp, Sp
  986.  Mov Si, [Bp+16]        ;get offset
  987.  Mov Ds, [Bp+14]        ;get segment
  988.  
  989.  Mov Cx, Cs
  990.  Mov Es, Cx             ;set local data segment
  991.  Mov Di, Offset MakeNamBuff ;local buffer
  992.  Mov Cl, [Si]           ;length
  993.  Sub Ch, Ch
  994.  Inc Si                 ;skip length
  995.  Rep
  996.  Movsb                  ;copy string
  997.  
  998.  Seg Es
  999.  Mov Byte [Di], 0       ;store terminating zero
  1000.  Mov Word [Bp+16], Offset MakeNamBuff ;save offset
  1001.  Mov [Bp+14], Es        ;save segment
  1002.  
  1003.  Pop Bp
  1004.  Pop Es
  1005.  Pop Ds
  1006.  Pop Si
  1007.  Pop Di
  1008.  Pop Cx
  1009.  Clc
  1010.  Ret
  1011.  
  1012. ;--- local storage
  1013.  
  1014. MakeNamBuff Label Byte
  1015.  Ds 256                 ;room for 255 bytes and 00
  1016.  Endp                   ;Make_Nam_P
  1017.  
  1018. ;================================================
  1019. ; Translate a name format string (a sequence of
  1020. ; characters terminated by byte 00) into a normal
  1021. ; string (a string of characters preceded by a byte
  1022. ; containing its length). The local string address
  1023. ; is returned on the stack.
  1024.  
  1025. Make_Str_P Proc Near
  1026.  Push Ax
  1027.  Push Di
  1028.  Push Si
  1029.  Push Ds
  1030.  Push Es
  1031.  Push Bp                ;save registers
  1032.  
  1033.  Mov Bp, Sp
  1034.  Mov Si, [Bp+16]        ;get offset
  1035.  Mov Ds, [Bp+14]        ;get segment
  1036.  
  1037.  Mov Ax, Cs
  1038.  Mov Es, Ax             ;set local data segment
  1039.  Mov Di, Offset MakeStrBuff+1 ;local buffer, skip length byte
  1040.  Sub Ah, Ah             ;initial byte count
  1041.  
  1042. ;--- loop for each byte
  1043.  
  1044. MakeStrLoop
  1045.  Lodsb                  ;load next byte
  1046.  Or Al, Al              ;check if end of string
  1047.  Jz MakeStrFinish       ;jump if so
  1048.  
  1049.  Inc Ah                 ;update count
  1050.  Jz MakeStrError        ;jump if too big
  1051.  Stosb                  ;store byte
  1052.  Jmp MakeStrLoop        ;loop back for next byte
  1053.  
  1054. ;--- finished
  1055.  
  1056. MakeStrFinish
  1057.  Clc
  1058.  
  1059. MakeStrDone
  1060.  Mov Di, Offset MakeStrBuff ;local buffer
  1061.  Seg Es
  1062.  Mov [Di], Ah           ;save string length
  1063.  Mov [Bp+16], Di        ;save offset
  1064.  Mov [Bp+14], Es        ;save segment
  1065.  
  1066.  Pop Bp
  1067.  Pop Es
  1068.  Pop Ds
  1069.  Pop Si
  1070.  Pop Di
  1071.  Pop Ax
  1072.  Clc
  1073.  Ret
  1074.  
  1075. ;--- error, string too long
  1076.  
  1077. MakeStrError
  1078.  Mov Ah, 255            ;max length
  1079.  Stc
  1080.  Jmps MakeStrDone
  1081.  
  1082. ;--- local storage
  1083.  
  1084. MakeStrBuff Label Byte
  1085.  Ds 256                 ;room for 255 bytes and length
  1086.  Endp                   ;Make_Str_P
  1087.  
  1088. ;================================================
  1089. ; Return the status of the standard input device.
  1090. ; ZF=1 if no characters waiting.
  1091.  
  1092. Input_Sta_P Proc Near
  1093.  Push Ax
  1094.  Mov Ah, 0bh            ;function number
  1095.  Int 21h                ;execute
  1096.  Or Al, Al              ;set ZF
  1097.  Pop Ax
  1098.  Ret
  1099.  Endp                   ;Input_Sta_P
  1100.  
  1101. ;================================================
  1102. ; Input a character from the standard input. AL
  1103. ; returns the character. AX not preserved.
  1104.  
  1105. Input_Chr_P Proc Near
  1106.  Mov Ah, 1              ;function number
  1107.  Int 21h                ;execute
  1108.  Ret
  1109.  Endp                   ;Input_Chr_P
  1110.  
  1111. ;================================================
  1112. ; Input a character from the standard input
  1113. ; without a screen echo. AL returns the
  1114. ; character. AX not preserved.
  1115.  
  1116. Input_Hid_P Proc Near
  1117.  Mov Ah, 8              ;function number
  1118.  Int 21h                ;execute
  1119.  Ret
  1120.  Endp                   ;Input_Hid_P
  1121.  
  1122. ;================================================
  1123. ; Input a string from the user and move the cursor
  1124. ; to the next line. The maximum input size (0 to
  1125. ; 254) must be in the low byte of a word pushed on
  1126. ; the stack. If the input length is too big the
  1127. ; carry is set, otherwise the carry is cleared and
  1128. ; the ZF will be set if the input length is zero.
  1129. ; The string address is returned.
  1130.  
  1131. Input_Str_P Proc Near
  1132.  Sub Sp, 2              ;allow for extra word of data
  1133.  Push Ax
  1134.  Push Bx
  1135.  Push Dx
  1136.  Push Ds
  1137.  Push Bp
  1138.  
  1139.  Mov Bp, Sp
  1140.  Mov Ax, Cs
  1141.  Mov Ds, Ax             ;set data segment
  1142.  
  1143.  Mov Ax, [Bp+12]
  1144.  Mov [Bp+10], Ax        ;fix return address
  1145.  
  1146.  Mov Al, [Bp+14]        ;get max input length
  1147.  Mov Word [Bp+14], Offset InputStrBuff+1 ;set offset
  1148.  Mov Word [Bp+12], Ds   ;set segment
  1149.  
  1150.  Inc Al                 ;account for CR
  1151.  Jz Badinput            ;jump if too big (can only be up to 254)
  1152.  Mov InputStrBuff, Al   ;save length
  1153.  
  1154.  Mov Ah, 0ah            ;function
  1155.  Mov Dx, Offset InputStrBuff ;formatted buffer
  1156.  Int 21h                ;execute
  1157.  
  1158.  Mov Dl, 10             ;linefeed
  1159.  Call Display_Chr_P     ;display
  1160.  
  1161.  Mov Bl, InputStrBuff + 1        ;get input length
  1162.  Sub Bh, Bh                      ;clear upper byte
  1163.  Mov Byte [Bx+InputStrBuff+2], 0 ;store 00 on CR
  1164.  Or Bx, Bx                       ;set ZF
  1165.  Clc
  1166.  
  1167. InputStrDone
  1168.  Pop Bp
  1169.  Pop Ds
  1170.  Pop Dx
  1171.  Pop Bx
  1172.  Pop Ax
  1173.  Ret
  1174.  
  1175. ;--- input was too big
  1176.  
  1177. Badinput
  1178.  Mov Byte InputStrBuff + 1, 0   ;set zero input length
  1179.  Stc
  1180.  Jmps InputStrDone
  1181.  
  1182. ;--- data
  1183.  
  1184. InputStrBuff Label Byte
  1185.  Db ?                   ;maximum length
  1186.  Db ?                   ;input length
  1187.  Ds 255                 ;storage for full string
  1188.  Endp                   ;Input_Str_P
  1189.  
  1190. ;================================================
  1191. ; Move the cursor to the upper left corner.
  1192.  
  1193. Home_Cur_P Proc Near
  1194.  Push Ax
  1195.  Mov Ax, Offset HomeCurCode
  1196.  Push Ax
  1197.  Push Cs
  1198.  Call Display_Str_P     ;send string
  1199.  Pop Ax
  1200.  Ret
  1201. HomeCurCode Db 6,27,'[1;1H' ;control string
  1202.  Endp                   ;Home_Cur_P
  1203.  
  1204. ;================================================
  1205. ; Move the cursor left one column.
  1206.  
  1207. Left_Cur_P Proc Near
  1208.  Push Ax
  1209.  Mov Ax, Offset LeftCurCode
  1210.  Push Ax
  1211.  Push Cs
  1212.  Call Display_Str_P     ;send string
  1213.  Pop Ax
  1214.  Ret
  1215. LeftCurCode Db 3,27,'[D'  ;control string
  1216.  Endp                   ;Left_Cur_P
  1217.  
  1218. ;================================================
  1219. ; Move the cursor right one column.
  1220.  
  1221. Right_Cur_P Proc Near
  1222.  Push Ax
  1223.  Mov Ax, Offset RightCurCode
  1224.  Push Ax
  1225.  Push Cs
  1226.  Call Display_Str_P     ;send string
  1227.  Pop Ax
  1228.  Ret
  1229. RightCurCode Db 3,27,'[C' ;control string
  1230.  Endp                   ;Right_Cur_P
  1231.  
  1232. ;================================================
  1233. ; Move the cursor up one row.
  1234.  
  1235. Up_Cur_P Proc Near
  1236.  Push Ax
  1237.  Mov Ax, Offset UpCurCode
  1238.  Push Ax
  1239.  Push Cs
  1240.  Call Display_Str_P     ;send string
  1241.  Pop Ax
  1242.  Ret
  1243. UpCurCode Db 3,27,'[A'    ;control string
  1244.  Endp                   ;Up_Cur_P
  1245.  
  1246. ;================================================
  1247. ; Move the cursor down one row.
  1248.  
  1249. Down_Cur_P Proc Near
  1250.  Push Ax
  1251.  Mov Ax, Offset DownCurCode
  1252.  Push Ax
  1253.  Push Cs
  1254.  Call Display_Str_P     ;send string
  1255.  Pop Ax
  1256.  Ret
  1257. DownCurCode Db 3,27,'[B'  ;control string
  1258.  Endp                   ;Down_Cur_P
  1259.  
  1260. ;================================================
  1261. ; Save the cursor positon.
  1262.  
  1263. Save_Cur_P Proc Near
  1264.  Push Ax
  1265.  Mov Ax, Offset SaveCurCode
  1266.  Push Ax
  1267.  Push Cs
  1268.  Call Display_Str_P     ;send string
  1269.  Pop Ax
  1270.  Ret
  1271. SaveCurCode Db 3,27,'[s' ;control string
  1272.  Endp                   ;Save_Cur_P
  1273.  
  1274. ;================================================
  1275. ; Restore the cursor position.
  1276.  
  1277. Restore_Cur_P Proc Near
  1278.  Push Ax
  1279.  Mov Ax, Offset RestoreCurCode
  1280.  Push Ax
  1281.  Push Cs
  1282.  Call Display_Str_P     ;send string
  1283.  Pop Ax
  1284.  Ret
  1285. RestoreCurCode Db 3,27,'[u' ;control string
  1286.  Endp                   ;Restore_Cur_P
  1287.  
  1288. ;================================================
  1289. ; Move the cursor to a specified position. The
  1290. ; column must be in the low byte of the word
  1291. ; pushed on the stack and the row must be in
  1292. ; the high byte. The upper left corner is 0,0.
  1293. ; Will only calculate up to 99,99 (which should be
  1294. ; large enough for most screens).
  1295.  
  1296. Locate_Cur_P Proc Near
  1297.  Push Ax
  1298.  Push Bx
  1299.  Push Dx
  1300.  Push Ds
  1301.  Push Bp
  1302.  
  1303.  Mov Ax, Cs
  1304.  Mov Ds, Ax
  1305.  Mov Bp, Sp
  1306.  Mov Bx, Offset LocateCurCode
  1307.  Mov Dl, 10             ;base number
  1308.  Mov Dh, '0'            ;ascii conversion value
  1309.  
  1310.  Mov Al, [Bp+13]        ;row
  1311.  Sub Ah, Ah
  1312.  Div Al, Dl             ;get digits
  1313.  
  1314.  Add Al, Dh
  1315.  Add Ah, Dh             ;make both ascii
  1316.  Mov [Bx+3], Al         ;store tens digit
  1317.  Mov [Bx+4], Ah         ;store ones digit
  1318.  
  1319.  Mov Al, [Bp+12]        ;column
  1320.  Sub Ah, Ah
  1321.  Div Al, Dl             ;get digits
  1322.  
  1323.  Add Al, Dh
  1324.  Add Ah, Dh             ;make both ascii
  1325.  Mov [Bx+6], Al         ;store tens digit
  1326.  Mov [Bx+7], Ah         ;store ones digit
  1327.  
  1328.  Push Bx
  1329.  Push Ds
  1330.  Call Display_Str_P     ;send string
  1331.  
  1332.  Pop Bp
  1333.  Pop Ds
  1334.  Pop Dx
  1335.  Pop Bx
  1336.  Pop Ax
  1337.  Ret 2
  1338. LocateCurCode Db 8,27,'[??;??H'
  1339.  Endp                   ;Locate_Cur_P
  1340.  
  1341. ;================================================
  1342. ; Set display attribute to normal.
  1343.  
  1344. Normal_Atr_P Proc Near
  1345.  Push Ax
  1346.  Mov Ax, Offset NormalAtrCode
  1347.  Push Ax
  1348.  Push Cs
  1349.  Call Display_Str_P     ;send string
  1350.  Pop Ax
  1351.  Ret
  1352. NormalAtrCode Db 4,27,'[0m' ;control string
  1353.  Endp                   ;Normal_Atr_P
  1354.  
  1355. ;================================================
  1356. ; Set display attribute to bold.
  1357.  
  1358. Bold_Atr_P Proc Near
  1359.  Push Ax
  1360.  Mov Ax, Offset BoldAtrCode
  1361.  Push Ax
  1362.  Push Cs
  1363.  Call Display_Str_P     ;send string
  1364.  Pop Ax
  1365.  Ret
  1366. BoldAtrCode Db 4,27,'[1m' ;control string
  1367.  Endp                   ;Bold_Atr_P
  1368.  
  1369. ;================================================
  1370. ; Set display attribute to underline.
  1371.  
  1372. Underline_Atr_P Proc Near
  1373.  Push Ax
  1374.  Mov Ax, Offset UnderlineAtrCode
  1375.  Push Ax
  1376.  Push Cs
  1377.  Call Display_Str_P     ;send string
  1378.  Pop Ax
  1379.  Ret
  1380. UnderlineAtrCode Db 4,27,'[4m' ;control string
  1381.  Endp                   ;Underline_Atr_P
  1382.  
  1383. ;================================================
  1384. ; Set display attribute to blink.
  1385.  
  1386. Blink_Atr_P Proc Near
  1387.  Push Ax
  1388.  Mov Ax, Offset BlinkAtrCode
  1389.  Push Ax
  1390.  Push Cs
  1391.  Call Display_Str_P     ;send string
  1392.  Pop Ax
  1393.  Ret
  1394. BlinkAtrCode Db 4,27,'[5m' ;control string
  1395.  Endp                   ;Blink_Atr_P
  1396.  
  1397. ;================================================
  1398. ; Set display attribute to reverse video.
  1399.  
  1400. Reverse_Atr_P Proc Near
  1401.  Push Ax
  1402.  Mov Ax, Offset ReverseAtrCode
  1403.  Push Ax
  1404.  Push Cs
  1405.  Call Display_Str_P     ;send string
  1406.  Pop Ax
  1407.  Ret
  1408. ReverseAtrCode Db 4,27,'[7m' ;control string
  1409.  Endp                   ;Reverse_Atr_P
  1410.  
  1411. ;================================================
  1412. ; Clear the screen and home the cursor.
  1413.  
  1414. Clear_Scr_P Proc Near
  1415.  Push Ax
  1416.  Mov Ax, Offset ClearScrCode
  1417.  Push Ax
  1418.  Push Cs
  1419.  Call Display_Str_P     ;send string
  1420.  Pop Ax
  1421.  Ret
  1422. ClearScrCode Db 4,27,'[2J' ;control string
  1423.  Endp                   ;Clear_Scr_P
  1424.  
  1425. ;================================================
  1426. ; Display the character in DL to the standard
  1427. ; output.
  1428.  
  1429. Display_Chr_P Proc Near
  1430.  Push Ax
  1431.  Mov Ah, 2              ;function number
  1432.  Int 21h                ;execute
  1433.  Pop Ax
  1434.  Ret
  1435.  Endp                   ;Display_Chr_P
  1436.  
  1437. ;================================================
  1438. ; Sound the speaker.
  1439.  
  1440. Sound_Bel_P Proc Near
  1441.  Push Dx
  1442.  Mov Dl, 7              ;BEL
  1443.  Call Display_Chr_P     ;display
  1444.  Pop Dx
  1445.  Ret
  1446.  Endp                   ;Sound_Bel_P
  1447.  
  1448. ;================================================
  1449. ; Start a new display line.
  1450.  
  1451. Line_P Proc Near
  1452.  Push Dx
  1453.  Mov Dl, 13             ;CR
  1454.  Call Display_Chr_P     ;display
  1455.  Mov Dl, 10             ;LF
  1456.  Call Display_Chr_P     ;display
  1457.  Pop Dx
  1458.  Ret
  1459.  Endp                   ;Line_P
  1460.  
  1461. ;================================================
  1462. ; Display the destination string to the
  1463. ; standard output device.
  1464.  
  1465. Display_Str_P Proc Near
  1466.  Push Ax
  1467.  Push Bx
  1468.  Push Cx
  1469.  Push Dx
  1470.  Push Ds
  1471.  Push Bp
  1472.  
  1473.  Mov Bp, Sp
  1474.  Mov Ah, 40h            ;function number
  1475.  Mov Bx, [Bp+16]        ;get offset
  1476.  Mov Ds, [Bp+14]        ;get segment
  1477.  Mov Cl, [Bx]           ;get length byte
  1478.  Sub Ch, Ch             ;clear upper byte, CX=length
  1479.  Mov Dx, Bx
  1480.  Inc Dx                 ;start of string body
  1481.  Mov Bx, 1              ;standard output
  1482.  Int 21h                ;execute
  1483.  
  1484.  Pop Bp
  1485.  Pop Ds
  1486.  Pop Dx
  1487.  Pop Cx
  1488.  Pop Bx
  1489.  Pop Ax
  1490.  Ret 4
  1491.  Endp                   ;Display_Str_P
  1492.  
  1493. ;================================================
  1494. ; Display the destination string to the
  1495. ; standard output device and then move the
  1496. ; cursor to the next line.
  1497.  
  1498. Display_Lin_P Proc Near
  1499.  Push Ax
  1500.  Push Bp
  1501.  Sub Sp, 4
  1502.  Mov Bp, Sp
  1503.  Mov Ax, [Bp+12]
  1504.  Mov [Bp+2], Ax         ;offset
  1505.  Mov Ax, [Bp+10]
  1506.  Mov [Bp], Ax           ;segment
  1507.  Call Display_Str_P     ;display string
  1508.  Call Line_P            ;next line
  1509.  Pop Bp
  1510.  Pop Ax
  1511.  Ret 4
  1512.  Endp                   ;Display_Lin_P
  1513.  
  1514. ;================================================
  1515. ; Open a file for reading and writing. The name
  1516. ; location must be on the stack. The file handle
  1517. ; is returned on the stack. The name should be a
  1518. ; byte 00 terminated string.
  1519.  
  1520. Open_Fil_P Proc Near
  1521.  Push Ax
  1522.  Push Dx
  1523.  Push Ds
  1524.  Push Bp
  1525.  
  1526.  Mov Bp, Sp
  1527.  Mov Al, 00000010b      ;read/write status
  1528.  Mov Ah, 3dh            ;function number
  1529.  Mov Dx, [Bp+12]        ;name offset
  1530.  Mov Ds, [Bp+10]        ;name segment
  1531.  Int 21h                ;execute
  1532.  Mov [Bp+12], Ax        ;save handle
  1533.  
  1534.  Pop Bp
  1535.  Pop Ds
  1536.  Pop Dx
  1537.  Pop Ax
  1538.  Ret 2
  1539.  Endp                   ;Open_Fil_P
  1540.  
  1541. ;================================================
  1542. ; Create or truncate a file for reading and
  1543. ; writing. The name location must be on the stack.
  1544. ; The file handle is returned on the stack. The
  1545. ; name should be a byte 00 terminated string.
  1546.  
  1547. Create_Fil_P Proc Near
  1548.  Push Ax
  1549.  Push Cx
  1550.  Push Dx
  1551.  Push Ds
  1552.  Push Bp
  1553.  
  1554.  Mov Bp, Sp
  1555.  Mov Ah, 3ch            ;function number
  1556.  Sub Cx, Cx             ;normal attribute
  1557.  Mov Dx, [Bp+14]        ;name offset
  1558.  Mov Ds, [Bp+12]        ;name segment
  1559.  Int 21h                ;execute
  1560.  Mov [Bp+14], Ax        ;save handle
  1561.  
  1562.  Pop Bp
  1563.  Pop Ds
  1564.  Pop Dx
  1565.  Pop Cx
  1566.  Pop Ax
  1567.  Ret 2
  1568.  Endp                   ;Create_Fil_P
  1569.  
  1570. ;================================================
  1571. ; Delete a file. The location of the name of the
  1572. ; file must be passed on the stack. The name should
  1573. ; be a byte 00 terminated string.
  1574.  
  1575. Delete_Fil_P Proc Near
  1576.  Push Ax
  1577.  Push Dx
  1578.  Push Ds
  1579.  Push Bp
  1580.  
  1581.  Mov Bp, Sp
  1582.  Mov Ah, 41h            ;function number
  1583.  Mov Dx, [Bp+12]        ;name offset
  1584.  Mov Ds, [Bp+10]        ;name segment
  1585.  Int 21h                ;execute
  1586.  
  1587.  Pop Bp
  1588.  Pop Ds
  1589.  Pop Dx
  1590.  Pop Ax
  1591.  Ret 4
  1592.  Endp
  1593.  
  1594. ;================================================
  1595. ; Read from a file. The handle, bytes to read,
  1596. ; and buffer address (32 bit) must be pushed on
  1597. ; the stack.  The handle and bytes read are returned.
  1598.  
  1599. Read_Fil_P Proc Near
  1600.  Push Ax
  1601.  Push Bx
  1602.  Push Cx
  1603.  Push Dx
  1604.  Push Ds
  1605.  Push Bp
  1606.  
  1607.  Mov Bp, Sp
  1608.  Mov Ah, 3fh            ;function number
  1609.  Mov Bx, [Bp+20]        ;handle
  1610.  Mov Cx, [Bp+18]        ;bytes to write
  1611.  Mov Dx, [Bp+16]        ;buffer offset
  1612.  Mov Ds, [Bp+14]        ;buffer segment
  1613.  Int 21h                ;execute
  1614.  Mov [Bp+18], Ax        ;save bytes written
  1615.  
  1616.  Pop Bp
  1617.  Pop Ds
  1618.  Pop Dx
  1619.  Pop Cx
  1620.  Pop Bx
  1621.  Pop Ax
  1622.  Ret 4
  1623.  Endp                   ;Read_Fil_P
  1624.  
  1625. ;================================================
  1626. ; Write to a file. The handle, bytes to write,
  1627. ; and buffer address (32 bit) must be pushed on
  1628. ; the stack.  The handle and bytes written are
  1629. ; returned.
  1630.  
  1631. Write_Fil_P Proc Near
  1632.  Push Ax
  1633.  Push Bx
  1634.  Push Cx
  1635.  Push Dx
  1636.  Push Ds
  1637.  Push Bp
  1638.  
  1639.  Mov Bp, Sp
  1640.  Mov Ah, 40h            ;function number
  1641.  Mov Bx, [Bp+20]        ;handle
  1642.  Mov Cx, [Bp+18]        ;bytes to write
  1643.  Mov Dx, [Bp+16]        ;buffer offset
  1644.  Mov Ds, [Bp+14]        ;buffer segment
  1645.  Int 21h                ;execute
  1646.  Mov [Bp+18], Ax        ;save bytes written
  1647.  
  1648.  Pop Bp
  1649.  Pop Ds
  1650.  Pop Dx
  1651.  Pop Cx
  1652.  Pop Bx
  1653.  Pop Ax
  1654.  Ret 4
  1655.  Endp                   ;Write_Fil_P
  1656.  
  1657. ;================================================
  1658. ; Seek an absolute location within a file. The
  1659. ; handle, a 16 bit record size, and a 32 bit (low
  1660. ; word first) record number must be passed on the
  1661. ; stack. The handle is returned. Does not check
  1662. ; for too large a seek.
  1663.  
  1664. Seek_Fil_P Proc Near
  1665.  Push Ax
  1666.  Push Bx
  1667.  Push Cx
  1668.  Push Dx
  1669.  Push Bp
  1670.  
  1671.  Mov Bp, Sp
  1672.  Mov Bx, [Bp+16]        ;record size
  1673.  Mov Ax, [Bp+12]        ;high word
  1674.  Mul Ax, Bx             ;multiply high word (error if carry)
  1675.  Mov Cx, Ax             ;first part of high word
  1676.  Mov Ax, [Bp+14]        ;low word high word of record number
  1677.  Mul Ax, Bx             ;multiply low word
  1678.  Add Cx, Dx             ;add in second part of high word (error if carry)
  1679.  Mov Dx, Ax             ;final absolute offset in CX.DX
  1680.  
  1681.  Mov Bx, [Bp+18]        ;handle
  1682.  Mov Ax, 4200h          ;function number
  1683.  Int 21h                ;execute
  1684.  
  1685.  Pop Bp
  1686.  Pop Dx
  1687.  Pop Cx
  1688.  Pop Bx
  1689.  Pop Ax
  1690.  Ret 6
  1691.  Endp                   ;Seek_Fil_P
  1692.  
  1693. ;================================================
  1694. ; Return the size of a file and move the read/
  1695. ; write pointer to the end of the file. The handle
  1696. ; and the (32 bit) size are returned. The high
  1697. ; word of the size must be popped first.
  1698.  
  1699. Size_Fil_P Proc Near
  1700.  Sub Sp, 4
  1701.  Push Ax
  1702.  Push Bx
  1703.  Push Cx
  1704.  Push Dx
  1705.  Push Bp
  1706.  
  1707.  Mov Bp, Sp
  1708.  Mov Ax, [Bp+14]
  1709.  Mov [Bp+10], Ax        ;fix return address
  1710.  
  1711.  Mov Ax, 4202h          ;function number
  1712.  Mov Bx, [Bp+16]        ;handle
  1713.  Sub Cx, Cx
  1714.  Mov Dx, Cx             ;move to offset from end 0000.0000
  1715.  Int 21h                ;execute
  1716.  
  1717.  Mov [Bp+14], Ax        ;low word
  1718.  Mov [Bp+12], Dx        ;high word
  1719.  
  1720.  Pop Bp
  1721.  Pop Dx
  1722.  Pop Cx
  1723.  Pop Bx
  1724.  Pop Ax
  1725.  Ret
  1726.  Endp                   ;Size_Fil_P
  1727.  
  1728. ;================================================
  1729. ; Close a file. The file handle must be passed on
  1730. ; the stack.
  1731.  
  1732. Close_Fil_P Proc Near
  1733.  Push Ax
  1734.  Push Bx
  1735.  Push Bp
  1736.  
  1737.  Mov Bp, Sp
  1738.  Mov Ah, 3eh            ;function number
  1739.  Mov Bx, [Bp+8]         ;get file handle
  1740.  Int 21h                ;execute
  1741.  
  1742.  Pop Bp
  1743.  Pop Bx
  1744.  Pop Ax
  1745.  Ret 2
  1746.  Endp
  1747.  
  1748. ;================================================
  1749. ; Return the number of bytes free on the disk.
  1750. ; The drive number (0=default, 1=A, etc.) must be
  1751. ; in the low byte of a word passed on the stack.
  1752. ; The 32 bit number containing the free bytes is
  1753. ; returned. Carry set if invalid drive.
  1754.  
  1755. Free_Dsk_P Proc Near
  1756.  Sub Sp, 2
  1757.  Push Ax
  1758.  Push Bx
  1759.  Push Cx
  1760.  Push Dx
  1761.  Push Bp
  1762.  
  1763.  Mov Bp, Sp
  1764.  Mov Ax, [Bp+12]
  1765.  Mov [Bp+10], Ax        ;fix return address
  1766.  
  1767.  Mov Ah, 36h            ;function number
  1768.  Mov Dl, [Bp+14]        ;drive code
  1769.  Int 21h                ;execute
  1770.  Cmp Ax, -1             ;check if error
  1771.  Je FreeDskError        ;jump if so
  1772.  
  1773.  Mul Ax, Bx             ;get available clusters in DX:AX
  1774.  Mov Bx, Ax             ;in DX:BX
  1775.  Mov Ax, Dx
  1776.  Mul Ax, Cx             ;high word of bytes, if DX<>0 then error (too big)
  1777.  Xchg Ax, Bx            ;save in BX
  1778.  Mul Ax, Cx             ;low word of bytes
  1779.  Add Dx, Bx             ;add both high words, if carry then error (too big)
  1780.  
  1781.  Mov [Bp+14], Ax        ;save low word
  1782.  Mov [Bp+12], Dx        ;save high word
  1783.  Clc
  1784.  
  1785. FreeDskDone
  1786.  Pop Bp
  1787.  Pop Dx
  1788.  Pop Cx
  1789.  Pop Bx
  1790.  Pop Ax
  1791.  Ret
  1792.  
  1793. ;--- invalid drive
  1794.  
  1795. FreeDskError
  1796.  Mov Word [Bp+14], 0    ;save low word
  1797.  Mov Word [Bp+12], 0    ;save high word
  1798.  Stc
  1799.  Jmps FreeDskDone
  1800.  Endp                   ;Free_Dsk_P
  1801.  
  1802. ;================================================
  1803. ; Sound the speaker at a specified frequency for
  1804. ; a specified amount of of time. The 16 bit
  1805. ; frequency (in hertz -- minimum is 21) and the 16
  1806. ; bit duration (in 1/100 seconds) must be passed
  1807. ; on the stack. The duration is dependent upon the
  1808. ; the speed and type of computer. If this routine 
  1809. ; is used on a faster computer, the number of nul
  1810. ; loops executed for a single 1/100 second cycle
  1811. ; should be adjusted accordingly. Though this
  1812. ; routine directly manipulates the hardware, it
  1813. ; does so in a fairly standardized manner, i.e.
  1814. ; it should work on most compatibles.
  1815.  
  1816. Sound_Spk_P Proc Near
  1817.  Push Ax
  1818.  Push Cx
  1819.  Push Dx
  1820.  Push Bp
  1821.  Mov Bp, Sp
  1822.  
  1823.  Mov Al, 0B6h
  1824.  Out 43h, Al            ;timer mode
  1825.  Mov Dx, 14h
  1826.  Mov Ax, 4f38h          ;divisor in DX.AX
  1827.  Mov Cx, [Bp+12]        ;tone
  1828.  Cmp Cx, 15h            ;check for minimum
  1829.  Jae SoundSpkOk         ;jump if ok
  1830.  Mov Cx, 15h            ;set to minimum (get divide overflow otherwise)
  1831. SoundSpkOk
  1832.  Div Ax, Cx
  1833.  Out 42h, Al            ;timer 2 low byte
  1834.  Mov Al, Ah
  1835.  Out 42h, Al            ;timer 2 high byte
  1836.  
  1837.  In Al, 61h             ;port B setting
  1838.  Mov Ah, Al
  1839.  Or Al, 3               ;turn on speaker
  1840.  Out 61h, Al
  1841.  
  1842.  Mov Dx, [Bp+10]        ;duration
  1843. SoundSpkWait
  1844.  Mov Cx, 2615           ;approx. 1/100 count (set for 4.77 MHz, 8088 computer)
  1845. SoundSpkLoop
  1846.  Loop SoundSpkLoop      ;loop for count
  1847.  Dec Dx                 ;reduce count
  1848.  Jnz SoundSpkWait       ;loop back if more
  1849.  
  1850.  Mov Al,Ah
  1851.  Out 61h,Al             ;turn off speaker
  1852.  
  1853.  Pop Bp
  1854.  Pop Dx
  1855.  Pop Cx
  1856.  Pop Ax
  1857.  Ret 4
  1858.  Endp
  1859.  
  1860.  Db Neg $Chksum         ;library checksum
  1861.  
  1862.