home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSSCMD.ASM < prev    next >
Assembly Source File  |  1993-05-14  |  76KB  |  2,406 lines

  1.     NAME    msscmd
  2. ; File MSSCMD.ASM
  3.     include mssdef.h
  4. ;  Copyright (C) 1985, 1992, Trustees of Columbia University in the 
  5. ;  City of New York.  Permission is granted to any individual or institution
  6. ;  to use this software as long as it is not sold for profit.  This copyright
  7. ;  notice must be retained.  This software may not be included in commercial
  8. ;  products without written permission of Columbia University.
  9. ;
  10. ; Edit history:
  11. ; 6 Sept 1991 version 3.11
  12. ; 13 March 1991 version 3.10
  13. ; Last edit 18 August 1992
  14. ; 5 Jan 1991 Add \$(Environment variable) substitution.
  15. ; 9 Sept 1990 Add \v(named variable) substitution.
  16. ; 21 Nov 1988 Version 2.32
  17. ; 17 Oct 1988 Make command keyword search failure yield global kstatus of
  18. ;  failure status, to inform Take/Macros of a defective command.
  19. ; 4 Aug 1988 Fix keyword count initialization in help display.
  20. ; 1 July 1988 Version 2.31
  21. ; 7 June 1988 Add comand.impdo flag to permit a keyword search failure to
  22. ;  retry as a DO cmd (macro table). Used only by main Kermit command level.
  23. ; 27 May 1988 Allow "-<cr>" as line continuation pair and let "\-<cr>" 
  24. ;  stand for "-<end of line>". Add comand.cmblen to sense buffer overflow on
  25. ;  calls to cmtxt; if comand.cmblen is left at zero then use 128 byte limit
  26. ;  (comand.cmblen is cleared at command end).
  27. ; 15 May 1988 Make :label keywords no-ops, make query ordinary char in TAKEs.
  28. ; 6 May 1988 Show ambiguous keywords at parse time, do graceful interaction.
  29. ; 28 March 1988 Permit '\%x' (x = '0' or above) in commands as 'variables'
  30. ;  (substituted string of text). Words are obtained from Macro table mcctab.
  31. ;  DEF MAC and DO MAC define variables. DEF macro uses comand.cmper > 0 to
  32. ;  allow '\%x'to be stored as a literal. Variables work in any command except
  33. ;  DEF MAC. Major redesign of whole parser. [jrd]
  34. ; 4 March 1988 Rewrite keyword parsing to permit non-alphabetized tables
  35. ;  and 8-bit characters. Add byte comand.cmwhite which when non-zero permits
  36. ;  leading whitespace in cmline and cmword commands; it is reset at command
  37. ;  completion. Move procedure Prompt here from mssker. [jrd]
  38. ; 27 Feb 1988 Add capability of stdin being a file. [jrd]
  39. ; 1 Jan 1988 version 2.30
  40.  
  41.      public comnd, comand, isdev, iseof, prompt, tolowr, valbuf, valtab
  42.     public parstate, pardone, parfail, nparam, param, lparam, ninter
  43.     public inter, atparse, atpclr, atdispat, cspb, dspb, mprompt, nvaltoa
  44.     public keyboard
  45.  
  46. env    equ    2CH            ; environment address in psp
  47. braceop    equ    7bh            ; opening curly brace
  48. bracecl    equ    7dh            ; closing curly brace
  49.  
  50. data     segment
  51.     extrn    flags:byte, taklev:byte, takadr:word, mcctab:byte
  52.     extrn    kstatus:word, oldtak:byte, errlev:byte, psp:word
  53.     extrn    portval:word, bdtab:byte, tdfmt:byte, machnam:byte
  54.     extrn    verident:word, kstatus:word, errlev:byte, comptab:byte
  55.     extrn    termtb:byte
  56.                 ; Start Patch structure. Must be first.
  57.     even
  58. dspb    dw    code        ; segment values for patcher
  59.     dw    code1
  60.     dw    code2
  61.     dw    data
  62.     db    64 dup (0)    ; data segment patch buffer
  63.                 ;  with space for other material, if req'd
  64.                 ; end of Patch structure
  65. progm    db    'MS-DOS_KERMIT$'    ; for \v(program)
  66. system    db    'MS-DOS$'        ; for \v(system)
  67. keyboard dw    88            ; \v(keyboard) kind of keybd 88/101
  68.  
  69. comand    cmdinfo    <>
  70. cmer00  db      cr,lf,'?Program internal error, recovering$'
  71. cmer01    db    cr,lf,'?More parameters are needed$'
  72. cmer02    db    cr,lf,'?Word "$'
  73. cmer03    db    '" is not usable here$'
  74. cmer04    db    '" is ambiguous$'
  75. cmer07    db    cr,lf,'?Ignoring extra characters "$'
  76. cmer08    db    '"$'
  77. cmer09    db    cr,lf,'?Text exceeded available buffer capacity$'
  78. cmin00  db      ' Press ENTER to execute command$'
  79. cmin01    db    ' One of the following:',cr,lf,'$'
  80. stkmsg    db    cr,lf,bell,'?Exhausted work space! Circular definition?$'
  81. crlf    db      cr,lf,'$'
  82. ctcmsg    db    5eh,'C$'
  83. cmunk    db    'unknown'
  84. errflag    db    0            ; non-zero to suppress cmcfrm errors
  85. kwstat    db    0            ; get-keyword status
  86. prevch    db    0            ; previous char read by cmgetc
  87. noparse    db    0            ; semicolons not special, if non-zero
  88. subcnt    db    0            ; count of chars matched in '\%'
  89. subtype db    0            ; kind of sub (% or v)
  90. bracecnt db    0            ; curly brace counter
  91. cmsflg    db    0            ; Non-zero when last char was a space
  92. cmdbuf    db    cmdblen dup (0)        ; Buffer for command parsing
  93.     even
  94. cmdstk    dw    0            ; stack pointer at comand call time
  95. cmptab    dw    0            ; Address of present keyword table
  96. cmhlp    dw    0            ; Address of present help
  97. cmwptr    dw    0            ; Pointer for next char write
  98. cmrptr    dw    0            ; Pointer for next char read
  99. cmsiz    dw    0            ; Size info of user input
  100. cmsptr    dw    0            ; Place to save a pointer
  101. mcmprmp    dw    0            ; master prompt, string address
  102. mcmrprs    dd    0            ; master prompt, reparse address
  103. mcmostp    dw    0            ; master prompt, stack pointer
  104. temp    dw    0            ; temp (counts char/line so far)
  105.  
  106. valtab    db    1+16            ; table of values for \v(value)
  107.     mkeyw    'argc)',1
  108.     mkeyw    'count)',2
  109.     mkeyw    'date)',3
  110.     mkeyw    'ndate)',14
  111.     mkeyw    'directory)',5
  112.     mkeyw    'errorlevel)',4
  113.     mkeyw    'keyboard)',10
  114.     mkeyw    'line)',15
  115.     mkeyw    'platform)',8
  116.     mkeyw    'port)',15
  117.     mkeyw    'program)',12
  118.     mkeyw    'speed)',11
  119.     mkeyw    'status)',13
  120.     mkeyw    'system)',9
  121.     mkeyw    'terminal)',16
  122.     mkeyw    'time)',6
  123.     mkeyw    'version)',7
  124.  
  125. envtab    db    1                     ; \$(..) Environment table
  126.     mkeyw    'An Environment variable)',0    ; reserve 0 in valtab
  127.  
  128. valtmp    dw    0
  129. valbuf    db    65 dup (0)        ; storage of variable definition
  130.  
  131.     even
  132. envadr    dd    0            ; seg:offset of a string in Environemt
  133. envlen    dw    0            ; length of envadr's string
  134.  
  135.     even                ; Control sequence storage area
  136. maxparam equ    16            ; number of ESC and DCS Parameters
  137. maxinter equ    16            ; number of ESC and DCS Intermediates
  138. parstate dw    0            ; parser state, init to startup
  139. pardone dw    0            ; where to jmp after Final char seen
  140. parfail    dw    0            ; where to jmp if parser fails
  141. nparam    dw    0            ; number of received Parameters
  142. param    dw    maxparam dup (0)    ; Parameters for ESC
  143. lparam    db    0            ; a single letter Parameter for ESC
  144. ninter    dw    0            ; number of received Intermediates
  145. inter    db    maxinter dup (0)    ; Intermediates for ESC 
  146.  
  147. pcmcfrm    dw    offset cmcfrm,seg cmcfrm ; FAR pointers to main parser procs
  148. pcmkeyw    dw    offset cmkeyw,seg cmkeyw ; located in code segment code1
  149. pcmtext    dw    offset cmtext,seg cmtext
  150. pcmfil0    dw    offset cmfil0,seg cmfil0
  151. pprserr    dw    offset prserr,seg prserr
  152. pcmexit    dw    offset cm6,seg cm6
  153. pfvaltoa dw    offset fvaltoa,seg fvaltoa
  154. data    ends
  155.  
  156.  
  157. code    segment
  158.     extrn    ctlu:near, cmblnk:near, locate:near, takrd:near, dec2di:near
  159.     extrn    takclos:near, docom:near, prtasz:near, getenv:near
  160.     extrn    getbaud:near, strlen:near, prtscr:near
  161.  
  162.     assume    cs:code, ds:data, es:nothing
  163.  
  164.                 ; Patch area. Must be first in MSK's Code Seg
  165. cspb    equ    this byte
  166.     db    (208-($-cspb)) dup (0)    ; code segment patch buffer
  167.                 ; end of Patch area
  168.  
  169. fctlu    proc    far        ; FAR callable versions of items in seg code
  170.     call    ctlu        ;  for calling from code segment code1 below
  171.     ret
  172. fctlu    endp
  173. fcmblnk    proc    far
  174.     call    cmblnk
  175.     ret
  176. fcmblnk    endp
  177. fgetbaud proc    far
  178.     call    getbaud
  179.     ret
  180. fgetbaud endp
  181. fgetenv    proc    far
  182.     call    getenv
  183.     ret
  184. fgetenv    endp
  185. flocate    proc    far
  186.     call    locate
  187.     ret
  188. flocate    endp
  189. ftakrd    proc    far
  190.     call    takrd
  191.     ret
  192. ftakrd    endp
  193. fdec2di    proc    far
  194.     call    dec2di
  195.     ret
  196. fdec2di    endp
  197. fstrlen    proc    far
  198.     call    strlen
  199.     ret
  200. fstrlen    endp
  201. ftakclos proc    far
  202.     call    takclos
  203.     ret
  204. ftakclos endp
  205. fprtasz    proc    far
  206.     call    prtasz
  207.     ret
  208. fprtasz    endp
  209. fprtscr    proc    far
  210.     call    prtscr
  211.     ret
  212. fprtscr    endp
  213. fisdev    proc    far
  214.     call    isdev
  215.     ret
  216. fisdev    endp
  217. fiseof    proc    far
  218.     call    iseof
  219.     ret
  220. fiseof    endp
  221. ftolowr    proc    far
  222.     call    tolowr
  223.     ret
  224. ftolowr    endp
  225. nvaltoa    proc    near
  226.     call    dword ptr pfvaltoa
  227.     ret
  228. nvaltoa    endp
  229.  
  230. ;       This routine parses the specified function in AH. Any additional
  231. ;       information is in DX and BX.
  232. ;       Returns carry clear on success and carry set on failure
  233.  
  234. COMND    PROC NEAR
  235.     mov    cmdstk,sp        ; save stack ptr for longjmp exit
  236.     mov    noparse,0          ; recognize semicolons in Take files
  237.     mov    bracecnt,0        ; curly brace counter
  238.     mov    al,taklev        ; Take level now
  239.     mov    oldtak,al        ; remember past internal takclos call
  240.     cmp    ah,cmeol        ; Parse a confirm?
  241.     jne    cm2            ; nz = no
  242.     call    dword ptr pcmcfrm    ; get a Carriage Return end of line
  243.     ret
  244. cm2:     cmp    ah,cmkey        ; Parse a keyword?
  245.     jne    cm3
  246.     call    dword ptr pcmkeyw    ; try and get one
  247.     ret
  248. cm3:    cmp    ah,cmline        ; parse line of text
  249.     jne    cm4
  250.     call    dword ptr pcmtext
  251.     ret
  252. cm4:    cmp    ah,cmword        ; parse arbitrary word
  253.     jne    cm5
  254.     call    dword ptr pcmfil0
  255.     ret
  256. cm5:    mov    ah,prstr        ; else give error
  257.     mov    dx,offset cmer00    ; "?Program internal error"
  258.     int    dos
  259.     jmp    dword ptr pprserr    ; reparse
  260.                     ; Control-C exit path (far to near)
  261. cm6:    mov    sp,cmdstk        ; restore command entry stack pointer
  262.     stc
  263.     ret                ;  and fail immediately (a longjmp)
  264.  
  265. COMND    ENDP
  266. code    ends
  267.  
  268. code1    segment
  269.     assume    cs:code1
  270.  
  271. ; This routine parses a keyword from the table pointed at by DX, help text
  272. ; point to by BX. Format of the table is as follows (use macro mkeyw):
  273. ;    addr:    db    N      ; Where N is the # of entries in the table
  274. ;        dw    M      ; M is the size of the keyword
  275. ;        db    'string'  ; String is the keyword
  276. ;        dw    value      ; Value is data to be returned
  277. ; Keywords may be in any order and in mixed case.
  278. ; Return is rskp for success and ret for failure.
  279.  
  280. ; cmptab: pointer to keyword table (supplied by caller)
  281. ; cmhlp: pointer to help message (supplied by caller)
  282. ; cmsptr: pointer to current user word text
  283. ; cmsiz: length of user text, excluding terminator
  284. ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
  285. ; comand.cmwhite: non-zero allows leading whitespace for cmline and cmword,
  286. ;                 reset automatically at end of call
  287. ; cmwptr: buffer write pointer to next free byte
  288. ; cmrptr: buffer read pointer for next free byte
  289. ; comand.cmper:    0 to do \%x substitution. Set to 0 at end of call
  290. ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
  291. ;         automatically at time of failure.
  292. cmkeyw    proc    far
  293.     mov    cmsiz,0            ; user word length
  294.     mov    ax,cmrptr        ; get command reading pointer
  295.     mov    cmsptr,ax        ; set pointer for start of user word
  296.     mov    cmhlp,bx        ; save the help pointer
  297.         mov    cmptab,dx        ; save the beginning of keyword table
  298.     mov    bx,dx
  299.     cmp    byte ptr[bx],0        ; get number of entries in table
  300.     jne    cmky1
  301.     jmp    cmky7            ; e = no keywords to check, error
  302. cmky1:    mov    cmsflg,0ffh        ; skip leading spaces/tabs
  303.     call    cmgtch            ; get char from the user into ah
  304.     jc    cmky3            ; c = terminator
  305.     mov    dx,cmrptr        ; next byte to read
  306.     dec    dx            ; where we just read a char
  307.     mov    cmsptr,dx        ; remember start of keyword
  308.     inc    cmsiz            ; start counting user chars
  309. cmky2:    call    cmgtch            ; read until terminator
  310.     jc    cmky3            ; c = terminator
  311.     inc    cmsiz            ; count user chars
  312.     jmp    short cmky2        ; no terminator yet
  313.  
  314. cmky3:    cmp    ah,'?'                  ; need help?
  315.     jne    cmky4            ; ne = no
  316.     jmp    cmkyhlp            ; do help and exit
  317. cmky4:    cmp    ah,escape        ; escape?
  318.     jne    cmky6            ; ne = no
  319.     call    cmkyesc            ; process escape
  320.     jc    cmky5            ; c = failure (no unique keyword yet)
  321.     mov    comand.cmper,0        ; reset to variable recognition
  322.     mov    comand.cmkeep,0
  323.     mov    comand.impdo,0        ; clear flag to prevent loops
  324.     mov    comand.cmquiet,0    ; permit echoing again
  325.     clc
  326.     ret                ; return successfully to user
  327.  
  328. cmky5:    cmp    cmsiz,0            ; started a word yet?
  329.     je    cmky1            ; e = no, ignore escape, keep looking
  330.     jmp    cmkyhlp            ; ne = yes, show type of error
  331.  
  332. cmky6:    cmp    cmsiz,0            ; length of user's text, empty?
  333.     je    cmky7            ; e = yes, parse error
  334.     push    bx
  335.     mov    bx,cmsptr        ; point at first user character
  336.     cmp    byte ptr[bx],':'    ; start of a label?
  337.     pop    bx
  338.     jne    cmky6a            ; ne = no, return success
  339.     mov    cmsiz,1            ; say just one byte
  340. cmky6a:    call    getkw            ; get unique kw, point to it with bx
  341.     jc    cmky8            ; c = not found
  342.     add    bx,[bx]            ; add length of keyword text (CNT)
  343.     add    bx,2            ; point at value field
  344.     mov    bx,[bx]            ; bx = return value following keyword
  345.     xor    ax,ax
  346.     mov    comand.cmper,al        ; reset to variable recognition
  347.     mov    comand.cmkeep,al
  348.     mov    comand.impdo,al        ; clear flag to prevent loops
  349.     mov    comand.cmquiet,al    ; permit echoing again
  350.     mov    errflag,al
  351.     clc
  352.     ret                ; return successfully
  353.                     ; all other terminators come here
  354. cmky7:    cmp    cmsiz,0            ; empty table or empty user's text?
  355.     jne    cmky8            ; ne = no
  356.     cmp    comand.cmcr,0        ; empty lines allowed?
  357.     jne    cmky10            ; ne = yes, do not complain
  358.     push    dx
  359.     mov    ah,prstr
  360.     mov    dx,offset cmer01    ; command word expected
  361.     int    dos
  362.     pop    dx
  363.     xor    al,al
  364.     mov    comand.cmquiet,al    ; permit echoing again
  365.     mov    comand.impdo,al        ; clear flag to prevent loops
  366.     stc                ; failure
  367.     ret
  368.  
  369. cmky8:    cmp    comand.impdo,0        ; failed here, ok to try Macro table?
  370.     je    cmky8a            ; e = no, use regular exit path
  371.     mov    comand.impdo,0        ; yes, but clear flag to prevent loops
  372.     mov    cmrptr,offset cmdbuf    ; reinit read pointer
  373.     mov    comand.cmquiet,1    ; suppress echoing of same keyword
  374.     mov    bx,offset docom        ; return DO as "found" keyword
  375.     clc
  376.     ret                ; return success to invoke DO
  377.  
  378. cmky8a:    mov    errflag,1        ; say already doing error recovery
  379.     or    kstatus,ksgen        ; global command status, failure
  380.     mov    comand.cmquiet,0    ; permit echoing again
  381.     call    fisdev            ; reading pretyped lines?
  382.     jnc    cmky9            ; nc = yes, consume rest of line
  383.     cmp    taklev,0        ; in a Take file?
  384.     jne    cmky9            ; ne = yes
  385.     call    cmskw            ; display offending keyword
  386.     dec    cmrptr            ; interactive, backup to terminator
  387.     mov    bx,cmrptr        ; look at it
  388.     cmp    byte ptr [bx],' '    ; got here on space terminator?
  389.     jne    cmky10            ; ne = no, (cr,lf,ff) exit failure
  390.     mov    ah,prstr        ; start a fresh line
  391.     mov    dx,offset crlf
  392.     int    dos
  393.     call    bufreset        ; cut back buffer to just before term
  394.     jmp    repars            ; reparse interactive lines
  395.  
  396. cmky9:    call    dword ptr pcmcfrm    ; get formal end of command line
  397.                     ;  to maintain illusion of typeahead
  398.                     ;  and let user backspace to correct
  399.                     ;  mistakes (we reparse everything)
  400.     call    cmskw            ; display offending keyword
  401. cmky10:    mov    comand.cmquiet,0    ; permit echoing again
  402.     stc                ; say failure
  403.     ret
  404. cmkeyw    endp
  405.  
  406. ;;;;;; start support routines for keyword parsing.
  407.  
  408. cmkyesc    proc    near            ; deal with escape terminator
  409.     call    bufreset        ; reset buffer to end just before ESC
  410.     cmp    cmsiz,0         ; user word length, empty?
  411.     jne    cmkye2            ; ne = have user text, else complain
  412. cmkye1:    call    esceoc            ; do normal escape end-of-command
  413.     stc                ; say failure to fill out word
  414.     ret
  415.                     ; add unique keyword to buffer
  416. cmkye2:    call    getkw            ; is there a matching keyword?
  417.     jc    cmkye1            ; c = ambiguous or not found
  418.     push    bx            ; unique, bx points to structure
  419.     push    si
  420.     mov    cx,[bx]            ; length of keyword
  421.     add    bx,2            ; point to first letter
  422.     mov    si,cmwptr        ; where next char goes
  423.     mov    dx,cmsiz        ; length of user word
  424.     add    bx,dx            ; add chars known so far
  425.     sub    cx,dx            ; calculate number yet to add
  426.     add    cmsiz,cx
  427.     jcxz    cmkye4            ; z = none
  428.     mov    ah,conout        ; display new char
  429. cmkye3:    mov    al,[bx]            ; get a keyword letter
  430.     inc    bx
  431.     call    ftolowr            ; lowercase
  432.     mov    [si],al            ; store it
  433.     inc    si
  434.     mov    dl,al
  435.     int    dos            ; display it
  436.     loop    cmkye3            ; do all new chars
  437. cmkye4:    mov    byte ptr[si],' '    ; insert space terminator in buffer
  438.     mov    dl,' '            ; display it
  439.     mov    ah,conout
  440.     int    dos
  441.     inc    si
  442.     mov    cmrptr,si        ; move token pointer after the space
  443.     mov    cmwptr,si        ; next free slot is after the space
  444.     mov    cmsflg,0ffh        ; set space-seen flag
  445.     pop    si
  446.     pop    bx            ; bx = keyword structure
  447.     add    bx,[bx]            ; add length of keyword text
  448.     add    bx,2            ; point at value field
  449.     mov    bx,[bx]            ; bx = return value following keyword
  450.     clc                ; carry clear for success
  451.     ret
  452. cmkyesc    endp
  453.  
  454. esceoc    proc    near            ; do normal escape end-of-command
  455.     push    ax
  456.     push    dx
  457.     mov    ah,conout        ; ring the bell
  458.     mov    dl,bell
  459.     int    dos
  460.     pop    dx
  461.     pop    ax
  462.     call    bufreset        ; reset buffer
  463.     stc                ; say error condition
  464.     ret
  465. esceoc    endp
  466.  
  467. ; Help. Question mark entered by user.  Display all the keywords that match
  468. ; user text. If text is null then use external help if available; otherwise,
  469. ; display all keywords in the table. Removes question mark from buffer and
  470. ; invokes reparse of command line to-date. User word starts at cmsptr and
  471. ; is cmsiz bytes long.
  472. cmkyhlp    proc    near
  473.     xor    cx,cx            ; clear number of keyword (none yet)
  474.     cmp    cmsiz,0            ; user text given?
  475.     jne    cmkyh1            ; ne = yes, use matching keywords
  476.     cmp    cmhlp,0            ; external help given?
  477.     jne    cmkyh6            ; yes, use it instead of full table
  478. cmkyh1:    mov    temp,0            ; count # chars printed on this line
  479.     mov    bx,cmptab        ; beginning of kw table
  480.     mov    ch,[bx]            ; length of table
  481.     xor    cl,cl            ; no keywords or help displayed yet
  482.     inc    bx            ; point at CNT field
  483. cmkyh2:    cmp    cmsiz,0            ; length of user word
  484.     je    cmkyh3            ; e = null, use full table
  485.     call    cmpwrd            ; compare keyword with user word
  486.     jc    cmkyh5            ; c = no match, get another keyword
  487. cmkyh3:    mov    ax,[bx]            ; length of table keyword
  488.     add    byte ptr temp,al    ; count chars printed so far
  489.     cmp    temp,76            ; will this take us beyond column 78?
  490.     jbe    cmkyh4            ; be = no, line has more room
  491.     mov    byte ptr temp,al    ; reset the count
  492.     mov    ah,prstr
  493.     mov    dx,offset crlf        ; break the line
  494.     int    dos
  495. cmkyh4:    or    cl,cl            ; any keywords found yet?
  496.     jnz    cmkyh4a            ; nz = yes
  497.     mov    dx,offset cmin01    ; start with One of the following: msg
  498.     mov    ah,prstr
  499.     int    dos
  500.     inc    cl            ; say one keyword has been found
  501. cmkyh4a:mov    dl,spc            ; put two spaces before each keyword
  502.     mov    ah,conout
  503.     int    dos
  504.     int    dos
  505.     add    temp,2            ; count output chars
  506.     mov    di,bx            ; get current keyword structure
  507.     add    di,2            ; text part
  508.     push    cx
  509.     mov    cx,[bx]            ; string length to cx, offset to di
  510.     call    fprtscr            ; display counted string
  511.     pop    cx
  512. cmkyh5:    dec    ch            ; are we at end of table?
  513.     jle    cmkyh7            ; le = yes, quit now
  514.     add    bx,[bx]            ; next keyword, add CNT chars to bx
  515.     add    bx,4            ; skip CNT and 16 bit value
  516.     jmp    cmkyh2            ; go examine this keyword
  517.  
  518. cmkyh6:    mov    dx,cmhlp        ; external help text
  519.     mov    ah,prstr
  520.     int    dos
  521.     inc    cl            ; say gave help already
  522. cmkyh7:    or    cl,cl            ; found any keywords?
  523.     jnz    cmkyh9            ; nz = yes
  524.     mov    cx,cmsiz        ; length of word
  525.     or    cx,cx
  526.     jg    cmkyh8            ; g = something to show
  527.     push    dx
  528.     mov    ah,prstr
  529.     mov    dx,offset cmer01    ; command word expected
  530.     int    dos
  531.     pop    dx
  532.     jmp    prserr
  533. cmkyh8:    mov    kwstat,0        ; set keyword not-found status
  534.     call    cmskw            ; display offending keyword
  535. cmkyh9:    mov    ah,prstr        ; start a fresh line
  536.     mov    dx,offset crlf
  537.     int    dos
  538.     call    bufreset        ; cut back buffer to just before '?'
  539.         jmp    repars
  540. cmkyhlp    endp
  541.  
  542. ; See if keyword is ambiguous or not from what the user has typed in.
  543. ; Return carry set if word is ambiguous or not found, carry clear otherwise.
  544. ; Uses table pointed at by cmptab, user text pointed at by cmsptr and length
  545. ; in cmsiz.
  546. cmambg    proc    near
  547.     push    bx
  548.     push    cx
  549.     push    dx
  550.     xor    dl,dl            ; count keyword matches so far
  551.     mov    bx,cmptab        ; look at start of keyword table
  552.     mov    cl,[bx]            ; get number of entries in table
  553.     xor    ch,ch            ; use cx as a counter
  554.     jcxz    cmamb8            ; z = no table so always ambiguous
  555.     inc    bx            ; look at CNT byte of keyword
  556. cmamb4:    call    cmpwrd            ; user vs table words, same?
  557.     jc    cmamb6            ; c = no match
  558.     inc    dl            ; count this as a match
  559.     cmp    dl,1            ; more than one match?
  560.     ja    cmamb8            ; a = yes, quit now
  561. cmamb6:    add    bx,[bx]            ; add CNT chars to bx
  562.     add    bx,4            ; skip CNT and 16 bit value
  563.     loop    cmamb4            ; do rest of keyword table
  564.     cmp    dl,1            ; how many matches were found?
  565.     jne    cmamb8            ; ne = none or more than 1: ambiguous
  566.     pop    dx            ; restore main registers
  567.     pop    cx
  568.     pop    bx
  569.     clc
  570.     ret                ; ret = not ambiguous
  571. cmamb8:    pop    dx            ; restore main registers
  572.     pop    cx
  573.     pop    bx
  574.     stc
  575.     ret                ; return ambiguous or not found
  576. cmambg    endp
  577.  
  578. ; Compare user text with keyword, abbreviations are considered a match.
  579. ; Enter with bx pointing at keyword table CNT field for a keyword.
  580. ; Return carry clear if they match, set if they do not match. User text
  581. ; pointed at by cmsptr and length is in cmsiz.
  582. ; Registers preserved.
  583.  
  584. cmpwrd    proc    near
  585.     push    cx
  586.     mov    cx,cmsiz        ; length of user's text
  587.     jcxz    cmpwrd2            ; z: null user word matches no keyword
  588.     cmp    cx,[bx]            ; user's text longer than keyword?
  589.     ja    cmpwrd2            ; a = yes, no match
  590.     push    ax
  591.     push    bx
  592.     push    si
  593.     add    bx,2                ; point at table's keyword text
  594.     mov    si,cmsptr        ; buffer ptr to user input
  595.     cld
  596. cmpwrd1:lodsb                ; user text
  597.     mov    ah,[bx]            ; keyword text
  598.     inc    bx            ; next keyword letter
  599.     call    ftolowr            ; force lower case on both chars
  600.     cmp    ah,al            ; same?
  601.     loope    cmpwrd1            ; e = same so far
  602.     pop    si
  603.     pop    bx
  604.     pop    ax
  605.     jne    cmpwrd2            ; ne = mismatch
  606.     pop    cx            ; recover keyword counter
  607.     clc                ; they match
  608.     ret
  609. cmpwrd2:pop    cx            ; recover keyword counter
  610.     stc                ; they do not match
  611.     ret
  612. cmpwrd    endp
  613.  
  614. ; Get pointer to keyword structure using user text. Uses keyword table
  615. ; pointed at by cmptab and cmsiz holding length of user's keyword (cmpwrd
  616. ; needs comand.cmsptr pointing at user's keyword and length of cmsiz).
  617. ; Structure pointer returned in BX.
  618. ; Return carry clear for success and carry set for failure. Modifies BX.
  619. getkw    proc    near
  620.     push    cx
  621.     mov    kwstat,0        ; keyword status, set to not-found
  622.     cmp    cmsiz,0            ; length of user word, empty?
  623.     je    getkw3            ; e = yes, fail
  624.     mov    bx,cmptab        ; table of keywords
  625.     mov    cl,[bx]            ; number of keywords in table
  626.     xor    ch,ch
  627.     jcxz    getkw3            ; z = none, fail
  628.     inc    bx            ; point to first
  629. getkw1:    call    cmpwrd            ; compare user vs table words
  630.     jc    getkw2            ; c = failed to match word, try next
  631.     mov    kwstat,1        ; say found one keyword, maybe more
  632.     push    dx
  633.     mov    dx,cmsiz        ; users word length
  634.     cmp    [bx],dx            ; same length (end of keyword)?
  635.     pop    dx
  636.     je    getkw4            ; e = yes, exact match. Done
  637.     call    cmambg            ; ambiguous?
  638.     jnc    getkw4            ; nc = unique, done, return with bx
  639.     mov    kwstat,2        ; say more than one such keyword
  640. getkw2:    add    bx,[bx]            ; next keyword, add CNT chars to bx
  641.     add    bx,4            ; skip CNT and 16 bit value
  642.     loop    getkw1            ; do all, exhaustion = failure
  643. getkw3:    pop    cx
  644.     stc                ; return failure
  645.     ret
  646. getkw4:    pop    cx
  647.     clc                ; return success
  648.     ret
  649. getkw    endp
  650.  
  651. ; show offending keyword message. Cmsptr points to user word,
  652. ; cmsiz has length. Modifies AX, CX, and DX.
  653. cmskw    proc    near
  654.     cmp    comand.cmquiet,0    ; Quiet mode?
  655.     je    cmskw0            ; e = no, regular mode
  656.     ret                ; else say nothing
  657. cmskw0:    mov    ah,prstr        ; not one of the above terminators
  658.     mov    dx,offset cmer02    ; '?Word "'
  659.     int    dos
  660.     mov    ah,conout
  661.     mov    cx,cmsiz        ; length of word
  662.     jcxz    cmskw3            ; z = null
  663.     mov    ah,conout
  664.     push    si
  665.     mov    si,cmsptr        ; point to word
  666.     cld
  667. cmskw1:    lodsb
  668.     cmp    al,' '            ; control code?
  669.     jae    cmskw2            ; ae = no
  670.     push    ax
  671.     mov    dl,5eh            ; caret
  672.     int    dos
  673.     pop    ax
  674.     add    al,'A'-1        ; plus ascii bias
  675. cmskw2:    mov    dl,al            ; display chars in word
  676.     int    dos
  677.     loop    cmskw1
  678.     pop    si
  679. cmskw3:    mov    dx,offset cmer03    ; '" not usable here.'
  680.     cmp    kwstat,1        ; kywd status from getkw, not found?
  681.     jb    cmskw4            ; b = not found, a = ambiguous
  682.     mov    dx,offset cmer04    ; '" ambiguous'
  683. cmskw4:    mov    ah,prstr
  684.         int    dos
  685.     ret
  686. cmskw    endp
  687. ;;;;;;;;;; end of support routines for keyword parsing.
  688.  
  689. ; Parse    arbitrary text up to a CR. Enter with BX = pointer to output buffer,
  690. ; DX pointing to help text. Produces asciiz string. Return updated pointer in
  691. ; BX and output size in AH. Leading spaces are omitted unless comand.cmwhite
  692. ; is non-zero (cleared upon exit). It does not need to be followed by the
  693. ; usual call to confirm the line. Byte comand.cmblen can be used to specify
  694. ; the length of the caller's buffer; cleared to zero by this command to
  695. ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
  696. cmtext    proc    far
  697.     mov    cmptab,bx        ; save pointer to data buffer
  698.     mov    cmhlp,dx        ; save the help message
  699.     xor    cx,cx            ; init the char count
  700.     cmp    comand.cmblen,0        ; length of user's buffer given?
  701.     jne    cmtxt0            ; ne = yes
  702.     mov    comand.cmblen,127    ; else set 127 byte limit plus null
  703. cmtxt0:    mov    cmsflg,0ffh        ; skip initial spaces
  704.     cmp    comand.cmwhite,0    ; allow leading whitespace?
  705.     je    cmtxt1a            ; e = no
  706. cmtxt1:    mov    cmsflg,0        ; get all spaces
  707. cmtxt1a:call    cmgtch            ; get a char
  708.     jnc    cmtxt5            ; nc = non-terminator, put in buffer
  709.     cmp    ah,' '            ; space?
  710.     je    cmtxt5            ; e = yes, record it
  711.     cmp    ah,escape        ; escape?
  712.     jne    cmtxt2            ; ne = no
  713.     call    esceoc            ; do normal escape end-of-command
  714.     jmp    short cmtxt0        ; try again
  715.  
  716. cmtxt2:    cmp    ah,'?'            ; asking a question?
  717.     je    cmtxt3            ; e = yes
  718.     cmp    ah,cr            ; formal carriage return?
  719.     je    cmtxt2a            ; e = yes
  720.     inc    cmrptr            ; accept char into buffer
  721.     jmp    short cmtxt5        ;  and record the char
  722. cmtxt2a:mov    bx,cmptab        ; return updated pointer
  723.     xor    ax,ax
  724.     mov    byte ptr[bx],al        ; put terminator into the buffer
  725.     mov    comand.cmwhite,al    ; clear leading whitespace flag
  726.     mov    comand.cmper,al        ; reset to variable recognition
  727.     mov    comand.cmblen,ax    ; set user buffer length to unknown
  728.     mov    comand.cmkeep,al
  729.     mov    ax,cx            ; return count in AX
  730.     call    rprompt            ; restore master prompt level
  731.     clc
  732.     ret
  733.                     ; Help processor
  734. cmtxt3:    inc    cmrptr            ; count the ?
  735.     or    cx,cx            ; is "?" the first char?
  736.     jnz    cmtxt5            ; nz = no, just add to buffer
  737.     dec    cmrptr
  738.     mov    cmsiz,0            ; no keyword for help
  739.     mov    comand.cmwhite,0    ; clear leading whitespace flag
  740.     cmp    cmhlp,0            ; external help given?
  741.     jne    cmtxt3a            ; ne = yes
  742.     mov    cmhlp,offset cmin00    ; confirm with c/r msg
  743.     mov    comand.cmblen,0        ; set user buf length to unknown
  744. cmtxt3a:jmp    cmkyhlp            ; do help process
  745.  
  746. cmtxt5:    inc    cx            ; increment the count
  747.     mov    bx,cmptab        ; pointer into destination array
  748.     mov    [bx],ah            ; put char into the buffer
  749.     inc    bx
  750.     xor    al,al
  751.     mov    [bx],al            ; insert null terminator
  752.     mov    cmptab,bx
  753.     cmp    cx,comand.cmblen    ; buffer filled?
  754.     ja    cmtxt6            ; a = yes, declare error
  755.     jb    cmtxt5a            ; a = not filled yet
  756.     mov    ah,conout        ; notify user that the buffer is full
  757.     mov    dl,bell
  758.     int    dos
  759. cmtxt5a:jmp    cmtxt1
  760. cmtxt6:    mov    ah,prstr
  761.     mov    dx,offset cmer09
  762.     int    dos
  763.     jmp    prserr            ; declare parse error
  764. cmtext    endp
  765.  
  766.  
  767. ; Parse arbitrary text up to whitespace.  Enter with DX pointing to output
  768. ; buffer and BX pointing to help text. Produces asciiz string. Return updated
  769. ; pointer in DX and input size in AH. Skips leading whitespace unless 
  770. ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit.
  771.  
  772. cmfil0    proc    far
  773.     mov    cmptab,dx        ; save pointer to data buffer
  774.     mov    cmhlp,bx        ; save the help message
  775.     mov    cmsiz,0            ; init the char count
  776.     cmp    comand.cmblen,0        ; length of user's buffer given?
  777.     jne    cmfil0a            ; ne = yes
  778.     mov    comand.cmblen,127    ; else set 127 byte limit plus null
  779. cmfil0a:cmp    comand.cmwhite,0    ; allow leading whitespace?
  780.     jne    cmfil1            ; ne = yes
  781.     mov    cmsflg,0ffh        ; omit leading space
  782. cmfil1:    call    cmgtch            ; get a char
  783.     jc    cmfi1a            ; c = terminator 
  784.     jmp    short cmfil5        ; put char into the buffer
  785. cmfi1a:    cmp    ah,escape        ; escape?
  786.     je    cmfi1b            ; e = yes
  787.     jmp    short cmfil2        ; process other terminators
  788. cmfi1b:    call    esceoc            ; do normal escape end-of-command
  789.     jmp    short cmfil0a        ; try again
  790.  
  791. cmfil2:    cmp    ah,'?'            ; asking a question?
  792.     je    cmfil3            ; e = yes
  793.     xchg    dx,bx            ; re-interchange bx and dx
  794.     xor    ax,ax
  795.     mov    comand.cmwhite,al    ; clear whitespace flag
  796.     mov    comand.cmper,al        ; reset to variable recognition
  797.     mov    comand.cmkeep,al    ; do not keep Take file open
  798.     mov    comand.cmblen,ax    ; set user buffer length to unknown
  799.     mov    bx,cmptab        ; pointer into destination array
  800.     mov    byte ptr[bx],al        ; put null terminator into the buffer
  801.     inc    bx
  802.     mov    ax,cmsiz        ; return count in AX
  803.     mov    dx,cmptab        ; return updated pointer
  804.     xchg    dx,bx            ; re-interchange bx and dx
  805.     call    rprompt            ; restore master prompt level
  806.     clc
  807.     ret                ; return success
  808.  
  809. cmfil3:    inc    cmrptr            ; count the ?
  810.     cmp    cmsiz,0            ; Is "?" first char?
  811.     jne    cmfil5            ; ne = no, just add to buffer
  812.     dec    cmrptr
  813.     mov    cmsiz,0
  814.     cmp    cmhlp,0            ; external help given?
  815.     jne    cmfil3a            ; ne = yes
  816.     mov    cmhlp,offset cmin00    ; confirm with c/r msg
  817. cmfil3a:jmp    cmkyhlp            ; do help process
  818.  
  819. cmfil5:    inc    cmsiz            ; increment the count
  820.     mov    bx,cmptab        ; pointer into destination array
  821.     mov    [bx],ah            ; put char into the buffer
  822.     inc    bx
  823.     mov    cmptab,bx
  824.     mov    cx,cmsiz        ; length of command so far
  825.     cmp    cx,comand.cmblen    ; buffer filled?
  826.     ja    cmfil7            ; a = yes, declare error
  827.     jb    cmfil6            ; a = not filled yet
  828.     mov    ah,conout        ; notify user that the buffer is full
  829.     mov    dl,bell
  830.     int    dos
  831. cmfil6:    jmp    cmfil1
  832.  
  833. cmfil7:    mov    ah,prstr
  834.     mov    dx,offset cmer09
  835.     int    dos
  836.     jmp    prserr            ; declare parse error
  837. cmfil0    endp
  838.  
  839. ; This routine gets a confirm (CR) and displays any extra non-blank text.
  840. ; errflag non-zero means suppress "extra text" display in this routine
  841. ; because another routine is handling errors.
  842. cmcfrm    proc    far
  843.     mov    comand.cmper,1        ; do not react to \%x substitutions
  844. cmcfr1:    mov    cmsflg,0ffh        ; set space-seen flag (skip spaces)
  845.     call    cmgtch            ; get a char
  846.     push    cmrptr
  847.     pop    temp            ; remember first non-space position
  848.     jc    cmcfr4            ; c = terminator
  849.     dec    temp            ; backup to text char
  850. cmcfr3:    mov    cmsflg,0ffh        ; set space-seen flag (skip spaces)
  851.     call    cmgtch
  852.     jnc    cmcfr3            ; read until terminator
  853. cmcfr4:    cmp    ah,' '
  854.     je    cmcfr3            ; ignore ending on space
  855.     cmp    ah,escape        ; escape?
  856.     jne    cmcfr5            ; ne = no
  857.     call    esceoc            ; do standard end of cmd on escape
  858.     mov    ax,cmrptr
  859.     cmp    ax,temp            ; started text yet?
  860.     je    cmcfr1            ; e = no
  861.     jmp    short cmcfr3        ; try again
  862. cmcfr5: cmp    ah,'?'            ; curious?
  863.         jne    cmcfr6            ; ne = no
  864.     mov    cmhlp,offset cmin00    ; msg Confirm with c/r
  865.     mov    cmsiz,0            ; no keyword
  866.     mov    errflag,0
  867.     jmp    cmkyhlp            ; do help
  868. cmcfr6:    cmp    ah,cr            ; the confirmation char?
  869.     jne    cmcfr3            ; ne = no
  870.     cmp    errflag,0        ; already doing one error?
  871.     jne    cmcfr7            ; ne = yes, skip this one
  872.     mov    cx,cmrptr        ; pointer to terminator
  873.     mov    dx,temp            ; starting place
  874.     sub    cx,dx            ; end minus starting point = length
  875.     jle    cmcfr7            ; le = nothing to display
  876.     push    dx            ; save source pointer
  877.     mov    ah,prstr
  878.     mov    dx,offset cmer07    ; ?Ignoring extras
  879.     int    dos
  880.     pop    dx
  881.     mov    bx,1            ; stdout handle, cx=count, dx=src ptr
  882.     mov    ah,write2        ; allow embedded dollar signs
  883.     int    dos
  884.     mov    ah,prstr
  885.     mov    dx,offset cmer08    ; trailer msg
  886.     int    dos
  887. cmcfr7:    mov    errflag,0
  888.     mov    comand.cmper,0        ; reset to variable recognition
  889.     mov    comand.cmkeep,0
  890.     call    rprompt            ; restore master prompt level
  891.     clc                ; return confirmed
  892.     ret
  893. cmcfrm    endp
  894.  
  895. ;;; Routines to get and edit incoming text.
  896.  
  897. ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
  898. ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
  899. ; then treat '\%' as literal characters. If no matching parameter exists
  900. ; just remove '\%x'. Ditto for \v(variable). Returns carry clear if nothing
  901. ; done, else carry set and new text already placed in user's buffer.
  902. ; Includes \v(variable) and \$(Environment variable) and \m(macro name).
  903. ; Uses depth-first recursion algorithm. All registers preserved.
  904. subst    proc    near
  905.     cmp    comand.cmper,0        ; recognize '\%','\v(','\$(','\m(' ?
  906.     jne    subst2            ; ne = no, treat as literals
  907.     cmp    ah,'\'            ; is it the first char of the pattern?
  908.     jne    subst1            ; ne = no, try next
  909.     mov    subcnt,1        ; say first is matched
  910.     mov    subtype,0
  911.     jmp    short subst2        ; exit successfully
  912. subst1:    cmp    subcnt,1        ; first char matched already?
  913.     ja    subst3            ; a = first two have been matched
  914.     jb    subst2            ; b = none yet
  915.     inc    subcnt            ; assume a match follows
  916.     mov    subtype,ah        ; remember kind of substitution
  917.     or    subtype,20h        ; convert to lower case
  918.     cmp    ah,'%'            ; second match char, same?
  919.     je    subst2            ; e = yes
  920.     cmp    subtype,'v'        ; \v(...)?
  921.     je    subst2            ; e = yes
  922.     cmp    subtype,'$'        ; \$(..)?
  923.     je    subst2
  924.     cmp    subtype,'m'        ; \m(..)?
  925.     je    subst2
  926. subst1a:mov    subcnt,0        ; mismatch, clear match counter
  927.     mov    subtype,0        ; clear substitution kind
  928. subst2:    clc                ; carry clear = no substitution done
  929.     ret
  930. subst3:    cmp    subtype,'v'        ; doing \v(..)?
  931.     je    subst3a            ; e = yes
  932.     cmp    subtype,'$'        ; doing \$(..)?
  933.     je    subst3a            ; e = yes
  934.     cmp    subtype,'m'        ; doing \m(..)?
  935.     jne    subst3b            ; ne = no, do \%<char>
  936. subst3a:cmp    ah,'('            ; have leading parenthesis?
  937.     jne    subst1a            ; ne = no, mismatch, exit
  938.     jmp    subst10            ; process \v(..), \$(..), \m(..)
  939. subst3b:mov    subcnt,0        ; do \%<char>, clear match counter
  940.     cmp    ah,'0'            ; third char is '0' or above?
  941.     jb    subst1a            ; b = out of range, no match
  942.     push    bx            ; save working regs
  943.     push    cx
  944.     push    es
  945.     sub    cmrptr,3        ; reread commands where backslash was
  946.     call    bufreset        ; reset buffer to this point
  947.     push    cmptab            ; save current keyword parsing parms
  948.     push    cmsptr
  949.     push    cmsiz
  950.     mov    bx,cmrptr        ; points at backslash
  951.     mov    cmsptr,bx        ; direct keyword routine to it
  952.     mov    cmsiz,3            ; three bytes (\%x) of user text
  953.     mov    cmptab,offset mcctab     ; use Macro table for new text
  954.     call    getkw            ; get ptr, bx, to matching keyword
  955.     pop    cmsiz            ; restore borrowed keyword parameters
  956.     pop    cmsptr
  957.     pop    cmptab
  958.     jc    substx            ; c = not found, keep after pops
  959.     cmp    taklev,maxtak        ; room in take level?
  960.     jae    subst6            ; ae = no
  961.     mov    cx,[bx]            ; length of found word
  962.     add    cx,2            ; plus count field
  963.     add    bx,cx            ; point to 16 bit value (string ptr)
  964.     mov    es,[bx]            ; point to string structure segment
  965.     xor    bx,bx
  966.     mov    cx,es:[bx]        ; length of string
  967.     add    takadr,size takinfo    ; pointer to new Take structure
  968.     inc    taklev
  969.     mov    bx,takadr        ; pointer to new Take structure
  970.     mov    [bx].takbuf,es        ; segment of Take buffer
  971.     mov    [bx].takcnt,cx        ; number of unread bytes
  972.     mov    [bx].taktyp,0fdh    ; flag as an internal macro
  973.     mov    [bx].takptr,2        ; init pointer to definition itself
  974. substx:    pop    es
  975.     pop    cx
  976.     pop    bx
  977.     stc                ; set carry to say have stored chars
  978.     ret
  979.  
  980. subst6:    mov    ah,prstr
  981.     mov    dx,offset stkmsg    ; out of work space msg
  982.     int    dos
  983.     jmp    prserr            ; and declare parse error
  984.  
  985.                     ; \m(..), \v(..), \$(..)
  986. subst10:push    bx            ; save working regs
  987.     push    cx
  988.     push    es
  989.     push    cmptab            ; save current keyword parsing parms
  990.     push    cmsptr
  991.     push    cmsiz
  992.     push    cmhlp
  993.     push    dx
  994.     mov    subcnt,0        ; clear match counter
  995.     mov    cmhlp,0
  996.     mov    ax,cmrptr
  997.     mov    valtmp,ax        ; remember current read pointer
  998.     mov    cmsptr,ax        ; start of word
  999.     mov    cmptab,offset valtab    ; table of keywords for \v(..)
  1000.     cmp    subtype,'v'        ; \v(..)?
  1001.     je    subst10a        ; e = yes
  1002.     mov    cmptab,offset envtab    ; Environment variable table \$(..)
  1003.     cmp    subtype,'$'        ; \$(..)?
  1004.     je    subst10a        ; e = yes
  1005.     mov    cmptab,offset mcctab    ; main Macro table for \m(..)
  1006. subst10a:mov    cmsflg,0        ; see leading spaces/tabs
  1007.     mov    cmsiz,0            ; word size
  1008. subst11:call    cmgtch            ; read a character into ah
  1009.     jnc    subst13            ; nc = non-terminator
  1010.     cmp    ah,'?'            ; need help?
  1011.     jne    subst11a        ; ne = no
  1012.     jmp    cmkyhlp            ; do help and exit
  1013. subst11a:cmp    ah,escape        ; escape?
  1014.     jne    subst12            ; ne = no
  1015.     mov    bx,cmsptr        ; where word started
  1016.     mov    cmrptr,bx        ; omit word to date
  1017.     mov    cmwptr,bx
  1018.     call    cmkyesc            ; process escape
  1019.     mov    dx,1            ; signal valtoa to add trailing space
  1020.     jnc    subst14            ; nc = success (found the keyword)
  1021.                     ;
  1022. subst12:mov    bx,cmsptr        ; where word started
  1023.     sub    bx,3            ; back over "\v(" pr "\$(" part
  1024.     mov    cmrptr,bx        ; omit "\v(..." or "\$(..." to date
  1025.     mov    cmwptr,bx        ;  and "\m(..." too
  1026.     jmp    repars            ; reparse command without \v(...
  1027.                     ;
  1028. subst13:inc    cmsiz            ; count user chars
  1029.     cmp    ah,')'            ; end bracket?
  1030.     jne    subst11            ; ne = no, keep looking
  1031.     dec    cmsiz            ; omit user's ')' from tests
  1032.     cmp    subtype,'$'        ; \$(..)?
  1033.     je    subst13a        ; e = yes, no keyword in table
  1034.     call    getkw            ; \m(..) and \v(..) test for keyword
  1035.     jc    subst12            ; c = failure
  1036.     jmp    short subst13b        ; success
  1037.  
  1038. subst13a:call    envvar            ; search Environment for the word
  1039.     jc    subst12            ; c = failure
  1040.     mov    bx,offset envtab+1    ; Environment data structure
  1041.  
  1042. subst13b:mov    ax,valtmp        ; where word started
  1043.     mov    cmrptr,ax
  1044.     sub    ax,3            ; backup to "\v(" or "\$("
  1045.     mov    cmrptr,ax        ; write output where backslash was
  1046.     mov    cmwptr,ax
  1047.     mov    cx,[bx]            ; bx = structure pointer, cx=keyw len
  1048.     add    cx,2            ; skip count byte
  1049.     add    bx,cx            ; point at 16 bit value field
  1050.     mov    bx,[bx]            ; get value to bx for valtoa
  1051.     xor    dx,dx            ; signal valtoa to not add trailing sp
  1052. subst14:
  1053.     cmp    taklev,maxtak        ; room in take level?
  1054.     jb    subst15            ; b = yes
  1055.     mov    dx,offset stkmsg    ; out of work space msg
  1056.     mov    ah,prstr        ; display error message
  1057.     int    dos
  1058.     jmp    short subst17
  1059. subst15:push    di
  1060.     call    valtoa            ; make text be an internal macro
  1061.     jc    subst16            ; c = failed
  1062.     add    takadr,size takinfo    ; pointer to new Take structure
  1063.     inc    taklev            ; next Take level
  1064.     push    bx
  1065.     mov    bx,takadr        ; address of take structure
  1066.     mov    ax,ds
  1067.     mov    [bx].takbuf,ax        ; segment of Take buffer
  1068.     mov    [bx].takptr,offset valbuf+2 ; offset of beginning of def text
  1069.     mov    [bx].takcnt,di        ; # of chars in buffer
  1070.     mov    [bx].taktyp,0fdh    ; flag as an internal macro
  1071.     pop    bx
  1072. subst16:pop    di
  1073. subst17:pop    dx
  1074.     pop    cmhlp
  1075.     pop    cmsiz            ; restore borrowed keyword parameters
  1076.     pop    cmsptr
  1077.     pop    cmptab
  1078.     jmp    repars            ; reparse cmd line with new material
  1079. subst    endp
  1080.  
  1081. ; Make an internal macro defined as the text for one of the value variables.
  1082. ; Use incoming DX as trailing space suppression flag, if null.
  1083. valtoa    proc    near
  1084.     push    dx            ; save trailing space flag
  1085.     mov    di,offset valbuf+2    ; start text here
  1086.     mov    word ptr [di],0        ; fill buffer with sweet nothings
  1087.                     ; BX has index of variable
  1088.     cmp    bx,0            ; Environment?
  1089.     jne    valtoa1            ; ne = no
  1090.     mov    cx,envlen        ; string length
  1091.     jcxz    valtoa0            ; z = empty
  1092.     push    es
  1093.     push    ds
  1094.     mov    ax,ds
  1095.     mov    es,ax            ; destination is es:di
  1096.     lds    si,envadr        ; ds:si is source from Environment
  1097.     cld
  1098.     rep    movsb            ; copy string
  1099.     pop    ds            ; recover ds
  1100.     pop    es
  1101. valtoa0:jmp    valtoa20
  1102.     
  1103. valtoa1:cmp    bx,1            ; ARGC?
  1104.     jne    valtoa2            ; ne = no
  1105.     call    wrtargc            ; write argc
  1106.     jmp    valtoa20
  1107. valtoa2:cmp    bx,2            ; COUNT?
  1108.     jne    valtoa3            ; ne = no
  1109.     call    wrtcnt            ; write it
  1110.     jmp    valtoa20
  1111. valtoa3:cmp    bx,3            ; DATE?
  1112.     jne    valtoa4
  1113.     call    wrtdate
  1114.     jmp    valtoa20
  1115. valtoa4:cmp    bx,4            ; ERRORLEVEL?
  1116.     jne    valtoa5            ; ne = no
  1117.     call    wrterr
  1118.     jmp    valtoa20
  1119. valtoa5:cmp    bx,5            ; DIR?
  1120.     jne    valtoa6
  1121.     call    wrtdir
  1122.     jmp    valtoa20
  1123. valtoa6:cmp    bx,6            ; TIME?
  1124.     jne    valtoa7
  1125.     call    wrttime
  1126.     jmp    valtoa20
  1127. valtoa7:cmp    bx,7            ; VERSION?
  1128.     jne    valtoa8            ; ne = no
  1129.     mov    ax,version        ; get version such as 300
  1130.     call    fdec2di            ; convert binary to asciiz
  1131.     mov    word ptr [di],0020h    ; space, null
  1132.     inc    di
  1133.     jmp    valtoa20
  1134. valtoa8:cmp    bx,8            ; PLATFORM?
  1135.     jne    valtoa9            ; ne = no
  1136.     call    wrtplat            ; get machine name, e.g. "IBM-PC"
  1137.     jmp    valtoa20
  1138. valtoa9:cmp    bx,9            ; SYSTEM?
  1139.     jne    valtoa10        ; ne = no
  1140.     call    wrtsystem        ; get "MS-DOS" string
  1141.     jmp    valtoa20
  1142. valtoa10:cmp    bx,10            ; KEYBOARD?
  1143.     jne    valtoa11        ; ne = no
  1144.     call    wrtkbd            ; 88 or 101 value
  1145.     jmp    valtoa20
  1146. valtoa11:cmp    bx,11            ; SPEED?
  1147.     jne    valtoa12        ; ne = no
  1148.     push    di
  1149.     call    fgetbaud        ; read baud rate from hardware
  1150.     pop    di
  1151.     mov    bx,portval
  1152.     mov    ax,[bx].baud
  1153.     cmp    al,byte ptr bdtab    ; index versus number of table entries
  1154.     jb    valtoa11a        ; b = index is in the table
  1155.     mov    si,offset cmunk-2    ; unrecognized value, say "unknown"
  1156.     mov    bx,7            ; length of string
  1157.     jmp    short valtoa11c
  1158. valtoa11a:mov    si,offset bdtab        ; ascii rate table
  1159.     mov    cl,[si]            ; number of entries
  1160.     inc    si            ; point to an entry
  1161. valtoa11b:
  1162.     mov    bx,[si]            ; length of text string
  1163.     cmp    ax,[si+bx+2]        ; our index vs table entry index
  1164.     je    valtoa11c        ; e = match
  1165.     add    si,bx            ; skip text
  1166.     add    si,4            ; skip count and index word
  1167.     loop    valtoa11b        ; look again
  1168.     mov    si,offset cmunk-2    ; unrecognized value, say "unknown"
  1169.     mov    bx,7            ; length of string
  1170. valtoa11c:mov    cx,bx            ; length of string
  1171.     add    si,2            ; point at string
  1172.     rep    movsb            ; copy string
  1173.     jmp    short valtoa20
  1174. valtoa12:cmp    bx,12            ; PROGRAM?
  1175.     jne    valtoa13        ; ne = no
  1176.     call    wrtprog            ; get "MS-DOS_KERMIT" string
  1177.     jmp    short valtoa20
  1178. valtoa13:cmp    bx,13            ; STATUS?
  1179.     jne    valtoa14        ; ne = no
  1180.     call    wrtstat            ; compose status string
  1181.     jmp    short valtoa20
  1182. valtoa14:cmp    bx,14            ; NDATE?
  1183.     jne    valtoa15        ; ne = no
  1184.     call    wrtndate
  1185.     jmp    short valtoa20
  1186. valtoa15:cmp    bx,15            ; LINE, PORT?
  1187.     jne    valtoa16        ; ne = no
  1188.     call    wrtport
  1189.     jmp    short valtoa20
  1190. valtoa16:cmp    bx,16            ; TERMINAL?
  1191.     jne    valtoa19        ; ne = no
  1192.     call    wrtterm
  1193.     jmp    short valtoa20
  1194. valtoa19:pop    dx            ; assume an internal Macro
  1195.     add    takadr,size takinfo    ; pointer to new Take structure
  1196.     inc    taklev            ; next Take level
  1197.     push    bx
  1198.     mov    ax,bx            ; save seg of string here
  1199.     mov    bx,takadr        ; address of take structure
  1200.     mov    [bx].takbuf,ax        ; segment of Take buffer
  1201.     mov    [bx].takptr,2         ; offset of beginning of def text
  1202.     push    es
  1203.     mov    es,ax            ; segment of string definition
  1204.     mov    di,es:[0]        ; get length of string text (count)
  1205.     pop    es
  1206.     mov    [bx].takcnt,di        ; # of chars in buffer
  1207.     mov    [bx].taktyp,0fdh    ; flag as an internal macro
  1208.     pop    bx
  1209.     jmp    short valtoax        ; exit early with CARRY SET(!)
  1210.  
  1211. valtoa20:pop    dx            ; trailing space flag
  1212.     or    dx,dx            ; leave the spaces?
  1213.     jnz    valtoa21        ; nz = yes
  1214.     cmp    word ptr [di-1],0020h    ; trailing space?
  1215.     jne    valtoa21        ; ne = no
  1216.     dec    di            ; remove space
  1217. valtoa21:sub    di,offset valbuf+2    ; di = length of the buffer contents
  1218.     clc
  1219.     ret
  1220. valtoax:stc
  1221.     ret
  1222. valtoa    endp
  1223.  
  1224. ; Far callable version
  1225. fvaltoa    proc    far
  1226.     call    valtoa
  1227.     ret
  1228. fvaltoa    endp
  1229. ; Set envadr to the string following the <variable=> keyword in the
  1230. ; Environment and set envlen to its length after removing leading and
  1231. ; trailing whitespace.
  1232. ; <variable> starts at ds:<valtmp>, of length cmsiz-1, and can be mixed case.
  1233. ; Return carry set if can't find the <variable=> line in the Environment.
  1234. envvar    proc    near
  1235.     push    es
  1236.     mov    bx,valtmp        ; start of variable name
  1237.     mov    cx,cmsiz        ; length of variable name, w/o ')'
  1238.     or    cx,cx            ; empty?
  1239.     jle    envvar3            ; le = nothing to look for, fail
  1240.     push    bx
  1241.     push    cx
  1242. envvar1:mov    al,byte ptr [bx]    ; scan variable name in our buffer
  1243.     cmp    al,'a'            ; lower case
  1244.     jb    envvar2            ; b = no
  1245.     cmp    al,'z'            ; still in lower case range?
  1246.     ja    envvar2            ; a = no
  1247.     and    al,not 20h        ; convert to DOS's upper case
  1248.     mov    byte ptr [bx],al    ; replace char
  1249. envvar2:inc    bx
  1250.     loop    envvar1
  1251.     pop    cx
  1252.     pop    bx            ; find "<variable>=" in Environment
  1253.     call    fgetenv            ; dx = offset in Environment of "="
  1254.     jnc    envvar4            ; nc = success
  1255. envvar3:pop    es            ; no such variable
  1256.     stc                ; c = failure
  1257.     ret
  1258. ; dx has offset in Environment of char "="
  1259. ; ds:valtmp is start of variable name, cmsiz is length + 1 of the name.
  1260. ; Return seg:offset and length variables so we can copy from there in valtoa
  1261. envvar4:push    di
  1262.     push    si
  1263.     xor    ax,ax
  1264.     mov    word ptr envadr,ax    ; offset in env of variable's string
  1265.     mov    word ptr envadr+2,ax    ; seg of same
  1266.     mov    envlen,ax        ; length of string
  1267.     mov    es,psp            ; our Prog Seg Prefix segment
  1268.     mov    ax,es:word ptr[env]    ; pick up Environment address
  1269.     mov    es,ax            ; set es: to Environment segment
  1270.     mov    di,dx            ; line scan pointer
  1271.     cmp    byte ptr es:[di],'='    ; did we stop on this?
  1272.     jne    envvar5            ; ne = no
  1273.     inc    di            ; skip the "=" char
  1274. envvar5:mov    al,es:[di]        ; scan over leading white space
  1275.     inc    di
  1276.     or    al,al            ; end of line terminator?
  1277.     jz    envvarf            ; z = yes, fail
  1278.     cmp    al,TAB            ; HT?
  1279.     jne    envvar6            ; ne = no
  1280.     mov    al,' '            ; HT becomes a space
  1281. envvar6:cmp    al,' '            ; white space?
  1282.     je    envvar5            ; scan off white space
  1283.     dec    di            ; backup to non-white char
  1284.     mov    word ptr envadr,di    ; offset of string in Environment
  1285.     mov    word ptr envadr+2,es    ; seg of string in Environment
  1286.     mov    si,di            ; remember starting offset here
  1287.                     ; remove trailing spaces from string
  1288.     xor    al,al            ; a null
  1289.     mov    cx,127            ; max length to search
  1290.     cld
  1291.     repne    scasb            ; skip over non-nulls
  1292.     dec    di            ; backup to null
  1293.     dec    di            ; backup to last string char
  1294.     mov    cx,di            ; ending offset
  1295.     inc    cx            ; count the char
  1296.     sub    cx,si            ; minus starting offset yields length
  1297.     jcxz    envvar9            ; z = empty string
  1298. envvar7:mov    al,es:[di]        ; last char
  1299.     dec    di            ; backup one char
  1300.     cmp    al,' '            ; space?
  1301.     je    envvar8            ; e = yes
  1302.     cmp    al,TAB            ; HT?
  1303.     jne    envvar9            ; ne = no, end of white space
  1304. envvar8:loop    envvar7            ; keep looking
  1305. envvar9:mov    envlen,cx        ; store the length
  1306.     clc                ; say success
  1307.     jmp    short envvarx
  1308. envvarf:stc                ; say failure
  1309. envvarx:pop    si
  1310.     pop    di
  1311.     pop    es
  1312.     ret
  1313. envvar    endp
  1314.  
  1315. ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
  1316. ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
  1317. ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
  1318. ; and indirect stdin files (\; means literal semicolon). Return char in AL.
  1319. CMGETC    proc    near            ; Basic raw character reader
  1320. cmget01:cmp    prevch,0        ; left over char yet to be exported?
  1321.     je    cmget02            ; e = no
  1322.     mov    al,prevch        ; get old char
  1323.     mov    prevch,0        ; clear storage
  1324.     jmp    cmget6            ; analyze it
  1325. cmget02:cmp    taklev,0        ; in a Take file?
  1326.     jne    cmget1            ; ne = yes, do Take reader section
  1327.     call    fisdev            ; is stdin a device or a file?
  1328.     jnc    cmget20            ; nc = file (redirection of stdin)
  1329.     jmp    cmget10            ; c = device, do separately
  1330.  
  1331. cmget20:call    fiseof            ; see if file is empty
  1332.     jc    cmget21            ; c = EOF on disk file
  1333.     mov    ah,coninq        ; read the char from file, not device
  1334.     int    dos
  1335.     cmp    al,cr            ; is it a cr?
  1336.     je    cmget01            ; yes, ignore and read next char
  1337.     cmp    al,ctlz            ; Control-Z?
  1338.     je    cmget21            ; e = yes, same as EOF here
  1339.     cmp    al,lf            ; LF's end lines from disk files
  1340.     jne    cmget8            ; ne = not LF, pass along as is
  1341.     mov    al,cr            ; make LF a CR for this parser
  1342.     call    fiseof            ; see if this is the last char in file
  1343.     jnc    cmget8            ; nc = not EOF, process new CR
  1344. cmget21:mov    flags.extflg,1        ; EOF on disk file, set exit flag
  1345.     jmp    short cmget6        ; do echoing and return
  1346.  
  1347. cmget1:    push    bx            ; read from Take file
  1348.     mov    bx,takadr        ; offset of this Take structure
  1349.     cmp    [bx].takcnt,0        ; bytes remaining in Take buffer
  1350.     jne    cmget4            ; ne = not empty
  1351.     cmp    [bx].taktyp,0feh    ; type of Take (file?)
  1352.     jne    cmget3            ; ne = no (macro)
  1353.     call    ftakrd            ; read another buffer
  1354.     cmp    [bx].takcnt,0        ; anything in the buffer?
  1355.     jne    cmget4            ; ne = yes
  1356. cmget3:    pop    bx            ; clear stack
  1357.     jmp    short cmget5        ; close take file
  1358.  
  1359. cmget4:    push    si
  1360.     push    es
  1361.     mov    es,[bx].takbuf        ; segment of Take buffer
  1362.     mov    si,[bx].takptr        ; current offset in Take buffer
  1363.     mov    al,es:[si]        ; read a char from Take buffer
  1364.     inc    si
  1365.     mov    [bx].takptr,si        ; move buffer pointer
  1366.     dec    [bx].takcnt        ; decrease number of bytes remaining
  1367.     pop    es
  1368.     pop    si
  1369.     pop    bx
  1370.     cmp    al,ctlz            ; Control-Z?
  1371.     jne    cmget6            ; ne = no
  1372. cmget5:    push    bx
  1373.     mov    bx,takadr        ; offset of this Take structure
  1374.     mov    ah,[bx].taktyp        ; save kind of Take/macro
  1375.     pop    bx
  1376.     cmp    ah,0fdh            ; internal macro?
  1377.     je    cmget5b            ; e = yes, close but no auto-CR
  1378.     cmp    comand.cmkeep,0        ; keep Take/macro open after eof?
  1379.     jne    cmget5a            ; ne = yes
  1380. cmget5b:push    ax
  1381.     call    ftakclos        ; close take file
  1382.     pop    ax
  1383.     cmp    ah,0fdh            ; internal macro?
  1384.     jne    cmget5a            ; ne = no, file or regular macro
  1385.     jmp    cmgetc            ; internal macros have no auto CR
  1386. cmget5a:mov    al,cr            ; report cr as last char
  1387.     mov    noparse,0        ; and say end of comment
  1388.                     ; start common code
  1389. cmget6:
  1390.     cmp    al,lf            ; line feed?
  1391.     jne    cmget8            ; ne = no
  1392.     jmp    cmget01            ; yes, ignore and read another char
  1393.                     ; handle comments (echo but not parse)
  1394. cmget8:    cmp    noparse,0        ; parsing?
  1395.     jne    cmget9            ; ne = yes, do echo and no parse
  1396.     cmp    prevch,0        ; have previous char to analyze?
  1397.     jne    cmget8c            ; ne = yes
  1398.     cmp    taklev,0        ; in a Take file or Macro?
  1399.     je    cmget8e            ; e = no, use ";" as a literal
  1400.     push    bx            ; treat ";" as literal in int macros
  1401.     mov    bx,takadr        ; offset of this Take structure
  1402.     cmp    [bx].taktyp,0fdh    ; internal macro?
  1403.     pop    bx
  1404.     je    cmget8e            ; e = yes, semicolons are literals
  1405.     cmp    al,'\'            ; start of '\;'?
  1406.     jne    cmget8a            ; ne = no
  1407.     mov    prevch,al        ; yes, maybe. save '\' til later
  1408.     jmp    cmget02            ; read next char
  1409. cmget8a:cmp    al,';'            ; possible start of comment?
  1410.     jne    cmget8e            ; no, export al
  1411.     mov    al,' '            ; replace ';' with space for comment
  1412.     jmp    short cmget9        ; go start a comment
  1413.  
  1414. cmget8c:cmp    al,';'            ; end of '\;'?
  1415.     je    cmget8d            ; e = yes, omit leading backslash
  1416.     xchg    prevch,al        ; no, save new, recover old '\'
  1417.     jmp    short cmget8e        ; export '\'
  1418. cmget8d:mov    prevch,0        ; clear old '\'
  1419. cmget8e:jmp    short cmget12        ; do parsing
  1420.  
  1421.                     ; echo comment
  1422. cmget9:    cmp    flags.takflg,0        ; echoing take files?
  1423.     je    cmget9a            ; e = no
  1424.     push    ax
  1425.     push    dx
  1426.     mov    ah,conout        ; echo current char
  1427.     mov    dl,al
  1428.     int    dos
  1429.     pop    dx
  1430.     pop    ax
  1431. cmget9a:mov    noparse,0        ; cr ends comment
  1432.     cmp    al,cr            ; end of comment?
  1433.     je    cmget13            ; e = yes, export cr
  1434.     mov    noparse,1        ; still in comment
  1435.     jmp    cmget01            ; read more chars
  1436.  
  1437.                     ; read from tty device
  1438. cmget10:mov    ah,coninq        ; Get a char from device, not file
  1439.     int    dos            ;  with no echoing
  1440.     or    al,al
  1441.     jnz    cmget12            ; ignore null bytes of special keys
  1442.     int    dos            ; read and discard scan code byte
  1443.     jmp    short cmget10        ; try again
  1444.  
  1445. cmget12:cmp    al,'C'and 1Fh        ; Control-C?
  1446.     je    cmget14            ; e = yes
  1447.     cmp    al,TAB            ; tab is replaced by space
  1448.     jne    cmget13            ; ne = not tab
  1449.     mov    al,' '
  1450.     ret
  1451. cmget13:cmp    al,LF            ; LF becomes CR interactively
  1452.     jne    cmget13a
  1453.     mov    al,CR
  1454. cmget13a:ret                ; normal exit, char is in AL
  1455.  
  1456. cmget14:mov    ah,prstr        ; Control-C handler
  1457.     push    dx
  1458.     mov    dx,offset ctcmsg    ; show Control-C
  1459.     int    dos
  1460.     pop    dx
  1461.     mov    prevch,0
  1462.     mov    flags.cxzflg,'C'    ; tell others the news
  1463.     jmp    dword ptr pcmexit    ; fail immediately via longjmp
  1464. cmgetc    endp
  1465.  
  1466. ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
  1467. ; cmbuf. Set read pointer cmrptr to next free buffer byte if
  1468. ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
  1469. ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
  1470. ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
  1471. ; Return char in AH.
  1472. CMINBF    proc    near            ; Buffer reader, final editor
  1473.     cmp    cmwptr,offset cmdbuf+size cmdbuf-3 ; max buffer size - 3
  1474.     jb    cminb1            ; b = not full for writing
  1475.     mov    ah,conout        ; almost full, notify user
  1476.     push    dx
  1477.     mov    dl,bell
  1478.     int    dos
  1479.     pop    dx
  1480.     cmp    cmrptr,offset cmdbuf+size cmdbuf ; reading beyond buffer?
  1481.     jb    cminb1            ; b = no
  1482.     mov    ah,prstr
  1483.     mov    dx,offset cmer09    ; command too long
  1484.     int    dos
  1485.     jmp    prserr            ; overflow = parse error
  1486.  
  1487. cminb1:    push    bx
  1488.     mov    bx,cmrptr        ; read pointer
  1489.     mov    ah,[bx]            ; get current command char while here
  1490.     cmp    bx,cmwptr        ; do we need to read more?
  1491.     pop    bx            ; no if cmrptr < cmwptr
  1492.     jb    cminb2            ; b: cmrptr < cmwptr (have extra here)
  1493.     call    cmgetc            ; no readahead, read another into al
  1494.     mov    ah,al            ; keep char in 'ah'
  1495.     push    bx
  1496.     mov    bx,cmwptr        ; get the pointer into the buffer
  1497.     mov    [bx],ah            ; put it in the buffer
  1498.     inc    bx
  1499.     mov    cmwptr,bx        ; inc write pointer
  1500.     pop    bx
  1501.     jmp    short cminb1        ; call cmgetc until cmwptr >= cmrptr
  1502.                     ; Char to be delivered is in ah
  1503. cminb2:    cmp    ah,'W' and 1fh        ; is it a ^W?
  1504.     jne    cminb3
  1505.     call    cntrlw            ; kill the previous word
  1506.     jnc    cminbf            ; nc = no change, get another char
  1507.     jmp    repars            ; need a new command scan (cleans stk)
  1508.  
  1509. cminb3:    cmp    ah,'U' and 1fh        ; is it a ^U?
  1510.     jne    cminb3a            ; ne = no
  1511.     mov    cmwptr,offset cmdbuf    ; reset buffer write pointer
  1512.     jmp    repars            ; go start over (cleans stack)
  1513.                     ; BS and DEL
  1514. cminb3a:cmp    ah,DEL            ; delete code?
  1515.     je    cminb3b            ; e = yes
  1516.     cmp    ah,BS            ; Backspace (a delete operator)?
  1517.     jne    cminb4            ; ne = no
  1518. cminb3b:call    bufdel            ; delete char from buffer
  1519.     jc    cminb3c            ; c = did erasure
  1520.     jmp    cminbf            ; no erasure, ignore BS, get more
  1521. cminb3c:jmp    repars            ; could have deleted previous token
  1522.  
  1523. cminb4:    push    bx            ; look for hyphen or \hyphen
  1524.     cmp    ah,cr            ; check for hyphen line continuation
  1525.     jne    cminb4b            ; ne = not end of line
  1526.     mov    bx,cmwptr        ; get the pointer into the buffer
  1527.     cmp    bx,offset cmdbuf-2    ; do we have a previous char?
  1528.     jb    cminb4b            ; b = no
  1529.     cmp    byte ptr[bx-2],'-'    ; previous char was a hyphen?
  1530.     jne    cminb4b            ; ne = no
  1531.     pop    bx
  1532.     call    bufdel            ; delete the hyphen
  1533.     jmp    repars
  1534. cminb4b:pop    bx
  1535.                     ; Echoing done here
  1536.     cmp    comand.cmquiet,0    ; quiet mode?
  1537.     jne    cminb5            ; yes, skip echoing
  1538.     cmp    taklev,0        ; in a take file?
  1539.     je    cminb4a            ; e = no
  1540.     cmp    flags.takflg,0        ; echo take file?
  1541.     je    cminb5            ; e = no
  1542. cminb4a:push    ax            ; save the char
  1543.     cmp    ah,' '            ; printable?
  1544.     jae    cminb4c            ; yes, no translation needed
  1545.     cmp    ah,cr            ; this is printable
  1546.     je    cminb4c
  1547.     cmp    ah,lf
  1548.     je    cminb4c
  1549.     cmp    ah,escape        ; escape?
  1550.     je    cminb4d            ; do not echo this character
  1551.     push    ax            ; show controls as caret char
  1552.     push    dx
  1553.     mov    dl,5eh            ; caret
  1554.     mov    ah,conout
  1555.     int    dos
  1556.     pop    dx
  1557.     pop    ax
  1558.     add    ah,'A'-1        ; make control code printable
  1559. cminb4c:push    dx
  1560.     mov    dl,ah
  1561.     mov    ah,conout
  1562.     int    dos            ; echo it ourselves
  1563.     pop    dx
  1564. cminb4d:pop    ax            ; and return char in ah
  1565.  
  1566. cminb5:    cmp    ah,cr            ; carriage return?
  1567.     je    cminb6
  1568.     cmp    ah,lf            ; line feed?
  1569.     je    cminb6
  1570.     cmp    ah,ff            ; formfeed?
  1571.     jne    cminb7            ; none of the above, report bare char
  1572.     call    fcmblnk            ; FF: clear the screen and
  1573.     push    bx
  1574.     push    cx
  1575.     push    dx
  1576.     call    flocate            ; Home the cursor
  1577.     mov    bx,cmwptr        ; make the FF parse like a cr
  1578.     mov    byte ptr [bx-1],cr    ; pretend a carriage return were typed
  1579.     pop    dx
  1580.     pop    cx
  1581.     pop    bx
  1582. cminb6: cmp    cmwptr,offset cmdbuf    ; parsed any chars yet?
  1583.     jne    cminb7            ; ne = yes
  1584.     cmp    comand.cmcr,0        ; bare cr's allowed?
  1585.     jne    cminb7            ; ne = yes
  1586.     jmp    prserr            ; If not, just start over
  1587. cminb7:    clc
  1588.     ret
  1589. cminbf    endp
  1590.  
  1591. ; Read chars from cminbf. Cmrptr points to next char to be read.
  1592. ; Compresses repeated spaces if cmsflg is non-zero. Exit with cmrptr pointing
  1593. ; at a terminator or otherwise at next free slot.
  1594. ; Non-space then space acts as a terminator but cmrptr is incremented.
  1595. ; Substitution variables, '\%x', are detected and expanded. Return char in AH.
  1596.  
  1597. CMGTCH    proc    near            ; return char in AH, from rescan buf
  1598.     call    cminbf            ; get char from buffer or user
  1599.     push    bx
  1600.     mov    bx,cmrptr        ; get read pointer into the buffer
  1601.     mov    ah,[bx]            ; read the next char
  1602.     inc    bx
  1603.     mov    cmrptr,bx        ; where to read next time
  1604.     pop    bx
  1605.     call    subst            ; examine for text substitution
  1606.     jnc    cmgtc1            ; nc = no substitutions done
  1607.     jmp    repars            ; reparse line with new material
  1608.  
  1609. cmgtc1:    cmp    ah,' '            ; space?
  1610.     jne    cmgtc3            ; ne = no
  1611.     cmp    bracecnt,0        ; are we within braces?
  1612.     jne    cmgtc3            ; ne = yes, treat space as literal
  1613.     cmp    cmsflg,0        ; space flag, was last char a space?
  1614.     jne    cmgtch            ; ne = yes, get another char
  1615.     mov    cmsflg,0FFH        ; Set the space(s)-seen flag
  1616.     mov    ah,' '            ; character for caller
  1617.     stc                ; set carry for terminator
  1618.     ret                ; return space as a terminator
  1619. cmgtc3: mov    cmsflg,0        ; clear the space-seen flag
  1620.     cmp    ah,braceop        ; opening brace?
  1621.     jne    cmgtc3b            ; ne = no
  1622.     inc    bracecnt        ; count it
  1623.     jmp    short cmgtc3c
  1624. cmgtc3b:cmp    ah,bracecl        ; closing brace?
  1625.     jne    cmgtc3c            ; ne = no
  1626.     sub    bracecnt,1        ; count down and get a sign bit
  1627.     jns    cmgtc3c            ; ns = no underflow
  1628.     mov    bracecnt,0        ; catch underflows
  1629. cmgtc3c:cmp    ah,escape        ; terminators remain in buffer but
  1630.     je    cmgtc4            ;  are ready to be overwritten
  1631.     cmp    ah,'?'            ; is the user curious?
  1632.     jne    cmgtc3a            ; ne = no
  1633.     cmp    taklev,0        ; in a Take file?
  1634.     jne    cmgtc3d            ; ne = yes, make query ordinary char
  1635.     je    cmgtc4
  1636. cmgtc3a:cmp    ah,cr
  1637.     je    cmgtc4
  1638.     cmp    ah,lf
  1639.     je    cmgtc4
  1640.     cmp    ah,ff
  1641.     je    cmgtc4
  1642. cmgtc3d:clc                ; carry clear for non-terminator
  1643.     ret
  1644. cmgtc4: dec    cmrptr            ; point at terminating char
  1645.     stc                ; set carry to say it is a terminator
  1646.     ret
  1647. cmgtch    endp
  1648.  
  1649. ; Reset comand.cmdbuf write pointer (cmwptr) to where the read pointer
  1650. ; (cmrptr) is now. Discards material not yet read.
  1651. bufreset proc    near
  1652.     push    cmrptr            ; where next visible char is read
  1653.     push    ax            ; count removed curly braces
  1654.     push    si
  1655.     mov    si,cmrptr        ; where to look
  1656.     mov    cx,cmwptr        ; last place being removed
  1657.     sub    cx,si            ; length to examine
  1658.     cld
  1659. bufres1:lodsb
  1660.     cmp    al,braceop        ; opening brace, counted already?
  1661.     jne    bufres2            ; ne = no
  1662.     dec    bracecnt        ; uncount it
  1663.     jmp    short bufres3
  1664. bufres2:cmp    al,bracecl        ; closing brace, counted already?
  1665.     jne    bufres3            ; jne = no
  1666.     inc    bracecnt        ; uncount it
  1667. bufres3:loop    bufres1
  1668.     cmp    bracecnt,0        ; negative?
  1669.     jge    bufres4            ; ge = no
  1670.     mov    bracecnt,0
  1671. bufres4:pop    si
  1672.     pop    ax
  1673.     pop    cmwptr            ; where new char goes in buffer
  1674.     ret
  1675. bufreset endp
  1676.  
  1677. ; Delete character from screen and adjust buffer. Returns carry clear if
  1678. ; no erasure, carry set otherwise.
  1679. bufdel    proc    near
  1680.     push    ax
  1681.     push    si
  1682.     mov    si,cmrptr
  1683.     mov    al,[si]
  1684.     cmp    al,braceop        ; opening brace, counted already?
  1685.     jne    bufdel1            ; ne = no
  1686.     dec    bracecnt        ; uncount it
  1687.     jmp    short bufdel2
  1688. bufdel1:cmp    al,bracecl        ; closing brace?
  1689.     jne    bufdel2            ; ne = no
  1690.     inc    bracecnt        ; uncount it
  1691. bufdel2:cmp    bracecnt,0        ; negative?
  1692.     jge    bufdel3            ; ge = no
  1693.     mov    bracecnt,0
  1694. bufdel3:pop    si
  1695.     pop    ax
  1696.     dec    cmrptr            ; remove previous char from buffer
  1697.     cmp    cmrptr,offset cmdbuf    ; back too far?
  1698.     jae    bufde2            ; ae = no, material can be erased
  1699.     mov    cmrptr,offset cmdbuf    ; set to start of buffer
  1700.     call    bufreset        ; reset buffer
  1701.     mov    bracecnt,0        ; ensure this is now cleared
  1702.     clc                ; say no erasure
  1703.     ret
  1704. bufde2:    call    bufreset        ; reset buffer
  1705.     stc                ; say did erasure
  1706.     ret
  1707. bufdel    endp
  1708.  
  1709. ; Come here is user types ^W when during input. Remove word from buffer.
  1710. cntrlw    proc    near
  1711.     push    ax
  1712.     push    cx
  1713.     push    dx
  1714.     call    bufreset        ; truncate buffer at cmrptr
  1715.     mov    cx,cmrptr        ; read pointer
  1716.     sub    cx,offset cmdbuf    ; compute chars in buffer
  1717.     clc                ; say have not yet modified line
  1718.     jcxz    ctlw2            ; z = nothing to do, exit no-carry
  1719.     push    es
  1720.     std                ; scan backward
  1721.     mov    ax,ds
  1722.     mov    es,ax            ; point to the data are
  1723.     mov    di,cmwptr        ; looking from here
  1724.     dec    di
  1725.     mov    al,' '
  1726.     repe    scasb            ; look for non-space
  1727.     je    ctlw1            ; all spaces, nothing to do
  1728.     inc    di            ; move back to non-space
  1729.     inc    cx
  1730.     repne    scasb            ; look for a space
  1731.     jne    ctlw1            ; no space, leave ptrs alone
  1732.     inc    di
  1733.     inc    cx            ; skip back over space
  1734. ctlw1:    inc    di
  1735.     pop    es
  1736.     cld                ; reset    direction flag
  1737.     mov    cmwptr,di        ; update pointer
  1738.     stc                ; set carry to say modified line
  1739. ctlw2:    pop    dx
  1740.     pop    cx
  1741.     pop    ax
  1742.     ret
  1743. cntrlw    endp
  1744.  
  1745. ; Jump to REPARS to do a rescan of the existing buffer.
  1746. ; Jump to PRSERR on a parsing error (quits command, clears old read material)
  1747.  
  1748. PRSERR    PROC NEAR
  1749.     mov    cmwptr,offset cmdbuf    ; initialize write pointer
  1750.     mov    ah,prstr
  1751.     mov    dx,offset crlf        ; leave old line, start a new one
  1752.     int    dos
  1753.     call    rprompt            ; restore master prompt level
  1754.                     ; reparse current line
  1755. REPARS:    mov    cmrptr,offset cmdbuf    ; reinit read pointer
  1756.     mov    comand.cmper,0        ; reset to variable recognition
  1757.     mov    cmsflg,0ffh        ; strip leading spaces
  1758.     mov    subcnt,0        ; clear substitution state variables
  1759.     mov    subtype,0
  1760.     mov    bracecnt,0
  1761.     cmp    taklev,0        ; in Take cmd?
  1762.     je    prser2            ; e = no
  1763.     cmp    flags.takflg,0        ; echo contents of Take file?
  1764.     je    prser3            ; e = no
  1765. prser2:    call    fctlu            ; clear display's line, reuse it
  1766.     mov    dx,comand.cmprmp    ; display the asciiz prompt
  1767.     call    fprtasz
  1768. prser3:    mov    bx,0ffffh        ; returned keyword value
  1769.     mov    sp,comand.cmostp    ; set new sp to old one
  1770.     jmp    dword ptr comand.cmrprs    ; jump to just before the prompt call
  1771. PRSERR    ENDP
  1772.  
  1773. ; Restore prompt material to that of the master prompt. This removes settings
  1774. ; of local PROMPT calls so we can reprompt at the main Kermit level.
  1775. RPROMPT    proc    near
  1776.     push    ax
  1777.     mov    ax,mcmprmp        ; address of prompt string
  1778.     or    ax,ax            ; any address given yet?
  1779.     jz    rprompt1        ; z = none, not inited yet
  1780.     mov    comand.cmprmp,ax    ; set current address ptr
  1781.     mov    ax,word ptr mcmrprs    ; offset of reparse address
  1782.     mov    word ptr comand.cmrprs,ax
  1783.     mov    ax,word ptr mcmrprs+2    ; segment of reparse address
  1784.     mov    word ptr comand.cmrprs+2,ax
  1785.     mov    ax,mcmostp        ; stack ptr at reparse time
  1786.     mov    comand.cmostp,ax
  1787. rprompt1:pop    ax
  1788.     ret
  1789. RPROMPT    endp
  1790.  
  1791.  
  1792.  
  1793. ; write \v(ARGC) contents to ds:di
  1794. wrtargc    proc    near
  1795.     xor    ax,ax
  1796.     cmp    taklev,0        ; in a Take/Macro?
  1797.     je    wrtarg1            ; e = no
  1798.     mov    bx,takadr        ; current Take structure
  1799.     mov    ax,[bx].takargc        ; get ARGC
  1800. wrtarg1:call    fdec2di            ; write as ascii
  1801.     mov    word ptr [di],0020h    ; space and null terminator
  1802.     inc    di
  1803.     ret
  1804. wrtargc    endp
  1805.  
  1806. ; write \v(COUNT) text to ds:di
  1807. wrtcnt    proc    near
  1808.     xor    ax,ax
  1809.     cmp    taklev,0        ; in a Take/Macro?
  1810.     je    wrtcnt1            ; e = no
  1811.     mov    bx,takadr        ; current Take structure
  1812.     mov    ax,[bx].takctr        ; get COUNT
  1813. wrtcnt1:call    fdec2di            ; write as ascii
  1814.     mov    word ptr [di],0020h    ; space and null terminator
  1815.     inc    di
  1816.     ret
  1817. wrtcnt    endp
  1818.  
  1819. ; write \v(DATE) text to ds:di
  1820. wrtdate    proc    near
  1821.     push    cx
  1822.     push    dx
  1823.     mov    ah,getdate        ; DOS date (cx= yyyy, dh= mm, dl= dd)
  1824.     int    dos
  1825.     xor    ah,ah
  1826.     cmp    tdfmt,0            ; USA standard mm/dd/yyyy?
  1827.     jne    wrtdat1            ; ne = no
  1828.     mov    al,dh            ; month
  1829.     call    wrtdat5            ; output
  1830.     mov    byte ptr [di],'/'    ; separate
  1831.     inc    di
  1832.     xor    ah,ah
  1833.     mov    al,dl            ; day
  1834.     call    wrtdat5
  1835.     mov    byte ptr [di],'/'
  1836.     inc    di
  1837.     mov    ax,cx
  1838.     jmp    short wrtdat3
  1839.  
  1840. wrtdat1:cmp    tdfmt,1            ; European standard dd/mm/yyyy?
  1841.     jne    wrtdat2            ; ne = no
  1842.     xor    ah,ah
  1843.     mov    al,dl            ; day
  1844.     call    wrtdat5
  1845.     mov    byte ptr [di],'/'
  1846.     inc    di
  1847.     xor    ah,ah
  1848.     mov    al,dh            ; month
  1849.     call    wrtdat5
  1850.     mov    byte ptr [di],'/'
  1851.     inc    di
  1852.     mov    ax,cx
  1853.     jmp    short wrtdat3
  1854.  
  1855. wrtdat2:mov    ax,cx            ; Japan yyyy:mm:dd,   year
  1856.     call    wrtdat5
  1857.     mov    byte ptr [di],':'
  1858.     inc    di
  1859.     xor    ah,ah
  1860.     mov    al,dh            ; month
  1861.     call    wrtdat5
  1862.     mov    byte ptr [di],':'
  1863.     inc    di
  1864.     xor    ah,ah
  1865.     mov    al,dl            ; day
  1866. wrtdat3:call    wrtdat5
  1867.     mov    word ptr [di],0020h    ; space and null terminator
  1868.     inc    di
  1869.     pop    dx
  1870.     pop    cx
  1871.     ret
  1872.     ret
  1873.  
  1874. wrtdat5:cmp    ax,10            ; leading tens digit present?
  1875.     jae    wrtdat6            ; ae = yes
  1876.     mov    byte ptr [di],'0'    ; insert leading 0
  1877.     inc    di
  1878. wrtdat6:call    fdec2di            ; write decimal asciiz to buffer
  1879.     ret
  1880.  
  1881. wrtdate    endp
  1882.  
  1883. ; write \v(ERRORLEVEL) text to ds:di
  1884. wrterr    proc    near
  1885.     mov    al,errlev        ; current Errorlevel
  1886.     xor    ah,ah
  1887.     call    fdec2di            ; write as ascii
  1888.     mov    word ptr [di],0020h    ; space and null terminator
  1889.     inc    di
  1890.     ret
  1891. wrterr    endp
  1892.  
  1893. ; write \v(KEYBOARD) text to ds:di
  1894. wrtkbd    proc    near
  1895.     mov    ax,keyboard        ; 88 or 101 keyboard keys
  1896.     call    fdec2di            ; write as ascii
  1897.     mov    word ptr [di],0020h    ; space and null terminator
  1898.     inc    di
  1899.     ret
  1900. wrtkbd    endp
  1901.  
  1902. ; write \v(NDATE) text to ds:di
  1903. ; where NDATE is YYYYMMDD
  1904. wrtndate proc    near
  1905.     mov    ah,getdate        ; DOS date (cx= yyyy, dh= mm, dl= dd)
  1906.     int    dos
  1907.     push    dx            ; save dx
  1908.     mov    ax,cx            ; year
  1909.     call    fdec2di            ; convert it
  1910.     pop    dx            ; get mm:dd
  1911.     push    dx
  1912.     mov    al,dh            ; months are next
  1913.     xor    ah,ah
  1914.     cmp    al,10            ; less than 10?
  1915.     ja    wrtndat1        ; a = no
  1916.     mov    byte ptr [di],'0'    ; leading 0
  1917.     inc    di
  1918. wrtndat1:call    fdec2di
  1919.     pop    dx
  1920.     mov    al,dl            ; get days
  1921.     xor    ah,ah
  1922.     cmp    al,10            ; less than 10?
  1923.     ja    wrtndat2        ; a = no
  1924.     mov    byte ptr [di],'0'    ; leading 0
  1925.     inc    di
  1926. wrtndat2:call    fdec2di
  1927.     mov    word ptr [di],0020h    ; space and null terminator
  1928.     inc    di
  1929.     ret
  1930. wrtndate endp
  1931.  
  1932. ; write \v(DIRECTORY) text to ds:di
  1933. wrtdir    proc    near
  1934.     push    si
  1935.     mov    ah,gcurdsk        ; get current disk
  1936.     int    dos
  1937.     add    al,'A'            ; make al = 0 == 'A'
  1938.     mov    [di],al
  1939.     mov    word ptr [di+1],'\:'
  1940.     mov    si,di            ; work buffer
  1941.     add    si,3            ; end with a colon and backslash
  1942.     mov    ah,gcd            ; get current directory
  1943.     xor    dl,dl            ; use current drive
  1944.     int    dos            ; get ds:si = asciiz path (no drive)
  1945.     mov    dx,di
  1946.     call    fstrlen
  1947.     add    di,cx
  1948.     cmp    cx,3            ; directory added?
  1949.     je    wrtdir1            ; e = no
  1950.     mov    byte ptr [di],'\'    ; add slash terminator so filenames
  1951.     inc    di            ;  can be appended easily
  1952. wrtdir1:mov    word ptr [di],0020h    ; space and null terminator
  1953.     inc    di
  1954.     pop    si
  1955.     ret
  1956. wrtdir    endp
  1957.  
  1958. ; write \v(PLATFORM) text to ds:di
  1959. wrtplat    proc    near
  1960.     push    si
  1961.     mov    si,offset machnam    ; machine name in sys dep file
  1962.     cld
  1963. wrtplat1:lodsb                ; get a char
  1964.     cmp    al,'$'            ; terminator?
  1965.     je    wrtplat2        ; e = yes
  1966.     mov    [di],al            ; store char
  1967.     inc    di
  1968.     jmp    short wrtplat1        ; keep going
  1969. wrtplat2:mov    word ptr [di],0020h    ; space and null terminator
  1970.     inc    di
  1971.     mov    temp,di            ; place for additional text
  1972.     pop    si
  1973.     ret
  1974. wrtplat    endp
  1975.  
  1976. wrtport    proc    near
  1977.     push    bx
  1978.     push    si
  1979.     mov    al,flags.comflg        ; get coms port indicator
  1980.     mov    bx,offset comptab    ; table of comms ports
  1981.     mov    cl,[bx]            ; number of entries
  1982.     xor    ch,ch
  1983.     inc    bx
  1984. wrtpor3:mov    dx,[bx]            ; length of this entry
  1985.     mov    si,bx
  1986.     add    si,2            ; points to entry text string
  1987.     add    si,dx            ; point to qualifier
  1988.     cmp    [si],al            ; our port?
  1989.     je    wrtpor4            ; e = yes
  1990.     add    bx,[bx]            ; add text length
  1991.     add    bx,4            ; plus count and qualifier
  1992.     loop    wrtpor3            ; next entry
  1993.     jmp    short wrtpor5        ; no match, curious
  1994. wrtpor4:mov    si,bx            ; point at entry
  1995.     add    si,2            ; point at string
  1996.     mov    cx,[bx]            ; length of string
  1997.     push    es
  1998.     mov    ax,ds
  1999.     mov    es,ax
  2000.     cld
  2001.     rep    movsb            ; copy to DS:DI
  2002.     pop    es
  2003. wrtpor5:mov    word ptr [di],0020h    ; space and null terminator
  2004.     inc    di
  2005.     pop    si
  2006.     pop    bx
  2007.     ret
  2008. wrtport    endp
  2009.  
  2010. ; write \v(PROGRAM) text to ds:si
  2011. wrtprog    proc    near
  2012.     push    si
  2013.     mov    si,offset progm        ; source string
  2014.     cld
  2015. wrtprg1:lodsb
  2016.     cmp    al,'$'            ; terminator?
  2017.     je    wrtprg2            ; e = yes
  2018.     mov    [di],al            ; store the char
  2019.     inc    di
  2020.     jmp    short wrtprg1
  2021. wrtprg2:mov    word ptr [di],0020h    ; space and null terminator
  2022.     inc    di
  2023.     mov    temp,di            ; place for additional text
  2024.     pop    si
  2025.     ret
  2026. wrtprog    endp
  2027.  
  2028. ; write \v(STATUS) text to ds:di
  2029. wrtstat    proc    near
  2030.     mov    ax,kstatus        ; Kermit status word
  2031.     call    fdec2di
  2032.     mov    word ptr [di],0020h    ; space and null terminator
  2033.     inc    di
  2034.     mov    temp,di            ; place for additional text
  2035.     ret
  2036. wrtstat    endp
  2037.  
  2038. ; write \v(SYSTEM) text to ds:di
  2039. wrtsystem proc    near
  2040.     push    si
  2041.     mov    si,offset system    ; system string "MS-DOS", dollar sign
  2042.     cld
  2043.     jmp    wrtplat1        ; use some common code
  2044. wrtsystem endp
  2045.  
  2046. ; write \v(TIME) text to ds:di
  2047. wrttime    proc    near
  2048.     mov    ah,gettim        ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
  2049.     int    dos
  2050.     push    dx            ; save dx
  2051.     xor    ah,ah
  2052.     mov    al,ch            ; Hours
  2053.     cmp    al,10            ; leading digit?
  2054.     jae    wrttim1            ; ae = yes
  2055.     mov    byte ptr [di],'0'    ; make our own
  2056.     inc    di
  2057. wrttim1:push    cx
  2058.     call    fdec2di            ; write decimal asciiz to buffer
  2059.     pop    cx
  2060.     mov    byte ptr [di],':'
  2061.     inc    di
  2062.     xor    ah,ah
  2063.     mov    al,cl            ; Minutes
  2064.     cmp    al,10            ; leading digit?
  2065.     jae    wrttim2            ; ae = yes
  2066.     mov    byte ptr [di],'0'    ; make our own
  2067.     inc    di
  2068. wrttim2:call    fdec2di            ; write decimal asciiz to buffer
  2069.     mov    byte ptr [di],':'
  2070.     inc    di
  2071.     pop    dx
  2072.     xor    ah,ah
  2073.     mov    al,dh            ; Seconds
  2074.     cmp    al,10            ; leading digit?
  2075.     jae    wrttim3            ; ae = yes
  2076.     mov    byte ptr [di],'0'    ; make our own
  2077.     inc    di
  2078. wrttim3:call    fdec2di            ; write decimal asciiz to buffer
  2079.     mov    word ptr [di],0020h    ; space and null terminator
  2080.     inc    di
  2081.     mov    temp,di            ; place for additional text
  2082.     ret
  2083. wrttime    endp
  2084.  
  2085. ; write \v(Version) text to ds:di
  2086. wrtver    proc    near
  2087.     mov    si,offset verident    ; MS Kermit version string in mssker
  2088.     cld
  2089. wrtver1:lodsb
  2090.     mov    [di],al
  2091.     inc    di
  2092.     cmp    al,'$'            ; end of string?
  2093.     jne    wrtver1            ; ne = no, continue copying
  2094.     dec    di
  2095.     mov    word ptr [di],0020h    ; space and null terminator
  2096.     inc    di
  2097.     mov    temp,di            ; place for additional text
  2098.     ret
  2099. wrtver    endp
  2100.  
  2101. ; write \v(terminal) text to ds:di
  2102. wrtterm    proc    near
  2103.     mov    ax,flags.vtflg        ; current terminal type
  2104.     mov    bx,offset termtb    ; terminal type table msx...
  2105.     mov    cl,[bx]            ; number of entries in our table
  2106.     xor    ch,ch
  2107.     inc    bx            ; point to the data
  2108. wrtter1:mov    si,[bx]            ; length of keyword
  2109.     cmp    ax,[bx+si+2]        ; value fields match?
  2110.     je    wrtter2            ; e = yes
  2111.     add    bx,si            ; add word length
  2112.     add    bx,4            ; skip count and value fields
  2113.     loop    wrtter1            ; keep searching
  2114.     jmp    short wrtter4        ; no match, use just a space
  2115. wrtter2:mov    cx,[bx]            ; get length of counted string
  2116.     mov    si,bx
  2117.     add    si,2            ; look at text
  2118.     cld
  2119. wrtter3:lodsb
  2120.     mov    [di],al            ; from ds:si to ds:di
  2121.     inc    di
  2122.     loop    wrtter3
  2123. wrtter4:mov    word ptr [di],0020h    ; space and null terminator
  2124.     inc    di
  2125.     mov    temp,di            ; place for additional text
  2126.     ret
  2127. wrtterm    endp
  2128.  
  2129. code1    ends
  2130.  
  2131. code    segment
  2132.     assume    cs:code
  2133.  
  2134. ; Set master prompt level. Enter with DX = offset of prompt string
  2135. MPROMPT    proc    near
  2136.     mov    mcmprmp,dx        ; offset of prompt string
  2137.     pop    ax            ; get the return address
  2138.     mov    word ptr mcmrprs,ax     ; offset to go to on reparse
  2139.     mov    mcmostp,sp        ; stack pointer at reparse time
  2140.     push    ax            ; put it on the stack again
  2141.     mov    ax,cs            ; our current code segment
  2142.     mov    word ptr mcmrprs+2,ax     ; segment of reparse address
  2143.     jmp    short prompt        ; now set the active prompt material
  2144. MPROMPT    endp
  2145.  
  2146.     
  2147. ; This routine prints the prompt and specifies the reparse address.
  2148. ; Enter with pointer to prompt string in dx. 
  2149. PROMPT    PROC  NEAR
  2150.     mov    comand.cmprmp,dx    ; save the prompt
  2151.     pop    ax            ; get the return address
  2152.     mov    word ptr comand.cmrprs,ax ; offset to go to on reparse
  2153.     mov    comand.cmostp,sp    ; save for later restoration
  2154.     push    ax            ; put it on the stack again
  2155.     mov    ax,cs            ; our current code segment
  2156.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  2157.     mov    ax,offset cmdbuf
  2158.     mov    cmwptr,ax        ; reset buffer read/write pointers
  2159.     mov    cmrptr,ax
  2160.     xor    al,al
  2161.     mov    comand.cmper,al        ; allow substitutions
  2162.     mov    cmsflg,0ffh        ; remove leading spaces
  2163.     cmp    flags.takflg,al        ; look at Take flag, zero?
  2164.     jne    promp1            ; ne=supposed to echo, skip this check
  2165.     cmp    taklev,al        ; inside a take file?
  2166.     je    promp1            ; no, keep going
  2167.     ret                ; yes, return
  2168. promp1:    mov    ah,prstr
  2169.     mov    dx,offset crlf
  2170.     int    dos
  2171.     mov    dx,comand.cmprmp    ; prompt pointer
  2172.     call    prtasz            ; show asciiz prompt string
  2173.     clc
  2174.     ret
  2175. PROMPT    ENDP
  2176.  
  2177. ISDEV    PROC    NEAR            ; Set carry if STDIN is non-disk
  2178.     push    ax
  2179.     push    bx
  2180.     push    dx
  2181.     xor    bx,bx            ; handle 0 is stdin
  2182.     xor    al,al            ; get device info
  2183.     mov    ah,ioctl
  2184.     int    dos
  2185.     rcl    dl,1            ; put ISDEV bit into the carry bit
  2186.     pop    dx            ; carry is set if device
  2187.     pop    bx
  2188.     pop    ax
  2189.     ret                ; carry set if device
  2190. ISDEV    ENDP
  2191.  
  2192. ISEOF    PROC    NEAR            ; Set carry if STDIN is at EOF
  2193.     push    ax            ;  but only if stdin is a non-device
  2194.     push    bx
  2195.     push    dx
  2196.     xor    bx,bx            ; handle 0 is stdin
  2197.     xor    al,al            ; get device info
  2198.     mov    ah,ioctl
  2199.     int    dos
  2200.     mov    ah,ioctl
  2201.     mov    al,6            ; get handle input status, set al
  2202.     test    dl,80h            ; bit set if handle is for a device
  2203.     jnz    iseof1            ; nz = device, always ready (al != 0)
  2204.     int    dos
  2205. iseof1:    or    al,al            ; EOF?
  2206.     pop    dx
  2207.     pop    bx
  2208.     pop    ax
  2209.     jnz    iseof2            ; nz = no
  2210.     stc                ; set carry for eof
  2211.     ret
  2212. iseof2:    clc                ; clear carry for not-eof
  2213.     ret
  2214. ISEOF    ENDP
  2215.  
  2216. ; Convert ascii characters in al and ah to lowercase.
  2217. ; All registers are preserved except AX, of course.
  2218.  
  2219. TOLOWR PROC NEAR
  2220.     cmp    ah,'A'            ; less that cap A?
  2221.     jl    tolow1            ; l = yes. leave untouched
  2222.     cmp    ah,'Z'+1        ; more than cap Z?
  2223.     jns    tolow1            ; ns = yes
  2224.     or    ah,20H            ; convert to lowercase
  2225. tolow1:    cmp    al,'A'            ; less that cap A?
  2226.     jl    tolow2            ; l = yes. leave untouched
  2227.     cmp    al,'Z'+1        ; more than cap Z?
  2228.     jns    tolow2            ; ns = yes
  2229.     or    al,20H            ; convert to lowercase
  2230. tolow2:    ret
  2231. TOLOWR    endp
  2232.  
  2233. ; Parse control sequences and device control strings.
  2234. ; Expect CSI, Escape [, or DCS lead-in characters to have been read.
  2235. ; Puts numerical Parameters in array param (16 bits, count is nparam) and
  2236. ;  a single letter Parameter in lparam, (Parameters are all ASCII column 3)
  2237. ;  Intermediate characters in array inter (count is ninter), (ASCII column 2)
  2238. ;  Final character in AL (ASCII columns 4-7).
  2239. ; Invoke by setting state to offset atparse, set pardone to offset of
  2240. ; procedure to jump to after reading Final char (0 means do just ret)
  2241. ; and optionally setting parfail to address to jump to if parsing failure.
  2242. ; When the Final char has been accepted this routine jumps to label held in
  2243. ; pardone for final action. Before the Final char has been read successful
  2244. ; operations return carry clear.
  2245. ; Failure exits are carry set, and an optional jump through parfail (if 
  2246. ; non-zero) or a return.
  2247.  
  2248. atparse    proc    near
  2249.     mov    bx,parstate        ; get parsing state
  2250.     or    bx,bx            ; have any state?
  2251.     jnz    atpars1            ; nz = have a state
  2252.     call    atpclr            ; do initialization
  2253.     mov    bx,parstate        ; get initial state
  2254. atpars1:call    bx            ; execute it
  2255.     jc    atpfail            ; c = failure
  2256.     cmp    parstate,offset atpdone    ; parsed final char?
  2257.     je    atpdone            ; e = yes
  2258.     ret                ; no, wait for another char
  2259.  
  2260.                 ; successful conclusion, final char is in AL
  2261. atpdone:mov    parstate,0        ; reset parsing state
  2262.     cmp    pardone,0        ; separate return address defined?
  2263.     jne    atpdon1            ; ne = yes
  2264.     clc
  2265.     ret                ; else just return
  2266. atpdon1:clc
  2267.     jmp    pardone            ; jmp to supplied action routine
  2268.  
  2269. atpfail:mov    parstate,0        ; failed, reset parser to normal state
  2270.     cmp    parfail,0        ; jump address specified?
  2271.     je    atpfail1        ; e = no
  2272.     jmp    parfail            ; yes, exit this way
  2273. atpfail1:stc
  2274.     ret
  2275.                     ; parsing workers
  2276. atparm:    cmp    ninter,0        ; Parameter, started intermediate yet?
  2277.     jne    atinter            ; ne = yes, no more parameters
  2278.     cmp    al,';'            ; argument separator?
  2279.     jne    atparm3            ; ne = no
  2280.     mov    ax,nparam        ; number of Parameters
  2281.     inc    ax            ; say a new one
  2282.     cmp    ax,maxparam        ; too many?
  2283.     jb    atparm2            ; b = no, continue
  2284.     stc                ; set carry to say failed
  2285.     ret                ; too many, ignore remainder
  2286. atparm2:mov    nparam,ax        ; say doing another Parameter
  2287.     clc
  2288.     ret
  2289.  
  2290. atparm3:mov    ah,al            ; copy char
  2291.     and    ah,not 0fh        ; ignore low nibble
  2292.     cmp    ah,30h            ; column 3, row 0? (30h='0')
  2293.     jne    atparm6            ; ne = no, check Intermediate/Final
  2294.     cmp    al,'9'            ; digit?
  2295.     ja    atparm5            ; a = no, check letter Parameters
  2296.     sub    al,'0'            ; ascii to binary
  2297.     mov    bx,nparam        ; current parameter number
  2298.     shl    bx,1            ; convert to word index
  2299.     mov    cx,param[bx]        ; current parameter value
  2300.     shl    cx,1            ; multiply by 10.  2 * cl
  2301.     push    bx
  2302.     mov    bx,cx            ; save 2 * cl
  2303.     shl    cx,1            ; 4 * cl
  2304.     shl    cx,1            ; 8 * cl
  2305.     add    cx,bx            ; 10 * cl
  2306.     pop    bx
  2307.     add    cl,al            ; add new digit
  2308.     adc    ch,0
  2309.     jnc    atparm4            ; nc = no carry out (65K or below)
  2310.     mov    cx,0ffffh        ; set to max value
  2311. atparm4:mov    param[bx],cx        ; current Parameter value
  2312.     clc
  2313.     ret
  2314.                     ; check non-numeric Parameters
  2315. atparm5:cmp    al,'?'            ; within column 3?
  2316.     ja    atfinal            ; a = no, check Final char
  2317.     mov    lparam,al        ; store non-numeric Parameter
  2318.     clc
  2319.     ret
  2320.  
  2321. atparm6:cmp    nparam,0        ; started a parameter yet?
  2322.     jne    atparm7            ; ne = yes
  2323.     cmp    param,0            ; got anything for param[0]?
  2324.     je    atinter            ; e = no
  2325. atparm7:inc    nparam            ; yes, say finished with another
  2326.  
  2327. atinter:mov    parstate,offset atinter    ; next state (intermediate)
  2328.     cmp    al,';'            ; argument separator?
  2329.     jne    atinte1            ; ne = no
  2330.     mov    ax,ninter        ; number of Intermediates 
  2331.     cmp    ax,maxinter        ; too many?
  2332.     jb    atinte2            ; b = no, continue
  2333.     stc                ; carry = failed
  2334.     ret                ; too many, ignore remainder
  2335. atinte1:test    al,not 2fh        ; column two = 20h - 2fh?
  2336.     jnz    atfinal            ; nz = not an Intermediate, try Final
  2337.     mov    bx,ninter        ; current Intermediate slot number
  2338.     mov    inter[bx],al        ; current Intermediate value
  2339. atinte2:inc    ninter            ; say doing another Intermediate
  2340.     clc
  2341.     ret
  2342.  
  2343. atfinal:cmp    al,40h            ; Final character, range is 40h to 7fh
  2344.     jb    atfina1            ; b = out of range
  2345.     cmp    al,7fh
  2346.     ja    atfina1            ; a = out of range
  2347.     mov    parstate,offset atpdone    ; next state is "done"
  2348.     clc                ; success, final char is in AL
  2349.     ret
  2350. atfina1:stc                ; c = failed
  2351.     ret
  2352. atparse    endp
  2353.  
  2354. ; Clear Parameter, Intermediate arrays in preparation for parsing
  2355. atpclr    proc    near
  2356.     push    ax
  2357.     push    cx
  2358.     push    di
  2359.     push    es
  2360.     xor    ax,ax            ; get a null
  2361.     mov    parstate,offset atparm    ; init parser state
  2362.     mov    lparam,al        ; clear letter Parameter
  2363.     mov    nparam,ax        ; clear Parameter count
  2364.     mov    cx,maxparam        ; number of Parameter slots
  2365.     mov    di,offset param        ; Parameter slots
  2366.     push    ds
  2367.     pop    es            ; use data segment for es:di below
  2368.     cld                ; set direction forward
  2369.     rep    stosw            ; clear the slots
  2370.     mov    ninter,ax        ; clear Intermediate count
  2371.     mov    cx,maxinter        ; number of Intermediate slots
  2372.     mov    di,offset inter        ; Intermediate slots
  2373.     rep    stosb            ; clear the slots
  2374.     pop    es
  2375.     pop    di
  2376.     pop    cx
  2377.     pop    ax
  2378.     ret
  2379. atpclr    endp
  2380.  
  2381. ; Dispatch table processor. Enter with BX pointing at table of {char count,
  2382. ; address of action routines, characters}. Jump to matching routine or return.
  2383. ; Enter with AL holding received Final char.
  2384. atdispat proc near
  2385.     mov    cl,[bx]            ; get table length from first byte
  2386.     xor    ch,ch
  2387.     mov    di,bx            ; main table
  2388.     add    di,3            ; point di at first char in table
  2389.     push    es
  2390.     push    ds
  2391.     pop    es            ; use data segment for es:di below
  2392.     cld                ; set direction forward
  2393.     repne    scasb            ; find matching character
  2394.     pop    es
  2395.     je    atdisp2            ; e = found a match, get action addr
  2396.     ret                ; ignore escape sequence
  2397. atdisp2:sub    di,bx            ; distance scanned in table
  2398.     sub    di,4            ; skip count byte, address word, inc
  2399.     shl    di,1            ; convert to word index
  2400.     inc    bx            ; point to address of action routines
  2401.     mov    bx,[bx]            ; get address of action table
  2402.     jmp    word ptr [bx+di]    ; dispatch to the routine
  2403. atdispat endp
  2404. code    ends
  2405.     end
  2406.