home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1990 / 16 / cmdedit.asm < prev    next >
Assembly Source File  |  1990-06-26  |  47KB  |  1,747 lines

  1. ;
  2. ; CMDEDIT.ASM
  3. ;(c) 1989, 1990 PC Magazine and Ashok P. Nadkarni
  4. ;
  5.  
  6. SIGNATURE1 equ <"CMDEDIT 2.0 (c) 1990 Ziff Communications Co.">
  7. SIGNATURE2 equ <"PC Magazine">
  8. SIGNATURE3 equ <"Ashok P. Nadkarni">
  9.  
  10. ; Main module for command line editor.
  11.  
  12.     INCLUDE common.inc
  13.     INCLUDE general.inc
  14.     INCLUDE ascii.inc
  15.     INCLUDE buffers.inc
  16.     INCLUDE dos.inc
  17.     INCLUDE bios.inc
  18.  
  19.     PUBLIC    dos_version_major
  20.     PUBLIC    dos_version_minor
  21.     PUBLIC    resident
  22.     PUBLIC    macro_level
  23.     PUBLIC    cur_macro
  24.     PUBLIC    cur_macro_len
  25.     PUBLIC    linebuf
  26.     PUBLIC    linelimit
  27.     PUBLIC    dot
  28.     PUBLIC    lastchar
  29.     PUBLIC    LINEBUF_END
  30.     PUBLIC    edit_mode
  31.     PUBLIC    default_imode
  32.     PUBLIC    caller_cursor
  33.     PUBLIC    omode_cursor
  34.     PUBLIC    pgm_name
  35.     PUBLIC    macrosize
  36.     PUBLIC    symsize
  37.     PUBLIC    dossize
  38.     PUBLIC    dirsize
  39.     PUBLIC    mfilename
  40.     PUBLIC    mfile_seen
  41.     PUBLIC    macro_ignore_char
  42.     PUBLIC    cmdlen
  43.     PUBLIC    silent
  44.     PUBLIC    endm_cmd
  45.     PUBLIC    defs
  46.     PUBLIC    defm
  47.     PUBLIC    tsr_install_end
  48.     PUBLIC    source
  49.     PUBLIC    abort_processing
  50.     PUBLIC    disp_line
  51.     PUBLIC    set_disp_marks
  52.     PUBLIC    insert_at_dot
  53.     PUBLIC    insert_chars
  54.     PUBLIC    remove_chars
  55.     PUBLIC    erase_to_dot
  56.     PUBLIC    init_over
  57.     PUBLIC    line_to_scr
  58.     PUBLIC    get_next_line
  59.     PUBLIC    reset_line
  60.     PUBLIC    in_appl
  61.     PUBLIC    user_command
  62.     PUBLIC    our_break_handler
  63.     PUBLIC    prev_isr1b
  64.     PUBLIC    old_int21vec
  65.     PUBLIC    cmdedit_isr
  66.     PUBLIC    makeroom
  67.     PUBLIC    locate_dosenv
  68.     PUBLIC    cmdedit
  69.  
  70.     IFE    TSR
  71.     PUBLIC    cmdedit_cmd
  72.     PUBLIC    debug_loop
  73.     PUBLIC    freadline
  74.     PUBLIC    get_file_line
  75.     PUBLIC    read_cmdfile
  76.     PUBLIC    disp_prompt
  77.     PUBLIC    prompt
  78.     PUBLIC    init_screen
  79.     ENDIF
  80.  
  81.  
  82. DGROUP    GROUP    CSEG
  83.  
  84. CSEG    SEGMENT    PARA PUBLIC 'CODE'
  85.     EXTRN    install_begin:BYTE
  86.     EXTRN    install:PROC
  87.     EXTRN    execute_defs:PROC
  88.     EXTRN    execute_defm:PROC
  89.     EXTRN    execute_dels:PROC
  90.     EXTRN    execute_delm:PROC
  91.     EXTRN    execute_cmdstat:PROC
  92.     EXTRN    execute_pushd:PROC
  93.     EXTRN    execute_popd:PROC
  94.     EXTRN    execute_chd:PROC
  95.     EXTRN    hist_init:PROC
  96.     EXTRN    hist_type:PROC
  97.     EXTRN    hist_top:PROC
  98.     EXTRN    dirs_init:PROC
  99.     EXTRN    macro_init:PROC
  100.     EXTRN    symbol_init:PROC
  101.     EXTRN    expand_macro:PROC
  102.     EXTRN    expand_symbol:PROC
  103.     EXTRN    get_macro_line:PROC
  104.     EXTRN    skip_whitespace:PROC
  105.     EXTRN    skip_nonwhite:PROC
  106.     EXTRN    stre_cmp:PROC
  107.     EXTRN    get_kbd_line:PROC
  108.     EXTRN    getargs:PROC
  109.     EXTRN    file_error:BYTE
  110.     EXTRN    abort_install:PROC
  111.     EXTRN    expand_var:PROC
  112.     EXTRN    execute_rsthist:PROC
  113.     EXTRN    execute_rstmac:PROC
  114.     EXTRN    execute_rstsym:PROC
  115.     EXTRN    execute_rstdir:PROC
  116.  
  117. ; Define important fields in the PSP.
  118.     ASSUME    CS:DGROUP
  119.     ORG    2Ch
  120. env    dw    ?    ;Segment of environment block
  121.  
  122.     ORG    80h
  123. PROMPT_BUF_SIZE EQU 80
  124. prompt    LABEL    BYTE    ;buffer used for prompt after TSRing
  125. cmdlen    DB    ?    ;Offset 80h in the PSP contains length of command
  126. ;             line when program is invoked
  127.  
  128.     ORG    80h+PROMPT_BUF_SIZE
  129. prompt_length    dw    ?
  130. cur_macro LABEL    BYTE    ;Start of area used after TSRing to
  131. ;             store the current macro expansion.
  132.  
  133.  
  134.     ASSUME    CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP
  135.     ORG    100h
  136. entry:    jmp    install
  137.  
  138. ; The following variables are LOST after TSRing since the space is
  139. ; reused for other purposes.
  140.  
  141. mfilename    db    64 DUP (0)    ;Storage for ASCIIZ filename
  142. mfile_seen    db    0        ;Indicate if command line
  143. ;                     specified an init file
  144. mfile_handle    dw    ?        ;Handle for open file
  145.  
  146. ; Entry init_over is jumped to from the installation code after all the
  147. ; command line parsing has been done. This part of the installation
  148. ; remains resident. It is not kept with the install code because that
  149. ; code sections gets overwritten with various buffers.
  150.  
  151. init_over proc    near
  152.  
  153. ; The command parameters have been parsed. Now get ready to terminate.
  154.     mov    si,offset DGROUP:install_begin
  155.                     ;First location in installation code
  156.     mov    bx,si            ; is where the buffers start.
  157.     mov    ax,dossize        ;Size of DOS history buffer
  158.     add    si,ax            ;SI <- end of DOS buffer
  159.     xor    cx,cx            ;Indicate DOS mode
  160.     call    near ptr hist_init    ;Initialize DOS history buffer
  161.     mov    bx,si            ;Repeat for directory stack
  162.     mov    ax,dirsize
  163.     add    si,ax
  164.     call    near ptr dirs_init
  165.     mov    bx,si            ;And finally for the macros
  166.     mov    ax,macrosize
  167.     add    si,ax
  168.     call    near ptr macro_init
  169.     mov    bx,si            ;And finally for the macros
  170.     mov    ax,symsize
  171.     add    si,ax
  172.     call    near ptr symbol_init
  173.  
  174.     ; SI->end of buffer area
  175. ; Read in the command file
  176.     call    near ptr init_screen     ;Need to do this because
  177. ;                     reset_line (called by
  178. ;                     execute_defm) restores cursor shape.
  179.     call    near ptr read_cmdfile
  180.  
  181. ; Initialize var source to get the next line from the keyboard.
  182.     mov    source,offset DGROUP:get_kbd_line
  183. ; All data structures initalized. Now setup stack pointer, release
  184. ; unneeded memory back to DOS, set up interrupt handler and TSR.
  185.     push    es            ;save ES
  186.     mov    es,env            ;Don't need environment block
  187.     ASSUME    ES:NOTHING
  188.     mov    ah,49h
  189.     int    21h            ;Release the block
  190.     IF    TSR
  191.     mov    ax,3521h        ;Get old interrupt vector
  192.     int    21h
  193.     mov    old_int21vec,bx        ;Remember offset
  194.     mov    old_int21vec+2,es        ;Remember segment
  195.  
  196.     mov    dx,offset DGROUP:cmdedit_isr ;Our handler
  197.                     ;DS = CS already
  198.     mov    ax,2521h        ;Set intr vector
  199.     int    21h
  200.     ENDIF
  201.     pop    es            ;Restore ES
  202.     ASSUME    ES:DGROUP
  203.  
  204.     lea    dx,STACK_SIZE+15[si]    ;Calculate end of TSR portion
  205. ;                     DX<-num bytes to keep resident
  206.     and    dl,0f0h            ;    rounded to para
  207. ;     Note DX->BEYOND last byte of program
  208.     mov    new_sp,dx        ;Remember it
  209.  
  210.     mov    resident,1        ;Indicate we're TSR
  211.  
  212.     IFE    TSR
  213. ; Don't actually TSR
  214. debug_loop:
  215. @init_over_10:
  216.     @DispCh    CR
  217.     @DispCh    LF
  218.     lea    dx,dummy_prompt
  219.     @DispStr dx
  220.     mov    dx,offset DGROUP:debug_buf     ;Offset
  221.     mov    debug_buf,DEBUG_BUFSIZE-2
  222.     mov    ah,0Ah            ;Function code
  223.     pushf                ;Simulate interrupt
  224.     push    cs            ;Simulate interrupt
  225.     call    near ptr cmdedit_isr    ;Simulate interrupt
  226.     jmp    short @init_over_10    ;Keep looping
  227. debug_buf    db    256 DUP (?)
  228. DEBUG_BUFSIZE    equ $-debug_buf
  229. dummy_prompt    db    "dummy>",DOLLAR
  230.     ENDIF
  231.  
  232.     int    27h            ;TSR
  233. init_over endp
  234.  
  235.  
  236. ;+
  237. ; FUNCTION : read_cmdfile
  238. ;
  239. ;    Reads commands from a file. The filename is in the variable
  240. ;    mfilename. The space occupied this function is overwritten
  241. ;    after TSRing so it must NOT be called once the program is resident.
  242. ;
  243. ; Parameters:
  244. ;    None.
  245. ;
  246. ; Returns:
  247. ;    AX =    0 on success, any other value if failure
  248. ;
  249. ; Register(s) destroyed:
  250. ;    AX,BX,CX,DX
  251. ;-
  252. read_cmdfile proc near
  253.     @save    si,di
  254.     cmp    mfile_seen,0
  255.     je    @read_cmdfile_100    ;No file specified
  256.  
  257.     @OpenFil mfilename,0
  258.     jc    @read_cmdfile_92    ;CF=1 for errors
  259. @read_cmdfile_30:
  260.     mov    source,offset DGROUP:get_file_line
  261. ;                    We want get_next_line to read
  262. ;                    from the file.
  263.     mov    mfile_handle,ax        ;Save file handle
  264.  
  265. @read_cmdfile_50:
  266.     mov    dx,offset DGROUP:linebuf ;Destination for file line
  267.     mov    ax,LINEBUF_SIZE
  268.     call    near ptr freadline    ;Get next line into buffer
  269.                     ;AX contains line length
  270.     jnc    @read_cmdfile_80    ;no error or EOF
  271.     or    ax,ax            ;No more bytes ?
  272.     jz    @read_cmdfile_99    ;EOF is not error
  273.     jmp    short @read_cmdfile_90    ;Error, abort install
  274. @read_cmdfile_80:
  275.     mov    dx,offset DGROUP:linebuf
  276.     add    dx,ax
  277.     mov    lastchar,dx        ;Update end of line
  278.     call    near ptr cmdedit_cmd    ;Execute as a command
  279.     jnc    @read_cmdfile_50    ;If not a command, better be a
  280. ;                     blank line
  281.     call    near ptr blankline
  282.     jnc    @read_cmdfile_50    ;Ignore blank lines
  283. ;     If not blank line and not CMDEDIT command, then error error handler
  284.  
  285. @read_cmdfile_90:
  286. ; Come here for error
  287.     @ClosFil mfile_handle        ;Close the file
  288. @read_cmdfile_92:
  289.     @DispStr file_error
  290.     mov    ax,-1            ;Indicate exit code
  291.     jmp    abort_install        ;Exit program
  292.  
  293. @read_cmdfile_99:
  294.     @ClosFil mfile_handle        ;Close the file
  295.     jc    @read_cmdfile_92    ;Abort if error closnig file
  296. @read_cmdfile_100:
  297.     @restore
  298.     ret
  299. read_cmdfile endp
  300.  
  301.  
  302.  
  303. ;+
  304. ; FUNCTION : get_file_line
  305. ;
  306. ;    Called indirectly through the global variable 'source'.
  307. ;    Currently this routine exists only during installation and must
  308. ;    NOT be called once the program is a TSR. The next line from the
  309. ;    file is copied to linebuf. If there is no next line, the
  310. ;    installation is aborted.
  311. ;
  312. ; Parameters:
  313. ;    None.
  314. ;
  315. ; Returns:
  316. ;    Nothing.
  317. ; Register(s) destroyed:
  318. ;    AX,BX,CX,DX
  319. ;-
  320. get_file_line proc near
  321.     mov    dx,offset DGROUP:linebuf
  322.     mov    ax,LINEBUF_SIZE
  323.     call    near ptr freadline
  324.     jnc    @get_file_line_99
  325. ;Error reading file or EOF
  326.     @DispStr file_error
  327.     jmp    abort_install
  328. @get_file_line_99:
  329.     mov    dx,offset DGROUP:linebuf
  330.     add    dx,ax
  331.     mov    lastchar,dx        ;Update end of line
  332.     ret
  333. get_file_line    endp
  334.  
  335.  
  336.  
  337.  
  338. ;+
  339. ; FUNCTION : freadline
  340. ;
  341. ;    Reads a line at a time from the file whose handle is in
  342. ;    mfile_handle into the buffer pointed to by AX. If the buffer is
  343. ;    too small or if there are any errors, the routine returns with CF set.
  344. ;    If EOF, then AX = 0 and CF is set.
  345. ;
  346. ; Parameters:
  347. ;    DX    = address of buffer
  348. ;     AX    = size of buffer
  349. ;
  350. ; Returns:
  351. ;    CF     = 0 if no errors (and not EOF), else 1.
  352. ;    AX    = num chars in line if CF = 0.
  353. ;          0 if EOF, ffff for other errors if CF = 1
  354. ;
  355. ; Register(s) destroyed:
  356. ;-
  357. freadline proc    near
  358.     @save    si,di
  359.     mov    di,dx            ;DI->buffer
  360.     mov    bx,mfile_handle
  361.     mov    si,ax            ;SI<-num bytes to read
  362.     xchg    cx,ax            ;CX<-num bytes to read
  363.     mov    ah,3Fh            ;File read function
  364.     int    21h
  365.     jc    @freadline_99        ;Error!
  366.     mov    cx,ax            ;CX<-num bytes read
  367.     jcxz    @freadline_99_a        ;EOF (note AX is 0 indicating EOF)
  368.     xchg    dx,ax            ;DX<-num bytes read
  369.     mov    bx,di            ;BX->start of buffer
  370.     mov    al,CR
  371.     repne    scasb            ;Hunt for CR
  372.     je    @freadline_50        ;Found
  373. ;    No CR found, this better be the last line in file.
  374.     cmp    dx,si            ;Were fewer bytes read than requested?
  375.     cmc
  376.     jc    @freadline_99        ;Error
  377.     push    dx            ;Save length of line
  378.     xor    ax,ax            ;AX<-num extra bytes read
  379.     jmp    short @freadline_60
  380. @freadline_50:
  381.     stc                ;Assume line too long
  382.     jcxz    @freadline_99        ;error if match in last char
  383. ;                     (line too long)
  384.     cmp    BYTE PTR [di],LF    ;Next char must be linefeed
  385.     stc                ;Assume error
  386.     jne    @freadline_99        ;Indeed an error if not LF
  387.     mov    ax,di
  388.     sub    ax,bx            ;AX<-num chars including CR
  389.     sub    dx,ax
  390.     xchg    ax,dx
  391.     dec    dx            ;DX<-num chars in line
  392.     dec    ax            ;AX<-num extra chars read
  393.     push    dx            ;Save num chars in line
  394.  
  395. @freadline_60:
  396. ; Top of stack contains num bytes in line.
  397. ; Now position file pointer to 'unread' characters.
  398. ; AX contains the num of extra characters read.
  399.     neg    ax
  400.     cwd
  401.     mov    cx,ax
  402.     xchg    cx,dx            ;CX:DX<-num bytes to 'unread'
  403.     mov    bx,mfile_handle
  404.     mov    ax,4201h        ;Move file ptr relative
  405.     int    21h            ;Seek file relative
  406. ; CF set/reset by error status
  407.     pop    ax            ;AX<-num bytes in line
  408.     clc                ;No errors
  409.     jmp    short @freadline_100
  410. @freadline_99:
  411.     mov    ax,0ffffh        ;Non-EOF error
  412. @freadline_99_a:
  413.     stc                ;Indicate error or EOF
  414. @freadline_100:
  415.     @restore
  416.     ret
  417. freadline endp
  418.  
  419.  
  420.  
  421. ;+
  422. ; FUNCTION : blankline
  423. ;
  424. ;    Checks whether the line in linebuf is blank or not. Also treats it
  425. ;    as blank line if it begins with a `-'.
  426. ;
  427. ; Parameters:
  428. ;    None.
  429. ;
  430. ; Returns:
  431. ;    CF    = 0 if blank line, else 1.
  432. ; Register(s) destroyed:
  433. ;    AX,BX,CX,DX
  434. ;-
  435. blankline proc    near
  436.     @save    si
  437.     mov    si,offset DGROUP:linebuf
  438.     cmp    byte ptr [si],'-'        ;Comment char ?
  439.     jne    @blankline_20
  440.     clc
  441.     jmp    short @blankline_99
  442. @blankline_20:
  443.     mov    cx,lastchar
  444.     sub    cx,si            ;CX<-num chars in line
  445.     call    near ptr skip_whitespace ;CF=1 if end of string
  446.     cmc
  447. @blankline_99:
  448.     @restore
  449.     ret
  450. blankline endp
  451.  
  452.  
  453. ; Extend the resident part of the installation code to form a buffer to
  454. ; hold the prompt and one to hold the current macro line arguments.
  455. ;  - 128 bytes from PSP + initial portion of CSEG.
  456. tsr_install_end LABEL BYTE
  457.     IF    ($-entry) LT (2+PROMPT_BUF_SIZE+LINEBUF_SIZE - 128)
  458.     DB    (2+PROMPT_BUF_SIZE+LINEBUF_SIZE - 128 - ($-entry)) DUP (?)
  459.     ENDIF
  460.  
  461. pgm_name   db    SIGNATURE1,CR,LF
  462. copyrite   db    SIGNATURE2,32,254,32,SIGNATURE3,CR,LF,LF,DOLLAR,26
  463.  
  464. ; Major and minor DOS versions.
  465. dos_version_major    db    ?
  466. dos_version_minor    db    ?
  467.  
  468. ;dos_envseg    dw    0            ;Segment for DOS
  469. ;                         environment. 0 indicates
  470. ;                         we don't know it.
  471.  
  472. resident    db    0        ;1 after becoming resident
  473. abort_entry_stack dw ?            ;Storage for stack state to be
  474. ;                     restored when processing is aborted
  475. abort_msg_hd db    '*** CMDEDIT : '    ;Header for abort message
  476. ABORT_HDR_LEN    equ $-abort_msg_hd
  477. abort_msg_tl db ' Any ongoing macro aborted! ***'            ;Tail for abort message
  478. ABORT_TAIL_LEN    equ $-abort_msg_tl
  479.  
  480. ; The following are error messages displayed by routine abort_processing.
  481. ; ALL MESSAGES MUST BE SHORT ENOUGH TO FIT INTO LINEBUF TOGETHER WITH
  482. ; abort_msg_hd and abort_msg_tl. The order of messages must be same as
  483. ; the order of Error code definitions in file common.inc
  484. abort_msg_table LABEL    BYTE
  485. line_trunc_msg     db    'Line too long.'
  486. saw_sig_msg     db    'Command aborted by user.'
  487. dirstk_empty_msg db    'Directory stack empty.'
  488. dirstk_msg     db    'Invalid dir or stack full.'
  489. dirstk_only_dos     db    'Command is DOS only.'
  490. nested_macro_msg db    'Nested macro definition.'
  491. nested_delm_msg     db    'DELM used inside macro.'
  492. ctrl_brk_msg     db    'Control-Break.'
  493. abort_msg_end    LABEL    BYTE
  494.  
  495. ; The following table holds pointers to each entry in the message table
  496. ; above. The length of each message is also stored here.
  497. abort_msg_ptrs    LABEL    WORD
  498.         dw    line_trunc_msg
  499.         dw    saw_sig_msg-line_trunc_msg
  500.         dw    saw_sig_msg
  501.         dw    dirstk_empty_msg-saw_sig_msg
  502.         dw    dirstk_empty_msg
  503.         dw    dirstk_msg-dirstk_empty_msg
  504.         dw    dirstk_msg
  505.         dw    dirstk_only_dos-dirstk_msg
  506.         dw    dirstk_only_dos
  507.         dw    nested_macro_msg-dirstk_only_dos
  508.         dw    nested_macro_msg
  509.         dw    nested_delm_msg-nested_macro_msg
  510.         dw    nested_delm_msg
  511.         dw    ctrl_brk_msg-nested_delm_msg
  512.         dw    ctrl_brk_msg
  513.         dw    abort_msg_end-ctrl_brk_msg
  514.  
  515. macrosize    dw    512    ;Default size of macro buffer
  516. symsize        dw    512    ;Default size of symbol buffer
  517. dossize        dw    512    ;Default size of DOS history buffer
  518. dirsize        dw    128    ;Default size of directory stack buffer
  519.  
  520. ;+-------------------------+
  521. ;| CMDEDIT state variables |
  522. ;+-------------------------+
  523. ; The variables source and macro_level together indicate the source of
  524. ; the next line. If macro_level is non-zero, the next line is obtained
  525. ; from an ongoing macro expansion. If macro_level is 0, then the
  526. ; variable source contains the address of the function to call to
  527. ; return the next line. This will be either get_kbd_line or
  528. ; get_file_line.
  529. macro_level    dw    0
  530. source        dw    ?        ;filled in during initialization
  531.  
  532.  
  533. ;+----------------------------------------------------------+
  534. ;| CMDEDIT commands. All commands preceded by a length byte.|
  535. ;| For each command that is added, make sure you update the |
  536. ;| table cmd_func_table below.                    |
  537. ;+----------------------------------------------------------+
  538. cmd_table    LABEL    BYTE
  539. defs        db    4,'defs'    ;Define a single line macro
  540. defm        db    4,'defm'    ;Start multiline macro definition
  541. pushd        db    5,'pushd'    ;Push on directory stack
  542. popd        db    4,'popd'    ;Pop from directory stack
  543. chd        db    3,'chd'        ;Change disk and directory
  544. dels        db    4,'dels'    ;Delete a symbol
  545. delm        db    4,'delm'    ;Delete a macro
  546. rsthist        db    7,'rsthist'    ;Reset history stack
  547. rstmac        db    6,'rstmac'    ;Reset macro buffer
  548. rstsym        db    6,'rstsym'    ;Reset symbol buffer
  549. rstdir        db    6,'rstdir'    ;Reset directory stack
  550. cmdstat        db    7,'cmdstat'    ;Show macro and symbol status
  551.  
  552. cmd_table_end    db    0        ;Terminate with a 0
  553. MAX_CMD_LEN    equ    7        ;Length of longest command
  554. ; Note endm is not a command except during a macro definition.
  555. endm_cmd    db    4,'endm'    ;End multiline macro definition
  556.  
  557.  
  558. ;+--------------------------------------------------------------+
  559. ;| CMDEDIT command functions. Must be in same order as commands.|
  560. ;+--------------------------------------------------------------+
  561. cmd_func_table    label WORD
  562.         dw    execute_defs
  563.         dw    execute_defm
  564.         dw    execute_pushd
  565.         dw    execute_popd
  566.         dw    execute_chd
  567.         dw    execute_dels
  568.         dw    execute_delm
  569.         dw    execute_rsthist
  570.         dw    execute_rstmac
  571.         dw    execute_rstsym
  572.         dw    execute_rstdir
  573.         dw    execute_cmdstat
  574.  
  575. linebuf_prefix    db    0        ;Fill byte/Sentinel before linebuf.
  576. ;                     Used in code to allow uniform
  577. ;                     checking of first linebuf character.
  578. linebuf        db    LINEBUF_SIZE DUP (?)    ;Temporary line buffer.
  579. LINEBUF_END    equ    $
  580. linebuf_suffix    db    ?            ;Need a byte at end of
  581. ;                         linebuf in various places
  582. macro_ignore_char db    ';'        ;Character used to prevent macro
  583. ;                     and symbol expansion.
  584. lastchar    dw    ?        ;Points beyond last char in the line
  585. cur_macro_len    dw    ?        ;Length of data in cur_macro
  586. dot        dw    ?        ;Current position in line
  587. disp_begin    dw    ?        ;disp_begin and disp_end are
  588. disp_end    dw    ?        ; markers into the line buffer
  589. ;                      that are used to keep track
  590. ;                      of the range that has been
  591. ;                      changed. This is used to
  592. ;                      selectively update the display.
  593. edit_mode    db    ?        ;1 if insert mode, else 0
  594. default_imode    db    0        ;By default overtype mode
  595.  
  596. linelimit    dw    ?        ;Upper limit for linebuf based
  597. ;                     on user's buffer length
  598. noted_dos_seg    db    0        ;1 after we have noted DOS segment
  599. dos_seg        dw    ?        ;Stores DOS segment
  600. in_appl        db    0        ;0 if dos, 1 if application
  601. user_command    db    0        ;This is set to 1 by certain
  602. ;                     CMDEDIT commands to return a
  603. ;                     string to the caller.
  604. ;                     (Basically put in as a kluge
  605. ;                     to get the prompt right after
  606. ;                     a pushd/popd/chd)
  607. ;+------------+
  608. ;| Video data |
  609. ;+------------+
  610. video_page    db    ?        ;Current video page
  611. screen_width    db    ?        ;width of screen
  612. initial_curcol    label    byte        ;initial cursor column
  613. initial_curpos    dw    ?        ;Initial cursor position
  614. ;Next two words must be contiguos
  615. omode_cursor    dw    ?        ;Cursor for overtype mode
  616. imode_cursor    dw    ?        ;Cursor for insert mode
  617. caller_cursor    dw    ?        ;Cursor shape of caller
  618.  
  619. silent        db    0        ;non-0 if bell should not be rung
  620.  
  621. ;+-------------------------------------------------------------------------+
  622. ;|Storage areas for various registers when called through INT 21 interface.|
  623. ;+-------------------------------------------------------------------------+
  624.  
  625. ssreg    dw    ?
  626. spreg    dw    ?
  627.  
  628. old_int21h LABEL DWORD        ;Storage for previous int 21h vector
  629. old_int21vec    DW    2 DUP (?)
  630.  
  631. new_sp    dw    ?        ;Store our stack ptr (bottom of stack).
  632.                 ;This is first para BEYOND cmdedit's memory.
  633.  
  634. prev_isr1b    dd    ?        ;Previous control break handler
  635.  
  636. ; check_break is set to 1 on entry to cmdedit, and restored to 0 on exit. If
  637. ; 1 on entry, then calling program must have been aborted with a break or
  638. ; critical error. The CMDEDIT Ctrl-Break ISR increments this flag every
  639. ; time it is called. If it is > 1, inside CMDEDIT, it indicates that a
  640. ; ctrl-break was entered. This allows runaway macros and symbols to be
  641. ; aborted.
  642. check_break    dw    0
  643. trap_break    db    0        ;If 1, does not allow original
  644. ;                     Ctrl-Break handler to see the
  645. ;                     Ctrl_break 
  646.  
  647.  
  648.  
  649. ;+
  650. ; FUNCTION : cmdedit_isr
  651. ;
  652. ;    This is our replacement for the DOS INT 21h handler.
  653. ;
  654. ; Parameters:
  655. ;    AH = function code
  656. ;
  657. ; Register(s) destroyed:
  658. ;-
  659. cmdedit_isr proc far
  660.     ASSUME    CS:DGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
  661.     pushf                ;Save flags
  662.     cmp    ah,0Ah            ;Is it the buffered input function ?
  663.     je    @cmdedit_isr_10        ;If so go on carry out our duty
  664.     popf                ;else restore flags
  665.     jmp    cs:old_int21h        ;and execute the original ISR
  666. @cmdedit_isr_10:
  667.                     ;Save registers
  668.     mov    cs:ssreg,ss        ;Stack segment
  669.     mov    cs:spreg,sp        ; and pointer
  670.     cli                ;Wanna change stack
  671.     push    cs
  672.     pop    ss
  673.     mov    sp,cs:new_sp        ;Bottom of stack
  674.     ASSUME    SS:DGROUP
  675.     sti                ;OK to interrupt now
  676.     @save    ax,bx,cx,dx,si,di,bp,ds,es
  677.     xchg    bx,dx
  678.     mov    al,byte ptr ds:[bx]    ;Length of caller buffer
  679.     xchg    dx,bx
  680.     xor    ah,ah            ;AX<-length of caller's buffer
  681.     push    ds            ;Save user segment
  682.     mov    cx,cs
  683.     mov    ds,cx            ;Init DS, ES to point to DGROUP
  684.     mov    es,cx
  685.     ASSUME    DS:DGROUP,ES:DGROUP
  686.     add    ax,offset dgroup:linebuf ;AX->last allowable linebuf
  687. ;                      location + 1
  688.     dec    ax            ;Need room for CR at end of line
  689.     mov    linelimit,ax        ;Store it
  690.     pop    ax            ;AX <- User's buffer segment
  691.                     ;DX already contains offset of
  692.                     ; user buffer
  693.     call    near ptr cmdedit    ;Main routine
  694.     @restore
  695.     cli
  696.     mov    ss,cs:ssreg
  697.     mov    sp,cs:spreg
  698.     sti
  699.  
  700.     popf
  701.     iret
  702. cmdedit_isr    endp
  703.  
  704.  
  705.  
  706.  
  707. ;+
  708. ; FUNCTION : cmdedit
  709. ;
  710. ;    Main routine called by the INT 21h ISR to get next line.
  711. ;    General Algorithm:
  712. ;    (1) Get the next line from the keyboard/macro expansion/file.
  713. ;    (2) Check for line begins with a macro. If so, expand it and
  714. ;        repeat step (2). Else go onto step (3).
  715. ;    (3) Check if the line is an internal CMDEDIT command. If so, execute
  716. ;        it and return to step (1).
  717. ;    (4) Copy line to caller's buffer and return.
  718. ;
  719. ; Parameters:
  720. ;    AX    = segment of user's buffer
  721. ;    DX    = offset of user's buffer
  722. ;
  723. ; Returns:
  724. ;    The next input line is copied into the user's buffer.
  725. ; Register(s) destroyed:
  726. ;    All except segment registers.
  727. ;-
  728. cmdedit    proc    near
  729.     push    es            ;Save ES
  730.     push    ax            ;Caller's buffer segment
  731.     push    dx            ;Caller's buffer offset
  732.     mov    trap_break,1        ;Trap Ctrl-Break handler
  733.     mov    cx,1
  734.     xchg    cx,CS:check_break    ;Check if last call did not
  735. ;                     exit normally. Also set flag
  736. ;                     for this call.
  737.     jcxz    @cmdedit_0        ;Last exit was OK
  738.     mov    macro_level,0        ;No it was not, so reset input
  739.     mov    source,offset DGROUP:get_kbd_line
  740. @cmdedit_0:
  741.     call    near ptr init_screen    ;Get screen/cursor data
  742.  
  743.     cmp    noted_dos_seg,0        ;Have we noted the DOS segment ?
  744.     jne    @cmdedit_1        ;Jump if we know it already
  745.     mov    noted_dos_seg,1        ;Remember that we now know it
  746.     mov    dos_seg,ax        ;Else remember it
  747.                     ;No point jumping over next
  748.                     ;couple of statements.
  749. @cmdedit_1:
  750.     mov    cx,1            ;Assume caller is not DOS
  751.     cmp    ax,dos_seg        ;Is the caller DOS ?
  752.     jne    @cmdedit_2
  753.     dec    cx            ;Yes, CX<-0
  754. @cmdedit_2:
  755.     mov    in_appl,cl        ;Rememeber whether caller is dos
  756.     call    near ptr hist_type    ;Set the history type (DOS/appl)
  757.  
  758. ; cmdedit_abort_entry is the entry point when command proessing is
  759. ; aborted for any reason. It is jumped to from abort_processing
  760.     mov    abort_entry_stack,sp    ;Remember stack state
  761. cmdedit_abort_entry    LABEL PROC
  762. @cmdedit_3:
  763.     call    near ptr reset_line    ;Reset cursor, line etc.
  764.     call    near ptr get_next_line    ;Get the next line from appropriate
  765. ;                     source (stored in linebuf)
  766. @cmdedit_10:
  767.     cmp    check_break,2        ;Check for any control breaks
  768.     jb    @cmdedit_11        ;No ctrl-breaks
  769.     mov    check_break,1
  770.     mov    ax,E_CTRL_BREAK        ;Message number
  771.     jmp    abort_processing
  772.  
  773. @cmdedit_11:
  774. ;If the first character is a ignore character, do not do a macro or symbol
  775. ;expansion.
  776.     mov    cx,lastchar        ;End of line
  777.     mov    si,offset DGROUP:linebuf ;SI->line buffer
  778.     sub    cx,si            ;CX<-length of line
  779.     jcxz    @cmdedit_15        ;Empty line, keep going since it
  780. ;                     can still be a macro or symbol
  781.     mov    al,[si]            ;AL<-first char of line
  782.     cmp    al,macro_ignore_char
  783.     jne    @cmdedit_15
  784. ; First is an ignore character so move up all characters and return
  785.     mov    di,si            ;DI->start of line
  786.     inc    si            ;SI->first char to copy
  787.     dec    cx            ;1 less character
  788.     dec    lastchar
  789. ;    Assume ES==DS, direction flag clear
  790.     rep    movsb            ;Move the bytes
  791.     jmp    @cmdedit_25        ;Yes, exit with carry flag set
  792.  
  793. @cmdedit_15:
  794.     call    near ptr expand_symbol    ;Check if symbol and expand
  795.     jnc    @cmdedit_10        ;If expanded, recurse
  796.     call    near ptr expand_macro    ;Check if line is a macro
  797. ;                     and expand if possible.
  798.     jnc    @cmdedit_10        ;If expanded, do recursively.
  799. ;                     (note that currently recursion
  800. ;                     will take place only on the
  801. ;                     last line of a macro definition)
  802. @cmdedit_25:
  803.  
  804.     mov    user_command,0        ;Init flag
  805.     call    near ptr cmdedit_cmd    ;Check if CMDEDIT command
  806.     jc    @cmdedit_30        ;No
  807. ; CMDEDIT command, but might want to return to caller anyway.
  808.     cmp    user_command,1        ;If 1, then return string to caller
  809.     je    @cmdedit_30        ; klugery here for PUSHD/POPD/CHD
  810. ;                     to intentionally return a
  811. ;                     blank line to DOS in order to
  812. ;                     get prompt right.
  813.  
  814.     jmp    short @cmdedit_3
  815.  
  816. @cmdedit_30:
  817. ; Expand variables if any.
  818.     call    near ptr replace_vars
  819.  
  820. ; Check if line too long for user buffer.
  821.     mov    ax,lastchar        ;AX->last character in buffer
  822.     cmp    ax,linelimit
  823.     jbe    @cmdedit_80        ;We're OK
  824.     mov    ax,E_TRUNCATE        ;error - line too long
  825.     jmp    near ptr abort_processing
  826. @cmdedit_80:
  827.     sub    ax,offset DGROUP:linebuf ;AX<-length of line
  828. ; OK now we have a line to give to the caller. Copy it into caller's
  829. ; buffer and return.
  830.     pop    di            ;Caller's buffer offset
  831.     pop    es            ;Caller's buffer segment
  832.     inc    di            ;ES:DI->second byte of user buffer
  833.     stosb                ;Store line length
  834.     mov    si,offset DGROUP:linebuf ;SI->Source string
  835.     xchg    cx,ax            ;CX<-length of string
  836.     rep    movsb            ;Copy bytes
  837.     mov    al,CR
  838.     stosb                ;Store terminating carraige-return
  839. ; Set cursor shape to caller's shape
  840.     call    near ptr restore_cursor    ;Restore user's cursor shape
  841.     mov    check_break,0        ;Reset flag
  842.     mov    trap_break,0        ; Ctrl-Break handler
  843.     pop    es            ;Restore ES
  844.     ret
  845. cmdedit endp
  846.  
  847.  
  848.  
  849.  
  850.  
  851. ;+
  852. ; FUNCTION : get_next_line
  853. ;
  854. ;    Gets the next line from the appropriate source and stores it in
  855. ;    the line buffer. THe source of the line may be either a macro
  856. ;    expansion or a file or the keyboard.
  857. ;
  858. ; Parameters:
  859. ;    None.
  860. ;
  861. ; Returns:
  862. ;    Nothing
  863. ; Register(s) destroyed:
  864. ;-
  865. get_next_line proc near
  866.     mov    lastchar,offset DGROUP:linebuf
  867.                     ;Empty line (in case not
  868. ;                     already done)
  869.     call    near ptr get_macro_line    ;Get next line in expansion
  870.     jnc    @get_next_line_99    ;Jump if there is a next line
  871.                     ;No next line in expansion, so
  872.                     ;get line from keyboard/file
  873. @get_next_line_10:
  874.     call    [source]        ;get_kbd_line / get_file_line
  875. @get_next_line_99:
  876.     ret
  877. get_next_line endp
  878.  
  879.  
  880.  
  881. ;+
  882. ; FUNCTION : replace_vars
  883. ;
  884. ;    Replaces all the variables in the current line with their
  885. ;    expansions. If the line is too long, aborts with a truncation
  886. ;    error.
  887. ;
  888. ; Parameters:
  889. ;    None.
  890. ;
  891. ; Returns:
  892. ;    Nothing.
  893. ; Register(s) destroyed:
  894. ;    AX,BX,CX,DX
  895. ;-
  896. replace_vars proc near
  897.     call    near ptr expand_var        ;CF set if error. AX
  898. ;                         contains error code
  899.     jnc    @replace_vars_99
  900.     jmp    near ptr abort_processing    ;Abort processing
  901.  
  902. @replace_vars_99:
  903.     ret
  904. replace_vars endp
  905.  
  906.  
  907.  
  908. ;+
  909. ; FUNCTION : get_curpos
  910. ;
  911. ;    Returns the current cursor position.
  912. ;
  913. ; Parameters:
  914. ;    Global    video_page indicates the page.
  915. ;
  916. ; Returns:
  917. ;    DX    = Current cursor position.
  918. ;    CX    = Current cursor scan lines.
  919. ; Register(s) destroyed: AX,BX
  920. ;-
  921. get_curpos proc    near
  922.     @GetCur    video_page
  923.     ret
  924. get_curpos    endp
  925.  
  926.  
  927. ;+
  928. ; FUNCTION : set_disp_marks
  929. ;
  930. ;    Sets the marks disp_begin and disp_end to indicate the start
  931. ;    and end positions in the line that have been changed. The
  932. ;    routine is passed two parameters which indicate
  933. ;    the potentially new values for disp_begin and disp_end
  934. ;    respectively. However the global disp_begin is changed only if
  935. ;    the new value is less than the current value. Similarly
  936. ;    disp_end is changed only if the new value is greater than the
  937. ;    current value.
  938. ;
  939. ; Parameters:
  940. ;    AX    = potential disp_end
  941. ;    DX    = potential disp_begin
  942. ;
  943. ; Returns:
  944. ;    Nothing.
  945. ;    May set globals disp_begin and disp_end.
  946. ;
  947. ; Register(s) destroyed: None.
  948. ;-
  949. set_disp_marks    proc near
  950.     cmp    ax,disp_end        ;New value greater ?
  951.     jb    @set_disp_marks_10    ;No
  952.     mov    disp_end,ax        ;New disp_end
  953. @set_disp_marks_10:
  954.     cmp    dx,disp_begin        ;New value smaller
  955.     jnb    @set_disp_marks_20    ;No
  956.     mov    disp_begin,dx        ;New disp_begin
  957. @set_disp_marks_20:
  958.     ret
  959. set_disp_marks    endp
  960.  
  961.  
  962. ;+
  963. ; FUNCTION : disp_line
  964. ;
  965. ;    Displays the current contents of the line buffer. Since the
  966. ;    entire line is not redisplayed everytime, all procedures that
  967. ;    change the contents of the line buffer have to follow certain
  968. ;    rules in order to make sure the display correctly shows the
  969. ;    line. The variable disp_begin must be set to the earliest
  970. ;    position in the line that has been changed and disp_end to beyond
  971. ;    last position in the line that has been changed.;
  972. ; Parameters:
  973. ;    None.
  974. ;
  975. ; Returns:
  976. ;    Nothing
  977. ; Register(s) destroyed:
  978. ;-
  979. disp_line proc near
  980.     @save    si,di
  981.     mov    ax,disp_begin        ;Lower limit of changed chars
  982.     mov    si,ax
  983.     mov    cx,disp_end        ;CX->byte after last char that
  984. ;                     has changed
  985.     sub    cx,si            ;CX<-num chars to be output
  986.     jcxz    @disp_line_90        ;Nothing to be updated
  987.     push    cx            ;Save CX across calls
  988.     call    near ptr line_to_scr    ;Move cursor to corresponding
  989. ;                     position on the screen.
  990. ;    OK, now we are ready to begin updating the screen.
  991.     call    near ptr get_curpos    ;DX<-current cursor position
  992.     pop    cx            ;Restore CX
  993.     mov    di,lastchar        ;DI->beyond last char
  994.     cmp    si,di            ;Beyond last char?
  995.     je    @disp_line_25        ;Go display blanks
  996. @disp_line_10:                ;Loop to output chars
  997.     lodsb                ;AL<-next char
  998.     @DispCh    al            ;Display it
  999.     push    cx            ;Save CX
  1000.     push    dx            ;Save old cursor position
  1001.     call    near ptr get_curpos    ;DX<-new cursor position
  1002.                     ; BX destroyed
  1003.     pop    bx            ;BX<-old cursor position
  1004.     pop    cx            ;Restore CX
  1005.     or    dl,dl            ;Column 0 ?
  1006.     jne    @disp_line_20        ;Nope
  1007.                     ;Col 0
  1008.     cmp    bh,dh            ;Is the row the same
  1009.     jne    @disp_line_20
  1010.                     ;yes, screen scrolled
  1011.     dec    initial_curpos+1    ;Decrement the row for initial
  1012. ;                     cursor position
  1013. @disp_line_20:
  1014.     mov    bx,dx            ;New cursor position
  1015.     cmp    si,di            ;Beyond last char?
  1016.     loopne    @disp_line_10        ;Keep looping until count exhausted or 
  1017. ;                     beyond last char
  1018. @disp_line_25:
  1019. ;    Now all changed positions have been displayed. If CX is not 0, 
  1020. ;    then the remaining char positions have to be 
  1021. ;    replaced with blanks. Note that since we are now overwriting  
  1022. ;    previously displayed positions, no need to check for line 
  1023. ;    wraparound or scroll. 
  1024.  
  1025.     jcxz    @disp_line_90        ;No more chars
  1026.  
  1027.     mov    al,' '            ;Overwrite with blanks
  1028. @disp_line_30:
  1029.     @DispCh    al
  1030.     loop    @disp_line_30
  1031. @disp_line_90:
  1032.     mov    ax,dot
  1033.     mov    disp_begin,ax        ;Initialize for next call
  1034.     mov    disp_end,ax
  1035.     call    near ptr line_to_scr    ;Set cursor at dot
  1036.  
  1037.     @restore
  1038.     ret
  1039. disp_line endp
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045. ;+
  1046. ; FUNCTION : line_to_scr
  1047. ;
  1048. ;    Places the cursor at the screen position corresponding to a
  1049. ;    specific position in the line buffer. The entire line buffer
  1050. ;    upto that position must have been displayed before.
  1051. ;
  1052. ; Parameters:
  1053. ;    AX    = Pointer into the line buffer
  1054. ;
  1055. ; Returns:
  1056. ;    Nothing.
  1057. ; Register(s) destroyed: AX, BX, DX
  1058. ;-
  1059. line_to_scr proc near
  1060.     sub    ax,offset dgroup:linebuf ;ax<-num chars
  1061.     mov    dx,initial_curpos    ;Initial cursor position
  1062. ;                     dh<-row, dl<-column
  1063.     xor    bh,bh
  1064.     mov    bl,dl            ;BX<-original column
  1065.     add    ax,bx            ;Compensate for initial position.
  1066. ;                     AX is now the 'virtual column'
  1067.     mov    bl,screen_width        ;BX<-width of screen
  1068. @line_to_scr_10:            ;Loop to skip over chars that
  1069. ;                     do not need to be updated
  1070.     cmp    ax,bx            ;Num of chars fit on a line?
  1071.     jb    @line_to_scr_20        ;Yes, exit loop
  1072.     sub    ax,bx            ;Go to next line
  1073.     inc    dh            ;Increment the row
  1074.     jmp    short @line_to_scr_10
  1075. @line_to_scr_20:
  1076. ; al now contains the column and dh the row where the cursor should
  1077. ; be placed 
  1078.     mov    dl,al            ;dx<-screen position
  1079.     @SetCurPos ,,video_page        ;Set the cursor position
  1080.     ret
  1081. line_to_scr endp
  1082.  
  1083.  
  1084.  
  1085.  
  1086. ;+
  1087. ; FUNCTION : insert_chars
  1088. ;
  1089. ;    Inserts a string of chars at the specified position in the
  1090. ;    linebuffer. If the length would exceed the size of the line buffer,
  1091. ;    chars are only store until the buffer is full and the carry flag is
  1092. ;    set. Dot is updated appropriately.
  1093. ;
  1094. ; Parameters :
  1095. ;
  1096. ;    SI    - ptr to source string
  1097. ;    DI    - ptr to insert position. This must lie in the line buffer.
  1098. ;    AX    - length of source string
  1099. ;
  1100. ; Returns:
  1101. ;    CF    = 1 if could not be fitted into linebuf
  1102. ;          0 otherwise
  1103. ;
  1104. ; Registers destroyed:
  1105. ;    AX,CX,DX
  1106. insert_chars proc near
  1107.     @save    si,di
  1108.     mov    dx,di            ;Save insert position in DX
  1109.     mov    di,lastchar        ;First empty position
  1110.     mov    cx,offset DGROUP:linebuf_suffix
  1111.     sub    cx,di            ;Subtract current last position
  1112. ;                     CX<-max chars that will fit
  1113.     cmp    cx,ax            ;Will all chars fit ?
  1114.     jb    @insert_chars_5    ;Not all chars will fit
  1115.     xchg    ax,cx            ;All chars will fit
  1116. @insert_chars_5:
  1117. ;    CX is number of chars to insert
  1118.     pushf                ;Remember CF
  1119. ;    Make place for the characters to be inserted by moving current
  1120. ;    characters up by CX.
  1121.     mov    ax,di
  1122.     sub    ax,dx            ;AX<-num chars to move
  1123.     push    si            ;Remember source address
  1124.     mov    si,di            ;SI->first char to be moved
  1125.     add    di,cx            ;DI -> new value of lastchar
  1126.     mov    lastchar,di        ;Store it
  1127.     xchg    ax,cx            ;AX<-num chars to insert
  1128. ;                     CX<-num chars to move
  1129.     std                ;Direction is downward
  1130.     cmpsb                ;Decrement SI,DI
  1131.     rep    movsb            ;Make place
  1132.     cld
  1133.     pop    si            ;Restore string source
  1134. ; Before inserting the chars, update the dot if it is affected.
  1135.     cmp    dx,dot            ;Is the dot at or after the insert
  1136. ;                     position ?
  1137.     jb    @insert_chars_50    ;No, jump
  1138.     add    dot,ax            ;Else update the dot
  1139. @insert_chars_50:
  1140.     mov    di,dx            ;DI->insert position
  1141.     xchg    cx,ax            ;CX<-num chars to insert
  1142.     rep    movsb            ;Copy string into linebuffer
  1143.     mov    ax,lastchar
  1144.     call    near ptr set_disp_marks    ;AX,DX are parameters
  1145.     popf                ;Restore CF
  1146.  
  1147.     @restore
  1148.     ret
  1149. insert_chars endp
  1150.  
  1151.  
  1152. ;+
  1153. ; FUNCTION : insert_at_dot
  1154. ;
  1155. ;    Inserts a string of characters into the line buffer in the
  1156. ;    position pointed to by dot. If the length specified in global
  1157. ;    caller_buflen will be exceeded,chars are only stored until the
  1158. ;    buffer is full and CF is set.
  1159. ;
  1160. ; Parameters:
  1161. ;    SI    = ptr to source string
  1162. ;    AL    = length of string
  1163. ;
  1164. ; Returns:
  1165. ;    CF    = 1 if could not be fitted into linebuf
  1166. ;          0 otherwise
  1167. ; Register(s) destroyed:
  1168. ;    <TBA>
  1169. ;-
  1170. insert_at_dot proc near
  1171.     @save    si,di,dx
  1172.     xor    ah,ah            ;AX<-length of source string
  1173.     mov    di,dot            ;DI-> insert position
  1174.     call    near ptr insert_chars    ;Params SI,DI,AX, returns status in CF
  1175.     @restore
  1176.     ret
  1177. insert_at_dot endp
  1178.  
  1179.  
  1180.  
  1181.  
  1182. ;+
  1183. ; FUNCTION : remove_chars
  1184. ;
  1185. ;    Removes a string of chars at the specified position in the
  1186. ;    linebuffer. The display markers and the lastchar global are updated
  1187. ;    accordingly. 
  1188. ;
  1189. ; Parameters :
  1190. ;
  1191. ;    SI    - ptr to position in linebuf from which to delete
  1192. ;    AX    - number of chars to delete.
  1193. ;
  1194. ; Returns:
  1195. ;    Nothing.
  1196. ;
  1197. ; Registers destroyed:
  1198. ;    AX,CX,DX
  1199. remove_chars proc near
  1200.     @save    si,di
  1201.     mov    di,ax            ;Save delete count
  1202.  
  1203. ; First update the display markers
  1204.     mov    ax,lastchar
  1205.     mov    dx,si
  1206.     call    near ptr set_disp_marks    ;AX,DX params
  1207.     mov    ax,lastchar
  1208.     sub    ax,si            ;Num chars after delete position
  1209.     cmp    ax,di            ;More than the specified number ?
  1210.     jb    @remove_chars_10    ;No, so just delete that many bytes
  1211.     mov    ax,di
  1212. @remove_chars_10:
  1213. ; AX is number of bytes to delete. See if the dot needs to be updated.
  1214.     mov    di,si            ;DI->delete position
  1215.     add    si,ax            ;SI->first char after delete string
  1216.     cmp    di,dot
  1217.     jnb    @remove_chars_40    ;dot before delete pos, so
  1218. ;                     unaffected
  1219.     cmp    si,dot            ;Is dot beyond it delete range
  1220.     jb    @remove_chars_30    ;Yes
  1221. ; dot is in delete region. Update it to point to first delete position
  1222.     mov    dot,di
  1223.     jmp    short @remove_chars_40
  1224. @remove_chars_30:
  1225. ; dot is beyond delete position. So subtract delete bytes from it.
  1226.     sub    dot,ax
  1227.  
  1228. @remove_chars_40:
  1229. ; Now that the screen markers and dot have been updated, get down to the
  1230. ; real business at hand. SI points to first char after delete string, DI is
  1231. ; the delete position. AX is number of bytes to be deleted.
  1232.     mov    cx,lastchar
  1233.     sub    lastchar,ax        ;Update lastchar
  1234.     sub    cx,si            ;CX<-num bytes to move
  1235.     rep    movsb            ;Move 'em
  1236. ; All done
  1237.  
  1238.     @restore
  1239.     ret
  1240. remove_chars endp
  1241.  
  1242.  
  1243. ;+
  1244. ; FUNCTION : erase_to_dot
  1245. ;
  1246. ;    Deletes all characters from the line buffer between the
  1247. ;    positions AX and dot. (Either AX or dot may be specify the
  1248. ;    beginning of range to be deleted). The markers disp_begin and
  1249. ;    disp_end are set to reflect the changed positions in the line.
  1250. ;    Global lastchar is also updated.
  1251. ; Parameters:
  1252. ;    AX    = One endpoint of the range to be deleted.
  1253. ;    Global    dot is the other.
  1254. ; Returns:
  1255. ;    Nothing.
  1256. ; Register(s) destroyed:
  1257. ;-
  1258. erase_to_dot proc near
  1259.     @save    si
  1260.     mov    si,dot
  1261.     cmp    ax,si            ;Make sure AX is after dot
  1262.     jnb    @erase_to_dot_10    ;Yes it is
  1263.     xchg    si,ax            ;Else exchange
  1264. @erase_to_dot_10:            ;AX is low end, SI high end
  1265.     sub    ax,si            ;AX is num bytes to delete
  1266.     call    near ptr remove_chars    ;Delete AX chars starting at [SI]
  1267.     @restore
  1268.     ret
  1269. erase_to_dot endp
  1270.  
  1271.  
  1272. ;+
  1273. ; FUNCTION : cmdedit_cmd
  1274. ;
  1275. ;    Checks if the line buffer contains a CMDEDIT command and if so
  1276. ;    executes it.
  1277. ;
  1278. ; Parameters:
  1279. ;    None.
  1280. ;
  1281. ; Returns:
  1282. ;    CF    = 0 if the line was a command
  1283. ;          1 otherwise.
  1284. ; Register(s) destroyed:
  1285. ;    AX,BX,CX,DX
  1286. ;-
  1287. cmdedit_cmd proc near
  1288.     @save    si,di
  1289.     mov    si,offset DGROUP:linebuf    ;SI->linebuf
  1290.     mov    di,lastchar            ;DI->end of line in linebuf
  1291. ; Skip leading whitespace
  1292.     mov    cx,di
  1293.     sub    cx,si                ;CX<-num chars in linebuf
  1294.     call    near ptr skip_whitespace    ;SI->first non-whitespace char
  1295. ;                         CX<-num remaining chars
  1296.     jcxz    @cmdedit_cmd_99            ;No command on line
  1297.     mov    di,si                ;DI->first char of word
  1298. ; Skip first word (name of this command)
  1299.     call    near ptr skip_nonwhite        ;SI->first whitespace after
  1300. ;                             command name
  1301. ;                         CX<-num remaining chars
  1302.     mov    ax,si
  1303.     sub    ax,di                ;AX<-num chars in word
  1304.     cmp    ax,MAX_CMD_LEN            ;Word too long to be command?
  1305.     ja    @cmdedit_cmd_98            ;Yes, exit
  1306. ; Now search thru the command table to see if the first word in the line is a
  1307. ; CMDEDIT command. Currently, DI->start of word, AX = num chars in word
  1308.     xor    dx,dx                ;DX<-Command number
  1309.     mov    si,offset dgroup:cmd_table    ;SI->Start of commands
  1310.  
  1311. @cmdedit_cmd_10:
  1312.     xor    ch,ch                ;Clear high bits
  1313.     mov    cl,[si]                ;CX<-Length of command
  1314.     jcxz    @cmdedit_cmd_98            ;End of table, exit
  1315.     inc    si                ;SI->command
  1316.     cmp    cx,ax                ;Lengths match
  1317.     jne    @cmdedit_cmd_30            ;No, go try next command
  1318.     xchg    bx,ax                ;BX<-num chars in word
  1319.     call    near ptr stre_cmp        ;Compare strings
  1320.     xchg    ax,bx                ;AX<-num chars in word
  1321.     je    @cmdedit_cmd_50            ;Command matched
  1322.  
  1323. @cmdedit_cmd_30:
  1324.     xor    ch,ch
  1325.     mov    cl,-1[si]            ;AX<-length of command
  1326.     add    si,cx                ;SI->length of next command
  1327.     inc    dx                ;Increment the command number
  1328.     jmp    short @cmdedit_cmd_10        ;Try next command
  1329.  
  1330. @cmdedit_cmd_50:                ;Found command
  1331.     mov    si,di                ;SI->first char of command
  1332.     add    si,ax                ;SI->first char after command
  1333.     mov    cx,lastchar
  1334.     sub    cx,si                ;CX<-num chars after command
  1335.     mov    di,dx                ;BX<-command number
  1336.     shl    di,1                ;BX<-offset into table
  1337.     call    cmd_func_table[di]        ;Execute it
  1338. ;                         Params:
  1339. ;                         SI->first char after command
  1340. ;                         CX = remaining length of line
  1341. ;                         (after command)
  1342.     cmp    source,offset DGROUP:get_kbd_line
  1343.     jne    @cmdedit_cmd_60
  1344.     call    near ptr disp_prompt        ;Display user prompt
  1345. @cmdedit_cmd_60:
  1346.     clc                    ;CF = 0
  1347.     jmp    short @cmdedit_cmd_99
  1348. @cmdedit_cmd_98:                ;No command found
  1349.     stc                    ;CF = 1
  1350. @cmdedit_cmd_99:
  1351.     @restore
  1352.     ret
  1353. cmdedit_cmd endp
  1354.  
  1355.  
  1356.  
  1357.  
  1358. ;+
  1359. ; FUNCTION : abort_processing
  1360. ;
  1361. ;    Called by various routines in case of any errors that require
  1362. ;    aborting of any ongoing processing. An error message is
  1363. ;    displayed and CMDEDIT state is reset to accept input from the
  1364. ;    keyboard. The routine adjusts the stack pointer to a previously
  1365. ;    stored state. Execution then continues at a `abort entry'
  1366. ;    point. The routine does NOT return to the caller.
  1367. ;
  1368. ; Parameters:
  1369. ;    AX    = Error message number.
  1370. ;
  1371. ; Returns:
  1372. ;    Does NOT return to caller.
  1373. ;
  1374. ; Register(s) destroyed:
  1375. ;    Potentially all but irrelevant since routine does not return to
  1376. ;    caller.
  1377. ;-
  1378. abort_processing proc near
  1379.     mov    macro_level,0            ;Reset macro level
  1380.     mov    source,offset DGROUP:get_kbd_line ;Set input to keyboard
  1381.  
  1382. ; Display a message
  1383.     mov    si,offset DGROUP:abort_msg_hd
  1384.     mov    di,offset DGROUP:linebuf
  1385.     mov    dot,di                ;dot MUST be at
  1386. ;                         beginning of line
  1387. ;                         since this position is
  1388. ;                         stored in the main routine
  1389.     mov    cx,ABORT_HDR_LEN
  1390.     rep    movsb                ;Copy message header
  1391.     sal    ax,1
  1392.     sal    ax,1                ;AX is now index into msg table
  1393.     xchg    ax,bx
  1394.     mov    si,abort_msg_ptrs[bx]        ;SI->message
  1395.     mov    cx,abort_msg_ptrs[bx+2]        ;CX<-length of message
  1396.     rep    movsb                ;Copy msg into linebuf
  1397.     mov    si,offset DGROUP:abort_msg_tl
  1398.     mov    cx,ABORT_TAIL_LEN
  1399.     rep    movsb                ;Copy tail of message
  1400.     mov    lastchar,di
  1401.     mov    ax,di                ;Set display marks
  1402.     mov    dx,offset DGROUP:linebuf
  1403.     call    near ptr set_disp_marks
  1404.     call    disp_line            ;Display message
  1405.     call    near ptr restore_cursor        ;Restore cursor to user shape
  1406.     @DispCh    CR
  1407.     @DispCh    LF
  1408.     call    near ptr disp_prompt
  1409.     mov    sp,abort_entry_stack
  1410.     jmp    near ptr cmdedit_abort_entry
  1411.  
  1412. abort_processing endp
  1413.  
  1414.  
  1415.  
  1416. ;+
  1417. ; FUNCTION : restore_cursor
  1418. ;
  1419. ;    Restores the cursor to the user's shape.
  1420. ;
  1421. ; Parameters:
  1422. ;    Global caller_cursor contains original shape
  1423. ;
  1424. ; Returns:
  1425. ;    
  1426. ; Register(s) destroyed:
  1427. ;    None.
  1428. ;-
  1429. restore_cursor    proc near
  1430.     @save    ax,cx
  1431.     mov    cx,caller_cursor
  1432.     IF    TOGGLE_CURSOR
  1433.     @SetCurSz ch,cl
  1434.     ENDIF
  1435.     @restore
  1436.     ret
  1437. restore_cursor    endp
  1438.  
  1439.  
  1440. ;+
  1441. ; FUNCTION : reset_line
  1442. ;
  1443. ;    Called to init various things like cursor shape, history buffer
  1444. ;    character positions etc.
  1445. ;
  1446. ; Parameters:
  1447. ;    None.
  1448. ;
  1449. ; Returns:
  1450. ;    Nothing.
  1451. ;
  1452. ; Register(s) destroyed:
  1453. ;    AX,BX,CX,DX
  1454. ;-
  1455. reset_line proc near
  1456.     call    near ptr hist_top    ;Reset history stack ptr to top
  1457.     call    near ptr restore_cursor    ;Reset cursor shape
  1458.     mov    ax,offset dgroup:linebuf
  1459.     mov    lastchar,ax        ;End of line
  1460.     mov    dot,ax            ;current pos in line
  1461.     mov    disp_begin,ax        ;first pos that changed
  1462.     mov    disp_end,ax        ;last pos that changed
  1463.  
  1464. ; Init overstrike/insert mode
  1465.     mov    bl,default_imode    ;Default edit mode
  1466. ;                     (insert/overstrike) 
  1467.     mov    edit_mode,bl        ;Init insert/overtype mode
  1468.  
  1469. ; Initialize the cursor shapes for insert and overstrike mode
  1470.     mov    ax,caller_cursor    ;Caller's cursor shape
  1471.     IF    TOGGLE_CURSOR
  1472.     mov    ah,al
  1473.     sub    ah,3
  1474.     mov    imode_cursor,ax        ;Insert mode cursor    
  1475.     mov    ah,al
  1476.     sub    ah,1
  1477.     mov    omode_cursor,ax        ;Overtype mode cursor    
  1478.  
  1479. ; Init cursor shape
  1480.     xor    bh,bh
  1481.     add    bx,bx
  1482.     mov    cx,omode_cursor[bx]
  1483.     mov    ah,01h
  1484.     int    10h
  1485.  
  1486.     ELSE
  1487.  
  1488.     mov    omode_cursor,ax
  1489.     mov    imode_cursor,ax
  1490.  
  1491.     ENDIF
  1492.  
  1493.     mov    bh,video_page
  1494.     @GetCur bh
  1495.     mov    initial_curpos,dx    ;Initial cursor position
  1496.  
  1497.     ret
  1498. reset_line endp
  1499.  
  1500.  
  1501. ;+
  1502. ; FUNCTION : init_screen
  1503. ;
  1504. ;    Inits various screen parameters. Reads the current prompt from
  1505. ;    the screen and store in the prompt buffer. prompt buffer is
  1506. ;    assumed to be at most the width of the screen.
  1507. ;
  1508. ; Parameters:
  1509. ;    None.
  1510. ;
  1511. ; Returns:
  1512. ;    Nothing.
  1513. ; Register(s) destroyed:
  1514. ;    AX,BX,CX,DX
  1515. ;-
  1516. init_screen proc near
  1517.     @save    si,di
  1518.     @GetMode            ;Get the video mode
  1519.     mov    video_page,bh        ;Store page
  1520.     mov    screen_width,ah        ; and width of display
  1521.  
  1522.     @GetCur    bh            ;Get the cursor shape and position
  1523.     mov    initial_curpos,dx    ;Initial cursor position
  1524.     mov    caller_cursor,cx    ;Caller's cursor shape
  1525.  
  1526.     mov    di,offset DGROUP:prompt
  1527.     mov    cx,PROMPT_BUF_SIZE    ;CX<-size of prompt buffer
  1528. ;                     (assumed not 0)
  1529.     mov    si,dx            ;DX<-cursor pos
  1530.     xor    dl,dl            ;DX<-position at start of row
  1531.  
  1532. @init_screen_5:
  1533. ; BH holds video page, DX is cursor position, SI is ending cursor
  1534. ; position, CX is remaining space in prompt buffer
  1535.     @SetCurPos    ,,bh        ;Set cursor position
  1536.     cmp    dx,si            ;Reached original position ?
  1537.     je    @init_screen_10        ;Yes, all done
  1538.     @GetChAtr    bh        ;Get char at cursor
  1539.     stosb                ;Store in prompt buffer
  1540.     inc    dl            ;Increment cursor position
  1541.     loop    @init_screen_5        ;loop unless prompt buffer full
  1542. @init_screen_10:
  1543.     sub    di,offset DGROUP:prompt
  1544.     mov    prompt_length,di    ;Store length of prompt
  1545.  
  1546.     @restore
  1547.     ret
  1548. init_screen endp
  1549.  
  1550.  
  1551.  
  1552. ;+
  1553. ; FUNCTION : disp_prompt
  1554. ;
  1555. ;    Called to display the user's prompt. The prompt is taken from
  1556. ;    the buffer 'prompt'.
  1557. ;
  1558. ; Parameters:
  1559. ;    None.
  1560. ;
  1561. ; Returns:
  1562. ;    Nothing.
  1563. ; Register(s) destroyed:
  1564. ;    <TBA>
  1565. ;-
  1566. disp_prompt    proc near
  1567.     @save    si
  1568.     @DispCh    CR
  1569.     @DispCh LF
  1570.     mov    cx,prompt_length
  1571.     jcxz    @disp_prompt_99
  1572.     mov    si,offset DGROUP:prompt
  1573. @disp_prompt_10:
  1574.     lodsb
  1575.     @DispCh    al
  1576.     loop    @disp_prompt_10
  1577. @disp_prompt_99:
  1578.     @restore
  1579.     ret
  1580. disp_prompt    endp
  1581.  
  1582.  
  1583.  
  1584.  
  1585. ;+
  1586. ; FUNCTION : makeroom
  1587. ;
  1588. ;    Called to push a specified number of characters from the end of a
  1589. ;    line to the back of the line buffer.
  1590. ;
  1591. ; Parameters:
  1592. ;    CX    - number of chars to push back
  1593. ;
  1594. ; Returns:
  1595. ;    DI    - points to the first char of the string pushed back.
  1596. ; Register(s) destroyed:
  1597. ;    CX
  1598. ;-
  1599. makeroom proc near
  1600.     @save    si
  1601.     mov    si,lastchar        ;end of line
  1602.     dec    si
  1603.     mov    di,offset DGROUP:linebuf_suffix ;Di->end of linebuf (we
  1604. ;                         want to move chars in
  1605. ;                         reverse order) 
  1606.     std
  1607.     rep    movsb            ;Move up characters
  1608.     cld
  1609.     inc    di            ;DI->start of string
  1610.     @restore
  1611.     ret
  1612. makeroom endp
  1613.  
  1614.  
  1615. ;+
  1616. ; FUNCTION : getpsp
  1617. ;
  1618. ;    Returns the PSP of the current process
  1619. ;
  1620. ; Returns:
  1621. ;    BX - segment of current PSP
  1622. ;
  1623. ; Registers destroyed :
  1624. ;    AX,BX
  1625. ;-
  1626. getpsp proc near
  1627. ; Get the PSP of the current process
  1628.     cmp    dos_version_major,2
  1629.     jbe    @getpsp_10
  1630. ;    DOS 3.x or above - use documented call
  1631.     mov    ah,62h
  1632.     jmp    short @getpsp_90
  1633. @getpsp_10:        
  1634. ; DOS version 2.x - use undocumented call
  1635.     mov    ah,51h
  1636. @getpsp_90:
  1637.     int    21h                ;BX->PSP segment
  1638.     ret
  1639. getpsp endp
  1640.     
  1641.  
  1642.  
  1643. ;+
  1644. ; Function : locate_dosenv
  1645. ;
  1646. ;    Locates the segment in which the current environment is located.
  1647. ;    This environment is the 'current' environment which may not
  1648. ;    necessarily be the root environment.
  1649. ;
  1650. ; Parameters:
  1651. ;    None.
  1652. ;
  1653. ; Returns:
  1654. ;    AX    - segment of environment
  1655. ;
  1656. ; Register(s) destroyed:
  1657. ;    AX
  1658. ;-
  1659. locate_dosenv proc near
  1660.     @save    bx,si,es
  1661.  
  1662.     call    near ptr getpsp            ;BX->segment of psp
  1663.     mov    es,bx                ;ES->segment of psp
  1664.  
  1665. ;    Loop to find the current command.com psp
  1666.     mov    si,16h                ;ES:SI->parent psp
  1667.     xor    ax,ax                ;Init for loop
  1668.     jmp    short @locate_dosenv_20        ;'while' loop
  1669.     
  1670. @locate_dosenv_10:
  1671.     mov    ax,es:[si]            ;AX<-psp seg
  1672.     mov    es,ax                ;ES->psp of parent
  1673. @locate_dosenv_20:
  1674.     cmp    ax,es:[si]            ;Is psp == parent psp ?
  1675.     jne    @locate_dosenv_10
  1676.  
  1677. ; ES contains DOS PSP.
  1678.     mov    ax,es:[2ch]            ;Offset 2c is env address
  1679.  
  1680. ; AX->DOS environment
  1681. ;    mov    dos_envseg,ax
  1682.     cmp    dos_version_major,2        ;DOS 2.x ?
  1683.     je    @locate_dosenv_50
  1684. ; Versions 3.x or higher
  1685.     cmp    dos_version_minor,10        ;3.1 or below ?
  1686.     jle    @locate_dosenv_50        ;If so handle like 2.x
  1687.     cmp    dos_version_minor,30        ;3,3 or above ?
  1688.     jge    @locate_dosenv_99        ;Then all done
  1689. ; DOS version higher than 3.1 but below 3.3.
  1690.     jmp    short @locate_dosenv_60
  1691.  
  1692.  
  1693. @locate_dosenv_50:
  1694. ; DOS version 2.x-3.1. If the environement is non-0, all done. Else the
  1695. ; environment is the memory block below the command.com.
  1696.     or    ax,ax                ;0 ?
  1697.     jne    @locate_dosenv_99        ;No, all done
  1698. @locate_dosenv_60:
  1699.     mov    si,es
  1700.     dec    si                ;SI is segment of memory
  1701. ;                         control block of command.com
  1702.     mov    es,si
  1703.     mov    ax,es:[3]            ;AX->size of command.com in
  1704. ;                         paragraphs 
  1705.     inc    ax                ;Add size of MCB to AX (in
  1706. ;                         paras) 
  1707.     add    ax,si                ;AX->MCB of environment
  1708.     inc    ax                ;AX->environment
  1709. ;    mov    dos_envseg,ax            ;Store it.
  1710.  
  1711. @locate_dosenv_99:
  1712. ; OK, now dos_envseg supposedly contains the environment segment. DO some
  1713. ; heuristics to make sure it is really what we think it is.
  1714.     
  1715.  
  1716.     @restore
  1717.     ret
  1718. locate_dosenv endp
  1719.  
  1720.  
  1721.  
  1722. ;+
  1723. ; FUNCTION : our_break_handler
  1724. ;
  1725. ;    This takes over the Ctrl-Break interrupt and sets a flag when
  1726. ;    Ctrl-Break is hit. It then jumps to the original Ctrl-Break handler.
  1727. ;
  1728. ; Parameters:
  1729. ;    
  1730. ;
  1731. ; Returns:
  1732. ;    
  1733. ; Register(s) destroyed:
  1734. ;-
  1735. our_break_handler proc near
  1736.     inc    CS:check_break
  1737.     cmp    CS:trap_break,1
  1738.     jne    @our_break_handler_10
  1739.     iret
  1740. @our_break_handler_10:
  1741.     jmp    CS:prev_isr1b
  1742. our_break_handler endp
  1743.  
  1744. CSEG    ENDS
  1745.  
  1746.     END    entry
  1747.