home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol3n25.zip / NPAD.ASM next >
Assembly Source File  |  1987-12-13  |  14KB  |  271 lines

  1. INTERRUPTS      SEGMENT AT 0H   ;This is where the keyboard interrupt
  2.         ORG     9H*4            ;holds the address of its service routine
  3. KEYBOARD_INT    LABEL   DWORD  
  4. INTERRUPTS      ENDS
  5.  
  6. SCREEN  SEGMENT AT 0B000H       ;A dummy segment to use as the
  7. SCREEN  ENDS                    ;Extra Segment 
  8.  
  9. ROM_BIOS_DATA   SEGMENT AT 40H  ;BIOS statuses held here, also keyboard buffer
  10.  
  11.         ORG     1AH
  12.         HEAD DW      ?                  ;Unread chars go from Head to Tail
  13.         TAIL DW      ?
  14.         BUFFER       DW      16 DUP (?)         ;The buffer itself
  15.         BUFFER_END   LABEL   WORD
  16.  
  17. ROM_BIOS_DATA   ENDS
  18.  
  19. CODE_SEG        SEGMENT
  20.         ASSUME  CS:CODE_SEG
  21.         ORG     100H            ;ORG = 100H to make this into a .COM file
  22. FIRST:  JMP     LOAD_PAD        ;First time through jump to initialize routine
  23.  
  24.         CNTRL_N_FLAG    DW      0               ;Cntrl-N on or off
  25.         PAD             DB      '_',499 DUP(' ')       ;Memory storage for pad  
  26.         PAD_CURSOR      DW      0               ;Current position in pad
  27.         PAD_OFFSET      DW      0               ;Chooses 1st 250 bytes or 2nd
  28.         FIRST_POSITION  DW      ?               ;Position of 1st char on screen
  29.         ATTRIBUTE       DB      112             ;Pad Attribute -- reverse video
  30.         SCREEN_SEG_OFFSET       DW      0       ;0 for mono, 8000H for graphics
  31.         IO_CHAR         DW      ?               ;Holds addr of Put or Get_Char
  32.         STATUS_PORT     DW      ?               ;Video controller status port
  33.         OLD_KEYBOARD_INT        DD      ?       ;Location of old kbd interrupt
  34.  
  35. N_PAD   PROC    NEAR            ;The keyboard interrupt will now come here.
  36.         ASSUME  CS:CODE_SEG
  37.         PUSH    AX              ;Save the used registers for good form
  38.         PUSH    BX
  39.         PUSH    CX
  40.         PUSH    DX
  41.         PUSH    DI
  42.         PUSH    SI
  43.         PUSH    DS
  44.         PUSH    ES
  45.         PUSHF                   ;First, call old keyboard interrupt
  46.         CALL    OLD_KEYBOARD_INT
  47.  
  48.         ASSUME  DS:ROM_BIOS_DATA        ;Examine the char just put in
  49.         MOV     BX,ROM_BIOS_DATA
  50.         MOV     DS,BX
  51.         MOV     BX,TAIL                 ;Point to current tail
  52.         CMP     BX,HEAD                 ;If at head, kbd int has deleted char
  53.         JE      IN                      ;So leave 
  54.         SUB     BX,2                    ;Point to just read in character
  55.         CMP     BX,OFFSET BUFFER        ;Did we undershoot buffer?
  56.         JAE     NO_WRAP                 ;Nope
  57.         MOV     BX,OFFSET BUFFER_END    ;Yes -- move to buffer top
  58.         SUB     BX,2
  59. NO_WRAP:MOV     DX,[BX]                 ;Char in DX now
  60.         CMP     DX,310EH                ;Is the char a Cntrl-N?
  61.         JNE     NOT_CNTRL_N             ;No
  62.         MOV     TAIL,BX                 ;Yes -- delete it from buffer
  63.         NOT     CNTRL_N_FLAG            ;Switch Modes
  64.         CMP     CNTRL_N_FLAG,0          ;Cntrl-N off?
  65.         JNE     CNTRL_N_ON              ;No, only other choice is on
  66. CNTRL_N_OFF:
  67.         MOV     ATTRIBUTE,7             ;Set up for normal video
  68.         MOV     PAD_OFFSET,250          ;Point to 2nd half of pad
  69.         LEA     AX,PUT_CHAR             ;Make IO call Put_Char as it scans
  70.         MOV     IO_CHAR,AX              ;over all locations in pad on screen
  71.         CALL    IO                      ;Restore screen
  72. IN:     JMP     OUT                     ;Done
  73. CNTRL_N_ON:
  74.         MOV     PAD_OFFSET,250          ;Point to screen stroage part of pad
  75.         LEA     AX,GET_CHAR             ;Make IO use Get_char so current screen
  76.         MOV     IO_CHAR,AX              ;is stored
  77.         CALL    IO                      ;Store Screen
  78.         CALL    DISPLAY                 ;And put up the pad
  79.         JMP     OUT                     ;Done here.
  80. NOT_CNTRL_N:
  81.         TEST    CNTRL_N_FLAG,1          ;Is Cntrl-N on?
  82.         JZ      IN                      ;No -- leave
  83.         MOV     TAIL,BX                 ;Yes, delete this char from buffer
  84.         CMP     DX,5300H                ;Decide what to do -- is it a Delete?
  85.         JNE     RUBOUT_TEST             ;No -- try Rubout
  86.         MOV     BX,249                  ;Yes -- fill pad with spaces
  87. DEL_LOOP:
  88.         MOV     PAD[BX],' '             ;Move space to current pad position
  89.         DEC     BX                      ;and go back one
  90.         JNZ     DEL_LOOP                ;until done.
  91.         MOV     PAD,'_'                 ;Put the cursor at the beginning
  92.         MOV     PAD_CURSOR,0            ;And start cursor over
  93.         CALL    DISPLAY                 ;Put up the new pad on screen
  94.         JMP     OUT                     ;And take our leave
  95. RUBOUT_TEST:
  96.         CMP     DX,0E08H                ;Is it a Rubout?
  97.         JNE     CRLF_TEST               ;No -- try carriage return-line feed
  98.         MOV     BX,PAD_CURSOR           ;Yes -- get current pad location
  99.         CMP     BX,0                    ;Are we at beginning?
  100.         JLE     NEVER_MIND              ;Yes -- can't rubout past beginning
  101.         MOV     PAD[BX],' '             ;No -- move space to current position
  102.         MOV     PAD[BX-1],'_'           ;And move cursor back one
  103.         DEC     PAD_CURSOR              ;Set the pad location straight
  104. NEVER_MIND:
  105.         CALL    DISPLAY                 ;And put the result on the screen
  106.         JMP     OUT                     ;Done here.
  107. CRLF_TEST:
  108.         CMP     DX,1C0DH                ;Is it a carriage return-line feed?
  109.         JNE     CHAR_TEST               ;No -- put it in the pad
  110.         CALL    CRLF                    ;Yes -- move to next line
  111.         CALL    DISPLAY                 ;And display result on screen
  112.         JMP     OUT                     ;Done.
  113. CHAR_TEST:
  114.         MOV     BX,PAD_CURSOR           ;Get current pad location
  115.         CMP     BX,249                  ;Are we past the end of the pad?
  116.         JGE     PAST_END                ;Yes -- throw away char
  117.         MOV     PAD[BX],DL              ;No -- move ASCII code into pad
  118.         MOV     PAD[BX+1],'_'           ;Advance cursor
  119.         INC     PAD_CURSOR              ;Increment pad location
  120.         PAST_END:
  121.         CALL    DISPLAY                 ;Put result on screen
  122. OUT:    POP     ES      ;Having done Pushes, here are the Pops
  123.         POP     DS
  124.         POP     SI
  125.         POP     DI
  126.         POP     DX
  127.         POP     CX
  128.         POP     BX
  129.         POP     AX     
  130.         IRET                    ;An interrupt needs an IRET
  131. N_PAD   ENDP
  132.  
  133. DISPLAY PROC    NEAR                    ;Puts the whole pad on the screen
  134.         PUSH    AX
  135.         MOV     ATTRIBUTE,112           ;Use reverse video
  136.         MOV     PAD_OFFSET,0            ;Use 1st 250 bytes of pad memory
  137.         LEA     AX,PUT_CHAR             ;Make IO use Put-Char so it does
  138.         MOV     IO_CHAR,AX              
  139.         CALL    IO                      ;Put result on screen
  140.         POP     AX
  141.         RET                             ;Leave
  142. DISPLAY ENDP
  143.  
  144. CRLF    PROC    NEAR                    ;This handles carriage returns
  145.         CMP     PAD_CURSOR,225          ;Are we on last line?
  146.         JGE     DONE                    ;Yes, can't do a carriage return, exit
  147. NEXT_CHAR:
  148.         MOV     BX,PAD_CURSOR           ;Get pad location
  149.         MOV     AX,BX                   ;Get another copy for destructive tests
  150. EDGE_TEST:
  151.         CMP     AX,24                   ;Are we at the edge of the pad display?
  152.         JE      AT_EDGE                 ;Yes -- fill pad with new cursor
  153.         JL      ADD_SPACE               ;No -- Advance another space
  154.         SUB     AX,25                   ;Subtract another line-width
  155.         JMP     EDGE_TEST               ;Check if at edge now
  156. ADD_SPACE:
  157.         MOV     PAD[BX],' '             ;Add a space
  158.         INC     PAD_CURSOR              ;Update pad location
  159.         JMP     NEXT_CHAR               ;Check if at edge now
  160. AT_EDGE:
  161.         MOV     PAD[BX+1],'_'           ;Put cursor in next location
  162.         INC     PAD_CURSOR              ;Update pad location to new cursor
  163. DONE:   RET                             ;And out.
  164. CRLF    ENDP
  165.  
  166. GET_CHAR        PROC    NEAR    ;Gets a char from screen and advances position
  167.         PUSH    DX
  168.         MOV     SI,2            ;Loop twice, once for char, once for attribute
  169.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  170. G_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  171.         IN      AL,DX           ;Make sure the video controller scan status
  172.         TEST    AL,1            ;is low
  173.         JNZ     G_WAIT_LOW
  174. G_WAIT_HIGH:                    ;After port has gone low, it must go high
  175.         IN      AL,DX           ;before it is safe to read directly from
  176.         TEST    AL,1            ;the screen buffer in memory
  177.         JZ      G_WAIT_HIGH
  178.         MOV     AH,ES:[DI]      ;Do the move from the screen, one byte at a time
  179.         INC     DI              ;Move to next screen location                   
  180.         DEC     SI              ;Decrement loop counter
  181.         CMP     SI,0            ;Are we done?
  182.         JE      LEAVE           ;Yes
  183.         MOV     PAD[BX],AH      ;No -- put char we got into the pad
  184.         JMP     G_WAIT_LOW      ;Do it again
  185. LEAVE:  INC     BX              ;Update pad location
  186.         POP     DX
  187.         RET
  188. GET_CHAR        ENDP
  189.  
  190. PUT_CHAR        PROC    NEAR    ;Puts one char on screen and advances position
  191.         PUSH    DX
  192.         MOV     AH,PAD[BX]      ;Get the char to be put onto the screen
  193.         MOV     SI,2            ;Loop twice, once for char, once for attribute
  194.         MOV     DX,STATUS_PORT  ;Get ready to read video controller status
  195. P_WAIT_LOW:                     ;Start waiting for a new horizontal scan -
  196.         IN      AL,DX           ;Make sure the video controller scan status
  197.         TEST    AL,1            ;is low
  198.         JNZ     P_WAIT_LOW
  199. P_WAIT_HIGH:                    ;After port has gone low, it must go high
  200.         IN      AL,DX           ;before it is safe to write directly to
  201.         TEST    AL,1            ;the screen buffer in memory
  202.         JZ      P_WAIT_HIGH
  203.         MOV     ES:[DI],AH      ;Move to screen, one byte at a time
  204.         MOV     AH,ATTRIBUTE    ;Load attribute byte for second pass
  205.         INC     DI              ;Point to next screen postion
  206.         DEC     SI              ;Decrement loop counter
  207.         JNZ     P_WAIT_LOW      ;If not zero, do it one more time
  208.         INC     BX              ;Point to next char in pad
  209.         POP     DX
  210.         RET                     ;Exeunt
  211. PUT_CHAR        ENDP
  212.  
  213. IO      PROC    NEAR           ;This scans over all screen positions of the pad
  214.         ASSUME  ES:SCREEN               ;Use screen as extra segment
  215.         MOV     BX,SCREEN
  216.         MOV     ES,BX
  217.         MOV     DI,SCREEN_SEG_OFFSET    ;DI will be pointer to screen postion
  218.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  219.         MOV     BX,PAD_OFFSET           ;BX will be pad location pointer
  220.         MOV     CX,10                   ;There will be 10 lines
  221. LINE_LOOP:      
  222.         MOV     DX,25                   ;And 25 spaces across
  223. CHAR_LOOP:
  224.         CALL    IO_CHAR                 ;Call Put-Char or Get-Char
  225.         DEC     DX                      ;Decrement character loop counter
  226.         JNZ     CHAR_LOOP               ;If not zero, scan over next character
  227.         ADD     DI,FIRST_POSITION       ;Add width of screen minus pad width
  228.         LOOP    LINE_LOOP               ;And now go back to do next line
  229.         RET                             ;Finished
  230. IO      ENDP
  231.  
  232. LOAD_PAD        PROC    NEAR    ;This procedure intializes everything
  233.         ASSUME  DS:INTERRUPTS   ;The data segment will be the Interrupt area
  234.         MOV     AX,INTERRUPTS
  235.         MOV     DS,AX
  236.         
  237.         MOV     AX,KEYBOARD_INT         ;Get the old interrupt service routine
  238.         MOV     OLD_KEYBOARD_INT,AX     ;address and put it into our location
  239.         MOV     AX,KEYBOARD_INT[2]      ;OLD_KEYBOARD_INT so we can call it.
  240.         MOV     OLD_KEYBOARD_INT[2],AX
  241.         
  242.         MOV     KEYBOARD_INT,OFFSET N_PAD  ;Now load the address of our notepad
  243.         MOV     KEYBOARD_INT[2],CS         ;routine into the keyboard interrupt
  244.                                         
  245.         MOV     AH,15                   ;Ask for service 15 of INT 10H 
  246.         INT     10H                     ;This tells us how display is set up
  247.         SUB     AH,25                   ;Move to twenty places before edge
  248.         SHL     AH,1                    ;Mult by two (char & attribute bytes)
  249.         MOV     BYTE PTR FIRST_POSITION,AH      ;Set screen cursor
  250.         MOV     STATUS_PORT,03BAH        ;Assume this is a monochrome display
  251.         TEST    AL,4                    ;Is it?
  252.         JNZ     EXIT                    ;Yes - jump out
  253.         MOV     SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
  254.         MOV     STATUS_PORT,03DAH
  255.  
  256. EXIT:   MOV     DX,OFFSET LOAD_PAD      ;Set up everything but LOAD_PAD to
  257.         INT     27H                     ;stay and attach itself to DOS
  258. LOAD_PAD        ENDP
  259.  
  260.         CODE_SEG        ENDS
  261.         
  262.         END     FIRST   ;END "FIRST" so 8088 will go to FIRST first.
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.