home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / msdos / info / help_7n1.arc / HELP.ASM < prev    next >
Assembly Source File  |  1987-10-02  |  22KB  |  816 lines

  1. ;from VOL7N1.ARC, PC Magazine Jan 88?
  2. ;            Help.asm
  3. ;         Resident help facility
  4. ; Format:  HELP filespec [... filespec][/Nn][/P][/Hn] | [/U]
  5. ; defaults: pages = 4; hot key = Alt H
  6.  
  7. CODE SEGMENT                ;********************************;
  8. ASSUME CS:CODE,DS:CODE            ;*                *;
  9. ORG 100H                ;*  Requires MASM 2.0 or later  *;
  10.                     ;*    Remember to EXE2BIN    *;
  11. START:        JMP    BEGINNING    ;*                *;
  12.                     ;********************************;
  13.  
  14. ;        DATA AREA
  15. ;        ---------
  16. COPYRIGHT    DB    "HELP 1.0 (c) 1987 Ziff Communications Co.",13,10
  17.         DB    "Successfully installed",13,10
  18. ALT_COMBO    DB    "Press Alt H to activate",10,0,26
  19.  
  20. PROGRAMMER    DB    "Michael J. Mefford"
  21.  
  22. OLD_KEYBOARD    DD    ?
  23. CRT_COLS    DW    ?
  24. STATUS_REG    DW    ?
  25. SCREEN_SEG    DW    0B000H
  26. LINE_COUNT    DB    25
  27. IMMEDIATE_FLAG    DB    0
  28. BUSY        DB    0
  29.  
  30. IMMEDIATE    DW    POP_IT
  31. DATA_SEG    DW    ?
  32. DATA_INT    DB    0
  33. INSTALLED_FLAG    DB    0
  34. POPUP_FLAG    DB    0
  35. HOT_KEY        DB    35
  36.  
  37. FILENAME    DW    ?
  38. ERROR_LEVEL    DB    0
  39.  
  40. CURRENT_PAGE    DB    1
  41. RESERVED_PAGES    DB    4
  42. ACTIVE_PAGES    DB    0
  43. PAGE_COUNT    DB    0
  44. DELIMITERS    DB    9,32,13,44,";","/"
  45.  
  46. SYNTAX LABEL BYTE
  47. DB  10,"Usage:  HELP filespec [... filespec][/Nn][/Hn][/P] | [/U]",13,10,10
  48. DB    "/Nn where n = number of reserved pages (1-14); default = 4",13,10
  49. DB    "/Hn where n = Alt hot key combo (A-Z,0-9,",34,45,34,44,34,61,34
  50. DB    "); default = H",13,10
  51. DB    "/P  = immediate pop-up",13,10
  52. DB    "/U  = uninstall",13,10,10
  53. DB    "Use: PgUp PgDn Home End to navigate through HELP",13,10
  54. DB    5 DUP(32),"ESC or hot key to exit",10,0
  55.  
  56.  
  57. ACTIVE_MSG    DB    " active page(s)",13,10,0
  58. RESERVED_MSG    DB    " total page(s)",13,10,10,0
  59. UNLOAD_MSG    DB    10,"HELP can't be uninstalled.",13,10
  60.         DB    "Uninstall resident programs in reverse order.",10,0
  61. UNINSTALL_MSG    DB    10,"HELP uninstalled",10,0
  62. NO_FREE        DB    "Too many resident programs",0
  63. NOT_FOUND    DB    32,"not found",13,10,0
  64. NOT_ENOUGH    DB    "Not enough memory",0
  65. ALLOCATE_MSG    DB    "Memory allocation error",13,10,0
  66.  
  67. SCAN_CODES LABEL BYTE
  68.  
  69. DB 45,130,48,129,49,120,50,121,51,122,52,123,53,124
  70. DB 54,125,55,126,56,127,57,128,61,131,65,30,66,48,67
  71. DB 46,68,32,69,18,70,33,71,34,72,35,73,23,74,36,75,37
  72. DB 76,38,77,50,78,49,79,24,80,25,81,16,82,19,83,31
  73. DB 84,20,85,22,86,47,87,17,88,45,89,21,90,44
  74.  
  75. ;                SCAN CODES FOR ALT COMBO
  76. ;
  77. ;    Code Key    Code Key    Code Key    Code    Key
  78. ;    16   Q        30   A        44    Z    120    1
  79. ;    17   W        31   S        45    X    121    2
  80. ;    18   E        32   D        46    C    122    3
  81. ;    19   R        33   F        47    V    123    4
  82. ;    20   T        34   G        48    B    124    5
  83. ;    21   Y        35   H        49    N    125    6
  84. ;    22   U        36   J        50    M    126    7
  85. ;    23   I        37   K                127    8
  86. ;    24   O        38   L                128    9
  87. ;    25   P                        129    0
  88. ;                            130    -
  89. ;    Default is 35 (Alt H)                131    =
  90.  
  91.  
  92. ;************* KEYBOARD INTERCEPTOR *************;
  93.  
  94. NEW_KEYBOARD:
  95.     STI
  96.     PUSHF                ;Simulate an interrupt
  97.     CALL    CS:OLD_KEYBOARD        ; by pushing flags and far call.
  98.  
  99. POP_IT:    PUSHF                ;On return save all registers
  100.     PUSH    DS            ; that will be used.
  101.     PUSH    ES
  102.     PUSH    AX
  103.     PUSH    BX
  104.     PUSH    CX
  105.     PUSH    DX
  106.     PUSH    SI
  107.     PUSH    DI
  108.     PUSH    BP
  109.  
  110.     PUSH    CS            ;Point to our data.
  111.     POP    DS
  112.     CLD                ;Moves in forward direction.
  113.     MOV    AX,40H            ;Point to ROM BIOS data area
  114.     MOV    ES,AX
  115.     MOV    AX,ES:[4AH]        ;Get number of columns on screen
  116.     MOV    CRT_COLS,AX        ; and store.
  117.     MOV    AX,ES:[63H]        ;Get base address of video card.
  118.     ADD    AX,6            ;Convert to status register
  119.     MOV    STATUS_REG,AX        ; and store.
  120.     CMP    AX,3BAH            ;Is it mono card?
  121.     JZ    MONO            ;If yes, use b800h.
  122.     MOV    SCREEN_SEG,0B800H        ; else point to color card.
  123. MONO:    MOV    AL,ES:[49H]        ;Retrieve video mode.
  124.     CMP    AL,3            ;Is it text mode?
  125.     JBE    GOOD_MODE            ;If yes, OK.
  126.     CMP    AL,7
  127.     JNZ    DONE_HERE            ;Exit if graphics
  128.  
  129. GOOD_MODE:
  130.     CMP    IMMEDIATE_FLAG,1         ;Is there a pop-up request?
  131.     JZ    NOW            ;If yes, pop-up right now.
  132.     CMP    BUSY,1            ;If the window is already popped
  133.     JZ    DONE_HERE            ; exit Int 9 back to window.
  134.     MOV    AH,1            ;Is an ASCII character ready?
  135.     INT    16H
  136.     JZ    DONE_HERE            ;If it's just a key release, exit.
  137.     CMP    AL,0            ;Is it extended code?
  138.     JNZ    DONE_HERE            ;If no, exit.
  139.     CMP    AH,HOT_KEY        ;Else, see if our Alt key combo.
  140.     JZ    OPEN_WINDOW        ;If yes, open window
  141. DONE_HERE:
  142.     JMP    SHORT EXIT_KEYBOARD    ; else exit.
  143.  
  144. ;------------------------------------;
  145. ; Save screen so we can pop up HELP. ;
  146. ;------------------------------------;
  147.  
  148. OPEN_WINDOW:
  149.     MOV    AH,0            ;Retrieve and discard hot key
  150.     INT    16H            ; character from keyboard buffer.
  151. NOW:    MOV    BUSY,1            ;Flag that window is open.
  152.     MOV    IMMEDIATE_FLAG,0         ;Restore immediate flag.
  153.     CALL    STORE_SCREEN        ;Store screen.
  154.  
  155. ;-----------------------------------------;
  156. ; Loop here looking for valid keystrokes. ;
  157. ;-----------------------------------------;
  158.  
  159. READ_KEY:
  160.     MOV    CL,CURRENT_PAGE        ;Get current page.
  161.     DEC    CL            ;Adjust for starting offset.
  162.     CALL    PAGE_SIZE            ;Get offset.
  163.     MOV    SI,DX
  164.     CALL    WRITE_SCREEN        ;Update the screen.
  165.     MOV    AH,0            ;Wait for a character.
  166.     INT    16H
  167.     CMP    AH,1            ;Is it Esc?
  168.     JZ    EXIT_WINDOW        ;If yes, exit window.
  169.     CMP    AH,BYTE PTR HOT_KEY    ;Is it our key combo?
  170.     JZ    EXIT_WINDOW        ;If yes, exit window.
  171.  
  172.     MOV    CL,CURRENT_PAGE        ;Get current page.
  173.     CMP    AH,49H            ;Is it PgUp?
  174.     JNZ    CK_PGDN
  175.     CMP    CL,1            ;If yes, is it already page one?
  176.     JZ    END_KEY
  177.     DEC    CL            ;If no, decrement page.
  178.  
  179. CK_PGDN:
  180.     CMP    AH,51H            ;Is it PgDn?
  181.     JNZ    CK_HOME
  182.     CMP    CL,ACTIVE_PAGES        ;If yes, are we already last page?
  183.     JZ    END_KEY
  184.     INC    CL            ;If no, increment page.
  185.  
  186. CK_HOME:
  187.     CMP    AH,47H            ;Is it Home?
  188.     JNZ    CK_END
  189.     MOV    CL,1            ;If yes, move to page one.
  190.  
  191. CK_END:    CMP    AH,4FH            ;Is it End?
  192.     JNZ    END_KEY
  193.     MOV    CL,ACTIVE_PAGES        ;If yes, move to last page.
  194.  
  195. END_KEY:
  196.     MOV    CURRENT_PAGE,CL        ;Store new current page.
  197.     JMP    SHORT READ_KEY
  198.  
  199. ;----------------------------------;
  200. ; This is the window exit routine. ;
  201. ;----------------------------------;
  202.  
  203. EXIT_WINDOW:
  204.     MOV    SI,OFFSET SCREEN_BUFFER    ;Point to the stored screen
  205.     CALL    WRITE_SCREEN        ; and restore the screen.
  206.     MOV    IMMEDIATE_FLAG,0         ;Reset the pop-up flag.
  207.     MOV    BUSY,0            ;Flag done with window.
  208.  
  209. EXIT_KEYBOARD:
  210.     POP    BP            ;Restore all registers.
  211.     POP    DI
  212.     POP    SI
  213.     POP    DX
  214.     POP    CX
  215.     POP    BX
  216.     POP    AX
  217.     POP    ES
  218.     POP    DS
  219.     POPF
  220.     IRET                ;Return from interrupt.
  221.  
  222.  
  223. ;************* FILE LOADING AND INSTALL PROCEDURE *************;
  224.  
  225. BEGINNING:
  226.     CLD
  227.     PUSH    CS
  228.     POP    DATA_SEG            ;Store our segment.
  229.     CMP    SP,65533            ;Do we have 64K?
  230.     JA    CK_PARA
  231.     MOV    SI,OFFSET NOT_ENOUGH    ;If no, exit with message.
  232.     JMP    ERROR_EXIT
  233.  
  234. CK_PARA:
  235.     CMP    BYTE PTR DS:[80H],0    ;Any parameters?
  236.     JNZ    CK_FREE
  237. OPTIONS:
  238.     MOV    SI,OFFSET SYNTAX         ;If no, exit with syntax message.
  239.     JMP    ERROR_EXIT
  240.  
  241. ;----------------------------------------------------------------------;
  242. ; Check user vectors to see if we are installed or if one is available ;
  243. ;----------------------------------------------------------------------;
  244.  
  245. CK_FREE:
  246.     MOV    AL,60H - 1        ;Available vectors are 60H - 67H.
  247. FREE_USER_INT:
  248.     INC    AL
  249.     MOV    AH,35H            ;Get vector address.
  250.     INT    21H
  251.     CMP    BX,0            ;Is offset being used?
  252.     JNZ    CK_SIGNATURE        ;If yes, see if it's us.
  253.     MOV    DX,ES
  254.     or    dx,dx    ;CMP    DX,0    ;Is segment being used?
  255.     JNZ    CK_SIGNATURE        ;If yes, see if it's us.
  256.     MOV    DATA_INT,AL        ;If available, save INT number.
  257.  
  258. NEXT_USER:
  259.     CMP    AL,67H            ;Have we checked all 7?
  260.     JNZ    FREE_USER_INT        ;If no, next one.
  261.     JMP    SHORT CK_SWITCHES
  262.  
  263. CK_SIGNATURE:
  264.     MOV    DI,BX            ;See if INT has our signature.
  265.     MOV    SI,100H
  266.     MOV    CX,30/2
  267.     REPZ    CMPSW
  268.     JNZ    NEXT_USER        ;If yes, already installed.
  269.     MOV    DATA_SEG,ES        ;Save segment.
  270.     MOV    INSTALLED_FLAG,1
  271.  
  272. ;--------------------------------------------;
  273. ; Check the command line for switch options. ;
  274. ;--------------------------------------------;
  275.  
  276. CK_SWITCHES:
  277.     PUSH    DATA_SEG        ;First point to installed segment.
  278.     POP    ES
  279.     MOV    SI,81H            ;First parameter.
  280.  
  281. NEXT_SWITCH:
  282.     LODSB                ;Get a byte.
  283.     CMP    AL,13            ;Is it carriage return?
  284.     JZ    CK_FILENAMES        ;If yes, done here.
  285.     CMP    AL,"/"            ;Is it switch character?
  286.     JNZ    NEXT_SWITCH        ;If no, get next byte
  287.     LODSB                ; else get switch.
  288.     CMP    AL,13            ;Is it carriage return?
  289.     JZ    CK_FILENAMES        ;If yes, done here
  290.     CALL    CAPITALIZE        ; else capitalize.
  291.  
  292.     CMP    AL,"U"            ;Is it "U"?
  293.     JNZ    CK_N
  294.     CMP    INSTALLED_FLAG,1     ;If yes, are we installed?
  295.     JNZ    NEXT_SWITCH
  296.     JMP    UNINSTALL            ;If yes, uninstall.
  297.  
  298. CK_N:    
  299.     CMP    AL,"N"            ;Is it "N"?
  300.     JNZ    CK_P
  301.     CMP    INSTALLED_FLAG,1     ;If yes, are we installed?
  302.     JZ    NEXT_SWITCH        ;If yes, can't change reserved.
  303.     CALL    DEC_TO_HEX        ;Else, convert decimal to hex.
  304.     CMP    BL,14            ;Request greater than 14 pages
  305.     JA    NEXT_SWITCH        ; or equal to zero?
  306.     CMP    BL,0
  307.     JZ    NEXT_SWITCH        ;If yes, ignore.
  308.     MOV    RESERVED_PAGES,BL    ;Else, store reserved pages.
  309.     JMP    SHORT NEXT_SWITCH
  310.  
  311. CK_P:    CMP    AL,"P"            ;Is it "P"?
  312.     JNZ    CK_H
  313.     MOV    POPUP_FLAG,1        ;If yes, flag to pop-up immediate.
  314.  
  315. CK_H:    CMP    AL,"H"            ;Is it "H"?
  316.     JNZ    NEXT_SWITCH
  317.     LODSB
  318.     DEC    SI            ;Adjust in case it's just CR.
  319.     CALL    CAPITALIZE
  320.     MOV    DI,OFFSET SCAN_CODES
  321.     MOV    CX,38            ;38 possible Alt key combos.
  322.  
  323. NEXT_ALT:
  324.     SCASB                ;Do we have a match?
  325.     JZ    GOT_ALT
  326.     INC    DI            ;If no, bump pointer to next byte.
  327.     LOOP    NEXT_ALT
  328.     JMP    SHORT NEXT_SWITCH
  329.  
  330. GOT_ALT:
  331.     MOV    ALT_COMBO + 10,AL    ;Store Alt key.
  332.     MOV    AL,[DI]            ;Get scan code
  333.     MOV    ES:HOT_KEY,AL        ; and store.
  334.     JMP    SHORT NEXT_SWITCH
  335.  
  336. ;-----------------------------------------------------;
  337. ; This routine parses the command line for filenames. ;
  338. ;-----------------------------------------------------;
  339.  
  340. CK_FILENAMES:
  341.     MOV    SI,81H            ;Point to first parameter.
  342. NEXT_FILENAME:
  343.     CALL    CK_DELIMITER        ;Is it a delimiter?
  344.     JC    CK_CR            ;If yes, see if end.
  345.     MOV    FILENAME,SI        ;Else, store filename start.
  346. FIND_END:
  347.     CALL    CK_DELIMITER        ;Look for delimiter to mark end.
  348.     JNC    FIND_END
  349.     PUSH    SI            ;Save pointer and delimiter.
  350.     PUSH    AX
  351.     CALL    READ_FILE            ;Read the file in.
  352.     POP    AX
  353.     POP    SI            ;Restore pointers.
  354.  
  355. CK_CR:    CMP    AL,13            ;Is it carriage return?
  356.     JZ    END_FILENAMES        ;If yes, done here.
  357.     CMP    AL,"/"            ;Is it switch character?
  358.     JNZ    NEXT_FILENAME        ;If no, get next filename.
  359. FIND_SWITCH:
  360.     CALL    CK_DELIMITER        ;Else, look for delimiter.
  361.     JNC    FIND_SWITCH
  362.     JMP    SHORT CK_CR        ;And check if carriage return.
  363.  
  364. END_FILENAMES:
  365.     MOV    AL,PAGE_COUNT        ;Retrieve page count.
  366.     CMP    INSTALLED_FLAG,1     ;Are we installed?
  367.     JZ    STORE_ACTIVE        ;If yes, check pages read.
  368.     CMP    AL,RESERVED_PAGES    ;Pages read greater than reserved?
  369.     JBE    STORE_ACTIVE
  370.     MOV    RESERVED_PAGES,AL    ;If yes, store as reserved.
  371.  
  372. STORE_ACTIVE:
  373.     CMP    AL,0            ;Did we read any pages?
  374.     JZ    CK_INSTALLED1        ;If no, check if installed.
  375.     MOV    ES:ACTIVE_PAGES,AL    ;Else, store active pages.
  376.     MOV    ES:CURRENT_PAGE,1    ;Reset the current page to one.
  377.     JMP    SHORT CK_POPUP        ;Check popup request.
  378.  
  379. CK_INSTALLED1:
  380.     CMP    INSTALLED_FLAG,1     ;Are we installed?
  381.     JNZ    CK_INSTALLED2        ;If no, exit.
  382.  
  383. ;----------------------------------------;
  384. ; This routine does an immediate pop-up. ;
  385. ;----------------------------------------;
  386.  
  387. CK_POPUP:
  388.     CMP    POPUP_FLAG,1        ;Is there a popup request?
  389.     JNZ    CK_INSTALLED2        ;If no, check pages read.
  390.     MOV    ES:IMMEDIATE_FLAG,1    ;Else, flag keyboard routine.
  391.     PUSHF                ;Simulate an interrupt.
  392.     CALL    DWORD PTR IMMEDIATE
  393.     MOV    BL,0            ;Error level of zero.
  394.     CMP    AL,0            ;Any pages read?
  395.     JZ    EXIT            ;If no, done here.
  396.  
  397. ;--------------------------------------------------;
  398. ; This routine checks to see if we are to install. ;
  399. ;--------------------------------------------------;
  400.  
  401. CK_INSTALLED2:
  402.     CMP    AL,0            ;Did we fail to open a file?
  403.     MOV    SI,OFFSET SYNTAX     ;If yes, exit with syntax message.
  404.     JZ    ERROR_EXIT
  405.     PUSH    AX
  406.     MOV    CL,AL            ;Save active pages.
  407.     MOV    DL,10
  408.     CALL    WRITE_IT            ;Display linefeed.
  409.     CALL    WRITE_NUMBER        ;Display active pages.
  410.     MOV    SI,OFFSET ACTIVE_MSG
  411.     CALL    DISPLAY_TEXT
  412.     POP    AX
  413.  
  414.     CMP    INSTALLED_FLAG,1     ;Are we already installed?
  415.     MOV    BL,ERROR_LEVEL
  416.     JZ    EXIT            ;If yes, done here
  417. CK_INT:
  418.     CMP    DATA_INT,0        ;Did we find a free user interrupt?
  419.     JNZ    INSTALL            ;If yes, install
  420.     MOV    SI,OFFSET NO_FREE    ;Else, exit with message.
  421.  
  422. ;-------------------;
  423. ; This is the exit. ;
  424. ;-------------------;
  425.  
  426. ERROR_EXIT:
  427.     MOV    BL,1            ;Error code of one.
  428. MSG_EXIT:
  429.     CALL    DISPLAY_TEXT
  430. EXIT:    MOV    AL,BL
  431.     MOV    AH,4CH            ;Return with error code.
  432.     INT    21H            ;Terminate.
  433.  
  434. ;--------------------------------;
  435. ; This is the install procedure. ;
  436. ;--------------------------------;
  437.  
  438. INSTALL:
  439.     MOV    AX,DS:[2CH]        ;Get environment segment.
  440.     MOV    ES,AX
  441.     MOV    AH,49H            ;Free up environment.
  442.     INT    21H
  443.     MOV    SI,OFFSET ALLOCATE_MSG
  444.     JC    ERROR_EXIT        ;If error, exit with message.
  445.  
  446.     MOV    DX,100H            ;Install user interrupt as
  447.     MOV    AL,DATA_INT        ; pointer to residency.
  448.     MOV    AH,25H
  449.     INT    21H
  450.  
  451.     MOV    AX,3509H            ;Get keyboard interrupt.
  452.     INT    21H
  453.     MOV    WORD PTR OLD_KEYBOARD,BX    ;Save old interrupt.
  454.     MOV    WORD PTR OLD_KEYBOARD[2],ES
  455.  
  456.     MOV    DX,OFFSET NEW_KEYBOARD        ;Install new interrupt.
  457.     MOV    AX,2509H
  458.     INT    21H
  459.  
  460.     MOV    CL,RESERVED_PAGES    ;Display reserved pages.
  461.     CALL    WRITE_NUMBER
  462.     MOV    SI,OFFSET RESERVED_MSG
  463.     CALL    DISPLAY_TEXT
  464.  
  465.     MOV    SI,OFFSET COPYRIGHT    ;Display install message.
  466.     CALL    DISPLAY_TEXT
  467.  
  468.     CALL    PAGE_SIZE            ;Convert reserved pages to offset.
  469.     MOV    CL,4
  470.     SHR    DX,CL            ;Convert to paragraphs.
  471.     INC    DX            ;Round up one.
  472.     MOV    AX,3100H            ;Return error code of zero.
  473.     INT    21H            ;Terminate but stay resident.
  474.  
  475.     ;*************;
  476.     ; SUBROUTINES ;
  477.     ;*************;
  478.  
  479. ;-----------------------------------------------;
  480. ; This subroutine uninstalls the resident help. ;
  481. ;-----------------------------------------------;
  482.  
  483. UNINSTALL:
  484.     MOV    AX,3509H            ;Get keyboard interrupt.
  485.     INT    21H
  486.     CMP    BX,OFFSET NEW_KEYBOARD ;Is the offset vector same?
  487.     MOV    SI,OFFSET UNLOAD_MSG    ;Error message if INT 9h changed.
  488.     MOV    BL,1            ;Error code of one if fails.
  489.     JNZ    MSG_EXIT
  490.     MOV    AX,ES            ;Is segment vector same?
  491.     CMP    AX,DATA_SEG
  492.     JNZ    MSG_EXIT            ;If no, exit with error.
  493.  
  494.     MOV    ES,DATA_SEG        ;Point to resident segment.
  495.     MOV    AH,49H            ;And return memory to system pool.
  496.     INT    21H
  497.     MOV    SI,OFFSET ALLOCATE_MSG
  498.     JNC    DEALLOCATED        ;Display message if problem.
  499.     CALL    DISPLAY_TEXT
  500.  
  501. DEALLOCATED:
  502.     MOV    DX,ES:WORD PTR OLD_KEYBOARD    ;Restore old INT 9.
  503.     MOV    DS,ES:WORD PTR OLD_KEYBOARD[2]
  504.     MOV    AX,2509H
  505.     INT    21H
  506.  
  507.     MOV    AL,ES:DATA_INT        ;Retrieve user interrupt.
  508.     XOR    DX,DX
  509.     MOV    DS,DX            ;Return vector to nulls.
  510.     MOV    AH,25H
  511.     INT    21H
  512.  
  513.     PUSH    CS
  514.     POP    DS
  515.     MOV    SI,OFFSET UNINSTALL_MSG     ;Display uninstall message.
  516.     MOV    BL,0             ;Error code of zero.
  517.     JMP    MSG_EXIT             ;And exit.
  518.  
  519. ;-----------------------------------------;
  520. ; These subroutines display the messages. ;
  521. ;-----------------------------------------;
  522.  
  523. WRITE_NUMBER:
  524.     MOV    BL,CL            ;Retrieve number.
  525.     CMP    BL,10            ;Is it greater than ten?
  526.     JB    ONES
  527.     MOV    DL,"1"            ;If yes, display a one.
  528.     CALL    WRITE_IT
  529.     SUB    BL,10
  530. ONES:    MOV    DL,BL
  531.     ADD    DL,"0"            ;Convert to decimal.
  532.     CALL    WRITE_IT            ;Display one's digit.
  533.     RET
  534.  
  535. ;----------------------------------------;
  536.  
  537. WRITE_IT:
  538.     MOV    AH,2            ;Display byte via DOS.
  539.     INT    21H
  540.     RET
  541.  
  542. ;----------------------------------------;
  543.  
  544. DISPLAY_IT:
  545.     CALL    WRITE_IT
  546. DISPLAY_TEXT:
  547.     LODSB                ;Get a byte
  548.     MOV    DL,AL
  549.     CMP    DL,0            ;Zero marks end of string.
  550.     JNZ    DISPLAY_IT
  551.     RET
  552.  
  553. ;-------------------------------------------------------------;
  554. ; This subroutine opens files if there is room to store them. ;
  555. ;-------------------------------------------------------------;
  556.  
  557. READ_FILE:
  558.     CALL    CK_SPACE            ;Is there room for help?
  559.     JC    END_READ
  560.     MOV    DX,FILENAME        ;If yes, open file.
  561.     DEC    DX
  562.     MOV    AX,3D00H
  563.     INT    21H
  564.     JNC    GOT_FILE
  565.     MOV    ERROR_LEVEL,1        ;Else, indicate had a problem.
  566.     MOV    SI,DX            ;Display filename and message
  567.     CALL    DISPLAY_TEXT        ; if file not found.
  568.     MOV    SI,OFFSET NOT_FOUND
  569.     CALL    DISPLAY_TEXT
  570.     RET
  571.  
  572. GOT_FILE:
  573.     MOV    BX,AX            ;Filehandle in BX.
  574. NEXT_READ:
  575.     CALL    READ_IT            ;Read it.
  576.     JC    CLOSE_FILE        ;Done here if nothing read.
  577.     CALL    CK_SPACE            ;If room, read balance, if any,
  578.     JNC    NEXT_READ            ; into next page.
  579.  
  580. CLOSE_FILE:
  581.     MOV    AH,3EH            ;Close file.
  582.     INT    21H
  583. END_READ:
  584.     RET
  585.  
  586. ;--------------------------------------------------------------------;
  587. ; This subroutine does the actual reading of help files into storage ;
  588. ;--------------------------------------------------------------------;
  589.  
  590. READ_IT:
  591.     MOV    CL,PAGE_COUNT        ;Retrieve page count.
  592.     CALL    PAGE_SIZE            ;Convert to offset.
  593.     PUSH    ES
  594.     POP    DS            ;Point to storage segment.
  595.     MOV    CX,4000            ;Read 4000 bytes.
  596.     MOV    AH,3FH
  597.     INT    21H
  598.     JC    READ_END
  599.     or    ax,ax        ;Did we read anything?
  600.     JZ    READ_END
  601.     INC    CS:PAGE_COUNT        ;If yes, increment page count.
  602.     SUB    CX,AX            ;Was it a full page?
  603.     JZ    SKIP_PAD
  604.     MOV    DI,DX            ;If no, pad balance with nulls.
  605.     ADD    DI,AX
  606.     XOR    AL,AL
  607.     REP    STOSB
  608. SKIP_PAD:
  609.     CLC                ;Indicate read something.
  610.     JMP    SHORT RESTORE_DS
  611.  
  612. READ_END:
  613.     STC                ;Indicate nothing read.
  614. RESTORE_DS:
  615.     PUSH    CS            ;Restore data segment.
  616.     POP    DS
  617.     RET
  618.  
  619. ;------------------------------------------------;
  620. ; This subroutine checks for free storage space. ;
  621. ;------------------------------------------------;
  622.  
  623. CK_SPACE:
  624.     CMP    PAGE_COUNT,14        ;Already a full 14 pages?
  625.     JZ    NO_SPACE            ;If yes, no space.
  626.     CMP    INSTALLED_FLAG,1     ;Are we installed.
  627.     JNZ    SPACE
  628.     MOV    AL,ES:RESERVED_PAGES    ;If yes, are reserved pages full?
  629.     CMP    AL,PAGE_COUNT
  630.     JZ    NO_SPACE            ;If yes, no space.
  631. SPACE:    CLC                ;Else, there is space.
  632.     RET
  633.  
  634. NO_SPACE:
  635.     STC
  636.     RET
  637.  
  638. ;-------------------------------------------------------;
  639. ; This subroutine calculates the page offsets.        ;
  640. ; Enter with CL = multiplicand; Return with DX = offset ;
  641. ;-------------------------------------------------------;
  642.  
  643. PAGE_SIZE:
  644.     MOV    AX,4000            ;Multiply by 4000 bytes.
  645.     XOR    DX,DX
  646.     XOR    CH,CH
  647.     MUL    CX
  648.     MOV    DX,OFFSET PAGE_BUFFER    ;Add to page buffer offset.
  649.     ADD    DX,AX
  650.     RET
  651.  
  652. ;------------------------------------------;
  653. ; This subroutine converts decimal to hex. ;
  654. ;------------------------------------------;
  655.  
  656. DEC_TO_HEX:
  657.     XOR    BL,BL            ;Start with zero.
  658. NEXT_NUMBER:
  659.     LODSB                ;Get a byte.
  660.     CMP    AL,"0"            ;Is it a number?
  661.     JB    END_NUMBER
  662.     CMP    AL,"9"
  663.     JA    END_NUMBER
  664.     SUB    AL,"0"            ;If yes convert to hex.
  665.     XCHG    AL,BL            ;Save it.
  666.     XOR    AH,AH            ;Multiply previous by 10.
  667.     MOV    DL,10
  668.     MUL    DL
  669.     XCHG    AL,BL            ;Retrieve current number.
  670.     ADD    BL,AL            ;And add to total.
  671.     JMP    SHORT NEXT_NUMBER
  672.  
  673. END_NUMBER:
  674.     DEC    SI            ;Adjust pointer.
  675.     RET
  676.  
  677. ;---------------------------------------------------------;
  678. ; This subroutine checks the command line for delimiters. ;
  679. ;---------------------------------------------------------;
  680.  
  681. CK_DELIMITER:
  682.     LODSB                ;Get a byte.
  683.     MOV    DI,OFFSET DELIMITERS    ;Point to delimiters.
  684.     MOV    CX,6
  685.     REPNZ    SCASB            ;And see if match.
  686.     JNZ    NO_DELIMITER
  687.     MOV    BYTE PTR [SI-1],0    ;If yes, convert to ASCIIZ.
  688.     STC
  689.     RET
  690.  
  691. NO_DELIMITER:
  692.     CLC
  693.     RET
  694.  
  695. ;-------------------------------------------------;
  696. ; This subroutine capitalizes the character in AL ;
  697. ;-------------------------------------------------;
  698.  
  699. CAPITALIZE:
  700.     CMP    AL,"a"
  701.     JB    END_CAPS
  702.     CMP    AL,"z"
  703.     JA    END_CAPS
  704.     AND    AL,5FH
  705. END_CAPS:
  706.     RET
  707.  
  708. ;------------------------------------------------------------------;
  709. ; This subroutine stores the screen so it can be restored on exit. ;
  710. ;------------------------------------------------------------------;
  711.  
  712. STORE_SCREEN:
  713.     MOV    LINE_COUNT,25        ;25 lines to save.
  714.     MOV    DX,STATUS_REG        ;Retrieve status register.
  715.     MOV    AX,SCREEN_SEG        ;Point to screen buffer.
  716.     MOV    DS,AX
  717.     PUSH    CS            ;Point to storage segment.
  718.     POP    ES
  719.     XOR    SI,SI                ;Top left corner.
  720.     MOV    DI,OFFSET SCREEN_BUFFER        ;Point to storage offset.
  721.  
  722. NEXT_LINE1:
  723.     MOV    BP,ES:CRT_COLS        ;Retrieve screen columns.
  724.     MOV    CX,80            ;Save maximum of 80 columns.
  725.  
  726. HORZ_RET1:
  727.     IN    AL,DX            ;Get status.
  728.     TEST    AL,1            ;Is it low?
  729.     JNZ    HORZ_RET1            ;If no, wait until it is.
  730.     CLI                ;No more interrupts.
  731.  
  732. WAIT1:    IN    AL,DX            ;Get status
  733.     TEST    AL,1            ;Is it high?
  734.     JZ    WAIT1            ;If no, wait until it is.
  735.     LODSW                ;Retrieve a word.
  736.     STI                ;Interrupts back on.
  737.     STOSW                ;Store the character/attribute.
  738.  
  739.     DEC    BP            ;Decrement screen column count.
  740.     JZ    SHORT_COLS1        ;Was it less than 80?
  741.     LOOP    HORZ_RET1            ;If no, loop until row done.
  742.  
  743.     SHL    BP,1            ;Convert balance to a word.
  744.     ADD    SI,BP            ;Add to screen offset.
  745.     JMP    SHORT CK_LINES1
  746.  
  747. SHORT_COLS1:
  748.     DEC    CX            ;Adjust balance.
  749.     SHL    CX,1            ;Convert to a word.
  750.     ADD    DI,CX            ;Add to storage offset.
  751.  
  752. CK_LINES1:
  753.     DEC    ES:LINE_COUNT        ;Do all 25 lines.
  754.     JNZ    NEXT_LINE1
  755.  
  756.     PUSH    CS            ;Restore data segment.
  757.     POP    DS
  758.     RET                ;Return.
  759.  
  760. ;---------------------------------------------;
  761. ; This subroutine writes to the screen buffer ;
  762. ;---------------------------------------------;
  763.  
  764. WRITE_SCREEN:
  765.     MOV    LINE_COUNT,25        ;25 lines to save.
  766.     MOV    DX,STATUS_REG        ;Retrieve status register.
  767.     MOV    AX,SCREEN_SEG        ;Point to screen buffer.
  768.     MOV    ES,AX
  769.     XOR    DI,DI            ;Top left corner.
  770.  
  771. NEXT_LINE2:
  772.     MOV    BP,CRT_COLS        ;Retrieve screen columns.
  773.     MOV    CX,80            ;Write maximum of 80 columns.
  774.  
  775. NEXT_BYTE:
  776.     LODSW                ;Get a byte.
  777.     MOV    BX,AX            ;Store it in AX.
  778.  
  779. HORZ_RET2:
  780.     IN    AL,DX            ;Get status.
  781.     TEST    AL,1            ;Is it low?
  782.     JNZ    HORZ_RET2            ;If no, wait until it is.
  783.     CLI                ;No more interrupts.
  784.  
  785. WAIT2:    IN    AL,DX            ;Get status.
  786.     TEST    AL,1            ;Is it high?
  787.     JZ    WAIT2            ;If no, wait until it is.
  788.     MOV    AX,BX            ;Retrieve the word
  789.     STOSW                ; and store it.
  790.     STI                ;Interrupts back on.
  791.  
  792.     DEC    BP            ;Decrement screen column count.
  793.     JZ    SHORT_COLS2        ;Was it less than 80?
  794.     LOOP    NEXT_BYTE            ;If no, loop until row done.
  795.  
  796.     SHL    BP,1            ;Convert balance to a word.
  797.     ADD    DI,BP            ;Add to storage offset.
  798.     JMP    SHORT CK_LINES2
  799.  
  800. SHORT_COLS2:
  801.     DEC    CX            ;Adjust balance.
  802.     SHL    CX,1            ;Convert to a word.
  803.     ADD    SI,CX            ;Add to screen offset.
  804.  
  805. CK_LINES2:
  806.     DEC    LINE_COUNT        ;Do all 25 lines.
  807.     JNZ    NEXT_LINE2
  808.     RET
  809.  
  810.  
  811. SCREEN_BUFFER    LABEL    BYTE
  812. PAGE_BUFFER    EQU    SCREEN_BUFFER + ( 2 * 80 * 25 )
  813.  
  814. CODE ENDS
  815. END    START
  816.