home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mskermit / msscmd.asm < prev    next >
Assembly Source File  |  2020-01-01  |  150KB  |  5,047 lines

  1.        NAME    msscmd
  2. ; File MSSCMD.ASM
  3.     include mssdef.h
  4. ;    Copyright (C) 1982, 1997, Trustees of Columbia University in the 
  5. ;    City of New York.  The MS-DOS Kermit software may not be, in whole 
  6. ;    or in part, licensed or sold for profit as a software product itself,
  7. ;    nor may it be included in or distributed with commercial products
  8. ;    or otherwise distributed by commercial concerns to their clients 
  9. ;    or customers without written permission of the Office of Kermit 
  10. ;    Development and Distribution, Columbia University.  This copyright 
  11. ;    notice must not be removed, altered, or obscured.
  12. ;
  13. ; Edit history
  14. ; 12 Jan 1995 version 3.14
  15. ; Last edit
  16. ; 12 Jan 1995
  17.  
  18.      public comnd, comand, isdev, iseof, prompt, tolowr, toupr, valtab
  19.     public parstate, pardone, parfail, nparam, param, lparam, ninter
  20.     public inter, atparse, atpclr, atdispat, cspb, dspb, mprompt, nvaltoa
  21.     public savepoff, saveplen, keyboard, fwrtdir, cspb1, filetdate
  22.     public    fqryenv, ifelse, oldifelse, retbuf, vfile
  23.  
  24. env    equ    2CH            ; environment address in psp
  25. braceop    equ    7bh            ; opening curly brace
  26. bracecl    equ    7dh            ; closing curly brace
  27.  
  28. ; codes for various \fxxx(arg list) operations
  29. F_char        equ    1
  30. F_code        equ    2
  31. F_contents     equ    3
  32. F_definition    equ    4
  33. ;F_eval        equ    5
  34. F_exec        equ    6
  35. F_files        equ    7
  36. F_index        equ    8
  37. F_length    equ    9
  38. F_literal    equ    10
  39. F_lower        equ    11
  40. F_lpad        equ    12
  41. F_maximum     equ    13
  42. F_minimum     equ    14
  43. F_nextfile    equ    15
  44. F_repeat     equ    16
  45. F_reverse    equ    17
  46. F_right        equ    18
  47. F_rpad        equ    19
  48. F_substr    equ    20
  49. F_upper        equ    21
  50. F_date        equ    22
  51. F_size        equ    23
  52. F_replace    equ    24
  53. F_eval        equ    25
  54. F_rindex    equ    26
  55. F_verify    equ    27
  56. F_ipaddr    equ    28
  57. F_tod2secs    equ    29
  58. F_chksum    equ    30
  59. F_basename    equ    31
  60.  
  61. ; Constants for valtoa 
  62. V_environ    equ    0
  63. V_argc        equ    1
  64. V_carrier    equ    22
  65. V_charset    equ    33
  66. V_console    equ    27
  67. V_count        equ    2
  68. V_cmdlevel    equ    29
  69. V_cps        equ    24
  70. V_date        equ    3
  71. V_ndate        equ    14
  72. V_dir        equ    5
  73. V_dosver    equ    19
  74. V_errlev    equ    4
  75. V_kbd        equ    10
  76. V_line        equ    15
  77. V_monitor     equ    28
  78. V_parity     equ    21
  79. V_platform     equ    8
  80. V_port         equ    15
  81. V_program     equ    12
  82. V_prompt     equ    23
  83. V_query        equ    31
  84. V_session     equ    17
  85. V_tcpip        equ    20
  86. V_space     equ    25
  87. V_speed     equ    11
  88. V_startup     equ    26
  89. V_status     equ    13
  90. V_sysid        equ    32
  91. V_system     equ    9
  92. V_terminal     equ    16
  93. V_time        equ    6
  94. V_ntime     equ    18
  95. V_version     equ    7
  96. V_input        equ    30
  97. V_inpath    equ    34
  98. V_disk        equ    35
  99. V_cmdfile    equ    36
  100. V_inidir    equ    37
  101. V_instatus    equ    38
  102. V_minput    equ    39
  103. V_return    equ    40
  104. V_connection    equ    41
  105. V_filespec    equ    42
  106.  
  107. ; Like main filest, but shorter for local usage.
  108. fileiost struc
  109. dta    db 26 dup(0)    ; DOS, 21 resev'd bytes, file attr, 2 each date & time
  110. sizelo    dw 0        ; DOS, file size double word
  111. sizehi    dw 0
  112. fname    db 13 dup(0)    ; DOS, filename, asciiz, with dot. End of DOS section
  113. fileiost ends
  114.  
  115. data     segment
  116.     extrn    flags:byte, taklev:byte, takadr:word, mcctab:byte
  117.     extrn    kstatus:word, errlev:byte, psp:word, fsta:word
  118.     extrn    portval:word, bdtab:byte, tdfmt:byte, machnam:byte
  119.     extrn    verident:word, kstatus:word, errlev:byte, comptab:byte
  120.     extrn    termtb:byte, dosnum:word, prmptr:word, startup:byte
  121.     extrn    crt_mode:byte, tmpbuf:byte, buff:byte, minpcnt:word
  122.     extrn    decbuf:byte, encbuf:byte, queryseg:word, inpath_seg:word
  123.     extrn    cmdfile:byte, inidir:byte, dos_bottom:byte, marray:word
  124.     extrn    input_status:word, domath_ptr:word, domath_cnt:word
  125.     extrn    domath_msg:word, atoibyte:byte, atoi_err:byte, atoi_cnt:word
  126.  
  127. ifndef    no_tcp
  128.     extrn    sescur:word, tcp_status:word
  129. endif    ; no_tcp
  130.  
  131.                 ; Start Patch structure. Must be first.
  132.     even
  133. dspb    dw    code        ; segment values for patcher
  134.     dw    code1
  135.     dw    code2
  136.     dw    data
  137.     dw    data1
  138.     dw    _TEXT
  139.     db    64 dup (0)    ; data segment patch buffer
  140.                 ;  with space for other material, if req'd
  141.                 ; end of Patch structure
  142. progm    db    'MS-DOS_KERMIT$'    ; for \v(program)
  143. system    db    'MS-DOS$'        ; for \v(system)
  144. keyboard dw    88            ; \v(keyboard) kind of keybd 88/101
  145. ten    db    10            ; for times ten
  146.  
  147. comand    cmdinfo    <>
  148. cmer00  db      cr,lf,'?Program internal error, recovering$'
  149. cmer01    db    cr,lf,'?More parameters are needed$'
  150. cmer02    db    cr,lf,'?Word "$'
  151. cmer03    db    '" is not usable here$'
  152. cmer04    db    '" is ambiguous$'
  153. cmer07    db    cr,lf,'?Ignoring extra characters "$'
  154. cmer08    db    '"$'
  155. cmer09    db    cr,lf,'?Text exceeded available buffer capacity$'
  156. cmin01    db    ' Use one of the following words in this position:',cr,lf,'$'
  157. stkmsg    db    cr,lf,bell,'?Exhausted work space! Circular definition?$'
  158. moremsg    db    '... more, press a key to continue ...$'
  159. crlf    db      cr,lf,'$'
  160. ctcmsg    db    5eh,'C$'
  161. cmunk    db    'unknown'
  162. errflag    db    0            ; non-zero to suppress cmcfrm errors
  163. kwstat    db    0            ; get-keyword status
  164. subcnt    db    0            ; count of chars matched in '\%'
  165. subtype db    0            ; kind of sub (% or v)
  166. evaltype dw    0            ; evaltoa kind
  167. bracecnt db    0            ; curly brace counter
  168. parencnt db    0            ; parenthesis counter
  169. report_binary db 0            ; subst reporting \number directly
  170. argptr    dw    3 dup (0)        ; \fxxx() argument pointers
  171. arglen    dw    3 dup (0)        ; \fxxx() argument lengths
  172. replay_cnt dw    0            ; report to app, no echo
  173. replay_skip db    0            ; non-zero to skip subst for replays
  174. retbuf    db    130 dup (0)        ; \v(return) buffer
  175. vfile    db    65 dup (0)        ; \v(filespec) buffer
  176. fileio    fileiost <>            ; find first/next support
  177. cmsflg    db    0            ; Non-zero when last char was a space
  178. cmkind    db    0            ; command kind request (cmkey etc)
  179. in_showprompt db 0            ; Non-zero when in showprompt
  180. cmdbuf    db    cmdblen dup (0)        ; Buffer for command parsing
  181. rawbuf    db    cmdblen dup (0)        ; input, what user provided
  182. read_source db    0            ; channel whence we read
  183. endedbackslash db 0
  184. in_reparse db    0
  185.     even
  186. cmdstk    dw    0            ; stack pointer at comand call time
  187. cmptab    dw    0            ; Address of present keyword table
  188. cmhlp    dw    0            ; Address of present help
  189. cmwptr    dw    0            ; Pointer for next char write
  190. cmrptr    dw    0            ; Pointer for next char read
  191. cmsiz    dw    0            ; Size info of user input
  192. cmsptr    dw    0            ; Place to save a pointer
  193. mcmprmp    dw    0            ; master prompt, string address
  194. mcmrprs    dd    0            ; master prompt, reparse address
  195. mcmostp    dw    0            ; master prompt, stack pointer
  196. temp    dw    0            ; temp (counts char/line so far)
  197. cmrawptr dw    0            ; non-substitution level, write ptr
  198.  
  199. ifndef    no_tcp
  200. valtab    db    1+42            ; table of values for \v(value)
  201. else
  202. valtab    db    1+42 - 2
  203. endif    ; no_tcp
  204.     mkeyw    'argc)',V_argc
  205.     mkeyw    'carrier)',V_carrier
  206.     mkeyw    'charset)',V_charset
  207.     mkeyw    'cmdfile)',V_cmdfile
  208.     mkeyw    'connection)',V_connection
  209.     mkeyw    'console)',V_console
  210.     mkeyw    'count)',V_count
  211.     mkeyw    'cmdlevel)',V_cmdlevel
  212.     mkeyw    'cps)',V_cps
  213.     mkeyw    'date)',V_date
  214.     mkeyw    'ndate)',V_ndate
  215.     mkeyw    'directory)',V_dir
  216.     mkeyw    'dosversion)',V_dosver
  217.     mkeyw    'disk)',V_disk
  218.     mkeyw    'errorlevel)',V_errlev
  219.     mkeyw    'filespec)',V_filespec
  220.     mkeyw    'inidir)',V_inidir
  221.     mkeyw    'inpath)',V_inpath
  222.     mkeyw    'input)',V_input
  223.     mkeyw    'instatus)',V_instatus
  224.     mkeyw    'keyboard)',V_kbd
  225.     mkeyw    'line)',V_port
  226.     mkeyw    'minput)',V_minput
  227.     mkeyw    'monitor)',V_monitor
  228.     mkeyw    'parity)',V_parity
  229.     mkeyw    'platform)',V_platform
  230.     mkeyw    'port)',V_port
  231.     mkeyw    'program)',V_program
  232.     mkeyw    'prompt)',V_prompt
  233.     mkeyw    'query)',V_query
  234.     mkeyw    'return)',V_return
  235. ifndef    no_tcp
  236.     mkeyw    'session)',V_session
  237.     mkeyw    'tcpip_status)',V_tcpip
  238. endif    ; no_tcp
  239.     mkeyw    'space)',V_space
  240.     mkeyw    'speed)',V_speed
  241.     mkeyw    'startup)',V_startup
  242.     mkeyw    'status)',V_status
  243.     mkeyw    'sysid)',V_sysid
  244.     mkeyw    'system)',V_system
  245.     mkeyw    'terminal)',V_terminal
  246.     mkeyw    'time)',V_time
  247.     mkeyw    'ntime)',V_ntime
  248.     mkeyw    'version)',V_version
  249.  
  250.  
  251. evaltab    db    29            ; \fverb(args)
  252.     mkeyw    'basename(',F_basename
  253.     mkeyw    'character(',F_char
  254.     mkeyw    'checksum(',F_chksum
  255.     mkeyw    'code(',F_code
  256.     mkeyw    'contents(',F_contents
  257.     mkeyw    'date(',F_date
  258.     mkeyw    'definition(',F_definition
  259.     mkeyw    'eval(',F_eval
  260.     mkeyw    'files(',F_files
  261.     mkeyw    'index(',F_index
  262.     mkeyw    'ipaddr(',F_ipaddr
  263.     mkeyw    'length(',F_length
  264.     mkeyw    'literal(',F_literal
  265.     mkeyw    'lower(',F_lower
  266.     mkeyw    'lpad(',F_lpad
  267.     mkeyw    'maximum(',F_maximum
  268.     mkeyw    'minimum(',F_minimum
  269.     mkeyw    'nextfile(',F_nextfile
  270.     mkeyw    'rindex(',F_rindex
  271.     mkeyw    'repeat(',F_repeat
  272.     mkeyw    'replace(',F_replace
  273.     mkeyw    'reverse(',F_reverse
  274.     mkeyw    'right(',F_right
  275.     mkeyw    'rpad(',F_rpad
  276.     mkeyw    'size(',F_size
  277.     mkeyw    'substr(',F_substr
  278.     mkeyw    'tod2secs(',F_tod2secs
  279.     mkeyw    'verify(',F_verify
  280.     mkeyw    'upper(',F_upper
  281. ; not implemented in MS-DOS Kermit
  282. ;    mkeyw    'execute(',F_exec
  283.  
  284. envtab    db    1                     ; \$(..) Environment table
  285.     mkeyw    'An Environment variable)',0    ; reserve 0 in valtab
  286.  
  287. numtab  db      1                               ; \number help table
  288.         mkeyw   'a number such as \123',0
  289.  
  290.                         ; table of Parity strings
  291. parmsgtab dw    parevnmsg,parmrkmsg,parnonmsg,paroddmsg,parspcmsg
  292. parevnmsg db    'EVEN',0
  293. parmrkmsg db    'MARK',0
  294. parnonmsg db    'NONE',0
  295. paroddmsg db    'ODD',0
  296. parspcmsg db    'SPACE',0
  297.  
  298. onoffmsgtab dw    offmsg,onmsg        ; on/off table, asciiz
  299. offmsg    db    'OFF',0
  300. onmsg    db    'ON',0
  301.  
  302. ansiword db    'ANSI',0        ; \v(console) ASCIIZ strings
  303. noneword db    'NONE',0
  304. colormsg db    'COLOR',0        ; \v(monitor) ASCIIZ strings
  305. monomsg    db    'MONO',0
  306. connmsg    db    'local',0        ; \v(connection) state
  307.  
  308. valtmp    dw    0
  309. numtmp    dw    0
  310.  
  311.     even
  312. envadr    dd    0            ; seg:offset of a string in Environemt
  313. envlen    dw    0            ; length of envadr's string
  314.  
  315.     even                ; Control sequence storage area
  316. maxparam equ    16            ; number of ESC and DCS Parameters
  317. maxinter equ    16            ; number of ESC and DCS Intermediates
  318.  
  319. savepoff label    word            ; Start per session save area
  320. parstate dw    0            ; parser state, init to startup
  321. pardone dw    0            ; where to jmp after Final char seen
  322. parfail    dw    0            ; where to jmp if parser fails
  323. nparam    dw    0            ; number of received Parameters
  324. param    dw    maxparam dup (0)    ; Parameters for ESC
  325. lparam    db    0            ; a single letter Parameter for ESC
  326. ninter    dw    0            ; number of received Intermediates
  327. inter    db    maxinter dup (0),0    ; Intermediates for ESC, + guard 
  328. saveplen dw    ($-savepoff)
  329. ifelse    db    0        ; non-zero if last IF statement failed
  330. oldifelse db    0        ; copy of ifelse from previous command
  331. month    db    'Jan ','Feb ','Mar ','Apr ','May ','Jun '
  332.     db    'Jul ','Aug ','Sep ','Oct ','Nov ','Dec '
  333. data    ends
  334.  
  335. data1    segment
  336.     db    0            ; so error msg has non-zero offset
  337. cmin00  db      ' Press ENTER to execute command$'
  338. f1hlp    db    ' number$'
  339. f2hlp    db    ' char$'
  340. f3hlp    db    ' variable or macro name$'
  341. f8hlp    db    ' pattern-text, string, start-position$'
  342. f9hlp    db    ' text$'
  343. f12hlp    db    ' text, pad-length, pad-char$'
  344. f15hlp    db    ' no argument$'
  345. f16hlp    db    ' repeat-text, repeat-count$'
  346. f18hlp    db    ' text, right-most count$'
  347. f20hlp    db    ' text, start-position, substring len$'
  348. f22hlp    db    ' filename$'
  349. f24hlp    db    ' source, pattern, replacement$'
  350. f25hlp    db    ' arithmetic expression$'
  351. f30hlp    db    ' string$'
  352. n1hlp    db    ' digits of a number whose value fits into one byte$'
  353. data1    ends
  354.  
  355. ifndef    no_terminal
  356. ifndef    no_tcp
  357. _TEXT    segment
  358.     extrn    cpatch:far
  359. _TEXT    ends
  360. endif    ; no_tcp
  361. endif    ; no_terminal
  362.  
  363. code1    segment
  364.     assume     cs:code1
  365.     extrn    shovarcps:near, dskspace:far, fparse:far
  366.     extrn    strlen:far, prtscr:far, strcpy:far, prtasz:far
  367.     extrn    dec2di:far, decout:far, malloc:far, domath:far
  368.         extrn   atoi:far, takrd:far, buflog:far, tod2secs:far
  369.  
  370. cspb1    equ    this byte
  371.     db    (256-($-cspb1)) dup (0)    ; code1 segment patch buffer
  372.                 ; end of Patch area
  373. code1    ends
  374.  
  375. code    segment
  376.     extrn    ctlu:near, cmblnk:near, locate:near
  377.     extrn    takclos:far, docom:near, getenv:near
  378.     extrn    getbaud:near, lnout:near, takopen_sub:far
  379.     extrn    takopen_macro:far
  380.  
  381.     assume    cs:code, ds:data, es:nothing
  382.  
  383.                 ; Patch area. Must be first in MSK's Code Seg
  384. cspb    equ    this byte
  385.     dw    seg code1
  386.     dw    seg code2
  387.     dw    seg data
  388.     dw    seg data1
  389.     dw    seg _TEXT
  390.     dw    seg _DATA
  391.  
  392. ifndef    no_terminal
  393. ifndef    no_tcp
  394.     dw    offset cpatch
  395. endif    ; no_tcp
  396. endif    ; no_terminal
  397.     db    (256-($-cspb)) dup (0)    ; code segment patch buffer
  398.                 ; end of Patch area
  399.  
  400. fctlu    proc    far        ; FAR callable versions of items in seg code
  401.     call    ctlu        ;  for calling from code segment code1 below
  402.     ret
  403. fctlu    endp
  404. fcmblnk    proc    far
  405.     call    cmblnk
  406.     ret
  407. fcmblnk    endp
  408. fgetbaud proc    far
  409.     call    getbaud
  410.     ret
  411. fgetbaud endp
  412. fgetenv    proc    far
  413.     call    getenv
  414.     ret
  415. fgetenv    endp
  416. flocate    proc    far
  417.     call    locate
  418.     ret
  419. flocate    endp
  420.  
  421. fdec2di    proc    far
  422.     push    cx
  423.     push    ds
  424.     mov    cx,es
  425.     mov    ds,cx
  426.     call    dec2di
  427.     pop    ds
  428.     pop    cx
  429.     ret
  430. fdec2di    endp
  431. ftakclos proc    far
  432.     call    takclos
  433.     ret
  434. ftakclos endp
  435.  
  436. nvaltoa    proc    near
  437.     push    es
  438.     mov    ax,ds
  439.     mov    es,ax
  440.     call    fvaltoa
  441.     pop    es
  442.     ret
  443. nvaltoa    endp
  444. flnout    proc    far
  445.     call    lnout
  446.     ret
  447. flnout    endp
  448. fdskspace proc    far
  449.     call    dskspace
  450.     ret
  451. fdskspace endp
  452.  
  453. ;       This routine parses the specified function in AH. Any additional
  454. ;       information is in DX and BX.
  455. ;       Returns carry clear on success and carry set on failure
  456.  
  457. COMND    PROC NEAR
  458.     mov    cmdstk,sp        ; save stack ptr for longjmp exit
  459.     mov    bracecnt,0        ; curly brace counter
  460.     cmp    ah,cmeol        ; Parse a confirm?
  461.     jne    cm2            ; nz = no
  462.     call    cmcfrm            ; get a Carriage Return end of line
  463.     ret
  464. cm2:    mov    cmkind,ah        ; remember for {} line continuation
  465.     cmp    ah,cmkey        ; Parse a keyword?
  466.     jne    cm3            ; ne = no
  467.     xor    al,al            ; get a zero/clear
  468.     xchg    al,ifelse        ; get current ifelse state
  469.     mov    oldifelse,al        ; remember here (one cmd delay)
  470.     call    cmkeyw            ; get keyword
  471.     ret
  472. cm3:    cmp    ah,cmline        ; parse line of text
  473.     jne    cm4
  474.     call    cmtxt
  475.     ret
  476. cm4:    cmp    ah,cmword        ; parse arbitrary word
  477.     jne    cm5
  478.     call    cmtxt
  479.     ret
  480. cm5:    mov    ah,prstr        ; else give error
  481.     mov    dx,offset cmer00    ; "?Program internal error"
  482.     int    dos
  483.     jmp    prserr            ; reparse
  484.                     ; Control-C exit path (far to near)
  485. cmexit    label    far
  486.     mov    sp,cmdstk        ; restore command entry stack pointer
  487.     stc
  488.     retn                ;  and fail immediately (a longjmp)
  489.  
  490. COMND    ENDP
  491. code    ends
  492.  
  493. code1    segment
  494.     assume    cs:code1
  495.  
  496. ; This routine parses a keyword from the table pointed at by DX, help text
  497. ; point to by BX. Format of the table is as follows (use macro mkeyw):
  498. ;    addr:    db    N      ; Where N is the # of entries in the table
  499. ;        dw    M      ; M is the size of the keyword
  500. ;        db    'string'  ; String is the keyword
  501. ;        dw    value      ; Value is data to be returned
  502. ; Keywords may be in any order and in mixed case.
  503. ; Return is carry clear for success and carry set for failure.
  504.  
  505. ; cmptab: pointer to keyword table (supplied by caller)
  506. ; cmhlp: pointer to help message (supplied by caller)
  507. ; cmsptr: pointer to current user word text
  508. ; cmsiz: length of user text, excluding terminator
  509. ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed
  510. ; comand.cmwhite: non-zero allows leading whitespace for cmline and cmword,
  511. ;                 reset automatically at end of call
  512. ; cmwptr: buffer write pointer to next free byte
  513. ; cmrptr: buffer read pointer for next free byte
  514. ; comand.cmper:    0 to do \%x substitution. Set to 0 at end of call
  515. ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset
  516. ;         automatically at time of failure.
  517. cmkeyw    proc    far
  518.     mov    cmsiz,0            ; user word length
  519.     mov    ax,cmrptr        ; get command reading pointer
  520.     mov    cmsptr,ax        ; set pointer for start of user word
  521.     mov    cmhlp,bx        ; save the help pointer
  522.         mov    cmptab,dx        ; save the beginning of keyword table
  523.     mov    bx,dx
  524.     cmp    byte ptr[bx],0        ; get number of entries in table
  525.     jne    cmky1
  526.     jmp    cmky7            ; e = no keywords to check, error
  527. cmky1:    mov    cmsflg,0ffh        ; skip leading spaces/tabs
  528.     call    cmgtch            ; get char from the user into ah
  529.     jc    cmky3            ; c = terminator
  530.     mov    dx,cmrptr        ; next byte to read
  531.     dec    dx            ; where we just read a char
  532.     mov    cmsptr,dx        ; remember start of keyword
  533.     inc    cmsiz            ; start counting user chars
  534. cmky2:    call    cmgtch            ; read until terminator
  535.     jc    cmky3            ; c = terminator
  536.     inc    cmsiz            ; count user chars
  537.     jmp    short cmky2        ; no terminator yet
  538.  
  539. cmky3:    cmp    ah,'?'                  ; need help?
  540.     jne    cmky4            ; ne = no
  541.     call    cmkyhlp            ; display help
  542.     jmp    repars
  543. cmky4:    cmp    ah,escape        ; escape?
  544.     jne    cmky6            ; ne = no
  545.     call    cmkyesc            ; process escape
  546.     jc    cmky5            ; c = failure (no unique keyword yet)
  547.     mov    comand.cmper,0        ; reset to variable recognition
  548.     mov    comand.cmkeep,0
  549.     mov    comand.impdo,0        ; clear flag to prevent loops
  550.     mov    comand.cmquiet,0    ; permit echoing again
  551.     mov    comand.cmcnvkind,cmcnv_none ; default is no conversion
  552.     clc
  553.     ret                ; return successfully to user
  554.  
  555. cmky5:    cmp    cmsiz,0            ; started a word yet?
  556.     je    cmky1            ; e = no, ignore escape, keep looking
  557.     call    cmkyhlp            ; display help
  558.     jmp    repars
  559.  
  560. cmky6:    cmp    cmsiz,0            ; length of user's text, empty?
  561.     je    cmky7            ; e = yes, parse error
  562.     push    bx
  563.     mov    bx,cmsptr        ; point at first user character
  564.     cmp    byte ptr[bx],':'    ; start of a label?
  565.     pop    bx
  566.     jne    cmky6a            ; ne = no, return success
  567.     mov    cmsiz,1            ; say just one byte
  568. cmky6a:    call    getkw            ; get unique kw, point to it with bx
  569.     jc    cmky8            ; c = not found
  570.     add    bx,[bx]            ; add length of keyword text (CNT)
  571.     add    bx,2            ; point at value field
  572.     mov    bx,[bx]            ; bx = return value following keyword
  573.     call    optionclr        ; clear parser options
  574.     mov    errflag,0
  575.     clc
  576.     ret                ; return successfully
  577.                     ; all other terminators come here
  578. cmky7:    cmp    cmsiz,0            ; empty table or empty user's text?
  579.     jne    cmky8            ; ne = no
  580.     cmp    comand.cmcr,0        ; empty lines allowed?
  581.     jne    cmky10            ; ne = yes, do not complain
  582.     push    dx
  583.     mov    ah,prstr
  584.     mov    dx,offset cmer01    ; command word expected
  585.     int    dos
  586.     pop    dx
  587.     xor    al,al
  588.     mov    comand.cmquiet,al    ; permit echoing again
  589.     mov    comand.impdo,al        ; clear flag to prevent loops
  590.     stc                ; failure
  591.     ret
  592.  
  593. cmky8:    cmp    comand.impdo,0        ; failed here, ok to try Macro table?
  594.     je    cmky8a            ; e = no, use regular exit path
  595.     mov    comand.impdo,0        ; yes, but clear flag to prevent loops
  596.     mov    cmrptr,offset cmdbuf    ; reinit read pointer
  597.     mov    comand.cmquiet,1    ; suppress echoing of same keyword
  598.     mov    bx,offset docom        ; return DO as "found" keyword
  599.     clc
  600.     ret                ; return success to invoke DO
  601.  
  602. cmky8a:    mov    errflag,1        ; say already doing error recovery
  603.     or    kstatus,ksgen        ; global command status, failure
  604.     mov    comand.cmquiet,0    ; permit echoing again
  605.     call    isdev            ; reading pretyped lines?
  606.     jnc    cmky9            ; nc = yes, consume rest of line
  607.     cmp    taklev,0        ; in a Take file?
  608.     jne    cmky9            ; ne = yes
  609.     call    cmskw            ; display offending keyword
  610.     mov    comand.impdo,0        ; clear flag to prevent loops
  611.     dec    cmrptr            ; interactive, backup to terminator
  612.     mov    bx,cmrptr        ; look at it
  613.     cmp    byte ptr [bx],' '    ; got here on space terminator?
  614.     jne    cmky10            ; ne = no, (cr,lf,ff) exit failure
  615.     mov    ah,prstr        ; start a fresh line
  616.     mov    dx,offset crlf
  617.     int    dos
  618.     call    bufdel            ; cut back buffer to last good char
  619.     jmp    repars            ; reparse interactive lines
  620.  
  621. cmky9:    call    cmcfrm            ; get formal end of command line
  622.                     ;  to maintain illusion of typeahead
  623.                     ;  and let user backspace to correct
  624.                     ;  mistakes (we reparse everything)
  625.     call    cmskw            ; display offending keyword
  626. cmky10:    mov    comand.cmquiet,0    ; permit echoing again
  627.     stc                ; say failure
  628.     ret
  629. cmkeyw    endp
  630.  
  631. ;;;;;; start support routines for keyword parsing.
  632.  
  633. cmkyesc    proc    near            ; deal with escape terminator
  634.     push    cmrptr            ; points at ESC
  635.     pop    cmwptr            ; pointed one byte beyond ESC
  636.     cmp    cmsiz,0         ; user word length, empty?
  637.     jne    cmkye2            ; ne = have user text, else complain
  638. cmkye1:    call    esceoc            ; do normal escape end-of-command
  639.     stc                ; say failure to fill out word
  640.     ret
  641.                     ; add unique keyword to buffer
  642. cmkye2:    call    getkw            ; is there a matching keyword?
  643.     jc    cmkye1            ; c = ambiguous or not found
  644.     push    bx            ; unique, bx points to structure
  645.     push    si
  646.     mov    cx,[bx]            ; length of keyword
  647.     add    bx,2            ; point to first letter
  648.     dec    cmrawptr        ; overwrite ESC
  649.     mov    si,cmrawptr        ; where raw writes go
  650.     mov    dx,cmsiz        ; length of user word
  651.     add    bx,dx            ; add chars known so far
  652.     sub    cx,dx            ; calculate number yet to add
  653.     jcxz    cmkye4            ; z = none
  654. cmkye3:    mov    al,[bx]            ; get a keyword letter
  655.     inc    bx
  656.     call    tolowr            ; lowercase
  657.     mov    [si],al            ; store it
  658.     inc    si
  659.     loop    cmkye3            ; do all new chars
  660. cmkye4:    mov    word ptr [si],'  '    ; add trailing space, clear old next
  661.     inc    si
  662.     mov    cmrawptr,si
  663.     pop    si
  664.     pop    bx            ; bx = keyword structure
  665.     inc    cmrawptr        ; bufdel backs up one char
  666.     jmp    bufdel
  667. cmkyesc    endp
  668.  
  669. esceoc    proc    near            ; do normal escape end-of-command
  670.     push    ax
  671.     push    dx
  672.     mov    ah,conout        ; ring the bell
  673.     mov    dl,bell
  674.     int    dos
  675.     pop    dx
  676.     pop    ax
  677.     call    bufreset        ; reset buffer
  678.     stc                ; say error condition
  679.     ret
  680. esceoc    endp
  681.  
  682. ; Help. Question mark entered by user.  Display all the keywords that match
  683. ; user text. If text is null then use external help if available; otherwise,
  684. ; display all keywords in the table. Removes question mark from buffer and
  685. ; invokes reparse of command line to-date. User word starts at cmsptr and
  686. ; is cmsiz bytes long.
  687. cmkyhlp    proc    near
  688.     xor    cx,cx            ; clear number of keyword (none yet)
  689.     cmp    cmsiz,0            ; user text given?
  690.     jne    cmkyh1            ; ne = yes, use matching keywords
  691.     cmp    cmhlp,0            ; external help given?
  692.     jne    cmkyh6            ; yes, use it instead of full table
  693. cmkyh1:    mov    temp,0            ; count # chars printed on this line
  694.     mov    bx,cmptab        ; beginning of kw table
  695.     mov    ch,[bx]            ; length of table
  696.     xor    cl,cl            ; no keywords or help displayed yet
  697.     inc    bx            ; point at CNT field
  698. cmkyh2:    cmp    cmsiz,0            ; length of user word
  699.     je    cmkyh3            ; e = null, use full table
  700.     call    cmpwrd            ; compare keyword with user word
  701.     jc    cmkyh5            ; c = no match, get another keyword
  702. cmkyh3:    mov    ax,[bx]            ; length of table keyword
  703.     add    byte ptr temp,al    ; count chars printed so far
  704.     cmp    temp,76            ; will this take us beyond column 78?
  705.     jbe    cmkyh4            ; be = no, line has more room
  706.     mov    byte ptr temp,al    ; reset the count
  707.     mov    ah,prstr
  708.     mov    dx,offset crlf        ; break the line
  709.     int    dos
  710. cmkyh4:    or    cl,cl            ; any keywords found yet?
  711.     jnz    cmkyh4a            ; nz = yes
  712.     mov    dx,offset cmin01    ; start with One of the following: msg
  713.     mov    ah,prstr
  714.     int    dos
  715.     inc    cl            ; say one keyword has been found
  716. cmkyh4a:mov    dl,spc            ; put two spaces before each keyword
  717.     mov    ah,conout
  718.     int    dos
  719.     int    dos
  720.     add    temp,2            ; count output chars
  721.     mov    di,bx            ; get current keyword structure
  722.     add    di,2            ; text part
  723.     push    cx
  724.     mov    cx,[bx]            ; string length to cx, offset to di
  725.     call    prtscr            ; display counted string
  726.     pop    cx
  727. cmkyh5:    dec    ch            ; are we at end of table?
  728.     jle    cmkyh7            ; le = yes, quit now
  729.     add    bx,[bx]            ; next keyword, add CNT chars to bx
  730.     add    bx,4            ; skip CNT and 16 bit value
  731.     jmp    cmkyh2            ; go examine this keyword
  732.  
  733. cmkyh6:    mov    si,cmhlp        ; external help text in seg data1
  734.     xor    bx,bx            ; line counter
  735.     push    es
  736.     mov    ax,seg data1        ; all help text is in data1
  737.     mov    es,ax
  738.     cld
  739. cmkyh10:mov    al,es:[si]        ; read a help msg byte
  740.     inc    si
  741.     cmp    al,'$'            ; end of message?
  742.     je    cmkyh14            ; e = yes, stop
  743. cmkyh11:mov    ah,conout
  744.     mov    dl,al
  745.     int    dos            ; display byte
  746.     cmp    dl,LF            ; line break?
  747.     jne    cmkyh10            ; ne = no
  748.     inc    bl            ; count line
  749.     cmp    bl,dos_bottom        ; (24) time for a more msg?
  750.     jbe    cmkyh10            ; be = not yet
  751.     xor    bl,bl            ; reset line count
  752.     call    iseof            ; are we at EOF, such as from disk?
  753.     jc    cmkyh10            ; c = yes, ignore more msg
  754.     mov    ah,prstr
  755.     mov    dx,offset moremsg    ; "... more..." msg
  756.     int    dos
  757. cmkyh13:mov    ah,coninq        ; read the char from file, not device
  758.     int    dos
  759.     cmp    al,3            ; a ^C?
  760.     je    short cmkyh14        ; e = yes, stop the display
  761.     push    bx            ; save line counter
  762.     push    es            ; and read pointer
  763.     push    si
  764.     call    fctlu            ; clear display's line, reuse it
  765.     pop    si
  766.     pop    es
  767.     pop    bx
  768.     jmp    short cmkyh10        ; continue
  769. cmkyh14:pop    es
  770.     inc    cl            ; say gave help already
  771.  
  772. cmkyh7:    or    cl,cl            ; found any keywords?
  773.     jnz    cmkyh9            ; nz = yes
  774.     mov    cx,cmsiz        ; length of word
  775.     or    cx,cx
  776.     jg    cmkyh8            ; g = something to show
  777.     push    dx
  778.     mov    ah,prstr
  779.     mov    dx,offset cmer01    ; command word expected
  780.     int    dos
  781.     pop    dx
  782.     jmp    prserr
  783. cmkyh8:    mov    kwstat,0        ; set keyword not-found status
  784.     call    cmskw            ; display offending keyword
  785. cmkyh9:    mov    ah,prstr        ; start a fresh line
  786.     mov    dx,offset crlf
  787.     int    dos
  788.     call    bufdel            ; unwrite the "?" (cmrptr is there)
  789.     ret
  790. cmkyhlp    endp
  791.  
  792. ; See if keyword is ambiguous or not from what the user has typed in.
  793. ; Return carry set if word is ambiguous or not found, carry clear otherwise.
  794. ; Uses table pointed at by cmptab, user text pointed at by cmsptr and length
  795. ; in cmsiz.
  796. cmambg    proc    near
  797.     push    bx
  798.     push    cx
  799.     push    dx
  800.     xor    dl,dl            ; count keyword matches so far
  801.     mov    bx,cmptab        ; look at start of keyword table
  802.     mov    cl,[bx]            ; get number of entries in table
  803.     xor    ch,ch            ; use cx as a counter
  804.     jcxz    cmamb8            ; z = no table so always ambiguous
  805.     inc    bx            ; look at CNT byte of keyword
  806. cmamb4:    call    cmpwrd            ; user vs table words, same?
  807.     jc    cmamb6            ; c = no match
  808.     inc    dl            ; count this as a match
  809.     cmp    dl,1            ; more than one match?
  810.     ja    cmamb8            ; a = yes, quit now
  811. cmamb6:    add    bx,[bx]            ; add CNT chars to bx
  812.     add    bx,4            ; skip CNT and 16 bit value
  813.     loop    cmamb4            ; do rest of keyword table
  814.     cmp    dl,1            ; how many matches were found?
  815.     jne    cmamb8            ; ne = none or more than 1: ambiguous
  816.     pop    dx            ; restore main registers
  817.     pop    cx
  818.     pop    bx
  819.     clc
  820.     ret                ; ret = not ambiguous
  821. cmamb8:    pop    dx            ; restore main registers
  822.     pop    cx
  823.     pop    bx
  824.     stc
  825.     ret                ; return ambiguous or not found
  826. cmambg    endp
  827.  
  828. ; Compare user text with keyword, abbreviations are considered a match.
  829. ; Enter with bx pointing at keyword table CNT field for a keyword.
  830. ; Return carry clear if they match, set if they do not match. User text
  831. ; pointed at by cmsptr and length is in cmsiz.
  832. ; Registers preserved.
  833.  
  834. cmpwrd    proc    near
  835.     push    cx
  836.     mov    cx,cmsiz        ; length of user's text
  837.     jcxz    cmpwrd2            ; z: null user word matches no keyword
  838.     cmp    cx,[bx]            ; user's text longer than keyword?
  839.     ja    cmpwrd2            ; a = yes, no match
  840.     push    ax
  841.     push    bx
  842.     push    si
  843.     add    bx,2                ; point at table's keyword text
  844.     mov    si,cmsptr        ; buffer ptr to user input
  845.     cld
  846. cmpwrd1:lodsb                ; user text
  847.     mov    ah,[bx]            ; keyword text
  848.     inc    bx            ; next keyword letter
  849.     call    tolowr            ; force lower case on both chars
  850.     cmp    ah,al            ; same?
  851.     loope    cmpwrd1            ; e = same so far
  852.     pop    si
  853.     pop    bx
  854.     pop    ax
  855.     jne    cmpwrd2            ; ne = mismatch
  856.     pop    cx            ; recover keyword counter
  857.     clc                ; they match
  858.     ret
  859. cmpwrd2:pop    cx            ; recover keyword counter
  860.     stc                ; they do not match
  861.     ret
  862. cmpwrd    endp
  863.  
  864. ; Get pointer to keyword structure using user text. Uses keyword table
  865. ; pointed at by cmptab and cmsiz holding length of user's keyword (cmpwrd
  866. ; needs cmsptr pointing at user's keyword and length of cmsiz).
  867. ; Structure pointer returned in BX.
  868. ; Return carry clear for success and carry set for failure. Modifies BX.
  869. getkw    proc    near
  870.     push    cx
  871.     mov    kwstat,0        ; keyword status, set to not-found
  872.     cmp    cmsiz,0            ; length of user word, empty?
  873.     je    getkw3            ; e = yes, fail
  874.     mov    bx,cmptab        ; table of keywords
  875.     mov    cl,[bx]            ; number of keywords in table
  876.     xor    ch,ch
  877.     jcxz    getkw3            ; z = none, fail
  878.     inc    bx            ; point to first
  879. getkw1:    call    cmpwrd            ; compare user vs table words
  880.     jc    getkw2            ; c = failed to match word, try next
  881.     mov    kwstat,1        ; say found one keyword, maybe more
  882.     push    dx
  883.     mov    dx,cmsiz        ; users word length
  884.     cmp    [bx],dx            ; same length (end of keyword)?
  885.     pop    dx
  886.     je    getkw4            ; e = yes, exact match. Done
  887.     call    cmambg            ; ambiguous?
  888.     jnc    getkw4            ; nc = unique, done, return with bx
  889.     mov    kwstat,2        ; say more than one such keyword
  890. getkw2:    add    bx,[bx]            ; next keyword, add CNT chars to bx
  891.     add    bx,4            ; skip CNT and 16 bit value
  892.     loop    getkw1            ; do all, exhaustion = failure
  893. getkw3:    pop    cx
  894.     stc                ; return failure
  895.     ret
  896. getkw4:    pop    cx
  897.     clc                ; return success
  898.     ret
  899. getkw    endp
  900.  
  901. ; show offending keyword message. Cmsptr points to user word,
  902. ; cmsiz has length. Modifies AX, CX, and DX.
  903. cmskw    proc    near
  904.     cmp    comand.cmquiet,0    ; Quiet mode?
  905.     je    cmskw0            ; e = no, regular mode
  906.     ret                ; else say nothing
  907. cmskw0:    mov    ah,prstr        ; not one of the above terminators
  908.     mov    dx,offset cmer02    ; '?Word "'
  909.     int    dos
  910.     mov    ah,conout
  911.     mov    cx,cmsiz        ; length of word
  912.     jcxz    cmskw3            ; z = null
  913.     mov    ah,conout
  914.     push    si
  915.     mov    si,cmsptr        ; point to word
  916.     cld
  917. cmskw1:    lodsb
  918.     cmp    al,' '            ; control code?
  919.     jae    cmskw2            ; ae = no
  920.     push    ax
  921.     mov    dl,5eh            ; caret
  922.     int    dos
  923.     pop    ax
  924.     add    al,'A'-1        ; plus ascii bias
  925. cmskw2:    mov    dl,al            ; display chars in word
  926.     int    dos
  927.     loop    cmskw1
  928.     pop    si
  929. cmskw3:    mov    dx,offset cmer03    ; '" not usable here.'
  930.     cmp    kwstat,1        ; kywd status from getkw, not found?
  931.     jb    cmskw4            ; b = not found, a = ambiguous
  932.     mov    dx,offset cmer04    ; '" ambiguous'
  933. cmskw4:    mov    ah,prstr
  934.         int    dos
  935.     ret
  936. cmskw    endp
  937. ;;;;;;;;;; end of support routines for keyword parsing.
  938.  
  939. ; CMLINE: Parse    arbitrary text up to a CR.
  940. ; CMWORD: Parse text up to first trailing space, or if starts with ()
  941. ;  then consume the line.
  942. ; Enter with BX = pointer to output buffer
  943. ; DX pointing to help text. Produces asciiz string. Return updated pointer in
  944. ; BX and output size in AX. Leading spaces are omitted unless comand.cmwhite
  945. ; is non-zero (cleared upon exit). It does not need to be followed by the
  946. ; usual call to confirm the line. Byte comand.cmblen can be used to specify
  947. ; the length of the caller's buffer; cleared to zero by this command to
  948. ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes.
  949. ; If the line starts with an opening curly brace, then physical lines are
  950. ; automatically continued until the closing curly brace is obtained.
  951. ; Continuation breaks are a comma in the data stream and a CR/LF to the
  952. ; visual screen. Material after the closing brace is discarded.
  953. ;
  954. ; Lines and words starting on a curly brace and ending on a matching
  955. ; curly brace plus optional whitespace have the trailing whitespace
  956. ; omitted and both outer braces removed.
  957. cmtxt    proc    far
  958.     mov    cmptab,bx        ; save pointer to data buffer
  959.     xor    ax,ax
  960.     mov    word ptr [bx],ax    ; clear result buffer
  961.     mov    cmhlp,dx        ; save the help message
  962.     mov    cmsiz,ax        ; init the char count
  963.     mov    parencnt,al        ; clear count of parentheses
  964.     cmp    comand.cmblen,ax    ; length of user's buffer given?
  965.     jne    cmtxt1            ; ne = yes
  966.     mov    comand.cmblen,127    ; else set 127 byte limit plus null
  967. cmtxt1:    cmp    comand.cmwhite,al    ; allow leading whitespace?
  968.     jne    cmtxt2            ; ne = yes
  969.     mov    cmsflg,0ffh        ; omit leading space
  970. cmtxt2:    call    cmgtch            ; get a char
  971.     jc    cmtxt3            ; c = terminator 
  972.     jmp    cmtxt10            ; put char into the buffer
  973.  
  974. cmtxt3:    cmp    ah,' '            ; space terminator?
  975.     jne    cmtxt4            ; ne = no
  976.     cmp    cmkind,cmline        ; parsing lines?
  977.     je    cmtxt10            ; e = yes, put space in the buffer
  978.     mov    bx,cmptab        ; words, check on () delimiters
  979.     sub    bx,cmsiz
  980.     cmp    byte ptr [bx],'('    ; started word with paren?
  981.     jne    cmtxt6            ; ne = no, it's a terminator
  982.     cmp    parencnt,0        ; outside parens?
  983.     jne    cmtxt10            ; ne = no, use as data inside (..)
  984.     jmp    cmtxt6            ; space is terminator
  985.  
  986. cmtxt4:    cmp    ah,escape        ; escape?
  987.     jne    cmtxt5            ; ne = no
  988.     call    esceoc            ; do normal escape end-of-command
  989.     jmp    short cmtxt1        ; try again
  990.  
  991. cmtxt5:    cmp    ah,'?'            ; asking a question?
  992.     je    cmtxt8            ; e = yes
  993.     cmp    ah,CR            ; bare CR?
  994.     je    cmtxt6            ; e = yes, always a terminator
  995.     cmp    cmkind,cmline        ; reading a line?
  996.     je    cmtxt10            ; e = yes, other terms go into buffer
  997.                     ; else terminators terminate words
  998.  
  999. cmtxt6:    mov    bx,cmptab        ; pointer into destination array
  1000.     mov    byte ptr[bx],0        ; put null terminator into the buffer
  1001.     xchg    ax,cmsiz        ; return count in AX
  1002.     or    ax,ax            ; empty?
  1003.     jz    cmtxt7a            ; z = yes
  1004.  
  1005. cmtxt7:    push    si            ; remove terminating curly braces
  1006.     mov    si,cmptab        ; where next output byte goes
  1007.     sub    si,ax            ; minus read, equals start of buffer
  1008.     mov    cx,ax            ; count to cx for unbrace
  1009.     call    unbrace            ; outer curly brace remover
  1010.     mov    ax,cx            ; returned length back to AX
  1011.     mov    bx,si
  1012.     add    bx,ax            ; bx points to null terminator
  1013.     pop    si
  1014. cmtxt7a:call    optionclr        ; clear parser options
  1015.     cmp    cmkind,cmline        ; lines?
  1016.     jne    cmtxt7f            ; ne = no, words
  1017.     call    rprompt            ; restore master prompt level
  1018. cmtxt7f:clc
  1019.     ret
  1020.  
  1021. cmtxt8:    inc    cmrptr            ; count the ?
  1022.     cmp    cmsiz,0            ; Is "?" first char?
  1023.     jne    cmtxt10            ; ne = no, just add to buffer
  1024.     dec    cmrptr
  1025.     cmp    cmhlp,0            ; external help given?
  1026.     jne    cmtxt9            ; ne = yes
  1027.     mov    cmhlp,offset cmin00    ; confirm with c/r msg
  1028. cmtxt9:    push    cmsiz
  1029.     mov    cmsiz,0            ; so we do not use keyword table
  1030.     call    cmkyhlp            ; use our help message
  1031.     pop    cmsiz
  1032.     jmp    cmtxt2
  1033.  
  1034. cmtxt10:inc    cmsiz            ; increment the output count
  1035.     mov    bx,cmptab        ; pointer into destination array
  1036.     mov    [bx],ah            ; put char into the buffer
  1037.     cmp    cmkind,cmword        ; word?
  1038.     jne    cmtxt12            ; ne = no, line
  1039.     cmp    ah,'('            ; opening paren?
  1040.     jne    cmtxt11            ; ne = no
  1041.     inc    parencnt        ; count up parens
  1042.     jmp    short cmtxt12
  1043. cmtxt11:cmp    ah,')'            ; closing paren?
  1044.     jne    cmtxt12            ; ne = no
  1045.     sub    parencnt,1
  1046.     jns    cmtxt12            ; ns = no underflow
  1047.     mov    parencnt,1        ; don't underflow
  1048. cmtxt12:inc    bx
  1049.     mov    cmptab,bx
  1050.     mov    cx,cmsiz        ; length of command so far
  1051.     cmp    cx,4            ; got four chars?
  1052.     jne    cmtxt12a        ; ne = no
  1053.     cmp    comand.cmarray,0    ; worry about \&<char> as destination?
  1054.     je    cmtxt12a        ; e = no
  1055.     cmp    word ptr [bx-4],'&\'    ; starts with array indicator?
  1056.     jne    cmtxt12a        ; ne = no
  1057.     mov    comand.cmper,0        ; allow substitution in [...]
  1058.     mov    comand.cmarray,0    ; say have done array destination test
  1059. cmtxt12a:
  1060.     cmp    cx,comand.cmblen    ; buffer filled?
  1061.     ja    cmtxt14            ; a = yes, declare error
  1062.     jb    cmtxt13            ; a = not filled yet
  1063.     mov    ah,conout        ; notify user that the buffer is full
  1064.     mov    dl,bell
  1065.     int    dos
  1066.     jmp    cmtxt6            ; quit
  1067.  
  1068. cmtxt13:jmp    cmtxt2
  1069.  
  1070. cmtxt14:mov    ah,prstr
  1071.     mov    dx,offset cmer09
  1072.     int    dos
  1073.     jmp    prserr            ; declare parse error
  1074. cmtxt    endp
  1075.  
  1076.  
  1077. ; This routine gets a confirm (CR) and displays any extra non-blank text.
  1078. ; errflag non-zero means suppress "extra text" display in this routine
  1079. ; because another routine is handling errors.
  1080. cmcfrm    proc    far
  1081.     mov    bracecnt,0
  1082.     mov    comand.cmper,1        ; do not react to \%x substitutions
  1083.     cmp    cmrptr,offset cmdbuf    ; empty buffer?
  1084.     je    cmcfr7            ; e = yes
  1085.     mov    bx,cmrptr        ; where to read next
  1086.     dec    bx            ; last read byte
  1087.     cmp    byte ptr [bx],CR    ; terminated already?
  1088.     je    cmcfr7            ; e = yes
  1089.  
  1090. cmcfr1:    mov    cmsflg,0ffh        ; set space-seen flag (skip spaces)
  1091.     call    cmgtch            ; get a char
  1092.     push    cmrptr
  1093.     pop    temp            ; remember first non-space position
  1094.     jc    cmcfr4            ; c = terminator
  1095.     dec    temp            ; backup to text char
  1096. cmcfr3:    mov    cmsflg,0ffh        ; set space-seen flag (skip spaces)
  1097.     call    cmgtch
  1098.     jnc    cmcfr3            ; read until terminator
  1099. cmcfr4:    cmp    ah,' '
  1100.     je    cmcfr3            ; ignore ending on space
  1101.     cmp    ah,escape        ; escape?
  1102.     jne    cmcfr5            ; ne = no
  1103.     call    esceoc            ; do standard end of cmd on escape
  1104.     mov    ax,cmrptr
  1105.     cmp    ax,temp            ; started text yet?
  1106.     je    cmcfr1            ; e = no
  1107.     jmp    short cmcfr3        ; try again
  1108. cmcfr5: cmp    ah,'?'            ; curious?
  1109.         jne    cmcfr6            ; ne = no
  1110.     mov    cmhlp,offset cmin00    ; msg Confirm with c/r
  1111.     mov    cmsiz,0            ; no keyword
  1112.     mov    errflag,0
  1113.     jmp    cmkyhlp            ; do help
  1114. cmcfr6:    cmp    ah,cr            ; the confirmation char?
  1115.     jne    cmcfr3            ; ne = no
  1116.     cmp    errflag,0        ; already doing one error?
  1117.     jne    cmcfr7            ; ne = yes, skip this one
  1118.     mov    cx,cmrptr        ; pointer to terminator
  1119.     mov    dx,temp            ; starting place
  1120.     sub    cx,dx            ; end minus starting point = length
  1121.     jle    cmcfr7            ; le = nothing to display
  1122.     push    dx            ; save source pointer
  1123.     mov    ah,prstr
  1124.     mov    dx,offset cmer07    ; ?Ignoring extras
  1125.     int    dos
  1126.     pop    dx
  1127.     mov    bx,1            ; stdout handle, cx=count, dx=src ptr
  1128.     mov    ah,write2        ; allow embedded dollar signs
  1129.     int    dos
  1130.     mov    ah,prstr
  1131.     mov    dx,offset cmer08    ; trailer msg
  1132.     int    dos
  1133. cmcfr7:    xor    ax,ax
  1134.     mov    errflag,al
  1135.     call    optionclr        ; clear parser options
  1136.     clc                ; return confirmed
  1137.     ret
  1138. cmcfrm    endp
  1139.  
  1140. ;;; Routines to get and edit incoming text.
  1141.  
  1142. ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string
  1143. ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0
  1144. ; then treat '\%' as literal characters. If no matching parameter exists
  1145. ; just remove '\%x'. Ditto for \v(variable). Returns carry clear if nothing
  1146. ; done, else carry set and new text already placed in user's buffer.
  1147. ; Includes \v(variable) and \$(Environment variable) and \m(macro name).
  1148. ; Uses depth-first recursion algorithm. All registers preserved.
  1149. subst    proc    near
  1150.     cmp    comand.cmper,0        ; recognize '\%','\v(','\$(','\m(' ?
  1151.     jne    subst0            ; ne = no, treat as literals
  1152.     cmp    taklev,0        ; in a Take file?
  1153.     je    subst0a            ; e = no
  1154.     push    bx
  1155.     mov    bx,takadr
  1156.     cmp    [bx].takper,0        ; expand macros?
  1157.     pop    bx
  1158.     je    subst0a            ; e = yes
  1159. subst0:    clc                ; report out to application
  1160.     ret
  1161. subst0a:cmp    subtype,'0'        ; doing \numbers already?
  1162.     jne    subst0b            ; ne = no
  1163.     jmp    subst30            ; continue to parse digits
  1164.  
  1165. subst0b:cmp    ah,'\'            ; is it the first char of the pattern?
  1166.     jne    subst1            ; ne = no, try next
  1167.     cmp    subcnt,1        ; \\?
  1168.     jne    subst0c            ; ne = no
  1169.     mov    subcnt,0        ; clear state and pass back one \
  1170.     clc
  1171.     ret
  1172. subst0c:cmp    endedbackslash,0    ; ended sub macro on backslash?
  1173.     jne    subst1a            ; ne = yes
  1174.     inc    subcnt            ; say first char (\) is matched
  1175.     and    subcnt,1        ; modulo 2
  1176.     mov    subtype,ah
  1177.     stc                ; do not pass to application
  1178.     ret
  1179.  
  1180. subst1:    cmp    subcnt,1        ; first char matched already?
  1181.     ja    subst3            ; a = first two have been matched
  1182.     jb    subst0            ; b = none yet
  1183.     mov    al,ah            ; test kind of substitution
  1184.     or    al,20h            ; convert to lower case
  1185.     cmp    ah,'%'            ; second match char, same?
  1186.     je    subst2            ; e = yes
  1187.     cmp    al,'v'            ; \v(...)?
  1188.     je    subst2            ; e = yes
  1189.     cmp    al,'$'            ; \$(..)?
  1190.     je    subst2            ; e = yes
  1191.     cmp    al,'m'            ; \m(..)?
  1192.     je    subst2            ; e = yes
  1193.     cmp    comand.cmarray,0    ; allow array recognition?
  1194.     jne    subst1d            ; ne = no
  1195.     cmp    al,'&'            ; \&<char>[..]?
  1196.     je    subst2            ; e = yes
  1197. subst1d:                ; start \number
  1198.     cmp    comand.cmdonum,0    ; convert \numbers allowed?
  1199.     je    subst1c            ; e = no
  1200.     cmp    ah,'{'            ; \{number}?
  1201.     je    subst1b            ; e = yes
  1202.     cmp    al,'d'            ; \Dnumber?
  1203.     je    subst1b            ; e = yes
  1204.     cmp    al,'o'            ; \Onumber?
  1205.     je    subst1b            ; e = yes
  1206.     cmp    al,'x'            ; \Xnumber?
  1207.     je    subst1b            ; e = yes
  1208.     cmp    ah,'0'            ; in range for numbers?
  1209.     jb    subst1c            ; b = no
  1210.     cmp    ah,'9'
  1211.     ja    subst1c            ; a = no
  1212. subst1b:mov    subtype,'0'        ; mark as numeric
  1213.     mov    subcnt,2        ; matched second introducer
  1214.     push    bx
  1215.     mov    bx,cmrptr
  1216.     sub    bx,2            ; point at \
  1217.     mov    numtmp,bx        ; where \number starts
  1218.     pop    bx
  1219.     stc                ; do not pass to application
  1220.     ret
  1221.                     ; end \number
  1222. subst1c:cmp    al,'f'            ; \fname(..)?
  1223.     jne    subst1a            ; ne = no
  1224.     mov    subtype,al        ; remember type
  1225.     inc    subcnt            ; count match
  1226.     jmp    subst10            ; read more bytes internally
  1227.  
  1228. subst1a:push    ax            ; replay bytes as literals
  1229.     mov    al,subcnt        ; previously matched bytes
  1230.     xor    ah,ah
  1231.     inc    ax            ; plus current byte
  1232.     sub    cmrptr,ax
  1233.     mov    replay_cnt,ax        ; trailer bytes, amount to replay
  1234.     pop    ax
  1235.     mov    subcnt,0        ; mismatch, clear match counter
  1236.     mov    subtype,0
  1237.     mov    endedbackslash,0
  1238.     stc                ; reread from input
  1239.     ret
  1240.  
  1241. subst2:    cmp    al,'%'            ; starting \%?
  1242.     jne    subst2b            ; ne = no
  1243.     cmp    subtype,'v'        ; doing \v(..)? (dirs of c:\%foobar)
  1244. ;;;    je    subst1a            ; e = yes, don't expand \% inside
  1245.  
  1246. subst2b:mov    subtype,al        ; remember kind of substitution
  1247.     inc    subcnt            ; count match
  1248.     cmp    al,'%'
  1249.     je    subst10
  1250.     cmp    al,'&'            ; doing \&<char>[..]?
  1251.     je    subst10            ; e = yes
  1252.     stc                ; do not pass to application
  1253.     ret
  1254.  
  1255. subst3:    cmp    subtype,'v'        ; doing \v(..)?
  1256.     je    subst3a            ; e = yes
  1257.     cmp    subtype,'$'        ; doing \$(..)?
  1258.     je    subst3a            ; e = yes
  1259.     cmp    subtype,'m'        ; doing \m(..)?
  1260.     je    subst3a            ; e = yes
  1261.     mov    subcnt,0        ; clear match counter
  1262.     jmp    subst1a            ; no match
  1263.  
  1264. subst3a:cmp    ah,'('            ; have leading parenthesis?
  1265.     jne    subst1a            ; ne = no, mismatch, exit
  1266.     jmp    subst10            ; process \v(..), \$(..), \m(..)
  1267.  
  1268.                     ; \fname(..), \m(..), \v(..), \$(..)
  1269. subst10:push    bx            ; save working regs
  1270.     push    cx
  1271.     push    es
  1272.     push    cmptab            ; save current keyword parsing parms
  1273.     push    cmsptr
  1274.     push    cmsiz
  1275.     push    valtmp
  1276.     push    dx
  1277.     mov    subcnt,0        ; clear match counter
  1278.     mov    cmhlp,0
  1279.     mov    ax,cmrptr
  1280.     mov    valtmp,ax        ; remember current read pointer
  1281.     mov    cmsptr,ax        ; start of word
  1282.     mov    cmptab,offset valtab    ; table of keywords for \v(..)
  1283.     cmp    subtype,'v'        ; \v(..)?
  1284.     je    subst10a        ; e = yes
  1285.     mov    cmptab,offset envtab    ; Environment variable table \$(..)
  1286.     cmp    subtype,'$'        ; \$(..)?
  1287.     je    subst10a        ; e = yes
  1288.     mov    cmptab,offset evaltab    ; evaluate (name) table
  1289.     cmp    subtype,'f'        ; \fname()?
  1290.     je    subst10a        ; e = yes
  1291.     mov    cmptab,offset mcctab    ; main Macro table for \m(..)
  1292. subst10a:mov    cmsflg,0        ; see leading spaces/tabs
  1293.     mov    cmsiz,0            ; word size
  1294. subst11:mov    ch,subtype        ; save \type
  1295.     push    cx
  1296.     call    cmgtch            ; read a character into ah
  1297.     rcl    al,1            ; put carry bit into low bit of al
  1298.     pop    cx
  1299.     xchg    ch,subtype        ; recover \type
  1300.     rcr    al,1            ; recover carry bit
  1301.     jnc    subst13            ; nc = non-terminator
  1302.  
  1303.     cmp    subtype,'%'        ; \%<char>?
  1304.     jne    subst11d        ; ne = no
  1305.     cmp    ah,' '            ; question or similar?
  1306.     jbe    subst13            ; be = no, a funny
  1307.     inc    cmrptr            ; accept the terminator as data
  1308.     jmp    subst13
  1309. subst11d:
  1310.     cmp    subtype,'m'        ; discard trailing spaces for these
  1311.     je    subst11b
  1312.     cmp    subtype,'v'
  1313.     je    subst11b
  1314.     cmp    subtype,'&'
  1315.     je    subst11b
  1316.     cmp    subtype,'$'
  1317.     jne    subst11c
  1318. subst11b:cmp    ah,' '            ; space terminator?
  1319.     je    subst11            ; e = yes, ignore it
  1320. subst11c:cmp    ah,'?'            ; need help?
  1321.     jne    subst11a        ; ne = no
  1322.     call    cmkyhlp            ; display help information
  1323.     jmp    short subst11
  1324.  
  1325. subst11a:cmp    ah,escape        ; escape?
  1326.     jne    subst12            ; ne = no
  1327.     cmp    in_showprompt,0        ; making new prompt?
  1328.     jne    subst12            ; ne = yes, include literal escape
  1329.     call    cmkyesc            ; process escape
  1330.     jmp    short subst11        ; failed, ignore esc, read more
  1331.                     ;
  1332. subst12:cmp    subtype,'f'        ; \fname(..)?
  1333.     je    subst12a        ; e = yes, else no need to replay
  1334.     jmp    subst17
  1335.  
  1336. subst12a:mov    bx,cmsptr        ; where \fname() word started
  1337.     sub    bx,2            ; back over "\f" part
  1338.     mov    cx,cmrptr        ; last read + 1
  1339.     sub    cx,bx            ; bytes in \foobar
  1340.     mov    cmrptr,bx        ; reread point is the \
  1341.     add    replay_cnt,cx        ; bytes to reread (+external \ fails)
  1342.     jmp    subst17
  1343.  
  1344. subst13:inc    cmsiz            ; count user chars
  1345.     cmp    subtype,'%'        ; \%<char>?
  1346.     jne    subst13j        ; ne = no
  1347.     cmp    ah,'0'            ; large enough?
  1348.     jb    subst17            ; b = no, fail
  1349.     mov    cmsiz,3+1        ; size is three bytes, plus dec below
  1350.     sub    cmsptr,2        ; backup to \
  1351.     jmp    short subst13b
  1352. subst13j:cmp    subtype,'f'        ; \fname(...)?
  1353.     jne    subst13a        ; ne = no
  1354.     cmp    ah,'('            ; look for "(" as terminator
  1355.     je    subst13b        ; e = found, lookup "name" as keyword
  1356.     cmp    ah,'0'            ; numeric?
  1357.     jb    subst12a        ; b = no, end of string
  1358.     cmp    ah,'9'
  1359.     jbe    subst11            ; be = yes, keep reading
  1360.     call    tolowr            ; to lower case
  1361.     cmp    ah,'z'
  1362.     ja    subst12a        ; a = non-alpha, end of string
  1363.     cmp    ah,'a'
  1364.     jae    subst11            ; ae = alpha, keep reading
  1365.     jmp    short subst12a        ; yes, stop here
  1366.  
  1367. subst13a:cmp    subtype,'&'        ; \&c[..]?
  1368.     jne    subst13i        ; ne = no
  1369.     cmp    ah,']'            ; end bracket?
  1370.     jne    subst11            ; ne = no, keep going
  1371.     jmp    short subst13b        ; have it
  1372. subst13i:cmp    ah,')'            ; end bracket?
  1373.     jne    subst11            ; ne = no, keep looking
  1374. subst13b:dec    cmsiz            ; omit user's ')' from tests
  1375.     cmp    subtype,'&'        ; \&char[..]?
  1376.     je    subst20            ; e = yes, have all bytes
  1377.     cmp    subtype,'$'        ; \$(..)?
  1378.     je    subst13c        ; e = yes, no keyword in table
  1379.     push    cmsptr            ; save pointer
  1380. subst13g:mov    bx,cmsptr
  1381.     cmp    byte ptr [bx],' '    ; leading spaces?
  1382.     jne    subst13h        ; ne = no
  1383.     inc    cmsptr            ; look at next char
  1384.     jmp    short subst13g
  1385. subst13h:call    getkw            ; \m(..) and \v(..) test for keyword
  1386.     pop    cmsptr
  1387.     jc    subst12            ; c = failure
  1388.     jmp    short subst13d        ; success
  1389.  
  1390. subst13c:call    envvar            ; search Environment for the word
  1391.     jc    subst12            ; c = failure
  1392.     mov    bx,V_environ        ; set bx to kind of value for valtoa
  1393.     jmp    short subst13f
  1394.  
  1395. subst13d:cmp    subtype,'f'        ; doing \fname(...)?
  1396.     jne    subst13f        ; ne = no
  1397.     mov    subcnt,0        ; clear \f match indicator
  1398.     add    bx,[bx]            ; add length of keyword text (CNT)
  1399.     add    bx,2            ; point at value field
  1400.     mov    bx,[bx]            ; get value
  1401. subst13e:mov    evaltype,bx        ; remember kind of operation
  1402.     call    evaltoa            ; do \fname argument evaluation
  1403.     jc    subst12a        ; error, reparse
  1404.     jmp    subst17
  1405.  
  1406. subst13f:mov    ax,valtmp        ; where word started
  1407.     sub    ax,3            ; backup to "\v(" or "\$("
  1408.     cmp    subtype,'%'        ; doing \%<char>?
  1409.     jne    subst13k        ; ne = no
  1410.     inc    ax            ; one less field byte than others
  1411. subst13k:mov    cmrptr,ax        ; write output where backslash was
  1412.     call    bufreset        ; resets cmwptr too
  1413.     xor    dx,dx            ; signal valtoa to not add trailing sp
  1414.     cmp    subtype,'$'        ; \$(..)?
  1415.     je    subst14            ; e = yes, no keyword structure
  1416.     mov    cx,[bx]            ; bx = structure pointer, cx=keyw len
  1417.     add    cx,2            ; skip count byte
  1418.     add    bx,cx            ; point at 16 bit value field
  1419.     mov    bx,[bx]            ; get value to bx for valtoa
  1420. subst14:cmp    taklev,maxtak        ; room in take level?
  1421.     jb    subst15            ; b = yes
  1422.     mov    dx,offset stkmsg    ; out of work space msg
  1423.     mov    ah,prstr        ; display error message
  1424.     int    dos
  1425.     jmp    subst17
  1426.  
  1427.                     ; \&char[..]
  1428. subst20:mov    ax,valtmp        ; where <char> started
  1429.     mov    bx,ax
  1430.     cmp    byte ptr [bx+1],'['
  1431.     jne    subst12a
  1432.  
  1433.     sub    ax,2            ; backup to "\&<char>["
  1434.     mov    cmrptr,ax        ; write output where backslash was
  1435.     add    cmsptr,2        ; point after "[" for index math
  1436.     call    bufreset        ; resets cmwptr too
  1437.     push    si
  1438.     mov    si,cmsptr        ; start of string after "["
  1439.     mov    cx,1024            ; cmsiz ignores leading spaces
  1440. subst20a:cmp    byte ptr [si],' '    ; remove leading spaces
  1441.     jne    subst20b
  1442.     inc    si
  1443.     loop    subst20a
  1444. subst20b:push    si            ; save starting point
  1445.     mov    cx,1024            ; assumed max string in [..]
  1446.     xor    bx,bx
  1447.     cld
  1448. subst20c:lodsb
  1449.     cmp    al,']'            ; terminator?
  1450.     je    subst20e        ; e = yes
  1451.     inc    bx            ; count string chars
  1452. subst20d:loop    subst20c
  1453. subst20e:pop    si            ; recover starting point
  1454.     push    si
  1455.     mov    domath_ptr,si        ; ptr to string
  1456.     mov    domath_cnt,bx        ; length of string
  1457.     call    domath            ; string to binary in dx:ax
  1458.     pop    si
  1459.     mov    si,cmsptr        ; points just after "\&<char>["
  1460.     mov    bl,[si-2]        ; back up to <char>
  1461.     cmp    bl,'_'            ; arg list \$_[list element]?
  1462.     jne    subst20g        ; ne = no
  1463.     pop    si            ; clean stack
  1464.     cmp    ax,9            ; too large?
  1465.     ja    subst17            ; a = yes, do nothing
  1466.     push    ax
  1467.     mov    ax,4+2            ; want four bytes plus count
  1468.     call    malloc            ; to seg in ax
  1469.     mov    es,ax
  1470.     pop    ax
  1471.     mov    word ptr es:[2],'%\'    ; compose string \%<digit>
  1472.     add    al,'0'            ; use index of 0..9
  1473.     xor    ah,ah
  1474.     mov    word ptr es:[4],ax    ; null terminate
  1475.     mov    cx,3
  1476.     mov    word ptr es:[0],cx    ; three bytes of text
  1477.     mov    ax,es            ; setup for below
  1478.     jmp    short subst20h        ; compose the macro
  1479.  
  1480. subst20g:and    bl,not 20h        ; upper case it
  1481.     cmp    bl,'Z'            ; last <char>
  1482.     ja    subst20f        ; a = out of range
  1483.     sub    bl,'@'            ; remove bias
  1484.     xor    bh,bh
  1485.     shl    bx,1            ; address words
  1486.     mov    si,marray[bx]        ; get segment of string storage
  1487.     or    si,si            ; any?
  1488.     jz    subst20f        ; z = none
  1489.     mov    es,si            ; look at segment of array
  1490.     cmp    es:[0],ax        ; number of elements vs index above
  1491.     jbe    subst20f        ; be = out of range, quit
  1492.     mov    si,ax
  1493.     shl    si,1            ; index words
  1494.     mov    ax,es:[si+2]        ; get definition string segment to ax
  1495.     pop    si
  1496.     or    ax,ax            ; any?
  1497.     jz    subst17            ; z = no, empty
  1498. subst20h:mov    es,ax            ; string seg
  1499.     mov    cx,es:[0]        ; length of definition
  1500.     jcxz    subst17            ; z = empty
  1501.     call    takopen_sub        ; open take as text substitution
  1502.     jc    subst17            ; c = cannot open
  1503.     mov    bx,takadr        ; pointer to new Take structure
  1504.     mov    [bx].takbuf,es        ; segment of Take buffer
  1505.     mov    [bx].takcnt,cx        ; number of unread bytes
  1506.     jmp    subst17
  1507.  
  1508. subst20f:pop    si            ; failure
  1509.     jmp    subst17
  1510.  
  1511. subst15:mov    subcnt,0        ; clear match indicator
  1512.     call    takopen_sub        ; open take as text substitution
  1513.     jc    subst17            ; c = failed
  1514.     mov    cx,bx            ; value command kind, save
  1515.     mov    ax,tbufsiz        ; bytes of buffer space wanted
  1516.     call    malloc
  1517.     jc    subst17            ; c = failed
  1518.     mov    bx,takadr        ; point to structure
  1519.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  1520.     mov    [bx].takbuf,ax        ; seg of buffer
  1521.     mov    es,ax            ; ES:DI will be buffer pointer
  1522.     mov    di,[bx].takptr        ; where to write next
  1523.     mov    [bx].takper,0        ; expand macros
  1524.     cmp    subtype,'m'        ; \m(..)?
  1525.     jne    subst16a        ; ne = no
  1526.     mov    [bx].takper,1        ; do not expand macros in \m(..)
  1527. subst16a:mov    bx,cx            ; value command
  1528.     call    valtoa            ; make text be an internal macro
  1529.     mov    bx,takadr
  1530.     mov    [bx].takcnt,di        ; length
  1531. subst17:
  1532.     pop    dx
  1533.     mov    subtype,0
  1534.     pop    valtmp
  1535.     pop    cmsiz            ; restore borrowed keyword parameters
  1536.     pop    cmsptr
  1537.     pop    cmptab
  1538.     pop    es
  1539.     pop    cx
  1540.     pop    bx
  1541.     stc                ; carry = signal reread source
  1542.     ret
  1543.                     ; convert \number
  1544. subst30:cmp    ah,'?'            ; asking for help?
  1545.     jne    subst30a        ; ne = no
  1546.     mov    cmsiz,0            ; no keyword to expand
  1547.     push    cmhlp            ; save existing help
  1548.     mov    cmhlp,offset n1hlp    ; our message
  1549.     call    cmkyhlp            ; display help message
  1550.     pop    cmhlp            ; restore old help
  1551.     stc                ; buffer has been cleaned by cmkyhlp
  1552.     ret
  1553. subst30a:push    si
  1554.     mov    si,numtmp        ; where \ starts
  1555.     mov    atoibyte,1        ; convert only one character
  1556.     mov    cx,cmrptr
  1557.     sub    cx,numtmp        ; byte count to examine
  1558.     mov    atoi_cnt,cx        ; tell atoi the count
  1559.     call    atoi            ; value to dx:ax
  1560.     mov    cmsflg,0        ; clear space-seen flag
  1561.     jnc    subst31            ; nc = converted a value
  1562.     cmp    atoi_err,4        ; insufficient bytes to resolve
  1563.     je    subst30b        ; e = yes, get more
  1564.     mov    cx,cmrptr        ; replay complete failure
  1565.     sub    cx,numtmp        ; where \ started
  1566.     add    replay_cnt,cx        ; count to replay
  1567.     mov    si,numtmp
  1568.     mov    cmrptr,si        ; replay from here
  1569.     mov    subcnt,0        ; mismatch, clear match counter
  1570.     mov    subtype,0        ; and substitution type 
  1571.     mov    endedbackslash,0    ; general principles
  1572. subst30b:pop    si
  1573.     stc                ; carry set to read more bytes
  1574.     ret
  1575. subst31:pop    si
  1576.     cmp    atoi_err,1        ; success and terminated?
  1577.     jne    subst31a        ; ne = no
  1578.     mov    ah,al            ; ah now has value for app
  1579.     mov    subtype,0
  1580.     mov    subcnt,0
  1581.     inc    report_binary        ; signal have number to report to app
  1582.     clc
  1583.     ret
  1584.  
  1585. subst31a:cmp    atoi_err,0        ; success, can accept more data?
  1586.     jne    subst32            ; ne = no
  1587.     stc                ; c = return to read more data
  1588.     ret
  1589. subst32:mov    ah,al            ; ah now has value for app
  1590.     mov    subtype,0
  1591.     mov    subcnt,0
  1592.     push    ax
  1593.     dec    cmrptr            ; reread break byte
  1594.     mov    replay_cnt,1        ; for non-\
  1595.     push    bx
  1596.     mov    bx,cmrptr        ; last read byte
  1597.     mov    ah,[bx]            ; get break byte
  1598.     pop    bx
  1599.     inc    report_binary        ; signal have number to report to app
  1600.     cmp    ah,'\'            ; substitution introducer?
  1601.     jne    subst34            ; ne = no, pass it to app
  1602.     inc    cmrptr            ; step over read byte
  1603.     mov    replay_cnt,0        ; no replay
  1604.     mov    subcnt,1        ; mark \ introducer as have been read
  1605. subst34:pop    ax
  1606.     clc
  1607.     ret
  1608. subst    endp
  1609.  
  1610. ; Make an internal macro defined as the text for one of the value variables.
  1611. ; Use incoming DX as trailing space suppression flag, if null.
  1612. valtoa    proc    near
  1613.     push    di            ; save starting di
  1614.     push    dx            ; save trailing space flag
  1615.     mov    word ptr es:[di],0    ; fill buffer with sweet nothings
  1616.                     ; BX has index of variable
  1617.     cmp    bx,V_environ        ; \$() Environment?
  1618.     jne    valtoa1            ; ne = no
  1619.     mov    cx,envlen        ; string length
  1620.     jcxz    valtoa0            ; z = empty
  1621.     cmp    cx,tbufsiz-2        ; greater than current buffer?
  1622.     jbe    valtoa0a        ; be = no
  1623.     push    cx
  1624.     mov    ax,[bx].takbuf        ; old buffer
  1625.     mov    es,ax            ; new ES from above
  1626.     mov    ah,freemem        ; free it
  1627.     int    dos
  1628.     mov    ax,cx            ; bytes wanted
  1629.     call    malloc            ; get more space
  1630.     mov    bx,takadr
  1631.     mov    [bx].takbuf,ax        ; seg of macro def
  1632.     mov    ES,ax            ; new ES
  1633.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  1634.     pop    cx
  1635. valtoa0a:
  1636.     push    si
  1637.     push    ds
  1638.     lds    si,envadr        ; ds:si is source from Environment
  1639.     cld
  1640.     rep    movsb            ; copy string
  1641.     pop    ds
  1642.     pop    si
  1643. valtoa0:jmp    valtoa90
  1644.     
  1645. valtoa1:cmp    bx,V_argc        ; \v(argc)?
  1646.     jne    valtoa2            ; ne = no
  1647.     call    wrtargc            ; write argc
  1648.     jmp    valtoa90
  1649. valtoa2:cmp    bx,V_count        ; \v(count)?
  1650.     jne    valtoa3            ; ne = no
  1651.     call    wrtcnt            ; write it
  1652.     jmp    valtoa90
  1653. valtoa3:cmp    bx,V_date        ; \v(date)?
  1654.     jne    valtoa4
  1655.     call    wrtdate
  1656.     jmp    valtoa90
  1657. valtoa4:cmp    bx,V_errlev        ; \v(errorlevel)?
  1658.     jne    valtoa5            ; ne = no
  1659.     call    wrterr
  1660.     jmp    valtoa90
  1661. valtoa5:cmp    bx,V_dir        ; \v(dir)?
  1662.     jne    valtoa6
  1663.     call    wrtdir
  1664.     jmp    valtoa90
  1665. valtoa6:cmp    bx,V_time        ; \v(time)?
  1666.     jne    valtoa7
  1667.     call    wrttime
  1668.     jmp    valtoa90
  1669. valtoa7:cmp    bx,V_version        ; \v(version)?
  1670.     jne    valtoa8            ; ne = no
  1671.     mov    ax,version        ; get version such as 300
  1672.     call    fdec2di            ; convert binary to asciiz
  1673.     jmp    valtoa90
  1674. valtoa8:cmp    bx,V_platform        ; \v(platform)?
  1675.     jne    valtoa9            ; ne = no
  1676.     call    wrtplat            ; get machine name, e.g. "IBM-PC"
  1677.     jmp    valtoa90
  1678. valtoa9:cmp    bx,V_system        ; \v(system)?
  1679.     jne    valtoa10        ; ne = no
  1680.     call    wrtsystem        ; get "MS-DOS" string
  1681.     jmp    valtoa90
  1682. valtoa10:cmp    bx,V_kbd        ; \v(keyboard)?
  1683.     jne    valtoa11        ; ne = no
  1684.     call    wrtkbd            ; 88 or 101 value
  1685.     jmp    valtoa90
  1686. valtoa11:cmp    bx,V_speed        ; \v(speed)?
  1687.     jne    valtoa12        ; ne = no
  1688.     push    di
  1689.     call    fgetbaud        ; read baud rate from hardware
  1690.     pop    di
  1691.     mov    bx,portval
  1692.     mov    ax,[bx].baud
  1693.     cmp    al,byte ptr bdtab    ; index versus number of table entries
  1694.     jb    valtoa11a        ; b = index is in the table
  1695.     mov    si,offset cmunk-2    ; unrecognized value, say "unknown"
  1696.     mov    bx,7            ; length of string
  1697.     jmp    short valtoa11c
  1698. valtoa11a:mov    si,offset bdtab        ; ascii rate table
  1699.     mov    cl,[si]            ; number of entries
  1700.     inc    si            ; point to an entry
  1701. valtoa11b:
  1702.     mov    bx,[si]            ; length of text string
  1703.     cmp    ax,[si+bx+2]        ; our index vs table entry index
  1704.     je    valtoa11c        ; e = match
  1705.     add    si,bx            ; skip text
  1706.     add    si,4            ; skip count and index word
  1707.     loop    valtoa11b        ; look again
  1708.     mov    si,offset cmunk-2    ; unrecognized value, say "unknown"
  1709.     mov    bx,7            ; length of string
  1710. valtoa11c:mov    cx,bx            ; length of string
  1711.     add    si,2            ; point at string
  1712.     rep    movsb            ; copy string
  1713.     jmp    valtoa90
  1714.  
  1715. valtoa12:cmp    bx,V_program        ; \v(program)?
  1716.     jne    valtoa13        ; ne = no
  1717.     call    wrtprog            ; get "MS-DOS_KERMIT" string
  1718.     jmp    valtoa90
  1719. valtoa13:cmp    bx,V_status        ; \v(status)?
  1720.     jne    valtoa14        ; ne = no
  1721.     call    wrtstat            ; compose status string
  1722.     jmp    valtoa90
  1723. valtoa14:cmp    bx,V_ndate        ; \v(ndate)?
  1724.     jne    valtoa15        ; ne = no
  1725.     call    wrtndate
  1726.     jmp    valtoa90
  1727. valtoa15:cmp    bx,V_port        ; \v(port)? or \v(line)?
  1728.     jne    valtoa16        ; ne = no
  1729.     call    wrtport
  1730.     jmp    valtoa90
  1731. valtoa16:cmp    bx,V_terminal        ; \v(terminal)?
  1732.     jne    valtoa17        ; ne = no
  1733.     call    wrtterm
  1734.     jmp    valtoa90
  1735. valtoa17:
  1736. ifndef    no_tcp
  1737.     cmp    bx,V_session        ; \v(session) (internal Telnet)?
  1738.     jne    valtoa18        ; ne = no
  1739.  
  1740.     mov    ax,sescur        ; get internal Telnet session ident
  1741.     inc    ax            ; count from 1 for users (0 == none)
  1742.     call    fdec2di            ; convert binary to asciiz
  1743.     jmp    valtoa90
  1744. endif    ; no_tcp
  1745. valtoa18:cmp    bx,V_ntime        ; \v(ntime) (seconds in day)?
  1746.     jne    valtoa19        ; ne = no
  1747.     mov    ah,gettim        ; get DOS time of day
  1748.     int    dos            ; ch=hh, cl=mm, dh=ss, dl=0.01 sec
  1749.     mov    bx,60
  1750.     mov    al,ch            ; hours
  1751.     mul    bl            ; to minutes
  1752.     xor    ch,ch
  1753.     add    ax,cx            ; plus minutes
  1754.     mov    cl,dh            ; preserve seconds
  1755.     mul    bx            ; need carry out to DX
  1756.     add    ax,cx            ; add seconds
  1757.     adc    dx,0
  1758.     push    di
  1759.     push    es
  1760.     mov    di,ds
  1761.     mov    es,di
  1762.     mov    di,offset cmdbuf-30-cmdblen
  1763.     call    flnout            ; 32 bit converter
  1764.     mov    dx,offset cmdbuf-30-cmdblen
  1765.     call    strlen
  1766.     mov    si,dx
  1767.     pop    es
  1768.     pop    di
  1769.     cld
  1770.     rep    movsb
  1771.     mov    word ptr [di],0020h    ; space, null
  1772.     jmp    valtoa90
  1773.  
  1774. valtoa19:cmp    bx,V_dosver        ; \v(dosversion)?
  1775.     jne    valtoa20        ; ne = no
  1776.     mov    ax,dosnum        ; DOS verson, major high, minor low
  1777.     push    ax
  1778.     xchg    ah,al
  1779.     xor    ah,ah
  1780.     call    fdec2di            ; write major
  1781.     pop    ax
  1782.     xor    ah,ah
  1783.     cmp    al,10            ; less than 10?
  1784.     ja    valtoa19a        ; a = no
  1785.     mov    byte ptr es:[di],'0'    ; use two digits for minor
  1786.     inc    di
  1787. valtoa19a:
  1788.     call    fdec2di            ; write minor
  1789.     jmp    valtoa90
  1790. valtoa20:
  1791. ifndef    no_tcp
  1792.     cmp    bx,V_tcpip        ; \v(tcp_status)?
  1793.     jne    valtoa21        ; ne = no
  1794.                     ; SUCCESS    0
  1795.                     ; NO_DRIVER    1
  1796.                     ; NO_LOCAL_ADDRESS 2
  1797.                     ; BOOTP_FAILED    3
  1798.                     ; RARP_FAILED    4
  1799.                     ; BAD_SUBNET_MASK 5
  1800.                     ; SESSIONS_EXCEEDED 6
  1801.                     ; HOST_UNKNOWN    7
  1802.                     ; HOST_UNREACHABLE 8
  1803.                     ; CONNECTION_REJECTED 9
  1804.     mov    ax,tcp_status        ; get tcp status, if any
  1805.     call    fdec2di            ; write value
  1806.     jmp    valtoa90
  1807. endif    ; no_tcp
  1808.  
  1809. valtoa21:cmp    bx,V_parity        ; \v(parity)?
  1810.     jne    valtoa22        ; ne = no
  1811.     mov    bx,portval
  1812.     mov    bl,[bx].parflg        ; parity
  1813.     xor    bh,bh
  1814.     shl    bx,1            ; address words
  1815.     cld
  1816.     mov    si,parmsgtab[bx]    ; offset of parity name string
  1817. valtoa21a:lodsb
  1818.     stosb
  1819.     or    al,al            ; end of string?
  1820.     jnz    valtoa21a        ; nz = no
  1821.     mov    word ptr es:[di-1],0020h ; space, null
  1822.     jmp    valtoa90
  1823.  
  1824. valtoa22:cmp    bx,V_carrier        ; \v(carrier)?
  1825.     jne    valtoa23        ; ne = no
  1826.     mov    bl,flags.carrier    ; carrier
  1827.     and    bl,1            ; just one bit
  1828.     xor    bh,bh
  1829.     shl    bx,1            ; address words
  1830.     cld
  1831.     mov    si,onoffmsgtab[bx]    ; offset of carrier string
  1832. valtoa22a:lodsb
  1833.     stosb
  1834.     or    al,al            ; end of string?
  1835.     jnz    valtoa22a        ; nz = no
  1836.     mov    word ptr es:[di-1],0020h ; space, null
  1837.     jmp    valtoa90
  1838.  
  1839. valtoa23:cmp    bx,V_prompt        ; \v(prompt)?
  1840.     jne    valtoa24        ; ne = no
  1841.     push    si
  1842.     mov    si,prmptr        ; current prompt raw text
  1843.     cld
  1844. valtoa23a:lodsb                ; read a byte
  1845.     stosb                ; store
  1846.     or    al,al            ; end of string?
  1847.     jnz    valtoa23a        ; z = no
  1848.     pop    si
  1849.     dec    di            ; don't show trailing null
  1850.     mov    word ptr es:[di],0020h    ; space, null
  1851.     jmp    valtoa90
  1852.  
  1853. valtoa24:cmp    bx,V_cps        ; \v(cps)?
  1854.     jne    valtoa25        ; ne = no
  1855.     push    di
  1856.     mov    di,offset decbuf+200    ; must be in DS data seg
  1857.     call    shovarcps        ; use worker in msssho.asm
  1858.     mov    si,offset decbuf+200    ; copy this buffer to es:di buffer
  1859.     pop    di
  1860.     cld
  1861.     mov    cx,7            ; limit loop
  1862. valtoa24a:lodsb                ; read result
  1863.     or    al,al            ; terminator?
  1864.     jz    valtoa24b        ; z = yes, stop
  1865.     stosb
  1866.     loop    valtoa24a
  1867. valtoa24b:jmp    valtoa90
  1868.  
  1869. valtoa25:cmp    bx,V_space        ; \v(space)?
  1870.     jne    valtoa26        ; ne = no
  1871.     xor    cx,cx            ; drive letter (null means current)
  1872.     call    fdskspace        ; compute space, get letter into CL
  1873.     jnc    valtoa25a        ; nc = success
  1874.     xor    ax,ax
  1875.     xor    dx,dx
  1876. valtoa25a:
  1877.     push    di
  1878.     push    es
  1879.     mov    di,ds
  1880.     mov    es,di
  1881.     mov    di,offset cmdbuf-30-cmdblen
  1882.     call    flnout
  1883.     mov    dx,offset cmdbuf-30-cmdblen
  1884.     call    strlen
  1885.     mov    si,dx
  1886.     pop    es
  1887.     pop    di
  1888.     cld
  1889.     rep    movsb
  1890.     mov    word ptr [di],0020h    ; space, null
  1891.     jmp    valtoa90
  1892.  
  1893. valtoa26:cmp    bx,V_startup        ; \v(startup)?
  1894.     jne    valtoa27        ; ne = no
  1895.     push    si
  1896.     mov    si,offset startup    ; startup directory string
  1897.     mov    dx,si
  1898.     call    strlen            ; get length to cx
  1899.     rep    movsb            ; copy string
  1900.     pop    si
  1901.     mov    word ptr es:[di],0020h    ; space, null
  1902.     jmp    valtoa90
  1903.  
  1904. valtoa27:cmp    bx,V_console        ; \v(console)?
  1905.     jne    valtoa28        ; ne = no
  1906.     mov    ax,1a00h        ; get ANSI.SYS installed state
  1907.     int    2fh
  1908.     mov    si,offset ansiword    ; assume installed
  1909.     or    al,al            ; installed?
  1910.     jnz    valtoa27a        ; nz = yes
  1911.     mov    si,offset noneword    ; say "NONE"
  1912. valtoa27a:lodsb                ; read a byte
  1913.     stosb                ; store a byte
  1914.     or    al,al            ; at end of string?
  1915.     jnz    valtoa27a        ; nz = no
  1916.     mov    word ptr es:[di-1],0020h ; space, null
  1917.     jmp    valtoa90
  1918.  
  1919. valtoa28:cmp    bx,V_monitor        ; \v(monitor)?
  1920.     jne    valtoa29        ; ne = no
  1921.     mov    si,offset colormsg    ; assume color monitor
  1922.     cmp    crt_mode,7        ; mono text
  1923.     jne    valtoa28a        ; ne = no
  1924.     mov    si,offset monomsg    ; say mono
  1925. valtoa28a:jmp    short valtoa27a        ; copy material
  1926.  
  1927. valtoa29:cmp    bx,V_cmdlevel        ; \v(cmdlevel)?
  1928.     jne    valtoa30        ; ne = no
  1929.     mov    al,taklev        ; take level
  1930.     xor    ah,ah
  1931.     call    fdec2di            ; write value
  1932.     jmp    valtoa90
  1933.  
  1934. valtoa30:cmp    bx,V_input        ; \v(input)?
  1935.     jne    valtoa31        ; ne = no
  1936.     push    temp
  1937.     push    si
  1938.     push    DS
  1939.     push    es
  1940.     call    buflog            ; get INPUT buffer pointers
  1941.     mov    ax,es            ; seg of input buffer
  1942.     pop    es
  1943.     jcxz    valtoa30b        ; z = empty
  1944.     cmp    cx,tbufsiz-2-1        ; buffer plus null terminator
  1945.     jbe    valtoa30a        ; be = enough space to hold text
  1946.     mov    cx,tbufsiz-2-1        ; limit text
  1947. valtoa30a:mov    DS,ax            ; ds:si is input buffer
  1948.     cld
  1949.     rep    movsb
  1950.     xor    al,al
  1951.     mov    es:[di],al        ; null terminator
  1952. valtoa30b:pop    DS
  1953.     pop    si
  1954.     pop    temp
  1955.     jmp    valtoa90
  1956.  
  1957. valtoa31:cmp    bx,V_query        ; \v(query)?
  1958.     jne    valtoa32        ; ne = no
  1959.     mov    word ptr es:[di],0020h     ; space, null
  1960.     cmp    queryseg,0        ; is there an malloc'd seg to use?
  1961.     je    valtoa90        ; e = no
  1962.     push    es
  1963.     mov    si,queryseg
  1964.     mov    es,si
  1965.     mov    cx,es:[0]        ; get length of string
  1966.     pop    es
  1967.     push    si
  1968.     cmp    cx,tbufsiz-2        ; greater than current buffer?
  1969.     jbe    valtoa31a        ; be = no
  1970.     push    cx
  1971.     mov    ax,[bx].takbuf        ; old buffer
  1972.     mov    es,ax            ; new ES from above
  1973.     mov    ah,freemem        ; free it
  1974.     int    dos
  1975.     mov    ax,cx            ; bytes wanted
  1976.     call    malloc            ; get more space
  1977.     mov    bx,takadr
  1978.     mov    [bx].takbuf,ax        ; seg of macro def
  1979.     mov    ES,ax            ; new ES
  1980.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  1981.     pop    cx
  1982.  
  1983. valtoa31a:push    ds
  1984.     mov    si,queryseg        ; get segment of query string
  1985.     mov    ds,si
  1986.     mov    si,2            ; skip count word
  1987.     cld
  1988.     rep    movsb            ; copy to es:di
  1989.     pop    ds
  1990.     pop    si
  1991.     jmp    valtoa90
  1992.  
  1993. valtoa32:cmp    bx,V_sysid        ; \v(sysid)?
  1994.     jne    valtoa33        ; ne = no
  1995.     mov    ax,'8U'            ; always report U8
  1996.     stosw
  1997.     jmp    valtoa90
  1998.  
  1999. valtoa33:cmp    bx,V_charset        ; \v(charset)?
  2000.     jne    valtoa34        ; ne = no
  2001.     mov    ax,'PC'
  2002.     stosw                ; CP prefix
  2003.     mov    ax,flags.chrset        ; get current Code Page
  2004.     call    fdec2di
  2005.     jmp    valtoa90
  2006.  
  2007. valtoa34:cmp    bx,V_inpath        ; \v(inpath)?
  2008.     jne    valtoa35        ; ne = no
  2009.     mov    si,inpath_seg        ; get segment of in_path string
  2010.     or    si,si            ; anything there?
  2011.     jz    valtoa34b        ; z = no
  2012.     push    ds
  2013.     mov    ds,si
  2014.     xor    si,si
  2015.     cld
  2016.     lodsw                ; get count word
  2017.     mov    cx,ax
  2018.     cmp    cx,64            ; keep it reasonable
  2019.     jbe    valtoa34a        ; be = ok
  2020.     mov    cx,64
  2021. valtoa34a:rep    movsb            ; copy to es:di
  2022.     dec    di            ; don't include trailing null from env
  2023.     pop    ds
  2024. valtoa34b:jmp    valtoa90
  2025.  
  2026. valtoa35:cmp    bx,V_disk        ; \v(disk)?
  2027.     jne    valtoa36        ; ne = no
  2028.     mov    ah,gcurdsk        ; get current disk
  2029.     int    dos
  2030.     add    al,'A'            ; make 1 == A (not zero)
  2031.     cld
  2032.     stosb
  2033.     xor    al,al
  2034.     mov    es:[di],al
  2035.     jmp    valtoa90
  2036.  
  2037. valtoa36:cmp    bx,V_cmdfile        ; \v(cmdfile)?
  2038.     jne    valtoa37        ; ne = no
  2039.     mov    si,offset cmdfile    ; path of last Take file
  2040.     mov    dx,si
  2041.     call    strlen
  2042.     cld
  2043.     rep    movsb
  2044.     jmp    valtoa90
  2045.  
  2046. valtoa37:cmp    bx,V_inidir        ; \v(inidir)?
  2047.     jne    valtoa38        ; ne = no
  2048.     mov    si,offset inidir    ; path of mskermit.ini
  2049.     mov    dx,si
  2050.     call    strlen
  2051.     cld
  2052.     rep    movsb
  2053.     jmp    valtoa90
  2054.  
  2055. valtoa38:cmp    bx,V_instatus        ; \v(instatus)?
  2056.     jne    valtoa39        ; ne = no
  2057.     mov    ax,input_status        ; special INPUT status word
  2058.     cmp    ax,0            ; negative?
  2059.     jge    valtoa38a        ; ge = no
  2060.     mov    byte ptr es:[di],'-'
  2061.     inc    di
  2062.     neg    ax
  2063. valtoa38a:call    fdec2di
  2064.     jmp    valtoa90
  2065.  
  2066. valtoa39:cmp    bx,V_minput        ; \v(minput)?
  2067.     jne    valtoa40        ; ne = no
  2068.     mov    ax,minpcnt        ; get minput match count
  2069.     call    fdec2di            ; convert to decimal
  2070.     jmp    short valtoa90        ; done
  2071.  
  2072. valtoa40:cmp    bx,V_return        ; \v(return)?
  2073.     jne    valtoa41        ; ne = no
  2074.     mov    si,offset retbuf    ; <word count><string from RETURN>
  2075.     mov    cx,[si]            ; get count word
  2076.     add    si,2            ; point at string
  2077.     cld
  2078.     rep    movsb            ; copy to variable buffer
  2079.     jmp    short valtoa90        ; done
  2080.  
  2081. valtoa41:cmp    bx,V_connection        ; \v(connection)?
  2082.     jne    valtoa42        ; ne = no
  2083.     mov    si,offset connmsg    ; word "local"
  2084.     mov    dx,si
  2085.     call    strlen            ; length to cx
  2086.     cld
  2087.     rep    movsb            ; copy to variable buffer
  2088.     jmp    short valtoa90        ; done
  2089.  
  2090. valtoa42:cmp    bx,V_filespec        ; \v(filespec)?
  2091.     jne    valtoa80        ; ne = no
  2092.     mov    si,offset vfile        ; last used file transfer name
  2093.     mov    dx,si
  2094.     call    strlen            ; length to cx
  2095.     cld
  2096.     rep    movsb            ; copy to variable buffer
  2097.     jmp    short valtoa90        ; done
  2098.  
  2099. valtoa80:push    bx            ; \m(macro_name)
  2100.     push    es
  2101.     mov    di,bx            ; save seg of macro def
  2102.     mov    bx,takadr
  2103.     test    [bx].takattr,take_malloc ; buffer already allocated?
  2104.     jz    valtoa80a        ; z = no
  2105.     push    es
  2106.     mov    ax,[bx].takbuf        ; old buffer
  2107.     or    ax,ax            ; if any allocated
  2108.     jz    valtoa80b        ; z = none
  2109.     mov    es,ax
  2110.     mov    ah,freemem        ; free it
  2111.     int    dos
  2112. valtoa80b:and    [bx].takattr,not take_malloc ; say no more freeing needed
  2113.     pop    es
  2114. valtoa80a:
  2115.     mov    [bx].takbuf,di        ; seg of macro def
  2116.     mov    [bx].takptr,2        ; offset of two
  2117.     mov    es,di
  2118.     mov    cx,es:[0]        ; get length of string
  2119.     pop    es
  2120.     pop    bx
  2121.     pop    dx
  2122.     pop    di
  2123.     mov    di,cx            ; report length in di
  2124.     clc
  2125.     ret
  2126. valtoa90:pop    dx            ; trailing space flag
  2127.     or    dx,dx            ; leave the spaces?
  2128.     jnz    valtoa91        ; nz = yes
  2129.     cmp    word ptr es:[di-1],0020h ; trailing space?
  2130.     jne    valtoa91        ; ne = no
  2131.     dec    di            ; remove space
  2132. valtoa91:pop    ax            ; saved starting di
  2133.     sub    di,ax            ; di = length of the buffer contents
  2134.     clc
  2135.     ret
  2136. valtoa    endp
  2137.  
  2138. ; Far callable version
  2139. fvaltoa    proc    far
  2140.     call    valtoa
  2141.     ret
  2142. fvaltoa    endp
  2143.  
  2144. ; Make an internal macro defined as the text for one of the value variables.
  2145. ; Use incoming DX as trailing space suppression flag, if null.
  2146. ; BX has keyword value (table envtab)
  2147. ; If these fail they consume their text quietly.
  2148. evaltoa    proc    near
  2149.     push    dx            ; save trailing space flag
  2150.     push    si
  2151.     push    temp            ; save work variable
  2152.     mov    al,comand.cmdonum
  2153.     push    ax
  2154.     mov    comand.cmdonum,0    ; kill \number conversion
  2155.     call    evarg            ; get argument array
  2156.     pop    ax
  2157.     mov    comand.cmdonum,al    ; restore \number conversion state
  2158.     mov    ax,valtmp        ; where '\fname' started
  2159.     sub    ax,2            ; back over \f
  2160.     mov    cmwptr,ax        ; where to write new output
  2161.         mov     cmrptr,ax               ; readjust read pointer too
  2162.     call    takopen_sub        ; open take as text substitution
  2163.     jnc    evalt5c            ; nc = success
  2164. evalt5b:jmp    evalt99            ; fail
  2165. evalt5c:mov    bx,takadr        ; Take structure
  2166.     mov    ax,tbufsiz        ; bytes of buffer space wanted
  2167.     call    malloc
  2168.     jc    evalt5b            ; c = failed
  2169.     mov    [bx].takbuf,ax        ; seg of allocated buffer
  2170.     or    [bx].takattr,take_malloc ; remember to dispose via takclos
  2171.     mov    es,ax
  2172.     mov    word ptr es:[0],tbufsiz
  2173.     mov    di,[bx].takptr        ; where to start writing
  2174.     mov    [bx].takcnt,0        ; number of unread bytes
  2175.     mov    [bx].takper,0
  2176.     cmp    evaltype,F_contents    ; \fcontents(macro)?
  2177.     je    evalt5d            ; e = yes
  2178.     cmp    evaltype,F_definition    ; \fdefinition(macro)?
  2179.     je    evalt5d            ; e = yes
  2180.     cmp    evaltype,F_literal    ; \fliteral(string)?
  2181.     jne    evalt5e            ; ne = no
  2182. evalt5d:mov    [bx].takper,1        ; treat macro names as literals
  2183.  
  2184. evalt5e:mov    bx,takadr
  2185.     mov    di,[bx].takptr        ; destination for replacment text
  2186.     cmp    evaltype,F_length    ; \flength(text)?
  2187.     jne    evalt6            ; ne = no
  2188.     mov    ax,arglen        ; length of variable name
  2189.     call    fdec2di            ; convert to ASCII string
  2190.     mov    bx,takadr
  2191.     sub    di,[bx].takptr        ; end minus start
  2192.     mov    [bx].takcnt,di        ; string length
  2193.     jmp    evalt99
  2194.  
  2195. evalt6:    cmp    evaltype,F_upper    ; \fupper(text)?
  2196.     je    evalt6a            ; e = yes
  2197.     cmp    evaltype,F_lower    ; \flower(text)?
  2198.     jne    evalt7            ; ne = no
  2199. evalt6a:mov    si,argptr        ; point to argument
  2200.     mov    cx,arglen        ; length of string
  2201.     jcxz    evalt6e            ; z = empty
  2202.     cld
  2203. evalt6b:lodsb                ; read from parse buffer
  2204.     cmp    evaltype,F_lower    ; to lower?
  2205.     ja    evalt6c            ; a = no, upper
  2206.     call    tolowr            ; move to lower case
  2207.     jmp    short evalt6d
  2208. evalt6c:call    toupr            ; move to upper case
  2209. evalt6d:stosb                ; write byte to Take buffer
  2210.     loop    evalt6b
  2211. evalt6e:mov    bx,takadr
  2212.     mov    cx,arglen        ; argument length
  2213.     mov    [bx].takcnt,cx        ; count entered bytes
  2214.     jmp    evalt99
  2215.  
  2216. evalt7:    cmp    evaltype,F_char        ; \fcharacter(n)?
  2217.     jne    evalt8            ; ne = no
  2218.     mov    si,argptr        ; point at text of number
  2219.     mov    domath_ptr,si
  2220.     mov    ax,arglen
  2221.     mov    domath_cnt,ax
  2222.     call    domath
  2223.     jc    evalt7d            ; c = failed
  2224.     cld
  2225.     stosb                ; store single byte
  2226.     mov    bx,takadr
  2227.     mov    [bx].takcnt,1        ; one byte as result
  2228. evalt7d:jmp    evalt99
  2229.  
  2230. evalt8:    cmp    evaltype,F_substr    ; \fsubstr(text, n1, n2)?
  2231.     jne    evalt9            ; ne = no
  2232.     xor    ax,ax
  2233.     mov    si,argptr[2]        ; point to n1 string
  2234.     mov    domath_ptr,si
  2235.     mov    ax,arglen[2]
  2236.     mov    domath_cnt,ax
  2237.     call    domath
  2238.     jnc    evalt8g            ; nc = got a number
  2239. evalt8f:xor    ax,ax
  2240.     xor    dx,dx
  2241.     jmp    short evalt8a
  2242. evalt8g:or    dx,dx            ; number overflowed to high word?
  2243.     jnz    evalt8f            ; nz = yes, reset number to zero
  2244.     or    ax,ax            ; zero?
  2245.     jz    evalt8a            ; z = yes
  2246.     dec    ax            ; count from 0 internally
  2247. evalt8a:mov    si,argptr        ; point at text
  2248.     add    si,ax            ; point at text[n1]
  2249.     mov    cx,arglen        ; length of 'text'
  2250.     sub    cx,ax            ; bytes remaining in 'text'
  2251.     jle    evalt8d            ; le = nothing left to extract
  2252.     push    si
  2253.     mov    si,argptr[4]        ; point to n2 string
  2254.     mov    domath_ptr,si
  2255.     mov    ax,arglen[4]
  2256.     mov    domath_cnt,ax
  2257.     call    domath
  2258.     pop    si
  2259.     jnc    evalt8b            ; nc = got a number
  2260.     mov    ax,arglen        ; default to full string
  2261.     xor    dx,dx
  2262. evalt8b:or    dx,dx            ; number overflowed to high word?
  2263.     jnz    evalt8d            ; nz = yes
  2264.     cmp    cx,ax            ; length available more than needed?
  2265.     jbe    evalt8c            ; be = no
  2266.     mov    cx,ax            ; use smaller n2
  2267. evalt8c:mov    bx,tbufsiz-2        ; unused buffer capacity (tbufsiz-2)
  2268.     cmp    cx,bx            ; n larger than buffer?
  2269.     jbe    evalt8e            ; be = no
  2270.     mov    ax,cx            ; remember amount wanted
  2271.     call    evmem            ; get more memory, want CX bytes
  2272.     xchg    ax,cx            ; now ax=amount available, cx=wanted
  2273.     cmp    cx,ax            ; wanted > available?
  2274.     jbe    evalt8e            ; be = no
  2275.     mov    cx,ax            ; limit to available memory
  2276. evalt8e:mov    bx,takadr
  2277.     mov    [bx].takcnt,cx        ; count of bytes
  2278.     cld
  2279.     rep    movsb            ; copy bytes to Take buffer
  2280. evalt8d:jmp    evalt99
  2281.  
  2282. evalt9:    cmp    evaltype,F_right    ; \fright(text, n)?
  2283.     jne    evalt10            ; ne = no
  2284.     mov    si,argptr[2]        ; point to n string
  2285.     mov    domath_ptr,si
  2286.     mov    ax,arglen[2]
  2287.     or    ax,ax            ; empty field?
  2288.     jz    evalt9d            ; z = yes, use whole string
  2289.     mov    domath_cnt,ax
  2290.     call    domath
  2291.     cmp    domath_cnt,0
  2292.     je    evalt9a            ; e = consummed whole string
  2293.     mov    arglen,0        ; force 0
  2294. evalt9d:mov    ax,arglen        ; default to full string
  2295.     xor    dx,dx
  2296. evalt9a:or    dx,dx            ; number overflowed to high word?
  2297.     jnz    evalt9c            ; nz = yes
  2298.     mov    cx,arglen        ; length of 'text'
  2299.     cmp    cx,ax            ; length available more than needed?
  2300.     jbe    evalt9b            ; be = no
  2301.     mov    cx,ax            ; use smaller n
  2302. evalt9b:mov    si,argptr        ; start of 'text'
  2303.     add    si,arglen        ; point at last + 1 byte of 'text'
  2304.     sub    si,cx            ; minus bytes to be copied
  2305.     mov    bx,takadr
  2306.     mov    [bx].takcnt,cx        ; count of bytes
  2307.     cld
  2308.     rep    movsb            ; copy bytes to Take buffer
  2309. evalt9c:jmp    evalt99
  2310.  
  2311. evalt10:cmp    evaltype,F_literal    ; \fliteral(text)?
  2312.     jne    evalt11            ; ne = no
  2313.     mov    si,argptr        ; start of string
  2314.     mov    cx,arglen        ; length of text (inc leading spaces)
  2315.     mov    bx,takadr
  2316.     mov    [bx].takcnt,cx        ; count of bytes
  2317.     cld
  2318.     rep    movsb            ; copy bytes to Take buffer
  2319.     jmp    evalt99
  2320.  
  2321. evalt11:cmp    evaltype,F_rpad        ; \frpad(text, n, c)?
  2322.     jne    evalt12
  2323.     mov    si,argptr[2]        ; get n
  2324.     mov    domath_ptr,si
  2325.     mov    ax,arglen[2]
  2326.     mov    domath_cnt,ax
  2327.     call    domath
  2328.     jc    evalt11d        ; c = error
  2329.     or    dx,dx            ; numeric overflow to high word?
  2330.     jne    evalt11d        ; ne = yes
  2331.     mov    bx,takadr
  2332.     mov    cx,tbufsiz-2        ; unused buffer capacity (tbufsiz-2)
  2333.     cmp    ax,cx            ; n larger than buffer?
  2334.     jbe    evalt11a        ; be = no
  2335.     call    evmem            ; get more memory
  2336.     jc    evalt11d        ; c = fail
  2337.     cmp    ax,cx            ; enough?
  2338.     jbe    evalt11a        ; be = yes
  2339.     mov    ax,cx
  2340. evalt11a:mov    cx,arglen        ; length of text
  2341.     cmp    ax,cx            ; field (n) shorter than text?
  2342.     jae    evalt11b        ; ae = no, use full text
  2343.     mov    cx,ax            ; copy just n of text
  2344. evalt11b:sub    ax,cx            ; available minus used bytes
  2345.     mov    bx,takadr
  2346.     mov    [bx].takcnt,cx        ; count of bytes
  2347.     mov    si,argptr        ; text
  2348.     cld
  2349.     rep    movsb            ; copy bytes to Take buffer
  2350.     mov    cx,ax            ; padding bytes
  2351.     jcxz    evalt11d        ; z = none
  2352.     add    [bx].takcnt,cx        ; increase count of bytes
  2353.     mov    bx,argptr+4        ; point to c
  2354.     mov    al,[bx]            ; padding character, if any
  2355.     cmp    arglen+4,0        ; any char given?
  2356.     jne    evalt11c        ; ne = yes
  2357.     mov    al,' '            ; else default to space
  2358. evalt11c:cld
  2359.     rep    stosb            ; append byte to Take buffer
  2360. evalt11d:jmp    evalt99
  2361.  
  2362. evalt12:cmp    evaltype,F_lpad        ; \flpad(text, n, c)?
  2363.     jne    evalt13
  2364.     push    si
  2365.     mov    si,argptr[2]        ; get n
  2366.     mov    domath_ptr,si
  2367.     mov    ax,arglen[2]
  2368.     mov    domath_cnt,ax
  2369.     call    domath
  2370.     pop    si
  2371.     jc    evalt12e        ; c = error
  2372.     or    dx,dx            ; numeric overflow to high word?
  2373.     jne    evalt12e        ; ne = yes
  2374.     mov    bx,takadr
  2375.     mov    cx,tbufsiz-2        ; unused buffer capacity (tbufsiz-2)
  2376.     cmp    ax,cx            ; n larger than buffer?
  2377.     jbe    evalt12a        ; be = no
  2378.     call    evmem            ; get more memory
  2379.     cmp    ax,cx            ; wanted > available?
  2380.     jbe    evalt12a        ; be = no
  2381.     mov    ax,cx            ; limit text
  2382. evalt12a:sub    ax,arglen        ; n - length of 'text'
  2383.     jns    evalt12b        ; ns = no underflow
  2384.     xor    ax,ax            ; else omit padding
  2385. evalt12b:mov    cx,ax            ; padding count
  2386.     mov    [bx].takcnt,cx        ; count of bytes
  2387.     mov    bx,argptr+4        ; point to c
  2388.     mov    al,[bx]            ; padding character, if any
  2389.     cmp    arglen+4,0        ; any char given?
  2390.     jne    evalt12c        ; ne = yes
  2391.     mov    al,' '            ; default to space
  2392. evalt12c:cld
  2393.     rep    stosb            ; copy byte to Take buffer
  2394.     mov    cx,arglen        ; length of text
  2395.     mov    cx,tbufsiz-2        ; buffer capacity
  2396.     mov    bx,takadr
  2397.     sub    cx,[bx].takcnt        ; minus bytes written so far
  2398.     mov    ax,arglen        ; length of 'text'
  2399.     cmp    ax,cx            ; n larger than buffer?
  2400.     jbe    evalt12d        ; be = no
  2401.     mov    ax,cx
  2402. evalt12d:mov    cx,ax            ; append count
  2403.     mov    bx,takadr
  2404.     add    [bx].takcnt,cx        ; increase count of bytes
  2405.     mov    si,argptr        ; start of text
  2406.     cld
  2407.     rep    movsb            ; append byte to Take buffer
  2408. evalt12e:jmp    evalt99
  2409.  
  2410. evalt13:cmp    evaltype,F_code        ; \fcode(char)?
  2411.     jne    evalt14            ; ne = no
  2412.     mov    bx,argptr        ; point to char address
  2413.     mov    al,[bx]            ; original char
  2414.     xor    ah,ah
  2415.     call    fdec2di            ; convert to ASCII string, no '\'
  2416.     mov    bx,takadr        ;   prefix
  2417.     sub    di,[bx].takptr        ; end minus start
  2418.     mov    [bx].takcnt,di        ; string length
  2419.     jmp    evalt99
  2420.  
  2421. evalt14:cmp    evaltype,F_definition    ; \fdefinition(macro)?
  2422.     je    evalt14i        ; e = yes
  2423.     cmp    evaltype,F_contents    ; \fcontents(macro)
  2424.     jne    evalt15
  2425. evalt14i:cmp    arglen,0        ; any name?
  2426.     jne    evalt14a        ; e = yes
  2427.     jmp    evalt14x        ; fail
  2428. evalt14a:mov    si,argptr        ; trim trailing spaces from user name
  2429.     mov    cx,arglen        ; length of raw user string
  2430.     mov    bx,si
  2431.     add    bx,cx
  2432. evalt14j:cmp    byte ptr [bx-1],' '    ; trailing space?
  2433.     jne    evalt14k        ; ne = no
  2434.     dec    arglen            ; remove it
  2435.     dec    bx            ; preceeding char
  2436.     loop    evalt14j
  2437. evalt14k:
  2438.     mov    si,offset mcctab    ; table of macro names
  2439.     cld
  2440.     lodsb
  2441.     mov    cl,al            ; number of macro entries
  2442.     xor    ch,ch
  2443.     jcxz    evalt14x        ; z = none
  2444. evalt14b:push    cx            ; save loop counter
  2445.     lodsw                ; length of macro name
  2446.     mov    cx,arglen        ; length of user's string
  2447.     cmp    ax,cx            ; mac name shorter that user spec?
  2448.     jb    evalt14d        ; b = yes, no match
  2449.     push    ax
  2450.     push    si            ; save these around match test
  2451.     push    di
  2452.     mov    di,argptr        ; user's string
  2453. evalt14c:mov    ah,[di]
  2454.     inc    di
  2455.     lodsb                ; al = mac name char, ah = user char
  2456.     and    ax,not 2020h        ; clear bits (uppercase chars)
  2457.     cmp    ah,al            ; same?
  2458.     loope    evalt14c        ; while equal, do more
  2459.     pop    di
  2460.     pop    si            ; restore regs
  2461.     pop    ax
  2462.     je    evalt14e        ; e = a match
  2463. evalt14d:add    si,ax            ; point to next name, add name length
  2464.     add    si,2            ;  and string pointer
  2465.     pop    cx            ; recover loop counter
  2466.     loop    evalt14b        ; one less macro to examine
  2467. evalt14x:jmp    evalt99
  2468.  
  2469. evalt14e:pop    cx            ; pop loop counter above
  2470.     cmp    byte ptr[si],0        ; name starts with null char?
  2471.     jne    evalt14f        ; ne = no
  2472.     jmp    evalt99            ; yes, TAKE file, ignore
  2473. evalt14f:mov    ax,[si-2]        ; length of macro name
  2474.     add    si,ax            ; skip over name
  2475.     push    es
  2476.     mov    es,[si]            ; segment of string structure
  2477.     xor    si,si            ; es:si = address of count + string
  2478.     mov    ax,es
  2479.     mov    cx,es:[si]        ; length of string
  2480.     mov    arglen+2,cx        ; save length here
  2481.     mov    argptr+2,ax        ; save es of es:si here
  2482.     pop    es
  2483.     call    evmem            ; get new memory, set new ES:DI
  2484.     cmp    cx,arglen+2        ; enough to hold material?
  2485.     jae    evalt14h        ; ae = yes
  2486.     mov    arglen+2,cx        ; shrink string size too
  2487.  
  2488. evalt14h:push    ds
  2489.     mov    bx,takadr
  2490.     mov    cx,arglen+2        ; length of string
  2491.     mov    [bx].takcnt,cx        ; macro length
  2492.     mov    [bx].takptr,2        ; offset of text in destination
  2493.     mov    ax,argptr+2        ; seg of string
  2494.     mov    ds,ax
  2495.     mov    si,2            ; offset of string
  2496.     cld
  2497.     rep    movsb            ; copy string
  2498.     pop    ds
  2499.     jmp    evalt99
  2500.  
  2501. evalt15:cmp    evaltype,F_maximum    ; \fmaximum(n1, n2)?
  2502.     je    evalt15a        ; e = yes
  2503.     cmp    evaltype,F_minimum    ; \fminimum(n1, n2)?
  2504.     jne    evalt16            ; ne = no
  2505. evalt15a:push    si
  2506.     mov    si,argptr[0]        ; point to n1 string
  2507.     mov    domath_ptr,si
  2508.     mov    ax,arglen[0]
  2509.     mov    domath_cnt,ax
  2510.     call    domath
  2511.     pop    si
  2512.     jc    evalt15x        ; c = failure
  2513.     push    ax            ; save result
  2514.     push    dx
  2515.     push    si
  2516.     mov    si,argptr[2]        ; point to n2 string
  2517.     mov    domath_ptr,si
  2518.     mov    ax,arglen[2]
  2519.     mov    domath_cnt,ax
  2520.     call    domath
  2521.     pop    si
  2522.     pop    cx            ; high first value
  2523.     pop    bx            ; low first value
  2524.     jc    evalt15x        ; c = failure
  2525.     mov    temp,0            ; assume reporting n1, subscript 0
  2526.     cmp    cx,dx            ; n1 > n2?
  2527.     jg    evalt15e        ; g = yes
  2528.     jl    evalt15d        ; l = no, but less than
  2529.     cmp    bx,ax            ; low order n1 >= n2?
  2530.     jge    evalt15e        ; ge = yes
  2531. evalt15d:mov    temp,2            ; say n2 is larger
  2532. evalt15e:cmp    evaltype,F_maximum    ; return max of the pair?
  2533.     je    evalt15f        ; e = yes
  2534.     xor    temp,2            ; change subscript
  2535. evalt15f:push    si
  2536.     mov    bx,temp            ; get subscript of reportable
  2537.     mov    si,argptr[bx]
  2538.     mov    cx,arglen[bx]
  2539.     cld
  2540.     rep    movsb            ; copy original string
  2541.     xor    al,al
  2542.     stosb                ; and null terminate
  2543.     pop    si
  2544.     mov    bx,takadr
  2545.     sub    di,[bx].takptr        ; bytes consumed
  2546.     mov    [bx].takcnt,di
  2547. evalt15x:jmp    evalt99
  2548.  
  2549. evalt16:cmp    evaltype,F_index    ; \findex(pat, string, [offset])
  2550.     je    evalt16common
  2551.     cmp    evaltype,F_rindex    ; \frindex(pat, string, [offset])
  2552.     jne    evalt17
  2553. evalt16common:                ; used for \frindex too
  2554.     cmp    arglen+4,0        ; optional offset given?
  2555.     je    evalt16a        ; e = no, use userlevel 1
  2556.     push    si
  2557.     mov    si,argptr[4]        ; evaluate optional offset
  2558.     mov    domath_ptr,si
  2559.     mov    ax,arglen[4]
  2560.     mov    domath_cnt,ax
  2561.     call    domath
  2562.     pop    si
  2563.     jnc    evalt16b        ; nc = got a number
  2564. evalt16a:mov    ax,1            ; default to one (user style)
  2565.     xor    dx,dx
  2566. evalt16b:or    dx,dx            ; too large?
  2567.     jnz    evalt16x        ; nz = too large, fail
  2568.     dec    ax            ; offset from start (0 base it)
  2569.     mov    temp,ax            ; remember offset
  2570.     cmp    evaltype,F_rindex    ; \frindex?
  2571.     jne    evalt16g        ; ne = no
  2572.     mov    cx,arglen+2        ; length of string
  2573.     sub    cx,arglen        ; minus length of pattern
  2574.     sub    cx,ax            ; minus displacement from right
  2575.     mov    temp,cx            ; new effective offset
  2576.     mov    ax,cx
  2577. evalt16g:
  2578.     push    es
  2579.     push    di
  2580.     mov    di,ds            ; string is in DS seg
  2581.     mov    es,di
  2582.     mov    cx,arglen+2        ; length of string
  2583.     sub    cx,arglen        ; minus length of pattern
  2584.     cmp    ax,cx            ; offset larger than this?
  2585.     jbe    evalt16c        ; be = no
  2586.     mov    temp,-1            ; to report zero
  2587.     jmp    short evalt16e        ;  fail
  2588. evalt16c:mov    si,argptr        ; pattern
  2589.     mov    di,argptr+2        ; string
  2590.     add    di,temp            ; plus offset
  2591.     mov    cx,arglen        ; pattern length
  2592.     mov    ax,cx
  2593.     add    ax,temp            ; plus offset
  2594.     cmp    ax,arglen+2        ; more than string?
  2595.     jbe    evalt16d        ; be = no, keep going
  2596.     mov    temp,-1            ; to report zero
  2597.     jmp    short evalt16e        ; a = no match
  2598. evalt16d:push    cx
  2599.     cld
  2600.     repe    cmpsb            ; compare strings
  2601.     pop    cx
  2602.     je    evalt16e        ; e = matched
  2603.     inc    temp            ; move pattern right one place
  2604.     cmp    evaltype,F_rindex    ; \frindex?
  2605.     jne    evalt16c        ; ne = no
  2606.     sub    temp,2            ; work to the left instead
  2607.     jmp    short evalt16c        ; try again
  2608. evalt16e:pop    di
  2609.     pop    es
  2610.     mov    ax,temp            ; report out number
  2611.     inc    ax            ; show 0 as 1 to user
  2612.     mov    bx,takadr
  2613.     call    fdec2di            ; binary to ASCIIZ
  2614.     mov    bx,takadr
  2615.     sub    di,[bx].takptr
  2616.     mov    [bx].takcnt,di        ; length of ASCIIZ result
  2617. evalt16x:jmp    evalt99
  2618.  
  2619. evalt17:cmp    evaltype,F_repeat    ; \frepeat(text,n)?
  2620.     jne    evalt18            ; ne = no
  2621.     cmp    arglen+2,0        ; number given?
  2622.     je    evalt17g        ; e = no, fail
  2623.     mov    si,argptr[2]        ; n
  2624.     mov    domath_ptr,si
  2625.     mov    ax,arglen[2]
  2626.     mov    domath_cnt,ax
  2627.     call    domath
  2628.     jc    evalt17g        ; c = fail
  2629.     or    dx,dx            ; number overflowed?
  2630.     jz    evalt17a        ; z = no
  2631.     mov    ax,1            ; default number
  2632. evalt17a:mov    arglen+2,ax        ; save reasonable value here
  2633.     mul    arglen            ; string length * repeats
  2634.     or    dx,dx            ; overflowed (> 64KB)?
  2635.     jnz    evalt17b        ; nz = yes
  2636.     cmp    ax,cmdblen        ; more than parse buffer?
  2637.     jbe    evalt17c        ; be = no
  2638. evalt17b:mov    ax,cmdblen        ; should be plenty (1000)
  2639. evalt17c:mov    cx,ax            ; bytes wanted
  2640.     call    evmem            ; allocate memory 
  2641.     mov    dx,cx            ; buffer length available
  2642. evalt17d:mov    cx,arglen        ; length of text
  2643.     cmp    cx,dx            ; length vs buffer capacity
  2644.     jbe    evalt17e        ; be = capacity exceeds string
  2645.     mov    cx,dx            ; chop string to fit
  2646. evalt17e:sub    dx,cx            ; deduct amount done
  2647.     mov    si,argptr        ; point at string
  2648.     cld
  2649.     rep    movsb
  2650.     dec    arglen+2        ; repeat count
  2651.     cmp    arglen+2,0        ; any more repeats to do?
  2652.     je    evalt17f        ; e = no
  2653.     or    dx,dx            ; any space left?
  2654.     jg    evalt17d        ; g = yes
  2655. evalt17f:mov    bx,takadr
  2656.     sub    di,[bx].takptr        ; end minus start
  2657.     mov    [bx].takcnt,di        ; string length
  2658. evalt17g:jmp    evalt99
  2659.  
  2660. evalt18:cmp    evaltype,F_reverse    ; \freverse(text)?
  2661.     jne    evalt19            ; ne = no
  2662.     mov    cx,arglen        ; length of string
  2663.     mov    si,argptr        ; string
  2664.     add    di,cx
  2665.     dec    di            ; last byte in output string
  2666.     mov    bx,takadr
  2667.     mov    [bx].takcnt,cx        ; length of output to buffer
  2668.     jcxz    evalt18b        ; z = empty string
  2669. evalt18a:cld
  2670.     lodsb                ; read left
  2671.     std
  2672.     stosb                ; write left, displaced, backward
  2673.     cld
  2674.     loop    evalt18a
  2675. evalt18b:jmp    evalt99
  2676.  
  2677. evalt19:cmp    evaltype,F_date        ; \fdate(filename)?
  2678.     je    evalt19a        ; e = yes
  2679.     cmp    evaltype,F_size        ; \fsize(filename)?
  2680.     jne    evalt20            ; ne = no
  2681. evalt19a:push    di
  2682.     mov    di,offset tmpbuf    ; work buffer in this data seg
  2683.     mov    byte ptr [di],0        ; terminator
  2684.     call    filedate        ; get info
  2685.     mov    dx,offset tmpbuf
  2686.     call    strlen            ; get length of results to CX
  2687.     pop    di
  2688.     mov    bx,takadr
  2689.     mov    [bx].takcnt,cx        ; length of results
  2690.     mov    si,offset tmpbuf
  2691.     cld
  2692.     rep    movsb            ; copy to Take buffer
  2693.     jmp    evalt99
  2694.  
  2695. evalt20:cmp    evaltype,F_files    ; \ffiles(filespec)?
  2696.     jne    evalt21            ; ne = no
  2697.     mov    temp,0            ; count found files
  2698.     call    filedate        ; find first
  2699.     jc    evalt20d        ; c = none
  2700.     push    di
  2701.     push    es
  2702.     inc    temp            ; count found file
  2703.     mov    dx,offset fileio.dta    ; point at dta
  2704.     mov    ah,setdma        ; set the dta address
  2705.     int    dos
  2706. evalt20b:mov    ah,next2        ; DOS 2.0 search for next
  2707.     int    dos
  2708.     jc    evalt20c        ; c = no more
  2709.     inc    temp            ; count found file
  2710.     jmp    short evalt20b        ; try for next
  2711. evalt20c:mov    ah,setdma        ; restore dta
  2712.     mov    dx,offset buff
  2713.     int    dos
  2714.     pop    es
  2715.     pop    di
  2716.     call    filedate        ; go back to find first again
  2717. evalt20d:mov    ax,temp            ; count of files found
  2718.     call    fdec2di            ; convert to ASCII string
  2719.     mov    bx,takadr
  2720.     sub    di,[bx].takptr        ; end minus start
  2721.     mov    [bx].takcnt,di        ; string length
  2722.     jmp    evalt99
  2723.  
  2724. evalt21:cmp    evaltype,F_nextfile    ; \fnextfile()?
  2725.     jne    evalt24            ; ne = no
  2726.     mov    si,offset fileio.fname    ; current filename from DOS
  2727.     mov    dx,si
  2728.     call    strlen            ; length of name
  2729.     mov    bx,takadr
  2730.     mov    [bx].takcnt,cx        ; length of result
  2731.     rep    movsb            ; copy to Take buffer
  2732.     push    di
  2733.     push    es
  2734.     mov    dx,offset fileio.dta    ; point at dta
  2735.     mov    ah,setdma        ; set the dta address
  2736.     int    dos
  2737.     mov    ah,next2        ; DOS 2.0 search for next
  2738.     int    dos
  2739.     mov    ah,setdma        ; restore dta
  2740.     mov    dx,offset buff
  2741.     int    dos
  2742.     pop    es
  2743.     pop    di
  2744. evalt21b:jmp    evalt99
  2745.  
  2746. evalt24:cmp    evaltype,F_replace    ; \freplace(source,pat,replacement)?
  2747.     jne    evalt25            ; ne = no
  2748.     cmp    arglen+2,0        ; arg2 omitted?
  2749.     jne    evalt24a        ; ne = no
  2750.     mov    cx,arglen        ; source length
  2751.     mov    si,argptr        ; source
  2752.     jmp    evalt24g        ; copy source to output
  2753.  
  2754. evalt24a:push    es            ; provided Take buffer, save
  2755.     push    di
  2756.     mov    ax,seg decbuf        ; use local temp buf
  2757.     mov    es,ax
  2758.     mov    di,offset decbuf    ; as es:di
  2759.     mov    si,argptr        ; make source ds:si
  2760.     mov    cx,arglen        ; length of source
  2761.     cld
  2762. evalt24b:push    cx            ; save source counter
  2763.     push    si            ; save source pointer
  2764.     cmp    cx,arglen+2        ; fewer source bytes than pattern?
  2765.     jb    evalt24e        ; b = yes, no replacement possible
  2766.     mov    bx,argptr+2        ; pattern
  2767.     mov    cx,arglen+2        ; length of pattern
  2768.  
  2769. evalt24c:mov    ah,[bx]            ; pattern byte
  2770.     cmp    [si],ah            ; same as source byte?
  2771.     jne    evalt24e        ; ne = no, no match
  2772.     inc    si            ; next bytes to match
  2773.     inc    bx
  2774.     loop    evalt24c        ; do all pattern bytes
  2775.     mov    si,argptr+4        ; get replacement pattern
  2776.     mov    cx,arglen+4        ; its length
  2777.     mov    ax,di            ; starting offset in temp buffer
  2778.     sub    ax,offset decbuf    ; minus start of buffer
  2779.     add    ax,cx            ; count of bytes to be in buffer
  2780.     cmp    ax,decbuflen        ; longer than buffer?
  2781.     jbe    evalt24d        ; be = no overflow
  2782.     sub    ax,cx            ; get back bytes already in buffer
  2783.     sub    ax,decbuflen
  2784.     neg    ax            ; bytes available
  2785.     mov    cx,ax            ; move just that many
  2786. evalt24d:rep    movsb            ; copy to output (may be nothing)
  2787.     pop    si
  2788.     pop    cx
  2789.     add    si,arglen+2        ; length of pattern
  2790.     sub    cx,arglen+2        ; bytes left in source
  2791.     jmp    short evalt24f
  2792.  
  2793. evalt24e:pop    si            ; mismatch comes here
  2794.     pop    cx
  2795.     movsb                ; write source byte to output buffer
  2796.     dec    cx            ; one less source byte
  2797. evalt24f:or    cx,cx            ; qty of source bytes remaining
  2798.     jg    evalt24b        ; g = more source bytes to examine
  2799.     sub    di,offset decbuf    ; length of output material
  2800.     mov    cx,di
  2801.     mov    ax,cx            ; save length in ax
  2802.     pop    di
  2803.     pop    es            ; original Take buffer
  2804.     call    evmem            ; allocate new Take buffer, len cx
  2805.     mov    si,offset decbuf
  2806.     mov    cx,ax            ; length used in decbuf
  2807. evalt24g:cld
  2808.     rep    movsb            ; copy decbuf to Take buffer
  2809.     mov    bx,takadr
  2810.     sub    di,[bx].takptr
  2811.     mov    [bx].takcnt,di        ; length of ASCIIZ result
  2812.     jmp    evalt99
  2813.  
  2814. evalt25:cmp    evaltype,F_eval        ; \feval(string)?
  2815.     jne    evalt26            ; ne = no
  2816.     mov    ax,argptr
  2817.     mov    domath_ptr,ax
  2818.     mov    ax,arglen
  2819.     or    ax,ax
  2820.     jz    evalt25b        ; z = no argument
  2821.     mov    domath_cnt,ax
  2822.     call    domath            ; return value in DX:AX
  2823.     jc    evalt25b        ; c = error, no value will be written
  2824.     push    di            ; save string destination es:di
  2825.     mov    di,offset decbuf    ; temp work space
  2826.     mov    word ptr [di],0        ; clear it
  2827.     or    dx,dx            ; is result negative?
  2828.     jns    evalt25a        ; ns = no, positive or zero
  2829.     neg    dx            ; flip sign
  2830.     neg    ax
  2831.     sbb    dx,0
  2832.     mov    byte ptr [di],'-'    ; show minus sign
  2833.     inc    di
  2834.  
  2835. evalt25a:call    flnout            ; convert DX:AX to ASCIIZ in DS:DI
  2836.     pop    di            ; recover original di
  2837.     mov    dx,offset decbuf
  2838.     mov    si,dx            ; save as source pointer too
  2839.     call    strlen            ; get length of string to cx
  2840.     cld
  2841.     rep    movsb            ; copy to final buffer
  2842.     mov    bx,takadr
  2843.     sub    di,[bx].takptr        ; end minus start
  2844.     mov    [bx].takcnt,di        ; string length
  2845. evalt25b:jmp    evalt99
  2846.  
  2847. evalt26:cmp    evaltype,F_verify    ; \fverify(pattern,string,offset)?
  2848.     jne    evalt27            ; ne = no
  2849.     cld
  2850.     push    es
  2851.     push    di
  2852.     mov    si,ds
  2853.     mov    es,si
  2854.     mov    di,argptr        ; pattern pointer
  2855.     mov    si,argptr+4        ; offset
  2856.     mov    ax,arglen+4        ; length of offset string
  2857.     call    domath
  2858.     jc    evalt26b        ; c = error
  2859.     mov    bx,ax            ; offset
  2860.     mov    si,argptr+2        ; string
  2861.     add    si,bx            ; string plus offset
  2862.     mov    cx,arglen+2        ; length of string
  2863.     sub    cx,bx            ; minus offset
  2864.     jg    evalt26a        ; g = have string left to compare
  2865.     mov    bx,-1            ; error, report -1 for no string
  2866.     jmp    short evalt26b
  2867. evalt26a:push    di
  2868.     lodsb                ; get a byte of string
  2869.     inc    bx            ; count based 1 for users
  2870.     push    cx            ; one less string byte
  2871.     mov    cx,arglen        ; length of pattern
  2872.     repne    scasb            ; scan for match
  2873.     pop    cx
  2874.     pop    di
  2875.     jne    evalt26b        ; ne = mismatch
  2876.     loop    evalt26a        ; next string char
  2877.     xor    bx,bx            ; report 0 if all match
  2878. evalt26b:mov    ax,bx            ; char position of first mismatch
  2879.     pop    di
  2880.     pop    es
  2881.     call    fdec2di            ; convert to ASCII string
  2882.     mov    bx,takadr
  2883.     sub    di,[bx].takptr        ; end minus start
  2884.     mov    [bx].takcnt,di        ; string length
  2885.     jmp    evalt99
  2886.  
  2887. evalt27:cmp    evaltype,F_ipaddr    ; \fipaddr(string, offset)?
  2888.     jne    evalt29            ; ne = no
  2889.     mov    si,argptr+2        ; offset
  2890.     mov    ax,arglen+2        ; length of offset string
  2891.     mov    domath_ptr,si        ; convert offset to binary
  2892.     mov    domath_cnt,ax
  2893.     call    domath            ; failure means use zero
  2894.     add    argptr,ax
  2895.     sub    arglen,ax
  2896. evalt27a:mov    si,argptr        ; scan string
  2897.     mov    cx,arglen
  2898.     cmp    cx,7            ; enough bytes to qualify?
  2899.     jl    evalt27x        ; l = no, quit
  2900.     cld
  2901. evalt27b:lodsb                ; trim leading spaces
  2902.     sub    al,'0'            ; remove ASCII bias
  2903.     cmp    al,9            ; numeric?
  2904.     jbe    evalt27c        ; be = yes
  2905.     loop    evalt27b
  2906. evalt27c:dec    si            ; break char
  2907.     inc    cx            ; byte count remaining
  2908.     mov    argptr,si        ; remember start of real text
  2909.     mov    arglen,cx        ; and its length
  2910.     call    evalt27w        ; scan for digits
  2911.     jc    evalt27x        ; c = fail
  2912.     cmp    byte ptr [si],'.'    ; looking at dot now?
  2913.     jne    evalt27x        ; ne = fail
  2914.     inc    si
  2915.     call    evalt27w        ; scan for digits
  2916.     jc    evalt27x        ; c = fail
  2917.     cmp    byte ptr [si],'.'    ; looking at dot now?
  2918.     jne    evalt27x        ; ne = fail
  2919.     inc    si
  2920.     call    evalt27w        ; scan for digits
  2921.     jc    evalt27x        ; c = fail
  2922.     cmp    byte ptr [si],'.'    ; looking at dot now?
  2923.     jne    evalt27x        ; ne = fail
  2924.     inc    si
  2925.     call    evalt27w        ; scan for digits
  2926.     jc    evalt27x        ; c = fail
  2927.     mov    al,[si]            ; break byte
  2928.     sub    al,'0'            ; remove ASCII bias
  2929.     cmp    al,9
  2930.     jbe    evalt27x        ; be = is still numberic, fail
  2931.     mov    cx,si            ; break postion
  2932.     sub    cx,argptr        ; minus start
  2933.     jle    evalt27x        ; le = problems, fail
  2934.     mov    si,argptr        ; start
  2935.     rep    movsb            ; copy string to destination
  2936.     mov    bx,takadr
  2937.     sub    di,[bx].takptr        ; end minus start
  2938.     mov    [bx].takcnt,di        ; string length
  2939.     jmp    evalt99
  2940.  
  2941. evalt27x:inc    argptr            ; step to next source byte
  2942.     dec    arglen            ; one less to examine
  2943.     cmp    arglen,7        ; any string left?
  2944.     jge    evalt27a        ; ge = yes, try again
  2945.     jmp    evalt99
  2946.  
  2947. evalt27w proc    near            ; worker to read digits, check range
  2948.     mov    cx,3            ; three digits
  2949.     xor    dx,dx            ; value of digits
  2950. evalt27w1:
  2951.     mov    ax,dx
  2952.     mul    ten            ; previous times ten to ax
  2953.     mov    dx,ax
  2954.     lodsb
  2955.     sub    al,'0'            ; remove ASCII bias
  2956.     cmp    al,9            ; validate decimal
  2957.     ja    evalt27w2        ; a = no
  2958.     add    dl,al            ; number so far
  2959.     jc    evalt27w3        ; c = overflow, fail
  2960.     loop    evalt27w1        ; while in digits
  2961.     inc    si            ; inc to offset dec below
  2962. evalt27w2:
  2963.     dec    si            ; back up to break byte
  2964.     cmp    cx,3            ; must have at least one digit
  2965.     je    evalt27w3        ; e = none, fail
  2966.     clc                ; success, have digits
  2967.     ret
  2968. evalt27w3:
  2969.     stc                ; fail
  2970.     ret
  2971. evalt27w endp
  2972.  
  2973. evalt29:cmp    evaltype,F_tod2secs    ; \ftod2secs(hh:mm:ss)?
  2974.     jne    evalt30            ; ne = no
  2975.     mov    si,argptr        ; hh:mm:ss string
  2976.     mov    bx,arglen
  2977.     mov    byte ptr [si+bx],0    ; terminate string
  2978.     call    tod2secs        ; convert to ASCII long in es:di
  2979.     jc    evalt99            ; c = failed to convert
  2980.     mov    bx,takadr
  2981.     sub    di,[bx].takptr        ; end minus start
  2982.     mov    [bx].takcnt,di        ; string length
  2983.     jmp    evalt99
  2984.  
  2985. evalt30:cmp    evaltype,F_chksum    ; \fchecksum(string)?
  2986.     jne    evalt31
  2987.     mov    si,argptr        ; string
  2988.     mov    cx,arglen
  2989.     xor    bx,bx            ; running sum, low and high portions
  2990.     xor    dx,dx
  2991.     cld
  2992. evalt30a:lodsb
  2993.     add    bl,al            ; accumulate checksum
  2994.     adc    bh,0            ; with carry
  2995.     adc    dx,0
  2996.     loop    evalt30a
  2997.     mov    ax,bx
  2998.     push    di
  2999.     push    es
  3000.     mov    di,ds
  3001.     mov    es,di
  3002.     mov    di,offset argptr
  3003.     call    flnout            ; 32 bit converter
  3004.     mov    dx,offset argptr
  3005.     call    strlen
  3006.     mov    si,dx
  3007.     pop    es
  3008.     pop    di
  3009.     cld
  3010.     rep    movsb
  3011.     mov    bx,takadr
  3012.     sub    di,[bx].takptr        ; end minus start
  3013.     mov    [bx].takcnt,di        ; string length
  3014.     jmp    evalt99
  3015.  
  3016. evalt31:cmp    evaltype,F_basename    ; \fbasename(string)?
  3017.     jne    evalt99
  3018.     mov    dx,argptr        ; string
  3019.     mov    cx,arglen
  3020.     mov    si,dx
  3021.     add    si,cx
  3022.     mov    byte ptr [si],0        ; force null termination
  3023.     push    di
  3024.     mov    di,offset decbuf+100    ; place for path part
  3025.     mov    si,offset decbuf    ; place for filename part
  3026.     call    fparse            ; split pieces
  3027.     pop    di
  3028.     mov    dx,si            ; look only at filename
  3029.     call    strlen
  3030.     rep    movsb            ; copy to result buffer
  3031.     mov    bx,takadr
  3032.     sub    di,[bx].takptr        ; end minus start
  3033.     mov    [bx].takcnt,di        ; string length
  3034.     jmp    evalt99
  3035.  
  3036. evalt99:pop    temp
  3037.     pop    si
  3038.     pop    dx            ; trailing space flag
  3039.     clc                ; success or fail, consume source
  3040.     ret
  3041. evaltoa    endp
  3042.  
  3043. ; Worker for evaltoa. 
  3044. ; Given start of string in DS:SI and string length in CMSIZ.
  3045. ; Return pointers to up to three arguments (as offset of start of their
  3046. ; non-white space) and the lengths of each argument field. Arrays argptr
  3047. ; and arglen hold these 16 bit values.
  3048. ; Bare commas separate arguments, curly braces and parentheses protect commas,
  3049. ; curly braces protect strings, starting with a curly brace is considered to 
  3050. ; mean use material within braces. A closing curly brace closes parens.
  3051. evarg    proc    near
  3052.     push    ax
  3053.     push    bx
  3054.     push    cx
  3055.     push    dx
  3056.     push    si
  3057.     push    temp
  3058.     mov    al,taklev
  3059.     xor    ah,ah
  3060.     mov    temp,ax
  3061.     xor    ax,ax
  3062.     mov    argptr,ax        ; clear arg pointer list
  3063.     mov    argptr+2,ax
  3064.     mov    argptr+4,ax
  3065.     mov    arglen,ax        ; clear arg length list
  3066.     mov    arglen+2,ax
  3067.     mov    arglen+4,ax
  3068.     xor    bx,bx            ; index of argument
  3069.                     ; read start of argument
  3070. evarg10:mov    si,cmrptr        ; last byte + 1 read
  3071.     xor    dx,dx            ; paren and curly brace counters
  3072.     mov    argptr[bx],si        ; where argument string starts
  3073.     mov    cmsiz,0            ; argument length counter
  3074.  
  3075. evarg12:mov    cl,comand.cmper        ; read next argument byte
  3076.     push    cx            ; preserve comand.cmper around call
  3077.     push    temp            ; preserve take level monitor
  3078.     push    evaltype        ; preserve, reading may recurse
  3079.     push    bx            ; preserve argument counter
  3080.     push    dx            ; preserve curly brace counter
  3081.     push    cmsiz
  3082.     mov    cmsflg,0        ; see leading spaces/tabs
  3083.     push    argptr            ; save our working variables
  3084.     push    argptr+2
  3085.     push    argptr+4
  3086.     push    arglen
  3087.     push    arglen+2
  3088.     push    arglen+4
  3089.     cmp    evaltype,F_contents    ; \fcontents(macro)?
  3090.     je    evarg13            ; e = yes
  3091.     cmp    evaltype,F_literal    ; \fliteral(string)?
  3092.     jne    evarg14            ; ne = no
  3093. evarg13:mov    comand.cmper,1        ; arg, treat macros as literals
  3094. evarg14:call    cmgtch            ; recursively read a character into ah
  3095.     pop    arglen+4
  3096.     pop    arglen+2
  3097.     pop    arglen
  3098.     pop    argptr+4
  3099.     pop    argptr+2
  3100.     pop    argptr
  3101.     pop    cmsiz
  3102.     pop    dx
  3103.     pop    bx
  3104.     pop    evaltype
  3105.     pop    temp
  3106.     pop    cx
  3107.     mov    comand.cmper,cl        ; restore macro expansion state
  3108.     pushf                ; save carry flag from cmgtch
  3109.     inc    cmsiz            ; count argument byte
  3110.     push    bx
  3111.     mov    bl,taklev        ; current take level
  3112.     cmp    bl,byte ptr temp    ; react to specials?
  3113.     pop    bx
  3114.     jbe    evarg15            ; be = yes, else in macro/take
  3115.     popf                ; clear stack of cmgtch carry status
  3116.     jmp    evarg12            ; read another byte
  3117.  
  3118. evarg15:popf                ; recover cmgtch carry status
  3119.     jnc    evarg50            ; nc = non-terminator
  3120.     cmp    ah,' '            ; just a space?
  3121.     jne    evarg17            ; ne = no
  3122.     cmp    cmsiz,1            ; is it a leading space?
  3123.     jne    evarg12            ; ne = no, consider it to be data
  3124.     cmp    evaltype,F_literal    ; \fliteral(string)?
  3125.     je    evarg12            ; e = yes, keep leading spaces
  3126.     jmp    evarg10            ; skip space, get first arg byte
  3127.     
  3128. evarg17:cmp    ah,'?'            ; need help?
  3129.     jne    evarg20            ; ne = no
  3130.     call    fcmdhlp            ; compute cmhlp to proper string
  3131.     mov    cmsiz,0            ; so help is with provided text
  3132.     call    cmkyhlp
  3133.     jmp    repars
  3134.  
  3135. evarg20:dec    cmsiz            ; omit byte from count
  3136.     cmp    ah,escape        ; ESC?
  3137.     jne    evarg22            ; ne = no
  3138.     cmp    evaltype,F_contents    ; \fcontents(macro)?
  3139.     je    evarg21            ; e = yes
  3140.     cmp    evaltype,F_definition    ; \fdefinition(macro)?
  3141.     jne    evarg22            ; ne = no
  3142. evarg21:push    cmptab            ; save working pointers
  3143.     push    cmsptr
  3144.     mov    cmptab,offset mcctab    ; look at table of macro names
  3145.     mov    cx,argptr[bx]        ; look at whole word todate
  3146.     mov    cmsptr,cx        ; start of word
  3147.     push    bx
  3148.     call    cmkyesc            ; do escape word completion
  3149.     pop    bx
  3150.     pop    cmsptr
  3151.     pop    cmptab
  3152.     xor    ah,ah            ; in case no match
  3153. evarg22:call    bufreset        ; reset cmwptr
  3154.     cmp    ah,escape        ; escape?
  3155.     jne    evarg30            ; ne = no
  3156.     push    ax
  3157.     push    dx
  3158.     mov    ah,conout        ; ring the bell
  3159.     mov    dl,bell
  3160.     int    dos
  3161.     pop    dx
  3162.     pop    ax
  3163.     jmp    evarg12            ; get next arg byte
  3164. evarg30:jmp    repars            ; reparse command
  3165.  
  3166. evarg50:cmp    ah,braceop        ; opening curly brace?
  3167.     jne    evarg52            ; ne = no
  3168.     inc    dl            ; count up curly brace
  3169.     jmp    evarg12            ; get next argument byte
  3170. evarg52:cmp    ah,bracecl        ; closing curly brace?
  3171.     jne    evarg60            ; ne = no
  3172.     sub    dl,1            ; count down curly braces
  3173.     jge    evarg54            ; ge = no underflow
  3174.      xor    dx,dx            ; clamp at zero
  3175. evarg54:jmp    evarg12
  3176.  
  3177. evarg60:or    dl,dl            ; within curly braces
  3178.     jnz    evarg3            ; nz = yes, don't count parens there
  3179.     cmp    ah,'('            ; opening paren?
  3180.     jne    evarg62            ; ne = no
  3181.     inc    dh            ; count up paren
  3182.     jmp    evarg12            ; get next byte of argument
  3183.  
  3184. evarg62:cmp    ah,')'            ; closing paren?
  3185.     jne    evarg3            ; ne = no
  3186.     sub    dh,1            ; count down closing paren
  3187.     jl    evarg64            ; l = reached terminator
  3188.     jmp    evarg12            ; get next byte of argument
  3189.  
  3190. evarg64:mov    cx,cmsiz
  3191.     dec    cx            ; don't count closing paren
  3192.     mov    arglen[bx],cx
  3193.     cmp    evaltype,F_literal    ; \fliteral(string)?
  3194.     je    evarg66            ; e = yes, keep trailing spaces
  3195.     mov    si,argptr[bx]        ; start of argument
  3196.     add    si,cx
  3197.     dec    si            ; last byte of argument
  3198.     jcxz    evarg66            ; z = no text to trim
  3199. evarg65:cmp    byte ptr [si],' '    ; trailing space?
  3200.     jne    evarg66            ; ne = no
  3201.     dec    si
  3202.     dec    arglen[bx]        ; one less argument byte
  3203.     loop    evarg65
  3204. evarg66:jmp    evarg7            ; ")" marks END of function
  3205.  
  3206. evarg3:    cmp    ah,','            ; possible argument terminator?
  3207.     jne    evarg5            ; ne = no
  3208.     or    dx,dx            ; within paren or curly braces?
  3209.     jne    evarg5            ; ne = yes, treat commas as data
  3210.     cmp    evaltype,F_literal    ; doing \fliteral()?
  3211.     je    evarg5            ; e = yes, commas are data
  3212.     cmp    evaltype,F_eval        ; doing \feval()?
  3213.     je    evarg5            ; e = yes, commas are data
  3214.     dec    cmsiz            ; do not count comma
  3215. evarg4:    mov    cx,cmsiz
  3216.     cmp    bx,3*2            ; done three args?
  3217.     jae    evarg4a            ; ae = yes, add no more args
  3218.     mov    arglen[bx],cx        ; mark argument length
  3219.     add    bx,2            ; next arg array element
  3220. evarg4a:jmp    evarg10            ; get next argument
  3221.  
  3222. evarg5:    jmp    evarg12            ; get next byte in argument
  3223.  
  3224. evarg7:    pop    temp
  3225.     pop    si
  3226.     pop    dx
  3227.     pop    cx
  3228.     pop    bx
  3229.     pop    ax
  3230.     clc
  3231.     ret
  3232. evarg    endp
  3233.  
  3234. ; Reallocates more memory than provided in the default takopen 128 byte buffer.
  3235. ; Enter with desired byte quantity in CX and a Take structure already
  3236. ; present at takadr. Returns with new buffer length in CX, ES:DI pointing
  3237. ; at buffer+2 ([bx].takbuf:[bx].takptr)
  3238. evmem    proc    near
  3239.     push    ax
  3240.     push    bx
  3241.     push    cx
  3242.     mov    bx,takadr
  3243.     mov    ax,[bx].takbuf        ; segment of preallocated memory
  3244.     mov    bx,cx            ; string length, in bytes
  3245.     add    bx,2+1+15        ; count + null term + round up
  3246.     mov    cl,4
  3247.     shr    bx,cl            ; convert to paragraphs (divide by 16)
  3248.     mov    cx,bx            ; remember desired paragraphs
  3249.     mov    ah,alloc        ; allocate a memory block
  3250.     int    dos            ; ax=seg, bx=paragraphs
  3251.     jc    evmem3            ; c = error, not enough memory
  3252.      cmp    bx,cx            ; obtained vs wanted
  3253.     jae    evmem2            ; ae = enough
  3254.     push    bx
  3255.     mov    bx,takadr
  3256.     mov    cx,[bx].takcnt        ; old unread-bytes
  3257.     shr    cx,1
  3258.     shr    cx,1
  3259.     shr    cx,1
  3260.     shr    cx,1            ; to paragraphs
  3261.     pop    bx
  3262.     cmp    bx,cx            ; more than we had originally?
  3263.     ja    evmem2            ; a = yes, so use the new larger buff
  3264.     push    es
  3265.     mov    es,ax            ; new allocated segment
  3266.     mov    ah,freemem        ; free it
  3267.     int    dos
  3268.     pop    es
  3269.     jmp    short evmem3        ; use original segment
  3270.  
  3271. evmem2:    mov    cl,4
  3272.     shl    bx,cl            ; paragraphs to bytes
  3273.     mov    cx,bx            ; return new bytes in CX
  3274.     sub    cx,2            ; minus two for len field
  3275.     mov    es,ax            ; set new segment
  3276.     mov    bx,takadr
  3277.     xchg    [bx].takbuf,ax        ; new segment, swap with old seg
  3278.     or    ax,ax            ; if any allocated
  3279.     jz    evmem2a            ; z = none
  3280.     push    es
  3281.     mov    es,ax            ; old allocated segment
  3282.     mov    ah,freemem        ; free old segment
  3283.     int    dos
  3284.     pop    es
  3285. evmem2a:mov    di,2            ; new offset
  3286.     mov    bx,takadr
  3287.     mov    [bx].takptr,di        ; new offset
  3288.     mov    [bx].takcnt,0        ; total buffer, unread bytes
  3289.     or    [bx].takattr,take_malloc ; malloc'd buffer to remove later
  3290.     pop    bx            ; discard old cx, return new cx
  3291.     pop    bx
  3292.     pop    ax
  3293.     ret
  3294.  
  3295. evmem3:    pop    cx            ; return original values
  3296.     pop    bx
  3297.     pop    ax
  3298.     ret
  3299. evmem    endp
  3300.  
  3301. ; Worker for evaltoa. Sets cmhlp to help string matching evaltype
  3302. fcmdhlp    proc    near
  3303.     mov    ax,evaltype        ; kind of \f command
  3304.     mov    bx,offset f1hlp        ; number
  3305.     cmp    ax,F_char        ; go through types
  3306.     je    fcmdh1            ; e = matched
  3307.     cmp    ax,F_maximum
  3308.     je    fcmdh1
  3309.     cmp    ax,F_minimum
  3310.     je    fcmdh1
  3311.     mov    bx,offset f2hlp        ; char
  3312.     cmp    ax,F_code
  3313.     je    fcmdh1
  3314.     mov    bx,offset f3hlp
  3315.     cmp    ax,F_contents
  3316.     je    fcmdh1
  3317.     cmp    ax,F_definition
  3318.     je    fcmdh1
  3319.     mov    bx,offset f8hlp
  3320.     cmp    ax,F_index
  3321.     je    fcmdh1
  3322.     mov    bx,offset f12hlp
  3323.     cmp    ax,F_lpad
  3324.     je    fcmdh1
  3325.     cmp    ax,F_rpad
  3326.     je    fcmdh1
  3327.     mov    bx,offset f15hlp
  3328.     cmp    ax,F_nextfile
  3329.     je    fcmdh1
  3330.     mov    bx,offset f16hlp
  3331.     cmp    ax,F_repeat
  3332.     je    fcmdh1
  3333.     mov    bx,offset f18hlp
  3334.     cmp    ax,F_right
  3335.     je    fcmdh1
  3336.     mov    bx,offset f20hlp
  3337.     cmp    ax,F_substr
  3338.     je    fcmdh1
  3339.     mov    bx,offset f22hlp
  3340.     cmp    ax,F_date
  3341.     je    fcmdh1
  3342.     cmp    ax,F_basename
  3343.     je    fcmdh1
  3344.     cmp    ax,F_size
  3345.     je    fcmdh1
  3346.     cmp    ax,F_files
  3347.     je    fcmdh1
  3348.     mov    bx,offset f25hlp
  3349.     cmp    ax,F_eval
  3350.     je    fcmdh1
  3351.     mov    bx,offset f8hlp
  3352.     cmp    ax,F_rindex
  3353.     je    fcmdh1
  3354.     mov    bx,offset f30hlp
  3355.     cmp    ax,F_chksum
  3356.     je    fcmdh1
  3357.     mov    bx,offset f9hlp        ; default to text
  3358. fcmdh1:    mov    cmhlp,bx        ; set help text pointer
  3359.     ret
  3360. fcmdhlp    endp
  3361.  
  3362.  
  3363. filedate proc    near
  3364.     push    di
  3365.     push    es
  3366.     mov    dx,offset fileio.dta    ; data transfer address
  3367.     mov    ah,setdma        ; set disk transfer address
  3368.     int    dos
  3369.     mov    bx,argptr        ; filename
  3370.     mov    dx,bx            ; for file open
  3371.     add    bx,arglen        ; length of it
  3372.     mov    byte ptr [bx],0        ; make it ASCIIZ
  3373.     xor    cx,cx            ; attributes: find only normal files
  3374.     mov    ah,first2        ; DOS 2.0 search for first
  3375.     int    dos            ; get file's characteristics
  3376.     pushf                ; save status
  3377.     mov    ah,setdma        ; restore dta
  3378.     mov    dx,offset buff
  3379.     int    dos
  3380.     popf                ; get status
  3381.     pop    es
  3382.     pop    di
  3383.     jnc    filed1            ; nc = success
  3384.     ret                ; fail
  3385. filed1:    cmp    evaltype,F_date        ; want date/time stamp?
  3386.     je    filed3            ; e = yes
  3387.     cmp    evaltype,F_size        ; want file length?
  3388.     jne    filed2            ; ne = no (probably \ffiles(..))
  3389.     mov    ax,fileio.sizelo    ; file size to dx:ax
  3390.     mov    dx,fileio.sizehi
  3391.     call    flnout            ; convert to ASCII
  3392.     mov    byte ptr [di],0        ; terminate
  3393. filed2:    clc
  3394.     ret
  3395.  
  3396. filed3:    mov    bx,offset fileio.dta    ; set work pointer
  3397.     call    filetdate        ; do the work
  3398.     ret
  3399. filedate endp
  3400.  
  3401. ; Write file date and timestamp to ds:di, given DTA in ds:bx.
  3402. filetdate proc    far
  3403.     push    es            ; time/date stamp yyyymmdd hh:mm:ss
  3404.     mov    ax,ds
  3405.     mov    es,ax
  3406.     xor    ah,ah
  3407.     mov    al,[bx+25]        ; yyyyyyym from DOS via file open
  3408.     shr    al,1            ; get year
  3409.     add    ax,1980            ; add bias
  3410.     xor    dx,dx
  3411.     call    flnout            ; put year (1990) in buffer
  3412.     mov    ax,[bx+24]        ; yyyyyyyym mmmddddd  year+month+day
  3413.     shr    ax,1            ; month to al
  3414.     xor    ah,ah
  3415.     mov    cl,4
  3416.     shr    al,cl            ; month to low nibble
  3417.     mov    byte ptr[di],'0'    ; leading digit
  3418.     inc    di
  3419.     cmp    al,9            ; more than one digit?
  3420.     jbe    filed4            ; be = no
  3421.     mov    byte ptr[di-1],'1'    ; new leading digit
  3422.     sub    al,10            ; get remainder
  3423. filed4:    add    al,'0'            ; to ascii
  3424.     stosb                ; end of month
  3425.     mov    al,[bx+24]        ; get day of month
  3426.     and    al,1fh            ; select day bits
  3427.     xor    ah,ah
  3428.     mov    cl,10
  3429.     div    cl            ; quot = al, rem = ah
  3430.     add    ax,'00'            ; add ascii bias
  3431.     stosw                ; leading digit and end of date
  3432.     mov    al,' '            ; space separator
  3433.     stosb
  3434.     mov    al,[bx+23]        ; hours  hhhhhmmm
  3435.     mov    cl,3
  3436.     shr    al,cl            ; move to low nibble
  3437.     xor    ah,ah
  3438.     mov    cl,10
  3439.     div    cl            ; quot = al, rem = ah
  3440.     add    ax,'00'            ; add ascii bias
  3441.     stosw                ; store hours
  3442.     mov    al,':'            ; separator
  3443.     stosb
  3444.     mov    ax,[bx+22]        ; get minutes: hhhhhmmm mmmsssss
  3445.     mov    cl,5
  3446.     shr    ax,cl            ; minutes to low byte
  3447.     and    al,3fh            ; six bits for minutes
  3448.     xor    ah,ah
  3449.     mov    cl,10
  3450.     div    cl
  3451.     add    ax,'00'            ; add ascii bias
  3452.     stosw
  3453.     mov    al,':'            ; separator
  3454.     stosb
  3455.     mov    al,[bx+22]        ; get seconds (double secs really)
  3456.     and    al,1fh
  3457.     shl    al,1            ; DOS counts by two sec increments
  3458.     xor    ah,ah
  3459.     mov    cl,10
  3460.     div    cl
  3461.     add    ax,'00'            ; add ascii bias
  3462.     stosw
  3463.     mov    byte ptr [di],0        ; terminate
  3464.     pop    es
  3465.     ret
  3466. filetdate endp
  3467.  
  3468. ; Set envadr to the string following the <variable=> keyword in the DOS
  3469. ; Environment and set envlen to its length after removing leading and
  3470. ; trailing whitespace.
  3471. ; <variable> starts at ds:<valtmp>, of length cmsiz-1, and can be mixed case.
  3472. ; Return carry set if can't find the <variable=> line in the Environment.
  3473. envvar    proc    near
  3474.     push    es
  3475.     mov    bx,valtmp        ; start of variable name
  3476.     mov    cx,cmsiz        ; length of variable name, w/o ')'
  3477.     or    cx,cx            ; empty?
  3478.     jle    envvar3            ; le = nothing to look for, fail
  3479.     push    bx
  3480.     push    cx
  3481. envvar1:mov    al,byte ptr [bx]    ; scan variable name in our buffer
  3482.     cmp    al,'a'            ; lower case
  3483.     jb    envvar2            ; b = no
  3484.     cmp    al,'z'            ; still in lower case range?
  3485.     ja    envvar2            ; a = no
  3486.     and    al,not 20h        ; convert to DOS's upper case
  3487.     mov    byte ptr [bx],al    ; replace char
  3488. envvar2:inc    bx
  3489.     loop    envvar1
  3490.     pop    cx
  3491.     pop    bx            ; find "<variable>=" in Environment
  3492.     call    fgetenv            ; dx = offset in Environment of "="
  3493.     jnc    envvar4            ; nc = success
  3494.  
  3495.     push    bx
  3496.     push    cx
  3497. envvar1a:mov    al,byte ptr [bx]    ; scan variable name in our buffer
  3498.     cmp    al,'A'            ; upper case
  3499.     jb    envvar2a        ; b = no
  3500.     cmp    al,'Z'            ; still in upper case range?
  3501.     ja    envvar2a        ; a = no
  3502.     or    al,20h            ; convert to DOS's lower case
  3503.     mov    byte ptr [bx],al    ; replace char
  3504. envvar2a:inc    bx
  3505.     loop    envvar1a
  3506.     pop    cx
  3507.     pop    bx            ; find "<variable>=" in Environment
  3508.     call    fgetenv            ; dx = offset in Environment of "="
  3509.     jnc    envvar4            ; nc = success
  3510.  
  3511. envvar3:pop    es            ; no such variable
  3512.     stc                ; c = failure
  3513.     ret
  3514. ; dx has offset in Environment of char "="
  3515. ; ds:valtmp is start of variable name, cmsiz is length + 1 of the name.
  3516. ; Return seg:offset and length variables so we can copy from there in valtoa
  3517. envvar4:push    di
  3518.     push    si
  3519.     xor    ax,ax
  3520.     mov    word ptr envadr,ax    ; offset in env of variable's string
  3521.     mov    word ptr envadr+2,ax    ; seg of same
  3522.     mov    envlen,ax        ; length of string
  3523.     mov    es,psp            ; our Prog Seg Prefix segment
  3524.     mov    ax,es:word ptr[env]    ; pick up Environment address
  3525.     mov    es,ax            ; set es: to Environment segment
  3526.     mov    di,dx            ; line scan pointer
  3527.     cmp    byte ptr es:[di],'='    ; did we stop on this?
  3528.     jne    envvar5            ; ne = no
  3529.     inc    di            ; skip the "=" char
  3530. envvar5:mov    al,es:[di]        ; scan over leading white space
  3531.     inc    di
  3532.     or    al,al            ; end of line terminator?
  3533.     jz    envvarf            ; z = yes, fail
  3534.     cmp    al,TAB            ; HT?
  3535.     jne    envvar6            ; ne = no
  3536.     mov    al,' '            ; HT becomes a space
  3537. envvar6:cmp    al,' '            ; white space?
  3538.     je    envvar5            ; scan off white space
  3539.     dec    di            ; backup to non-white char
  3540.     mov    word ptr envadr,di    ; offset of string in Environment
  3541.     mov    word ptr envadr+2,es    ; seg of string in Environment
  3542.     mov    si,di            ; remember starting offset here
  3543.                     ; remove trailing spaces from string
  3544.     xor    al,al            ; a null
  3545.     mov    cx,127            ; max length to search
  3546.     cld
  3547.     repne    scasb            ; skip over non-nulls
  3548.     dec    di            ; backup to null
  3549.     dec    di            ; backup to last string char
  3550.     mov    cx,di            ; ending offset
  3551.     inc    cx            ; count the char
  3552.     sub    cx,si            ; minus starting offset yields length
  3553.     jcxz    envvar9            ; z = empty string
  3554. envvar7:mov    al,es:[di]        ; last char
  3555.     dec    di            ; backup one char
  3556.     cmp    al,' '            ; space?
  3557.     je    envvar8            ; e = yes
  3558.     cmp    al,TAB            ; HT?
  3559.     jne    envvar9            ; ne = no, end of white space
  3560. envvar8:loop    envvar7            ; keep looking
  3561. envvar9:mov    envlen,cx        ; store the length
  3562.     clc                ; say success
  3563.     jmp    short envvarx
  3564. envvarf:stc                ; say failure
  3565. envvarx:pop    si
  3566.     pop    di
  3567.     pop    es
  3568.     ret
  3569. envvar    endp
  3570.  
  3571. ; Worker for Remote Query System name in mssser.
  3572. ; Enter with variable name in decbuf+6 et seq, name length byte in decbuf+5
  3573. ; with ' ' bias.
  3574. fqryenv    proc    far
  3575.     mov    valtmp,offset decbuf+6    ; start of variable name
  3576.     mov    cl,decbuf+5        ; name length plus bias
  3577.     sub    cl,' '            ; remove bias
  3578.     xor    ch,ch
  3579.     mov    cmsiz,cx        ; name length
  3580.     call    envvar            ; get address of environmental string
  3581.     jnc    fqryenv1        ; nc = success
  3582.     xor    cx,cx            ; failure
  3583.     ret
  3584.  
  3585. fqryenv1:mov    cx,envlen        ; length of string in environment
  3586.     push    es
  3587.     push    ds
  3588.     lds    si,envadr        ; pointer to string
  3589.     mov    di,seg encbuf        ; destination buffer
  3590.     mov    es,di
  3591.     mov    di,offset encbuf
  3592.     cld
  3593.     rep    movsb            ; copy string
  3594.     pop    ds
  3595.     pop    es
  3596.     mov    cx,envlen        ; string length again
  3597.     ret
  3598. fqryenv    endp
  3599.  
  3600. ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove
  3601. ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W.
  3602. ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take
  3603. ; and indirect stdin files (\; means literal semicolon). Return char in AL.
  3604. CMGETC    proc    near            ; Basic raw character reader
  3605.     mov    read_source,0        ; assume direct reading
  3606.     mov    endedbackslash,0    ; clear end of sub scan flag
  3607. cmget01:cmp    comand.cmdirect,0    ; read directly?
  3608.     jne    cmget02            ; ne = yes
  3609.     cmp    taklev,0        ; in a Take file?
  3610.     jne    cmget1            ; ne = yes, do Take reader section
  3611. cmget02:call    isdev            ; is stdin a device or a file?
  3612.     jnc    cmget20            ; nc = file (redirection of stdin)
  3613.     jmp    cmget10            ; c = device, do separately
  3614.  
  3615. cmget20:call    iseof            ; see if file is empty
  3616.     jc    cmget21            ; c = EOF on disk file
  3617.     mov    ah,coninq        ; read the char from file, not device
  3618.     int    dos
  3619.     cmp    al,cr            ; is it a cr?
  3620.     je    cmget01            ; yes, ignore and read next char
  3621.     cmp    al,ctlz            ; Control-Z?
  3622.     je    cmget21            ; e = yes, same as EOF here
  3623.     cmp    al,lf            ; LF's end lines from disk files
  3624.     jne    cmget12            ; ne = not LF, pass along as is
  3625.     mov    al,cr            ; make LF a CR for this parser
  3626.     call    iseof            ; see if this is the last char in file
  3627.     jnc    cmget12            ; nc = not EOF, process new CR
  3628. cmget21:mov    flags.extflg,1        ; EOF on disk file, set exit flag
  3629.     jmp    cmget12            ; do echoing and return
  3630.  
  3631. cmget1:    push    bx            ; read from Take file
  3632.     mov    bx,takadr        ; offset of this Take structure
  3633.     mov    al,[bx].taktyp
  3634.     mov    read_source,al
  3635.     cmp    [bx].takcnt,0        ; bytes remaining in Take buffer
  3636.     jne    cmget4            ; ne = not empty
  3637.     cmp    al,take_file        ; type of Take (file?)
  3638.     jne    cmget3            ; ne = no (macro)
  3639.     call    takrd            ; read another buffer
  3640.     cmp    [bx].takcnt,0        ; anything in the buffer?
  3641.     jne    cmget4            ; ne = yes
  3642. cmget3:    pop    bx            ; clear stack
  3643.     jmp    short cmget5        ; close the Take file
  3644.  
  3645. cmget4:    push    si            ; read from Take non-empty buffer
  3646.     push    es
  3647.     mov    es,[bx].takbuf        ; segment of Take buffer
  3648.     mov    si,[bx].takptr        ; current offset in Take buffer
  3649.     mov    al,es:[si]        ; read a char from Take buffer
  3650.     pop    es
  3651.     inc    si
  3652.     mov    [bx].takptr,si        ; move buffer pointer
  3653.     pop    si
  3654.     dec    [bx].takcnt        ; decrease number of bytes remaining
  3655.     cmp    read_source,take_sub    ; substitution macro?
  3656.     jne    cmget4b            ; ne = no
  3657.     cmp    [bx].takcnt,0        ; read last byte?
  3658.     jne    cmget4b            ; ne = no
  3659.     cmp    al,'\'            ; ended on a backsash?
  3660.     jne    cmget4b            ; ne = no
  3661.     mov    endedbackslash,al    ; setup break end of sub scan
  3662. cmget4b:pop    bx
  3663.  
  3664.     cmp    read_source,take_file    ; kind of Take/macro, file?
  3665.     jne    cmget12            ; ne = no, not a file
  3666.     cmp    al,LF            ; LF?
  3667.     je    cmget01            ; e = yes, ignore
  3668.     cmp    al,ctlz            ; Control-Z?
  3669.     jne    cmget12            ; ne = no, else ^Z = EOF
  3670.  
  3671. cmget5:    push    bx            ; end of file on Take buffer
  3672.     mov    bx,takadr        ; offset of this Take structure
  3673.     mov    ah,[bx].takattr        ; save kind of autoCR
  3674.     pop    bx
  3675.     cmp    read_source,take_sub    ; text subsititution?
  3676.     je    cmget5a            ; e = yes, cannot keep open
  3677.     cmp    comand.cmkeep,0        ; keep Take/macro open after eof?
  3678.     jne    cmget5b            ; ne = yes
  3679. cmget5a:push    ax
  3680.     call    ftakclos        ; close take file
  3681.     pop    ax
  3682.     test    ah,take_autocr        ; add CR on EOF?
  3683.     jnz    cmget5b            ; nz = yes
  3684.     jmp    cmgetc            ; internal macros have no auto CR
  3685. cmget5b:mov    al,CR            ; report CR as last char
  3686.     jmp    short cmget12
  3687.                     ; read from tty device
  3688. cmget10:mov    ah,coninq        ; Get a char from device, not file
  3689.     int    dos            ;  with no echoing
  3690.     or    al,al
  3691.     jnz    cmget11            ; ignore null bytes of special keys
  3692.     int    dos            ; read and discard scan code byte
  3693.     jmp    short cmget10        ; try again
  3694. cmget11:cmp    al,LF            ; LF?
  3695.     jne    cmget12            ; ne = no
  3696.     mov    al,CR            ; replace interactive LF with CR
  3697.  
  3698. cmget12:cmp    al,'C'and 1Fh        ; Control-C?
  3699.     je    cmget14            ; e = yes
  3700.     cmp    al,TAB            ; tab is replaced by space
  3701.     jne    cmget13            ; ne = not tab
  3702.     mov    al,' '
  3703. cmget13:ret                ; normal exit, char is in AL
  3704.  
  3705. cmget14:cmp    in_showprompt,0        ; Non-zero when in showprompt
  3706.     jne    cmget13            ; ne = yes, no editing
  3707.     test    read_source,take_sub+take_macro    ; substitution or macro?
  3708.     jnz    cmget13            ; nz = yes, do not edit line
  3709.     mov    bracecnt,0
  3710.     mov    ah,prstr        ; Control-C handler
  3711.     push    dx
  3712.     mov    dx,offset ctcmsg    ; show Control-C
  3713.     int    dos
  3714.     pop    dx
  3715.     mov    flags.cxzflg,'C'    ; tell others the news
  3716.     jmp    cmexit            ; fail immediately via longjmp
  3717. cmgetc    endp
  3718.  
  3719. ; Read chars from user (cmgetc). Detect terminators. Reads from buffer
  3720. ; cmbuf. Set read pointer cmrptr to next free buffer byte if
  3721. ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for
  3722. ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen.
  3723. ; Edit "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
  3724. ; Return char in AH.
  3725. CMINBF    proc    near            ; Buffer reader, final editor
  3726.     cmp    cmwptr,offset cmdbuf+size cmdbuf-3 ; max buffer size - 3
  3727.     jb    cminb1            ; b = not full for writing
  3728.     mov    ah,conout        ; almost full, notify user
  3729.     push    dx
  3730.     mov    dl,bell
  3731.     int    dos
  3732.     pop    dx
  3733.     cmp    cmrptr,offset cmdbuf+size cmdbuf ; reading beyond buffer?
  3734.     jb    cminb1            ; b = no
  3735.     mov    ah,prstr
  3736.     mov    dx,offset cmer09    ; command too long
  3737.     int    dos
  3738.     jmp    prserr            ; overflow = parse error
  3739.  
  3740. cminb1:    push    bx
  3741.     mov    bx,cmrptr        ; read pointer
  3742.     mov    ah,[bx]            ; get current command char while here
  3743.     cmp    bx,cmwptr        ; do we need to read more?
  3744.     pop    bx            ; no if cmrptr < cmwptr
  3745.     jb    cminb2            ; b: cmrptr < cmwptr (have extra here)
  3746.     call    cmgetc            ; no readahead, read another into al
  3747.     mov    ah,al            ; keep char in 'ah'
  3748.     cmp    read_source,take_sub    ; substitution?
  3749.     je    cminb1a            ; e = yes
  3750.     push    bx
  3751.     mov    bx,cmrawptr        ; where raw writes go (inc remakes)
  3752.     mov    [bx],ah            ; store byte
  3753.     inc    cmrawptr
  3754.     pop    bx
  3755. cminb1a:
  3756.     push    bx
  3757.     mov    bx,cmwptr        ; get the pointer into the buffer
  3758.     mov    [bx],ah            ; put it in the buffer
  3759.     inc    bx
  3760.     mov    cmwptr,bx        ; inc write pointer
  3761.     pop    bx
  3762.     jmp    short cminb1        ; call cmgetc until cmwptr >= cmrptr
  3763.                     ; Char to be delivered is in ah
  3764. cminb2:    cmp    in_showprompt,0        ; Non-zero when in showprompt
  3765.     jne    cminb5            ; ne = yes, no editing
  3766.     test    read_source,take_sub+take_macro    ; substitution or macro?
  3767.     jnz    cminb4            ; nz = yes, do not edit line
  3768.     cmp    ah,'W' and 1fh        ; is it a ^W?
  3769.     jne    cminb3            ; ne = no
  3770.     call    cntrlw            ; kill the previous word
  3771.     jmp    repars            ; need a new command scan (cleans stk)
  3772.  
  3773. cminb3:    cmp    ah,'U' and 1fh        ; is it a ^U?
  3774.     jne    cminb3a            ; ne = no
  3775.     mov    cmwptr,offset cmdbuf    ; reset buffer write pointer
  3776.     mov    cmrptr,offset cmdbuf
  3777.     mov    cmrawptr,offset rawbuf    ; clear raw buffer
  3778.     jmp    repars            ; go start over (cleans stack)
  3779.                     ; BS and DEL
  3780. cminb3a:cmp    ah,DEL            ; delete code?
  3781.     je    cminb3b            ; e = yes
  3782.     cmp    ah,BS            ; Backspace (a delete operator)?
  3783.     jne    cminb4            ; ne = no
  3784. cminb3b:call    bufdel            ; delete char from buffer
  3785.     jc    cminb3c            ; c = did erasure
  3786.     jmp    cminbf            ; no erasure, ignore BS, get more
  3787. cminb3c:jmp    repars            ; could have deleted previous token
  3788.  
  3789. cminb4:    push    bx            ; look for hyphen or \hyphen
  3790.     cmp    ah,CR            ; check for hyphen line continuation
  3791.     jne    cminb4b            ; ne = not end of line
  3792.     call    crprot            ; protect CR?
  3793.     jnc    cminb4e            ; nc = no
  3794.                     ; cmtxt {continued lines} section
  3795.     dec    cmwptr            ; back over CR for both buffers
  3796.     dec    cmrptr
  3797.     mov    bx,cmwptr
  3798.     mov    ah,','            ; replace CR with comma
  3799.     mov    [bx-1],ah
  3800.     mov    bx,cmrawptr
  3801.     mov    [bx-1],ah
  3802.     mov    bx,cmrptr
  3803.     mov    [bx],ah
  3804.                     ; deal with echoing
  3805.     cmp    comand.cmquiet,0    ; quiet mode?
  3806.     jne    cminb4g            ; yes, skip echoing
  3807.     cmp    comand.cmdirect,0    ; direct reading?
  3808.     jne    cminb4f            ; ne = yes, do echoing
  3809.     cmp    taklev,0        ; in a take file?
  3810.     je    cminb4f            ; e = no
  3811.     cmp    read_source,take_comand    ; command reread macro?
  3812.     je    cminb4f            ; e = yes, echo
  3813.     cmp    flags.takflg,0        ; echo take file?
  3814.     je    cminb4g            ; e = no
  3815.     cmp    read_source,take_sub    ; don't echo string substitution
  3816.     je    cminb4g
  3817. cminb4f:
  3818.     push    ax
  3819.     push    dx
  3820.     mov    dl,ah
  3821.     mov    ah,conout        ; echo comma to screen now
  3822.     int     dos
  3823.     mov    ah,prstr        ; and then visually break the line
  3824.     mov    dx,offset crlf
  3825.     int    dos
  3826.     pop    dx
  3827.     pop    ax
  3828. cminb4g:pop    bx
  3829.     clc                ; returns ah = comma
  3830.     ret
  3831.                     ; start regular hyphenation part
  3832. cminb4e:mov    bx,cmwptr        ; get the pointer into the buffer
  3833.     cmp    bx,offset cmdbuf+2    ; do we have a previous char?
  3834.     jb    cminb4b            ; b = no
  3835.     cmp    byte ptr[bx-2],'-'    ; previous char was a hyphen?
  3836.     jne    cminb4b            ; ne = no
  3837.     pop    bx
  3838.     sub    cmwptr,2        ; back over -<cr> for both buffers
  3839.     sub    cmrawptr,2
  3840.     jmp    repars            ; reparse what we now have
  3841. cminb4b:pop    bx
  3842.                     ; Echoing done here
  3843.     cmp    comand.cmquiet,0    ; quiet mode?
  3844.     jne    cminb5            ; yes, skip echoing
  3845.     cmp    comand.cmdirect,0    ; direct reading?
  3846.     jne    cminb4a            ; ne = yes, do echoing
  3847.     cmp    taklev,0        ; in a take file?
  3848.     je    cminb4a            ; e = no
  3849.  
  3850.     cmp    read_source,take_comand    ; command reread macro?
  3851.     je    cminb4a            ; e = yes, echo
  3852.     cmp    flags.takflg,0        ; echo take file?
  3853.     je    cminb5            ; e = no
  3854.     cmp    read_source,take_sub    ; don't echo string substitution
  3855.     je    cminb5
  3856.  
  3857. cminb4a:push    ax            ; save the char
  3858.     cmp    ah,' '            ; printable?
  3859.     jae    cminb4c            ; yes, no translation needed
  3860.     cmp    ah,CR            ; this is printable
  3861.     je    cminb4c
  3862.     cmp    ah,LF
  3863.     je    cminb4c
  3864.     cmp    ah,ESCAPE        ; escape?
  3865.     je    cminb4d            ; do not echo this character
  3866.     push    ax            ; show controls as caret char
  3867.     push    dx
  3868.     mov    dl,5eh            ; caret
  3869.     mov    ah,conout
  3870.     int    dos
  3871.     pop    dx
  3872.     pop    ax
  3873.     add    ah,'A'-1        ; make control code printable
  3874. cminb4c:push    dx
  3875.     mov    dl,ah
  3876.     mov    ah,conout
  3877.     int    dos            ; echo it ourselves
  3878.     pop    dx
  3879. cminb4d:pop    ax            ; and return char in ah
  3880.  
  3881. cminb5:    cmp    ah,CR            ; carriage return?
  3882.     je    cminb6            ; e = yes
  3883.     cmp    ah,LF            ; line feed?
  3884.     je    cminb6
  3885.     cmp    ah,FF            ; formfeed?
  3886.     jne    cminb7            ; none of the above, report bare char
  3887.     call    fcmblnk            ; FF: clear the screen and
  3888.     push    bx
  3889.     push    cx
  3890.     push    dx
  3891.     call    flocate            ; Home the cursor
  3892.     mov    bx,cmwptr        ; make the FF parse like a cr
  3893.     mov    byte ptr [bx-1],cr    ; pretend a carriage return were typed
  3894.     pop    dx
  3895.     pop    cx
  3896.     pop    bx
  3897. cminb6: cmp    cmwptr,offset cmdbuf    ; parsed any chars yet?
  3898.     jne    cminb7            ; ne = yes
  3899.     cmp    comand.cmcr,0        ; bare cr's allowed?
  3900.     jne    cminb7            ; ne = yes
  3901.     jmp    prserr            ; If not, just start over
  3902. cminb7:    clc
  3903.     ret
  3904. cminbf    endp
  3905.  
  3906. ; Read chars from cminbf. Cmrptr points to next char to be read.
  3907. ; Compresses repeated spaces if cmsflg is non-zero. Exit with cmrptr pointing
  3908. ; at a terminator or otherwise at next free slot.
  3909. ; Non-space then space acts as a terminator but cmrptr is incremented.
  3910. ; Substitution variables, '\%x', and \numbers are detected and expanded.
  3911. ; Return char in AH.
  3912. ; If a \blah parse fails then report the \ to the caller and start over, 
  3913. ; without echo, on the char following that \. Replay_skip does the \
  3914. ; passage without calling subst, replay_cnt rereads bytes after it.
  3915. CMGTCH    proc    near            ; return char in AH, from rescan buf
  3916.     cmp    replay_cnt,0        ; starting a replay?
  3917.     je    cmgtc5            ; e = no
  3918.     mov    replay_skip,1        ; set latch to skip subst on 1st byte
  3919. cmgtc5:    cmp    in_reparse,0        ; replaying material?
  3920.     je    cmgtc0            ; e = no
  3921.     call    remake            ; remake command line as macro
  3922.  
  3923. cmgtc0:    cmp    replay_cnt,0        ; replay with no echo?
  3924.     jne    cmgtc1            ; ne = yes, have in cmdbuf now
  3925.     call    cminbf            ; get char from buffer or user
  3926. cmgtc1:    push    bx
  3927.     mov    bx,cmrptr        ; get read pointer into the buffer
  3928.     mov    ah,[bx]            ; read the next char
  3929.     inc    bx
  3930.     mov    cmrptr,bx        ; where to read next time
  3931.     cmp    replay_cnt,0        ; replaying?
  3932.     jne    cmgtc6            ; ne = yes, don't take the branch
  3933.     cmp    bx,cmwptr        ; still reading analyzed text?
  3934. cmgtc6:    pop    bx
  3935.     jb    cmgtc2            ; b = yes, don't reexpand
  3936.     cmp    replay_skip,0        ; replay latch set?
  3937.     je    cmgtc7            ; e = no, re-read new bytes in subst
  3938.     mov    replay_skip,0         ; clear latch after the first re-read byte
  3939.     jmp    cmgtc2            ; and skip subst on that first byte
  3940.     cmp    replay_cnt,0        ; replaying?
  3941.     jne    cmgtc2            ; ne = yes
  3942. cmgtc7:
  3943.     call    subst            ; examine for text substitution
  3944.     jc    cmgtch            ; c = reread input material
  3945.     cmp    report_binary,0        ; report binary number directly?
  3946.     je    cmgtc2b            ; e = no
  3947.     mov    report_binary,0        ; clear flag
  3948.     clc                ; value is in ah, non-terminator
  3949.     ret
  3950.  
  3951. cmgtc2:    push    bx
  3952.     mov    bx,replay_cnt        ; count down replay bytes
  3953.     or    bx,bx    
  3954.     jz    cmgtc2a            ; z = empty 
  3955.     dec    replay_cnt
  3956. cmgtc2a:pop    bx
  3957. cmgtc2b:cmp    ah,','            ; comma?
  3958.     jne    cmgtc2c            ; ne = no
  3959.     cmp    comand.cmcomma,0    ; comma is space equivalent?
  3960.     je    cmgtc2c            ; e = no
  3961.     mov    ah,' '            ; convert comma to space
  3962. cmgtc2c:cmp    ah,' '            ; space?
  3963.     jne    cmgtc3            ; ne = no
  3964.     cmp    cmsiz,0            ; started user data?
  3965.     je    cmgtc2d            ; e = no, this is a leading space
  3966.     cmp    cmkind,cmline        ; doing full lines of text?
  3967.     je    cmgtc3            ; e = yes, retain all spaces
  3968. cmgtc2d:cmp    bracecnt,0        ; are we within braces?
  3969.     jne    cmgtc3            ; ne = yes, treat space as literal
  3970.     cmp    cmsflg,0        ; space flag, was last char a space?
  3971.     jne    cmgtch            ; ne = yes, get another char
  3972.     mov    cmsflg,0FFH        ; set the space(s)-seen flag
  3973.     stc                ; set carry for terminator
  3974.     ret                ; return space as a terminator
  3975. cmgtc3: mov    cmsflg,0        ; clear the space-seen flag
  3976.     cmp    ah,braceop        ; opening brace?
  3977.     jne    cmgtc3b            ; ne = no
  3978.     inc    bracecnt        ; count it
  3979.     jmp    short cmgtc3c
  3980. cmgtc3b:cmp    ah,bracecl        ; closing brace?
  3981.     jne    cmgtc3c            ; ne = no
  3982.     sub    bracecnt,1        ; count down and get a sign bit
  3983.     jns    cmgtc3c            ; ns = no underflow
  3984.     mov    bracecnt,0        ; catch underflows
  3985.                     ; terminators remain in buffer but
  3986.                     ;  are ready to be overwritten
  3987. cmgtc3c:test    read_source,take_sub    ; substitution macro?
  3988.     jnz    cmgtc3d            ; nz = yes, pass all bytes as data
  3989.     cmp    ah,escape        ; Escape expander?
  3990.     jne    cmgtc3e            ; ne = no
  3991.     cmp    read_source,0        ; reading from keyboard directly?
  3992.     jne    cmgtc4            ; ne = no, escape is regular char
  3993.  
  3994. cmgtc3e:cmp    ah,'?'            ; is the user curious?
  3995.     jne    cmgtc3a            ; ne = no
  3996.     cmp    taklev,0        ; in a Take file?
  3997.     jne    cmgtc3d            ; ne = yes, make query ordinary char
  3998.     je    cmgtc4
  3999. cmgtc3a:cmp    ah,CR            ; these terminators?
  4000.     je    cmgtc4            ; e = yes
  4001.     cmp    ah,LF
  4002.     je    cmgtc4
  4003.     cmp    ah,FF
  4004.     je    cmgtc4
  4005.     cmp    ah,ESCAPE
  4006.     je    cmgtc4
  4007. cmgtc3d:clc                ; carry clear for non-terminator
  4008.     ret
  4009. cmgtc4:    dec    cmrptr            ; point at terminating char
  4010.     stc                ; set carry to say it is a terminator
  4011.     ret
  4012. cmgtch    endp
  4013.  
  4014. ; Reset cmdbuf write pointer (cmwptr) to where the read pointer
  4015. ; (cmrptr) is now. Discards material not yet read.
  4016. bufreset proc    near
  4017.     push    cmrptr            ; where next visible char is read
  4018.     push    ax            ; count removed curly braces
  4019.     push    si
  4020.     mov    si,cmrptr        ; where to look
  4021.     mov    cx,cmwptr        ; last place being removed
  4022.     xor    ah,ah            ; get a null
  4023.     sub    cx,si            ; length to examine
  4024.     jle    bufres3a        ; le = nothing to scan
  4025.     cld
  4026. bufres1:lodsb
  4027.     cmp    al,braceop        ; opening brace, counted already?
  4028.     jne    bufres2            ; ne = no
  4029.     dec    bracecnt        ; uncount it
  4030.     jmp    short bufres3
  4031. bufres2:cmp    al,bracecl        ; closing brace, counted already?
  4032.     jne    bufres3            ; jne = no
  4033.     inc    bracecnt        ; uncount it
  4034. bufres3:loop    bufres1
  4035. bufres3a:cmp    bracecnt,ah        ; negative?
  4036.     jge    bufres4            ; ge = no
  4037.     mov    bracecnt,ah
  4038. bufres4:mov    word ptr [si],0        ; terminate buffer
  4039.     pop    si
  4040.     pop    ax
  4041.     pop    cmwptr            ; where new char goes in buffer
  4042.     ret
  4043. bufreset endp
  4044.  
  4045. ; Delete character from screen and adjust buffer. Returns carry clear if
  4046. ; no erasure, carry set otherwise.
  4047. bufdel    proc    near
  4048.     cmp    read_source,take_sub    ; substitution macro?
  4049.     je    bufdel0            ; e = yes, does not change cmrawptr
  4050.     cmp    cmrawptr,offset rawbuf    ; anything written to base level buf?
  4051.     ja    bufdel7            ; a = yes
  4052.     mov    cmrawptr,offset rawbuf    ; safety
  4053.     mov    ax,offset cmdbuf
  4054.     mov    cmrptr,ax
  4055.     mov    cmwptr,ax
  4056.     clc                ; do nothing
  4057.     ret
  4058. bufdel7:dec    cmrawptr        ; backup one byte
  4059.     push    bx
  4060.     mov    bx,cmrawptr
  4061.     cmp    byte ptr [bx],BS    ; last read was BackSpace?
  4062.     pop    bx
  4063.     jne    bufdel8            ; ne = not BS
  4064.     dec    cmrawptr        ; backup write pointer over BS too
  4065. bufdel8:cmp    cmrawptr,offset rawbuf    ; sanity check, back too far?
  4066.     jae    bufdel9            ; ae = not too far
  4067.     mov    cmrawptr,offset rawbuf    ; reset to start of buffer
  4068. bufdel9:cmp    comand.cmdirect,0    ; doing direct reading?
  4069.     jne    bufdel0            ; ne = yes
  4070.     mov    ax,offset cmdbuf
  4071.     mov    cmwptr,ax        ; reset normal parse buffer
  4072.     mov    cmrptr,ax
  4073.     mov    bx,ax
  4074.     mov    word ptr [bx],0        ; terminate buffer
  4075.     mov    in_reparse,1        ; say need to replay from rawbuf
  4076.     jmp    repars            ; reparse command
  4077.  
  4078. bufdel0:cmp    cmrptr,offset cmdbuf    ; at start of buffer now?
  4079.     jbe    bufdel5            ; be = yes
  4080.     push    ax
  4081.     push    si
  4082.     mov    si,cmrptr
  4083.     mov    al,[si]
  4084.     dec    si
  4085.     xor    ah,ah            ; get a null
  4086.     cmp    al,braceop        ; opening brace, counted already?
  4087.     jne    bufdel1            ; ne = no
  4088.     dec    bracecnt        ; uncount it
  4089.     jmp    short bufdel2
  4090. bufdel1:cmp    al,bracecl        ; closing brace?
  4091.     jne    bufdel2            ; ne = no
  4092.     inc    bracecnt        ; uncount it
  4093. bufdel2:cmp    bracecnt,ah        ; negative?
  4094.     jge    bufdel3            ; ge = no
  4095.     mov    bracecnt,ah
  4096. bufdel3:pop    si
  4097.     pop    ax
  4098.     mov    replay_cnt,0        ; clear protected replay byte count
  4099.     dec    cmrptr            ; remove previous char from buffer
  4100.     cmp    cmrptr,offset cmdbuf    ; back too far?
  4101.     jae    bufdel4            ; ae = no, material can be erased
  4102.     mov    cmrptr,offset cmdbuf    ; set to start of buffer
  4103.     mov    bracecnt,ah        ; ensure this is now cleared
  4104. bufdel5:call    bufreset        ; reset buffer
  4105.     clc                ; say no erasure
  4106.     ret
  4107. bufdel4:call    bufreset        ; reset buffer
  4108.     stc                ; say did erasure
  4109.     ret
  4110. bufdel    endp
  4111.  
  4112. ; Remake the current command line, omitting substitution macro contents,
  4113. ; as a macro (kind is comand, almost "macro"). Current command line is
  4114. ; in rawbuf, with cmrawptr pointing next place to write.
  4115. ; Closes currently active substitution macros.
  4116. remake    proc    near
  4117.     push    bx
  4118.     push    cx
  4119.     push    dx
  4120.     push    di
  4121.     mov    cmrptr,offset cmdbuf
  4122.     mov    cmwptr,offset cmdbuf    ; clear work buffer
  4123.     mov    cx,cmrawptr        ; where to write next
  4124.     mov    cmrawptr,offset rawbuf
  4125.     sub    cx,offset rawbuf    ; length of string
  4126.     jle    remake3            ; le = nothing to do
  4127. remake1:cmp    taklev,0        ; in a take file?
  4128.     je    remake2            ; e = no
  4129.     mov    bx,takadr
  4130.     cmp    [bx].taktyp,take_sub    ; sub macro?
  4131.     jne    remake2            ; ne = no
  4132.     push    cx
  4133.     call    ftakclos        ; close sub macros
  4134.     pop    cx
  4135.     jmp    short remake1        ; next victim
  4136. remake2:call    takopen_macro        ; open take as macro (comand kind)
  4137.     mov    bx,takadr        ; pointer to new Take structure
  4138.     mov    [bx].taktyp,take_comand ; that's us
  4139.     and    [bx].takattr,not take_autocr ; no CR at end of macro please
  4140.     mov    [bx].takcnt,cx        ; number of unread bytes
  4141.     mov    [bx].takbuf,seg rawbuf    ; segment of Take buffer
  4142.     mov    cx,offset rawbuf
  4143.     mov    [bx].takptr,cx         ; offset to read from
  4144.     mov    cmrawptr,cx
  4145. remake3:mov    in_reparse,0        ; clear our flag
  4146.     mov    bracecnt,0
  4147.     mov    replay_cnt,0
  4148.     mov    comand.cmkeep,0
  4149.     pop    di
  4150.     pop    dx
  4151.     pop    cx
  4152.     pop    bx
  4153.     ret
  4154. remake endp
  4155.  
  4156. ; Come here is user types ^W when during input. Remove word from buffer.
  4157. cntrlw    proc    near
  4158.     push    ax
  4159.     push    cx
  4160.     push    dx
  4161.     call    bufreset        ; truncate buffer at cmrptr
  4162.     mov    si,cmwptr        ; assumed source pointer
  4163.     mov    cx,cmrptr        ; read pointer
  4164.     sub    cx,offset cmdbuf    ; compute chars in buffer
  4165.     cmp    comand.cmdirect,0    ; direct reading?
  4166.     jne    cntrl3            ; ne = yes, only one buffer
  4167.  
  4168.     dec    cmrawptr        ; back over ^W
  4169.     mov    si,cmrawptr        ; use raw buf as source pointer
  4170.     mov    cx,si            ; point at last written byte
  4171.     sub    cx,offset rawbuf    ; count of bytes before ^W
  4172.     jle    ctlw2            ; le = none
  4173. cntrl3:    clc                ; say have not yet modified line
  4174.     jcxz    ctlw2            ; z = nothing to do, exit no-carry
  4175.     push    es
  4176.     std                ; scan backward
  4177.     mov    ax,ds
  4178.     mov    es,ax            ; point to the data are
  4179.     mov    di,si            ; looking from here
  4180.     dec    di
  4181.     mov    al,' '
  4182.     repe    scasb            ; look for non-space
  4183.     je    ctlw1            ; all spaces, nothing to do
  4184.     inc    di            ; move back to non-space
  4185.     inc    cx
  4186.     repne    scasb            ; look for a space
  4187.     jne    ctlw1            ; no space, leave ptrs alone
  4188.     inc    di
  4189.     inc    cx            ; skip back over space
  4190. ctlw1:    inc    di
  4191.     pop    es
  4192.     cld                ; reset    direction flag
  4193.     mov    cmwptr,di        ; update pointer
  4194.     cmp    comand.cmdirect,0    ; direct reading?
  4195.     jne    ctlw2            ; ne = yes, only one buffer
  4196.     inc    di            ; leave a char for bufdel
  4197.     mov    cmrawptr,di        ; setup delete initial byte of word
  4198.     call     bufdel            ; delete item, reparse
  4199. ctlw2:    pop    dx
  4200.     pop    cx
  4201.     pop    ax
  4202.     ret
  4203. cntrlw    endp
  4204.  
  4205. ; returns carry set if CR is to be protected
  4206. ; returns carry clear if CR is unprotected
  4207. crprot proc near            ; cmtxt {continued lines} section
  4208.     cmp    comand.cmcnvkind,cmcnv_crprot    ; braces span lines?
  4209.     jne    crprotx            ; ne = no, do regular hyphenation
  4210.     cmp    cmkind,cmkey
  4211.     je    crprotx
  4212.     cmp    bracecnt,0        ; are curly braces matched yet?
  4213.     je    crprotx            ; e = yes, then this is ignorable
  4214.     stc                ; CR needs protection
  4215.     ret
  4216. crprotx:clc
  4217.     ret
  4218. crprot    endp
  4219.  
  4220. ; Jump to REPARS to do a rescan of the existing buffer.
  4221. ; Jump to PRSERR on a parsing error (quits command, clears old read material)
  4222.  
  4223. PRSERR    PROC FAR
  4224.     mov    cmwptr,offset cmdbuf    ; initialize write pointer
  4225.     mov    ah,prstr
  4226.     mov    dx,offset crlf        ; leave old line, start a new one
  4227.     int    dos
  4228.     call    rprompt            ; restore master prompt level
  4229.                     ; reparse current line
  4230. REPARS:    mov    cmrptr,offset cmdbuf    ; reinit read pointer
  4231.     xor    ax,ax
  4232.     mov    cmsflg,0ffh        ; strip leading spaces
  4233.     mov    subcnt,al        ; clear substitution state variables
  4234.     mov    subtype,al
  4235.     mov    bracecnt,al
  4236.     call    optionclr        ; clear parser options
  4237.     cmp    in_showprompt,al    ; redoing the prompt itself?
  4238.     jne    prser3            ; ne = yes, suppress display
  4239.     cmp    comand.cmdirect,al    ; doing direct reading?
  4240.     jne    prser2            ; ne = yes
  4241.     cmp    taklev,al        ; in Take cmd?
  4242.     je    prser2            ; e = no
  4243.     cmp    flags.takflg,al        ; echo contents of Take file?
  4244.     je    prser3            ; e = no
  4245. prser2:    call    fctlu            ; clear display's line, reuse it
  4246.     mov    dx,comand.cmprmp    ; display the asciiz prompt
  4247.     call    prtasz
  4248. prser3:    mov    bx,0ffffh        ; returned keyword value
  4249.     mov    sp,comand.cmostp    ; set new sp to old one
  4250.     jmp    dword ptr comand.cmrprs    ; jump to just after the prompt call
  4251. PRSERR    ENDP
  4252.  
  4253. ; Restore prompt material to that of the master prompt. This removes settings
  4254. ; of local PROMPT calls so we can reprompt at the main Kermit level.
  4255. RPROMPT    proc    near
  4256.     push    ax            ; Must preserve AX
  4257.     mov    replay_cnt,0
  4258.     mov    ax,mcmprmp        ; address of prompt string
  4259.     or    ax,ax            ; any address given yet?
  4260.     jz    rprompt1        ; z = none, not inited yet
  4261.     mov    comand.cmprmp,ax    ; set current address ptr
  4262.     mov    ax,word ptr mcmrprs    ; offset of reparse address
  4263.     mov    word ptr comand.cmrprs,ax
  4264.     mov    ax,word ptr mcmrprs+2    ; segment of reparse address
  4265.     mov    word ptr comand.cmrprs+2,ax
  4266.     mov    ax,mcmostp        ; stack ptr at reparse time
  4267.     mov    comand.cmostp,ax
  4268.     mov    cmrawptr,offset rawbuf    ; base/raw buffer write ptr, reset
  4269.     mov    in_reparse,0        ; clear buffer remake flag
  4270. rprompt1:pop    ax
  4271.     ret
  4272. RPROMPT    endp
  4273.  
  4274. ; Clear comand.* options to defaults
  4275. optionclr proc    near
  4276.     push    ax
  4277.     xor    ax,ax
  4278.     mov    comand.cmwhite,al    ; clear whitespace flag
  4279.     mov    comand.cmper,al        ; reset to variable recognition
  4280.     mov    comand.cmkeep,al    ; do not keep Take file open
  4281.     mov    comand.impdo,al        ; clear flag to prevent loops
  4282.     mov    comand.cmquiet,al    ; permit echoing again
  4283.     mov    comand.cmblen,ax    ; set user buffer length to unknown
  4284.     mov    comand.cmdonum,al    ; defeat \number expansion
  4285.     mov    comand.cmcomma,al    ; comma is not a space
  4286.     mov    comand.cmarray,al    ; disallow sub in [..]
  4287.     mov    comand.cmcnvkind,cmcnv_none ; default is no conversion
  4288.     pop    ax
  4289.     ret
  4290. optionclr endp
  4291.  
  4292. ; write \v(ARGC) contents to ds:di
  4293. wrtargc    proc    near
  4294.     xor    ax,ax
  4295.     cmp    taklev,0        ; in a Take/Macro?
  4296.     je    wrtarg1            ; e = no
  4297.     mov    bx,takadr        ; current Take structure
  4298.     mov    ax,[bx].takargc        ; get ARGC
  4299. wrtarg1:call    fdec2di            ; write as ascii
  4300.     mov    word ptr es:[di],0020h    ; space and null terminator
  4301.     ret
  4302. wrtargc    endp
  4303.  
  4304. ; write \v(COUNT) text to ds:di
  4305. wrtcnt    proc    near
  4306.     xor    ax,ax
  4307.     cmp    taklev,0        ; in a Take/Macro?
  4308.     je    wrtcnt1            ; e = no
  4309.     mov    bx,takadr        ; current Take structure
  4310.     mov    ax,[bx].takctr        ; get COUNT
  4311. wrtcnt1:call    fdec2di            ; write as ascii
  4312.     ret
  4313. wrtcnt    endp
  4314.  
  4315. ; write \v(DATE) text to ds:di
  4316. wrtdate    proc    near
  4317.     push    cx
  4318.     push    dx
  4319.     mov    ah,getdate        ; DOS date (cx= yyyy, dh= mm, dl= dd)
  4320.     int    dos
  4321.     xor    ah,ah
  4322.     mov    al,dl            ; day
  4323.     call    wrtdat5
  4324.     mov    byte ptr es:[di],' '
  4325.     inc    di
  4326.     xor    bh,bh
  4327.     mov    bl,dh            ; month
  4328.     dec    bx            ; count from zero
  4329.     shl    bx,1            ; count four byte groups
  4330.     shl    bx,1
  4331.     mov    ax,word ptr month[bx]
  4332.     stosw
  4333.     mov    ax,word ptr month[bx+2]
  4334.     stosw
  4335.     mov    ax,cx            ; year
  4336. wrtdat3:call    wrtdat5
  4337.     mov    word ptr es:[di],0020h    ; space and null terminator
  4338.     pop    dx
  4339.     pop    cx
  4340.     ret
  4341.  
  4342. wrtdat5:cmp    ax,10            ; leading tens digit present?
  4343.     jae    wrtdat6            ; ae = yes
  4344.     mov    byte ptr es:[di],'0'    ; insert leading 0
  4345.     inc    di
  4346. wrtdat6:call    fdec2di            ; write decimal asciiz to buffer
  4347.     ret
  4348.  
  4349. wrtdate    endp
  4350.  
  4351. ; write \v(ERRORLEVEL) text to ds:di
  4352. wrterr    proc    near
  4353.     mov    al,errlev        ; current Errorlevel
  4354.     xor    ah,ah
  4355.     call    fdec2di            ; write as ascii
  4356.     mov    word ptr es:[di],0020h    ; space and null terminator
  4357.     ret
  4358. wrterr    endp
  4359.  
  4360. ; write \v(KEYBOARD) text to ds:di
  4361. wrtkbd    proc    near
  4362.     mov    ax,keyboard        ; 88 or 101 keyboard keys
  4363.     call    fdec2di            ; write as ascii
  4364.     mov    word ptr es:[di],0020h    ; space and null terminator
  4365.     ret
  4366. wrtkbd    endp
  4367.  
  4368. ; write \v(NDATE) text to ds:di
  4369. ; where NDATE is YYYYMMDD
  4370. wrtndate proc    near
  4371.     mov    ah,getdate        ; DOS date (cx= yyyy, dh= mm, dl= dd)
  4372.     int    dos
  4373.     push    dx            ; save dx
  4374.     mov    ax,cx            ; year
  4375.     call    fdec2di            ; convert it
  4376.     pop    dx            ; get mm:dd
  4377.     push    dx
  4378.     mov    al,dh            ; months are next
  4379.     xor    ah,ah
  4380.     cmp    al,10            ; less than 10?
  4381.     jae    wrtndat1        ; ae = no
  4382.     mov    byte ptr es:[di],'0'    ; leading 0
  4383.     inc    di
  4384. wrtndat1:call    fdec2di
  4385.     pop    dx
  4386.     mov    al,dl            ; get days
  4387.     xor    ah,ah
  4388.     cmp    al,10            ; less than 10?
  4389.     jae    wrtndat2        ; ae = no
  4390.     mov    byte ptr es:[di],'0'    ; leading 0
  4391.     inc    di
  4392. wrtndat2:call    fdec2di
  4393.     mov    word ptr es:[di],0020h    ; space and null terminator
  4394.     ret
  4395. wrtndate endp
  4396.  
  4397. ; write \v(DIRECTORY) text to es:di
  4398. wrtdir    proc    near
  4399.     push    si
  4400.     mov    ah,gcurdsk        ; get current disk
  4401.     int    dos
  4402.     add    al,'A'            ; make al = 0 == 'A'
  4403.     stosb
  4404.     mov    ax,'\:'
  4405.     stosw
  4406.     mov    si,di            ; work buffer
  4407.     push    ds
  4408.     mov    cx,es
  4409.     mov    ds,cx
  4410.     mov    ah,gcd            ; get current directory
  4411.     xor    dl,dl            ; use current drive
  4412.     int    dos            ; get ds:si = asciiz path (no drive)
  4413.     pop    ds
  4414.     mov    dx,si
  4415.     push    ds
  4416.     mov    cx,es
  4417.     mov    ds,cx
  4418.     call    strlen
  4419.     pop    ds
  4420.     add    di,cx
  4421. wrtdir1:mov    word ptr es:[di],0020h    ; space and null terminator
  4422.     pop    si
  4423.     ret
  4424. wrtdir    endp
  4425.  
  4426. fwrtdir    proc    far
  4427.     call    wrtdir
  4428.     ret
  4429. fwrtdir    endp
  4430.  
  4431. ; write \v(PLATFORM) text to ds:di
  4432. wrtplat    proc    near
  4433.     push    si
  4434.     mov    si,offset machnam    ; machine name in sys dep file
  4435.     cld
  4436. wrtplat1:lodsb                ; get a char
  4437.     cmp    al,'$'            ; terminator?
  4438.     je    wrtplat2        ; e = yes
  4439.     stosb                ; store char
  4440.     jmp    short wrtplat1        ; keep going
  4441. wrtplat2:mov    word ptr es:[di],0020h    ; space and null terminator
  4442.     pop    si
  4443.     ret
  4444. wrtplat    endp
  4445.  
  4446. ; write \v(PORT) text to ds:di
  4447. wrtport    proc    near
  4448.     push    bx
  4449.     push    si
  4450.     mov    al,flags.comflg        ; get coms port indicator
  4451.     mov    bx,offset comptab    ; table of comms ports
  4452.     mov    cl,[bx]            ; number of entries
  4453.     xor    ch,ch
  4454.     inc    bx
  4455. wrtpor3:mov    dx,[bx]            ; length of this entry
  4456.     mov    si,bx
  4457.     add    si,2            ; points to entry text string
  4458.     add    si,dx            ; point to qualifier
  4459.     cmp    [si],al            ; our port?
  4460.     je    wrtpor4            ; e = yes
  4461.     add    bx,[bx]            ; add text length
  4462.     add    bx,4            ; plus count and qualifier
  4463.     loop    wrtpor3            ; next entry
  4464.     jmp    short wrtpor5        ; no match, curious
  4465. wrtpor4:mov    si,bx            ; point at entry
  4466.     add    si,2            ; point at string
  4467.     mov    cx,[bx]            ; length of string
  4468.     cld
  4469.     rep    movsb            ; copy to DS:DI
  4470. wrtpor5:mov    word ptr es:[di],0020h    ; space and null terminator
  4471.     pop    si
  4472.     pop    bx
  4473.     ret
  4474. wrtport    endp
  4475.  
  4476. ; write \v(PROGRAM) text to ds:si
  4477. wrtprog    proc    near
  4478.     push    si
  4479.     mov    si,offset progm        ; source string
  4480.     cld
  4481. wrtprg1:lodsb
  4482.     cmp    al,'$'            ; terminator?
  4483.     je    wrtprg2            ; e = yes
  4484.     stosb                ; store the char
  4485.     jmp    short wrtprg1
  4486. wrtprg2:mov    word ptr es:[di],0020h    ; space and null terminator
  4487.     pop    si
  4488.     ret
  4489. wrtprog    endp
  4490.  
  4491. ; write \v(STATUS) text to ds:di
  4492. wrtstat    proc    near
  4493.     mov    ax,kstatus        ; Kermit status word
  4494.     call    fdec2di
  4495.     mov    word ptr es:[di],0020h    ; space and null terminator
  4496.     ret
  4497. wrtstat    endp
  4498.  
  4499. ; write \v(SYSTEM) text to ds:di
  4500. wrtsystem proc    near
  4501.     push    si
  4502.     mov    si,offset system    ; system string "MS-DOS", dollar sign
  4503.     cld
  4504.     jmp    wrtplat1        ; use some common code
  4505. wrtsystem endp
  4506.  
  4507. ; write \v(TIME) text to ds:di
  4508. wrttime    proc    near
  4509.     mov    ah,gettim        ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
  4510.     int    dos
  4511.     push    dx            ; save dx
  4512.     xor    ah,ah
  4513.     mov    al,ch            ; Hours
  4514.     cmp    al,10            ; leading digit?
  4515.     jae    wrttim1            ; ae = yes
  4516.     mov    byte ptr es:[di],'0'    ; make our own
  4517.     inc    di
  4518. wrttim1:call    fdec2di            ; write decimal asciiz to buffer
  4519.     mov    byte ptr es:[di],':'
  4520.     inc    di
  4521.     xor    ah,ah
  4522.     mov    al,cl            ; Minutes
  4523.     cmp    al,10            ; leading digit?
  4524.     jae    wrttim2            ; ae = yes
  4525.     mov    byte ptr es:[di],'0'    ; make our own
  4526.     inc    di
  4527. wrttim2:call    fdec2di            ; write decimal asciiz to buffer
  4528.     mov    byte ptr es:[di],':'
  4529.     inc    di
  4530.     pop    dx
  4531.     xor    ah,ah
  4532.     mov    al,dh            ; Seconds
  4533.     cmp    al,10            ; leading digit?
  4534.     jae    wrttim3            ; ae = yes
  4535.     mov    byte ptr es:[di],'0'    ; make our own
  4536.     inc    di
  4537. wrttim3:call    fdec2di            ; write decimal asciiz to buffer
  4538.     mov    word ptr es:[di],0020h    ; space and null terminator
  4539.     ret
  4540. wrttime    endp
  4541.  
  4542. ; write \v(Version) text to ds:di
  4543. wrtver    proc    near
  4544.     mov    si,offset verident    ; MS Kermit version string in mssker
  4545.     cld
  4546. wrtver1:lodsb
  4547.     stosb
  4548.     cmp    al,'$'            ; end of string?
  4549.     jne    wrtver1            ; ne = no, continue copying
  4550.     dec    di
  4551.     mov    word ptr es:[di],0020h    ; space and null terminator
  4552.     ret
  4553. wrtver    endp
  4554.  
  4555. ; write \v(TERMINAL) text to ds:di
  4556. wrtterm    proc    near
  4557.     mov    ax,flags.vtflg        ; current terminal type
  4558.     mov    bx,offset termtb    ; terminal type table msx...
  4559.     mov    cl,[bx]            ; number of entries in our table
  4560.     xor    ch,ch
  4561.     inc    bx            ; point to the data
  4562. wrtter1:mov    si,[bx]            ; length of keyword
  4563.     cmp    ax,[bx+si+2]        ; value fields match?
  4564.     je    wrtter2            ; e = yes
  4565.     add    bx,si            ; add word length
  4566.     add    bx,4            ; skip count and value fields
  4567.     loop    wrtter1            ; keep searching
  4568.     jmp    short wrtter4        ; no match, use just a space
  4569. wrtter2:mov    cx,[bx]            ; get length of counted string
  4570.     mov    si,bx
  4571.     add    si,2            ; look at text
  4572.     cld
  4573.     rep    movsb
  4574. wrtter4:mov    word ptr es:[di],0020h    ; space and null terminator
  4575.     ret
  4576. wrtterm    endp
  4577.  
  4578. fcmgtch    proc    far
  4579.     call    cmgtch
  4580.     ret
  4581. fcmgtch    endp
  4582.  
  4583. code1    ends
  4584.  
  4585. code    segment
  4586.     assume    cs:code
  4587.  
  4588. ; Set master prompt level. Enter with DX = offset of prompt string
  4589. MPROMPT    proc    near
  4590.     mov    mcmprmp,dx        ; offset of prompt string
  4591.     pop    ax            ; get the return address
  4592.     mov    word ptr mcmrprs,ax     ; offset to go to on reparse
  4593.     mov    mcmostp,sp        ; stack pointer at reparse time
  4594.     push    ax            ; put it on the stack again
  4595.     mov    ax,cs            ; our current code segment
  4596.     mov    word ptr mcmrprs+2,ax     ; segment of reparse address
  4597.     mov    comand.cmdirect,0    ; read normally (vs force to kbd/file)
  4598.     mov    cmrawptr,offset rawbuf    ; base/raw buffer write ptr, reset
  4599.     mov    cmwptr,offset cmdbuf
  4600.     mov    cmrptr,offset cmdbuf
  4601. MPROMPT    endp
  4602.  
  4603. ; This routine prints the prompt and specifies the reparse address.
  4604. ; Enter with pointer to prompt string in dx. 
  4605. PROMPT    PROC  NEAR
  4606.     xor    ax,ax            ; get a zero
  4607.     xchg    al,comand.cmdirect    ; set cmdirect to zero for showprompt
  4608.     xchg    ah,comand.cmper
  4609.     push    ax
  4610.     xor    al,al
  4611.     xchg    al,flags.takflg        ; take echo flag, off in showprompt
  4612.     push    ax
  4613.     call    showprompt        ; convert string with variables
  4614.     pop    ax
  4615.     xchg    al,flags.takflg        ; restore take echo flag
  4616.     pop    ax
  4617.     mov    comand.cmdirect,al    ; restore direct mode (if any)
  4618.     mov    comand.cmper,ah
  4619.     mov    comand.cmprmp,dx    ; save the prompt
  4620.     pop    ax            ; get the return address
  4621.     mov    word ptr comand.cmrprs,ax ; offset to go to on reparse
  4622.     mov    comand.cmostp,sp    ; save for later restoration
  4623.     push    ax            ; put it on the stack again
  4624.     mov    ax,cs            ; our current code segment
  4625.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  4626.     mov    ax,offset cmdbuf
  4627.     mov    cmrptr,ax        ; reset buffer read/write pointers
  4628.     mov    cmwptr,ax
  4629.     mov    cmrawptr,offset rawbuf
  4630.     mov    in_reparse,0
  4631.     xor    ax,ax
  4632.     mov    subcnt,al        ; substitution variable state info
  4633.     mov    subtype,al
  4634.     mov    bracecnt,al
  4635.     mov    replay_cnt,ax
  4636.     mov    cmsiz,ax
  4637.     mov    comand.cmper,al        ; allow substitutions
  4638.     mov    cmsflg,0ffh        ; remove leading spaces
  4639.     cmp    comand.cmdirect,al    ; doing direct reading?
  4640.     jne    promp1            ; ne = yes
  4641.     cmp    flags.takflg,al        ; look at Take flag, zero?
  4642.     jne    promp1            ; ne=supposed to echo, skip this check
  4643.     cmp    taklev,al        ; inside a take file?
  4644.     je    promp1            ; e = no, keep going
  4645.     clc
  4646.     ret                ; yes, return
  4647. promp1:    mov    ah,prstr
  4648.     mov    dx,offset crlf
  4649.     int    dos
  4650.     mov    dx,comand.cmprmp    ; prompt pointer
  4651.     call    prtasz            ; show asciiz prompt string
  4652.     clc
  4653.     ret
  4654. PROMPT    ENDP
  4655.  
  4656. ; Convert ASCIIZ prompt string given in DS:DX to string in DS:comand.cmprmp
  4657. ; with expansion of substitution variables. Final prompt is in DX and in
  4658. ; comand.cmprmp = offset cmdbuf+cmdblen/2 (of a 1000 byte total buffer).
  4659. showprompt proc far
  4660.     cmp    in_showprompt,0        ; doing this routine already?
  4661.     je    showp0            ; e = no
  4662.     mov    dx,comand.cmprmp    ; yes, return current prompt string
  4663.     ret
  4664. showp0:    mov    word ptr cmdbuf+cmdblen/2,0    ; clear final prompt string
  4665.     mov    comand.cmprmp,offset cmdbuf+cmdblen/2 ; prompt pointer
  4666.     mov    si,dx            ; raw prompt string ds:dx
  4667.     call    strlen            ; get string length
  4668.     or    cx,cx            ; empty?
  4669.     jnz    showp1            ; nz = no
  4670.     ret                ; return empty prompt string
  4671. showp1:    inc    cx            ; include null in length
  4672.     mov    al,taklev        ; entering taklev
  4673.     cmp    al,maxtak        ; room in take level?
  4674.     jb    showp2            ; b = yes
  4675.     mov    comand.cmprmp,dx    ; original raw prompt offset
  4676.     ret                ; return it
  4677.  
  4678. showp2:    push    ax            ; save take level
  4679.     mov    si,offset cmdbuf    ; reset parse buffer pointers
  4680.     mov    cmrptr,si
  4681.     mov    cmwptr,si
  4682.     mov    cmrawptr,offset rawbuf
  4683.     xor    ax,ax
  4684.     mov    subcnt,al        ; clear substitution state variables
  4685.     mov    subtype,al
  4686.     mov    bracecnt,al
  4687.     call    takopen_sub        ; open take as text substitution
  4688.     mov    bx,takadr        ; address of take structure
  4689.     mov    ax,ds
  4690.     mov    [bx].takbuf,ax        ; segment of Take buffer
  4691.     mov    [bx].takptr,dx         ; offset of beginning of def text
  4692.     mov    [bx].takcnt,cx        ; # of chars in buffer (includes NUL)
  4693.     or    [bx].takattr,take_autocr ; imply CR at end of prompt
  4694.     mov    in_showprompt,1        ; say making new prompt
  4695.     xor    ax,ax
  4696.     mov    cmsflg,al        ; get all spaces
  4697.     mov    comand.cmper,al        ; reset to variable recognition
  4698.     mov    comand.cmquiet,1    ; no echo
  4699.     mov    comand.cmwhite,1    ; leading white space is ok
  4700.     mov    comand.cmcr,1        ; bare cr's allowed
  4701.     mov    comand.cmostp,sp    ; set reprompt stack pointer here
  4702.     mov    comand.cmcnvkind,cmcnv_none ; default is no conversion
  4703.     mov    cmkind,cmword        ; say getting a word, not a line
  4704.     mov    comand.cmdonum,0    ; disable \number expansion
  4705.     mov    word ptr comand.cmrprs,offset showp3 ; offset for reparse
  4706.     mov    ax,cs            ; our current code segment
  4707.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  4708.  
  4709. showp3:    mov    cmptab,offset cmdbuf+cmdblen/2 ; buffer for new string
  4710.     mov    comand.cmblen,(cmdblen/2)-100 ; length of our buffer (plenty)
  4711.  
  4712. showp4:    call    fcmgtch            ; get a char
  4713.     jnc    showp5            ; nc = non-terminator
  4714.     cmp    ah,' '            ; space terminator?
  4715.     je    showp5            ; e = yes
  4716.     inc    cmrptr            ; 'read' other kinds of terminator
  4717. showp5:    mov    bx,cmptab        ; pointer into destination array
  4718.     mov    [bx],ah            ; put char into the buffer
  4719.     inc    bx
  4720.     xor    al,al
  4721.     mov    [bx],al            ; insert null terminator
  4722.     mov    cmptab,bx
  4723.     cmp    bx,offset cmdbuf+cmdblen ; end of buffer?
  4724.     jae    showp6            ; ae = end of buffer, terminate
  4725.     mov    cmsflg,0        ; still get spaces
  4726.     or    ah,ah            ; this terminator?
  4727.     jnz    showp4            ; nz = no, keep reading
  4728.  
  4729. showp6:    pop    ax            ; saved entering taklev
  4730.     cmp    al,taklev        ; saved versus current taklev
  4731.     jae    showp7            ; ae = nothing new to be removed
  4732.     push    ax            ; save again for loop
  4733.     call    takclos            ; close Take file
  4734.     jmp    showp6            ; keep at it
  4735. showp7:    xor    ax,ax
  4736.     mov    comand.cmwhite,al    ; clear leading whitespace flag
  4737.     mov    comand.cmblen,ax    ; set user buffer length to unknown
  4738.     mov    comand.cmquiet,al    ; enable echo
  4739.     mov    comand.cmcr,al        ; bare cr's not allowed
  4740.     mov    comand.cmdonum,al    ; disable \number expansion
  4741.     mov    in_showprompt,al    ; done making new prompt
  4742.     mov    dx,offset cmdbuf+cmdblen/2 ; return in DX
  4743.     mov    comand.cmprmp,dx     ; returned prompt pointer
  4744.     mov    subcnt,al
  4745.     mov    subtype,al
  4746.     ret
  4747. showprompt endp
  4748. code    ends
  4749.  
  4750. code1    segment
  4751.     assume    cs:code1
  4752.  
  4753. ISDEV    PROC    FAR            ; Set carry if STDIN is non-disk
  4754.     push    ax
  4755.     push    bx
  4756.     push    dx
  4757.     xor    bx,bx            ; handle 0 is stdin
  4758.     xor    al,al            ; get device info
  4759.     mov    ah,ioctl
  4760.     int    dos
  4761.     rcl    dl,1            ; put ISDEV bit into the carry bit
  4762.     pop    dx            ; carry is set if device
  4763.     pop    bx
  4764.     pop    ax
  4765.     ret                ; carry set if device
  4766. ISDEV    ENDP
  4767.  
  4768. ISEOF    PROC    FAR            ; Set carry if STDIN is at EOF
  4769.     push    ax            ;  but only if stdin is a non-device
  4770.     push    bx
  4771.     push    dx
  4772.     xor    bx,bx            ; handle 0 is stdin
  4773.     xor    al,al            ; get device info
  4774.     mov    ah,ioctl
  4775.     int    dos
  4776.     mov    ah,ioctl
  4777.     mov    al,6            ; get handle input status, set al
  4778.     test    dl,80h            ; bit set if handle is for a device
  4779.     jnz    iseof1            ; nz = device, always ready (al != 0)
  4780.     int    dos
  4781. iseof1:    or    al,al            ; EOF?
  4782.     pop    dx
  4783.     pop    bx
  4784.     pop    ax
  4785.     jnz    iseof2            ; nz = no
  4786.     stc                ; set carry for eof
  4787.     ret
  4788. iseof2:    clc                ; clear carry for not-eof
  4789.     ret
  4790. ISEOF    ENDP
  4791.  
  4792. ; Convert ascii characters in al and ah to lowercase.
  4793. ; All registers are preserved except AX, of course.
  4794.  
  4795. TOLOWR PROC FAR
  4796.     cmp    ah,'A'            ; less that cap A?
  4797.     jl    tolow1            ; l = yes. leave untouched
  4798.     cmp    ah,'Z'+1        ; more than cap Z?
  4799.     jns    tolow1            ; ns = yes
  4800.     or    ah,20H            ; convert to lowercase
  4801. tolow1:    cmp    al,'A'            ; less that cap A?
  4802.     jl    tolow2            ; l = yes. leave untouched
  4803.     cmp    al,'Z'+1        ; more than cap Z?
  4804.     jns    tolow2            ; ns = yes
  4805.     or    al,20H            ; convert to lower case
  4806. tolow2:    ret
  4807. TOLOWR    endp
  4808.  
  4809. TOUPR PROC FAR
  4810.     cmp    ah,'a'            ; less that lower A?
  4811.     jb    toup1            ; l = yes. leave untouched
  4812.     cmp    ah,'z'            ; more than lower Z?
  4813.     ja    toup1            ; ns = yes
  4814.     and    ah,not 20H        ; convert to upper case
  4815. toup1:    cmp    al,'a'            ; less that lower A?
  4816.     jb    toup2            ; l = yes. leave untouched
  4817.     cmp    al,'z'            ; more than lower Z?
  4818.     ja    toup2            ; ns = yes
  4819.     and    al,not 20H        ; convert to upper case
  4820. toup2:    ret
  4821. TOUPR    endp
  4822.  
  4823. ; Revise string in ds:si et seq. Expect incoming length to be in CX.
  4824. ; Controlled by comand.cmcnvkind.
  4825. ; Original string modified to replace bare commas with Carriage Returns.
  4826. ; Top level braces removed, but only if the string begins with an 
  4827. ; opening brace, and hence commas revealed are also converted to CR.
  4828. ; Converted text has a forced null termination to assist callers of cmtxt
  4829. ; which don't remember returned byte count.
  4830. ; All registers preserved except CX (returned length).
  4831. unbrace    proc    far
  4832.     or    cx,cx            ; count of zero or less?
  4833.     jg    unbrac1            ; g = no, but could be huge
  4834.     ret
  4835. unbrac1:push    ax
  4836.     push    si            ; src and dest are ds:si
  4837.     push    di
  4838.     mov    di,si            ; si = source
  4839.     add    di,cx            ; skip to end of line + 1
  4840. unbrac2:cmp    byte ptr [di-1],' '    ; trailing space?
  4841.     jne    unbrac3            ; ne = no
  4842.     dec    di            ; backup another byte
  4843.     loop    unbrac2
  4844. unbrac3:cmp    byte ptr [si],braceop    ; now opens with brace?
  4845.     jne    unbrac4            ; ne = no, nothing to do
  4846.     cmp    byte ptr [di-1],bracecl    ; ended on brace?
  4847.     jne    unbrac4            ; ne = no, nothing to do
  4848.     mov    cx,di            ; ending spot
  4849.     sub    cx,si            ; minus start
  4850.     mov    di,si            ; destination
  4851.     sub    cx,2            ; minus opening and closing braces
  4852.     inc    si            ; skip opening brace
  4853.     push    cx
  4854.     push    es
  4855.     mov    ax,ds
  4856.     mov    es,ax
  4857.     cld
  4858.     rep    movsb            ; copy down text inside braces
  4859.     xor    al,al
  4860.     mov    bx,di            ; report null in BX
  4861.     stosb                ; forced null terminator
  4862.     pop    es
  4863.     pop    cx
  4864. unbrac4:pop    di
  4865.     pop    si
  4866.     pop    ax
  4867.     clc
  4868.     ret
  4869. unbrace    endp
  4870.  
  4871. ; Parse control sequences and device control strings.
  4872. ; Expect CSI, Escape [, or DCS lead-in characters to have been read.
  4873. ; Puts numerical Parameters in array param (16 bits, count is nparam) and
  4874. ;  a single letter Parameter in lparam, (Parameters are all ASCII column 3)
  4875. ;  Intermediate characters in array inter (count is ninter), (ASCII column 2)
  4876. ;  Final character in AL (ASCII columns 4-7).
  4877. ; Invoke by setting state to offset atparse, set pardone to offset of
  4878. ; procedure to jump to after reading Final char (0 means do just ret)
  4879. ; and optionally setting parfail to address to jump to if parsing failure.
  4880. ; When the Final char has been accepted this routine jumps to label held in
  4881. ; pardone for final action. Before the Final char has been read successful
  4882. ; operations return carry clear.
  4883. ; Failure exits are carry set, and an optional jump through parfail (if 
  4884. ; non-zero) or a return.
  4885.  
  4886. atparse    proc    near
  4887.     mov    bx,parstate        ; get parsing state
  4888.     or    bx,bx            ; have any state?
  4889.     jnz    atpars1            ; nz = have a state
  4890.     call    atpclr            ; do initialization
  4891.     mov    bx,parstate        ; get initial state
  4892. atpars1:call    bx            ; execute it
  4893.     jc    atpfail            ; c = failure
  4894.     cmp    parstate,offset atpdone    ; parsed final char?
  4895.     je    atpdone            ; e = yes
  4896.     ret                ; no, wait for another char
  4897.  
  4898.                 ; successful conclusion, final char is in AL
  4899. atpdone:mov    parstate,0        ; reset parsing state
  4900.     cmp    pardone,0        ; separate return address defined?
  4901.     jne    atpdon1            ; ne = yes
  4902.     clc
  4903.     ret                ; else just return
  4904. atpdon1:clc
  4905.     jmp    pardone            ; jmp to supplied action routine
  4906.  
  4907. atpfail:mov    parstate,0        ; failed, reset parser to normal state
  4908.     cmp    parfail,0        ; jump address specified?
  4909.     je    atpfail1        ; e = no
  4910.     jmp    parfail            ; yes, exit this way
  4911. atpfail1:stc
  4912.     ret
  4913.                     ; parsing workers
  4914. atparm:    cmp    ninter,0        ; Parameter, started intermediate yet?
  4915.     jne    atinter            ; ne = yes, no more parameters
  4916.     cmp    al,';'            ; argument separator?
  4917.     jne    atparm3            ; ne = no
  4918.     mov    ax,nparam        ; number of Parameters
  4919.     inc    ax            ; say a new one
  4920.     cmp    ax,maxparam        ; too many?
  4921.     jb    atparm2            ; b = no, continue
  4922.     stc                ; set carry to say failed
  4923.     ret                ; too many, ignore remainder
  4924. atparm2:mov    nparam,ax        ; say doing another Parameter
  4925.     clc
  4926.     ret
  4927.  
  4928. atparm3:mov    ah,al            ; copy char
  4929.     and    ah,not 0fh        ; ignore low nibble
  4930.     cmp    ah,30h            ; column 3, row 0? (30h='0')
  4931.     jne    atparm6            ; ne = no, check Intermediate/Final
  4932.     cmp    al,'9'            ; digit?
  4933.     ja    atparm5            ; a = no, check letter Parameters
  4934.     sub    al,'0'            ; ascii to binary
  4935.     mov    bx,nparam        ; current parameter number
  4936.     shl    bx,1            ; convert to word index
  4937.     mov    cx,param[bx]        ; current parameter value
  4938.     shl    cx,1            ; multiply by 10.  2 * cl
  4939.     push    bx
  4940.     mov    bx,cx            ; save 2 * cl
  4941.     shl    cx,1            ; 4 * cl
  4942.     shl    cx,1            ; 8 * cl
  4943.     add    cx,bx            ; 10 * cl
  4944.     pop    bx
  4945.     add    cl,al            ; add new digit
  4946.     adc    ch,0
  4947.     jnc    atparm4            ; nc = no carry out (65K or below)
  4948.     mov    cx,0ffffh        ; set to max value
  4949. atparm4:mov    param[bx],cx        ; current Parameter value
  4950.     clc
  4951.     ret
  4952.                     ; check non-numeric Parameters
  4953. atparm5:cmp    al,'?'            ; within column 3?
  4954.     ja    atfinal            ; a = no, check Final char
  4955.     mov    lparam,al        ; store non-numeric Parameter
  4956.     clc
  4957.     ret
  4958.  
  4959. atparm6:cmp    nparam,0        ; started a parameter yet?
  4960.     jne    atparm7            ; ne = yes
  4961.     cmp    param,0            ; got anything for param[0]?
  4962.     je    atinter            ; e = no
  4963. atparm7:inc    nparam            ; yes, say finished with another
  4964.  
  4965. atinter:mov    parstate,offset atinter    ; next state (intermediate)
  4966.     cmp    al,';'            ; argument separator?
  4967.     jne    atinte1            ; ne = no
  4968.     cmp    ninter,maxinter        ; too many intermediates?
  4969.     jb    atinte2            ; b = no, continue
  4970.     stc                ; carry = failed
  4971.     ret                ; too many, ignore remainder
  4972. atinte1:test    al,not 2fh        ; column two = 20h - 2fh?
  4973.     jnz    atfinal            ; nz = not an Intermediate, try Final
  4974.     cmp    ninter,maxinter        ; too many intermediates?
  4975.     jb    atinte1a        ; b = no, continue
  4976.     stc                ; carry = failed
  4977.     ret                ; too many, ignore remainder
  4978. atinte1a:mov    bx,ninter        ; current Intermediate slot number
  4979.     mov    inter[bx],al        ; current Intermediate value
  4980. atinte2:inc    ninter            ; say doing another Intermediate
  4981.     clc
  4982.     ret
  4983.  
  4984. atfinal:cmp    al,40h            ; Final character, range is 40h to 7fh
  4985.     jb    atfina1            ; b = out of range
  4986.     cmp    al,7fh
  4987.     ja    atfina1            ; a = out of range
  4988.     mov    parstate,offset atpdone    ; next state is "done"
  4989.     clc                ; success, final char is in AL
  4990.     ret
  4991. atfina1:stc                ; c = failed
  4992.     ret
  4993. atparse    endp
  4994.  
  4995. ; Clear Parameter, Intermediate arrays in preparation for parsing
  4996. atpclr    proc    near
  4997.     push    ax
  4998.     push    cx
  4999.     push    di
  5000.     push    es
  5001.     xor    ax,ax            ; get a null
  5002.     mov    parstate,offset atparm    ; init parser state
  5003.     mov    lparam,al        ; clear letter Parameter
  5004.     mov    nparam,ax        ; clear Parameter count
  5005.     mov    cx,maxparam        ; number of Parameter slots
  5006.     mov    di,offset param        ; Parameter slots
  5007.     push    ds
  5008.     pop    es            ; use data segment for es:di below
  5009.     cld                ; set direction forward
  5010.     rep    stosw            ; clear the slots
  5011.     mov    ninter,ax        ; clear Intermediate count
  5012.     mov    cx,maxinter        ; number of Intermediate slots
  5013.     mov    di,offset inter        ; Intermediate slots
  5014.     rep    stosb            ; clear the slots
  5015.     pop    es
  5016.     pop    di
  5017.     pop    cx
  5018.     pop    ax
  5019.     ret
  5020. atpclr    endp
  5021.  
  5022. ; Dispatch table processor. Enter with BX pointing at table of {char count,
  5023. ; address of action routines, characters}. Jump to matching routine or return.
  5024. ; Enter with AL holding received Final char.
  5025. atdispat proc near
  5026.     mov    cl,[bx]            ; get table length from first byte
  5027.     xor    ch,ch
  5028.     mov    di,bx            ; main table
  5029.     add    di,3            ; point di at first char in table
  5030.     push    es
  5031.     push    ds
  5032.     pop    es            ; use data segment for es:di below
  5033.     cld                ; set direction forward
  5034.     repne    scasb            ; find matching character
  5035.     pop    es
  5036.     je    atdisp2            ; e = found a match, get action addr
  5037.     ret                ; ignore escape sequence
  5038. atdisp2:sub    di,bx            ; distance scanned in table
  5039.     sub    di,4            ; skip count byte, address word, inc
  5040.     shl    di,1            ; convert to word index
  5041.     inc    bx            ; point to address of action routines
  5042.     mov    bx,[bx]            ; get address of action table
  5043.     jmp    word ptr [bx+di]    ; dispatch to the routine
  5044. atdispat endp
  5045. code1    ends
  5046.     end
  5047.