home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / KEYBOARD / CMDED2E5.ZIP / CMDEDIT.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-07-13  |  48.2 KB  |  1,803 lines

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