home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / cpm86 / fmacs86.ark / MINTPRIM.A86 < prev    next >
Text File  |  1989-02-09  |  28KB  |  1,216 lines

  1.     pagesize    86
  2.  
  3. c_mode        equ    6Dh
  4. c_writestr    equ    09h
  5. f_errmode    equ    2dh
  6. m_alloc        equ    80h
  7. s_sysdat    equ    9Ah
  8. p_term        equ    8Fh
  9.  
  10. sysdat_sysdisk    equ    byte ptr 4Bh
  11.  
  12.     codemacro CCPM parm:db            ;call CCPM
  13.         db 0b1h ! db parm            ;mov cl,parm
  14.         db 0cdh ! db 0e0h            ;int 0E0H
  15.         endm
  16.  
  17. ;    .xlist
  18.     include    mintdefs.a86
  19.  
  20. code    cseg    byte public
  21.     extrn    ccpm_init:near
  22.     extrn    ccpm_create_file:near
  23.     extrn    ccpm_open_file:near
  24.     extrn    ccpm_close_file:near
  25.     extrn    ccpm_create_file:near
  26.     extrn    ccpm_read_file:near
  27.     extrn    ccpm_write_file:near
  28.     extrn    ccpm_delete_file:near
  29.     extrn    ccpm_lseek_file:near
  30.     extrn    ccpm_get_time:near
  31. ;    extrn    ccpm_get_date:near
  32.     extrn    buffer_allocate:near
  33. ;code    ends
  34.  
  35. data    dseg    byte public
  36.  
  37.     extrn    next_ids: word
  38.     extrn    formb:    word
  39.     extrn    forme:    word
  40.     extrn    fbgn:    word
  41.     extrn    fend:    word
  42.     extrn    actptr:    word
  43.  
  44.     extrn    filename: byte
  45.  
  46. size_buf    rw    1
  47.  
  48.     public    save_stack
  49. save_stack    rw    1
  50.  
  51.     public    read_errors
  52. read_errors    dw    read_error_1
  53.     dw    read_error_2
  54.     dw    read_error_3
  55.     dw    read_error_4
  56.     dw    read_error_5
  57.  
  58.     public    write_errors
  59. write_errors    dw    write_error_1
  60.     dw    write_error_2
  61.     dw    write_error_3
  62.     dw    write_error_4
  63.  
  64. read_error_1    rb    0
  65. read_error_2    db    'File too large'
  66. read_error_3    db    'File not found'
  67. read_error_4    db    'End of file'
  68. read_error_5    rb    0
  69.  
  70. write_error_1    rb    0
  71. write_error_2    db    'Disk full'
  72. write_error_3    db    'Directory full or bad filename'
  73. write_error_4    rb    0
  74.  
  75.  
  76. runline        db    'env.RUNLINE'
  77. sysdisk        db    'env.SYSDISK'
  78.  
  79. form_prefix_len    rw    1        ;for use by ln prim
  80. form_prefix_ptr    rw    1        ;...
  81.  
  82. out_of_memory_msg    db    'Not enough memory.$'
  83.  
  84.     extrn    stackp: byte
  85.  
  86. ;data    ends
  87.  
  88. code    cseg    byte public
  89.     ;*** assume    cs:code, ds:data, es:data
  90.  
  91. ;starting address of program.
  92. init:    mov ax,ds ! mov ss,ax        ;set our own stack
  93.     mov sp,offset stackp
  94.     mov dl,0ffh ! ccpm f_errmode
  95.     call    ccpm_init
  96.     call    mint_init
  97.     call    init_entry
  98.     call    init_screen
  99.     call    paint_screen
  100.     mov    ax,0ffffh        ;start at the end of memory.
  101.     mov    formb,ax        ;delete all forms.
  102.     mov    forme,ax
  103.  
  104. ;xx    push    ds            ;set the fatal error address.
  105. ;xx    push    cs
  106. ;xx    pop    ds
  107. ;xx    mov    dx,offset abort_fatal
  108. ;xx    mov    ax,2524h
  109. ;xx    int    21h
  110. ;xx    pop    ds
  111.  
  112. ;*****    mov dx,4h ! ccpm c_mode        ;disable CTRL-C termination
  113.     jmp    init_ids
  114.  
  115. init_exit:
  116.     mov    dx,offset out_of_memory_msg
  117.     ccpm c_writestr
  118.     mov dl,0ffh
  119.     ccpm p_term        ;halt because of no memory.
  120.  
  121.  
  122.     extrn    init_screen: near
  123.     extrn    init_ids: near        ;restart mint interpreter
  124.     extrn    abort_fatal: near    ;fatal error handler
  125.     extrn    mint_init: near        ;perform any special mint initing.
  126.     extrn    return_null: near
  127.     extrn    paint_screen: near    ;start with the screen unpainted.
  128.  
  129. ;The following two externs init and uninit anything that's machine specific.
  130.     extrn    init_entry: near
  131.     extrn    uninit_exit: near
  132.  
  133.     extrn    set_form_pointer: near
  134. ;set_form_pointer updates the form pointer.  It does the dirty work
  135. ;    for return_form.
  136.  
  137.     extrn    return_form: near
  138. ;return_form updates the form pointer and jumps to return_tos
  139.  
  140.     extrn    return_arg: near
  141.     extrn    return_arg_active: near
  142. ;return_arg and return_arg_active return the argument whose number is given
  143. ;    in cx.  return_arg_active always returns the argument as active.
  144.  
  145.     extrn    return_string: near
  146. ;return_string returns the ALth string out of the table pointed to by bx.
  147.  
  148.     extrn    return_sicx: near
  149. ;return_sicx returns the string pointed to by si.  The length of the
  150. ;    string is given in cx.
  151.  
  152.     extrn    return_tos: near
  153. ;return_tos returns the string pointed to by the top of the stack.
  154. ;    The length of the string is the difference between di and the
  155. ;    beginning of the stirng.
  156.  
  157.     extrn    nomem: near
  158.  
  159. ;primitives here
  160.  
  161. hl_prim:
  162.     call    uninit_exit
  163.     mov dl,0ffh ! ccpm p_term
  164.  
  165. eq_prim:
  166.     call    getarg1        ;get the first argument
  167.     mov    dx,cx        ;save size of first argument
  168.     mov    di,si        ;save pointer to first argument
  169.     mov    cx,2        ;get second argument
  170.     call    getarg
  171.     cmp    cx,dx        ;lengths equal?
  172.     jne    eq_prim_1    ;no, return 4th
  173.     repe    cmpsb        ;strings equal?
  174.     jne    eq_prim_1    ;no, return 4th.
  175.     mov    cx,3
  176.     jmp    return_arg
  177. eq_prim_1:
  178.     mov    cx,4
  179.     jmp    return_arg
  180.  
  181.  
  182. nc_prim:
  183.     call    getarg1
  184.     mov di,fbgn ! dec di ! push di
  185.     mov    ax,cx
  186.     jmp    return_number
  187.  
  188.  
  189. sc_prim:
  190. bc_prim:
  191.     mov    cx,2        ;get 'from' argument.
  192.     call    getarg
  193.     mov    dl,'a'        ;default to ASCII
  194.     jcxz    bc_prim_1
  195.     mov    dl,[si]        ;get from type.
  196. bc_prim_1:
  197.     mov    cx,3        ;get 'to' argument.
  198.     call    getarg
  199.     mov    dh,'d'        ;default to decimal
  200.     jcxz    bc_prim_2
  201.     mov    dh,[si]
  202. bc_prim_2:
  203.     call    getarg1
  204.     call    bc_prim_base    ;get the source base.
  205.     or    bx,bx        ;ASCII?
  206.     jnz    bc_prim_4    ;no.
  207.     lodsb
  208.     mov    ah,0
  209.     jmps    bc_prim_3
  210. bc_prim_4:
  211.     push    dx        ;preserve dx.
  212.     call    get_number
  213.     pop    dx
  214. bc_prim_3:
  215. ;we now have the number in ax.
  216.     mov    dl,dh
  217.     call    bc_prim_base
  218.     mov di,fbgn ! dec di ! push di
  219.     or    bx,bx
  220.     jnz    bc_prim_5
  221.     stosb
  222.     jmp    return_tos
  223. bc_prim_5:
  224.     mov    cx,0        ;use only as many digits as are needed.
  225.     call    put_number
  226.     jmp    return_tos
  227.  
  228. ;private subroutine, used only bc_prim.
  229. bc_prim_base:
  230. ;enter with dl=base character.
  231. ;exit with bx=base if number; bx=0 if ASCII.
  232.     or    dl,20h        ;convert UPPER case to lower case.
  233.     cmp    dl,'d'
  234.     jne    bc_prim_base_1
  235.     mov    bx,10
  236.     ret
  237. bc_prim_base_1:
  238.     cmp    dl,'o'
  239.     jne    bc_prim_base_2
  240.     mov    bx,8
  241.     ret
  242. bc_prim_base_2:
  243.     cmp    dl,'h'
  244.     jne    bc_prim_base_3
  245.     mov    bx,16
  246.     ret
  247. bc_prim_base_3:
  248.     cmp    dl,'c'
  249.     jne    bc_prim_base_4
  250.     mov    bx,0
  251.     ret
  252. bc_prim_base_4:
  253.     cmp    dl,'a'        ;a alias character.
  254.     jne    bc_prim_base_5
  255.     mov    bx,0
  256.     ret
  257. bc_prim_base_5:
  258.     cmp    dl,'b'
  259.     jne    bc_prim_base_6
  260.     mov    bx,2
  261.     ret
  262. bc_prim_base_6:
  263.     ret
  264.  
  265.  
  266.  
  267. db_prim:
  268.     int    3
  269.     jmp    return_null
  270.  
  271.  
  272. dt_prim:    ;get date
  273.     mov di,fbgn ! dec di ! push di
  274. ;    mov    ah,2ah
  275. ;    int    21h        ;*****************************************
  276.     mov cx,0 ! mov dx,cx    ;***** must be changed to CCPM later *****
  277.     mov al,0        ;*****************************************
  278.  
  279.     mov    bx,10        ;do all conversions in decimal.
  280.     push    cx
  281.     push    dx
  282.     mov    al,dh        ;get month
  283.     mov    ah,0
  284.     mov    cx,2
  285.     call    put_number
  286.     mov    al,'-'
  287.     stosb
  288.     pop    ax        ;pushed as dx (get date)
  289.     mov    ah,0
  290.     mov    cx,2
  291.     call    put_number
  292.     mov    al,'-'
  293.     stosb
  294.     pop    ax        ;pushed as cx (get year)
  295.     sub    ax,1900        ;only output the last two digits.
  296.     mov    cx,2
  297.     call    put_number
  298.     jmp    return_tos
  299.  
  300.  
  301. tm_prim:    ;get time
  302.     mov di,fbgn ! dec di ! push di
  303. ;    mov    ah,2ch
  304. ;    int    21h
  305.     call ccpm_get_time
  306.     mov    bx,10        ;do all conversions in decimal.
  307.     push    dx
  308.     push    cx
  309.     mov    al,ch        ;get hours
  310.     mov    ah,0
  311.     mov    cx,2
  312.     call    put_number
  313.     mov    al,':'
  314.     stosb
  315.     pop    ax        ;pushed as cx (get minutes)
  316.     mov    ah,0
  317.     mov    cx,2
  318.     call    put_number
  319.     mov    al,':'
  320.     stosb
  321.     pop    dx        ;get seconds
  322.     mov    al,dh
  323.     mov    ah,0
  324.     mov    cx,2
  325.     call    put_number
  326.     jmp    return_tos
  327.  
  328. ;form primitives
  329.  
  330.  
  331. ds_prim:
  332.     mov    cx,2        ;get data first.
  333.     call    getarg
  334.     mov    dx,cx
  335.     mov    di,si
  336.     call    getarg1
  337.     mov    bx,0        ;reset form pointer.
  338.     call    define_form
  339.     jmp    return_null
  340.  
  341.  
  342. ss_prim:
  343.     call    find_arg1
  344.     jnc    ss_prim_3
  345.     mov    dx,data_length[bx]    ;save the count of the form in dx.
  346.     lea    di,name_offset[bx]
  347.     add    di,name_length[bx]    ;save the pointer to the form in di.
  348.     mov    si,fbgn        ;point si at the zeroth arg.
  349.     mov    si,[si]        ;point si at the form name.
  350.     mov    si,[si]        ;point si at the first argument.
  351.     mov    ah,sgap+1    ;start with sgap 1.
  352. ss_prim_1:
  353.     cmp    si,[si]        ;are we pointing at fend?
  354.     je    ss_prim_3
  355.     push    si        ;save pointer to args.
  356.     mov    cx,[si]        ;compute length of this arg.
  357.     sub    cx,si
  358.     sub    cx,mark_overhead
  359.     add    si,mark_overhead-1    ;make si=> text of argument.
  360. ;at this point, si,cx => arg; di,dx => form.
  361.     push    di
  362.     push    dx
  363.     jcxz    ss_prim_5    ;ignore null strings.
  364. ss_prim_4:
  365.     call    string_search
  366.     jc    ss_prim_5    ;not found.  Done with this arg.
  367. ;at this point, we have found a string.  We proceed to replace it by
  368. ;the appropriate segment gap.  We have already ensured that the string
  369. ;is at least one character long.
  370.     push    cx        ;preserve cx
  371.     mov    al,ah        ;get the sgap.
  372.     stosb            ;store it.
  373. ;by the way, at this point, the relation (cx <= dx) is always true.
  374.     sub    dx,cx        ;count it, and the ones we're getting rid of.
  375.     dec    cx        ;one less to get rid of.
  376.     mov    al,sgap        ;get rid of the rest of the chars.
  377.     rep    stosb        ;cx may be zero, but it doesn't hurt.
  378.     pop    cx
  379.     jmps    ss_prim_4
  380. ss_prim_5:
  381.     pop    dx
  382.     pop    di
  383.     pop    si        ;restore pointer to args.
  384.     mov    si,[si]        ;make it point to next arg.
  385.     inc    ah        ;increment sgap to next arg.
  386.     jmps    ss_prim_1
  387. ss_prim_3:
  388.     jmp    return_null
  389.  
  390.  
  391. nb_prim:
  392.     call    find_arg1
  393.     mov    cx,3
  394.     jnc    nb_prim_1
  395.     mov    cx,2
  396. nb_prim_1:
  397.     jmp    return_arg
  398.  
  399.  
  400. ;default primitive is the same as the cl primitive, only we start counting
  401. ;  arguments from zero, not one.
  402. dflt:
  403.     mov    bp,0
  404.     jmps    cl_prim_entry
  405. cl_prim:
  406.     mov    bp,1
  407. cl_prim_entry:
  408.     mov    cx,bp        ;get the number of the form name arg.
  409.     mov di,fend ! inc di ! inc di ! push di
  410.     call    find_arg
  411.     jnc    cl_prim_1
  412.     jcxz    cl_prim_1    ;if no characters, return null.
  413.     or    bp,bp        ;is this dflt or cl?
  414.     jne    cl_prim_2    ;cl - use specified args.
  415.     dec    bp        ;make bp+1 be the number of the form name arg.
  416. cl_prim_2:
  417.     lodsb            ;get char
  418.     or    al,al        ;test it for sgapness
  419.     jge    cl_prim_3    ;go if not sgap
  420.     sub    al,sgap        ;which sgap?
  421.     jz    cl_prim_4    ;ignore sgap0's
  422.     cbw            ;we're going to be counting off ax
  423.     add    ax,bp        ;add in the first arg number.
  424.     push    si        ;preserve pointer, count of the form
  425.     push    cx
  426.     mov    cx,ax
  427.     call    getarg
  428.     push di ! add di,cx ! cmp di,actptr
  429.         pop di ! jb $+5 ! jmp nomem
  430.     rep    movsb
  431.     pop    cx        ;restore pointer, count of the form
  432.     pop    si
  433.     jmps    cl_prim_4
  434. cl_prim_3:
  435.     cmp di,actptr ! jb $+5 ! jmp nomem
  436.     stosb
  437. cl_prim_4:
  438.     loop    cl_prim_2
  439. cl_prim_1:
  440.     jmp    return_tos
  441.  
  442.  
  443. cc_prim:
  444.     call    find_arg1
  445.     jnc    cc_prim_1    ;form not found.
  446.     jcxz    cc_prim_2    ;no chars left.
  447.     mov di,fbgn ! dec di ! push di
  448.     movsb            ;no need to check for collision with actptr.
  449.     dec    cx
  450.     jmp    return_form
  451. cc_prim_2:
  452.     mov    cx,2
  453.     jmp    return_arg_active
  454. cc_prim_1:
  455.     jmp    return_null
  456.  
  457.  
  458. cr_prim:
  459.     call    find_arg1
  460.     jnc    cr_prim_1
  461.     mov    form_pointer[bx],0
  462. cr_prim_1:
  463.     jmp    return_null
  464.  
  465.  
  466. cn_prim:
  467.     call    find_arg1
  468.     jnc    cn_prim_1
  469.     jcxz    cn_prim_2
  470.     push    si        ;save pointer, count to form.
  471.     push    cx
  472.     push    bx
  473.     mov    cx,2        ;get number of chars to call.
  474.     call    get_decimal_arg
  475.     mov    dx,ax        ;save in dx.
  476.     pop    bx
  477.     pop    cx
  478.     pop    si
  479.     mov di,fbgn ! dec di ! push di
  480.     cmp    dx,cx        ;are we trying to get more than exists?
  481.     jbe    cn_prim_3    ;no - move the requested amount.
  482.     mov    dx,cx        ;yes - truncate to the amount that exists.
  483. cn_prim_3:
  484.     xchg    dx,cx        ;swap the count remaining and the get count.
  485.     sub    dx,cx        ;dec the count remaining by the get count.
  486.     push di ! add di,cx ! cmp di,actptr
  487.         pop di ! jb $+5 ! jmp nomem        ;check for collision
  488.     rep    movsb        ;move all the chars.
  489.     mov    cx,dx        ;return the count remaining in cx.
  490.     jmp    return_form
  491. cn_prim_2:
  492.     mov    cx,3
  493.     jmp    return_arg_active
  494. cn_prim_1:
  495.     jmp    return_null
  496.  
  497.  
  498.  
  499. in_prim:
  500.     call    find_arg1
  501.     jnc    in_prim_1    ;if form not found, return null.
  502.     jcxz    in_prim_2    ;if nothing to search, return two.
  503.     push    si
  504.     mov    di,si
  505.     mov    dx,cx
  506.     mov    cx,2
  507.     call    getarg
  508. ;now si,cx => short string, di,dx => long string.
  509.     call    string_search
  510.     jc    in_prim_3    ;if it's not found, just return arg 3.
  511. ;what we want to do now is to return the string from [tos] to [di],
  512. ;  and advance the form pointer to point after the found string.
  513.     sub    dx,cx        ;dx gets long length - short length.
  514.     pop    si
  515.     mov    cx,di        ;get the number of characters before
  516.     sub    cx,si        ;  the search string.
  517.     mov di,fbgn ! dec di ! push di        ;prepare to return a string.
  518.     push di ! add di,cx ! cmp di,actptr
  519.         pop di ! jb $+5 ! jmp nomem        ;make sure we have enough room.
  520.     rep    movsb
  521.     mov    cx,dx        ;return_form expects the count in cx.
  522.     jmp    return_form
  523. in_prim_3:
  524.     add    sp,2        ;get rid of the pointer to the search string.
  525. in_prim_2:
  526.     mov    cx,3
  527.     jmp    return_arg_active
  528. in_prim_1:
  529.     jmp    return_null
  530.  
  531.  
  532. ev_prim:
  533.     mov    di,fbgn
  534.     mov    si,80h
  535.     lodsb                ;get the line length.
  536.     mov    dl,al
  537.     mov    dh,0
  538.     mov    cx,dx            ;put it where movs can destroy it.
  539.     rep    movsb
  540.  
  541.     mov    di,fbgn            ;restore di again.
  542.     mov    si,offset runline
  543.     mov    cx,length runline
  544.     xor    bx,bx
  545.     call    define_form
  546.  
  547.     push es ! ccpm s_sysdat
  548.     mov al,es:sysdat_sysdisk[bx]
  549.     add al,'A' ! mov ah,':'
  550.     pop es ! mov di,fbgn
  551.     mov [di],ax ! mov dx,2
  552.     mov si,offset sysdisk
  553.     mov cx,length sysdisk
  554.     xor bx,bx ! call define_form
  555.  
  556.     jmp    return_null
  557.  
  558.   if 0
  559. pa_prim:
  560. ;#(ps,prefix, seperator, arguments)
  561.     mov di,fend ! inc di ! inc di ! push di
  562.     call    getarg1            ;get seperator and save it.
  563.     mov    bp,si            ;store the pointer to arg1 in bp
  564.     mov    dx,cx            ;store the size of arg1 in dx
  565.     mov    cx,2            ;get the form prefix.
  566.     call    getarg
  567.     mov    form_prefix_len,cx
  568.     mov    form_prefix_ptr,si
  569.     mov    si,fbgn            ;point si at the zeroth arg.
  570.     mov    si,[si]            ;point si at the prefix
  571.     mov    si,[si]            ;point si at the seperator.
  572.     mov    si,[si]            ;point si at the arguments.
  573. pa_prim_1:
  574.     cmp    si,[si]            ;are we pointing at fend?
  575.     je    pa_prim_2        ;yes, exit.
  576.     push    si            ;save pointer to args.
  577.     mov    cx,[si]            ;compute length of this arg.
  578.     sub    cx,si
  579.     sub    cx,mark_overhead
  580.     add    si,mark_overhead-1    ;make si=> text of argument.
  581. ;at this point, si,cx => arg
  582.     cmp    cx,dx            ;is argument length < prefix length?
  583.     jb    pa_prim_4        ;yes - prefix can't match.
  584.     push    di            ;save the source pointers.
  585.     push    si
  586.     push    cx
  587.     mov    di,bp
  588.     mov    cx,dx
  589.     repe    cmpsb            ;compare the prefix to the form name.
  590.     pop    cx
  591.     pop    si
  592.     pop    di
  593.     jne    pa_prim_4        ;the prefixes didn't match - ignore it.
  594. pa_prim_3:
  595.     push di ! add di,cx ! cmp di,actptr
  596.         pop di ! jb $+5 ! jmp nomem
  597.     rep    movsb            ;move the name in.
  598.     mov    si,form_prefix_ptr    ;get the seperator ptr, count.
  599.     mov    cx,form_prefix_len
  600.     push di ! add di,cx ! cmp di,actptr
  601.         pop di ! jb $+5 ! jmp nomem
  602.     rep    movsb            ;move it in.
  603. pa_prim_4:
  604.     pop    si            ;get the argument pointer back.
  605.     mov    si,[si]            ;get the next argument.
  606.     jmps    pa_prim_1        ;and continue.
  607. pa_prim_2:
  608.     jmp    return_tos
  609.   endif
  610.  
  611. ln_prim:
  612.     mov    bx,formb        ;get pointer to forms.
  613.     mov di,fend ! inc di ! inc di ! push di
  614.     call    getarg1            ;get seperator and save it.
  615.     mov    bp,si            ;store the pointer to arg1 in bp
  616.     mov    dx,cx            ;store the size of arg1 in dx
  617.     mov    cx,2            ;get the form prefix.
  618.     call    getarg
  619.     mov    form_prefix_len,cx
  620.     mov    form_prefix_ptr,si
  621. ln_prim_1:
  622.     cmp    bx,forme        ;at end?
  623.     je    ln_prim_2        ;yes, exit.
  624.     lea    si,name_offset[bx]    ;get the name pointer.
  625.     mov    cx,form_prefix_len
  626.     jcxz    ln_prim_3        ;zero prefixes match anything.
  627.     cmp    cx,name_length[bx]    ;is prefix length>name length?
  628.     ja    ln_prim_4        ;yes - prefix can't match.
  629.     push    di            ;save the source pointers.
  630.     push    si
  631.     mov    di,form_prefix_ptr
  632.     repe    cmpsb            ;compare the prefix to the form name.
  633.     pop    si
  634.     pop    di
  635.     jne    ln_prim_4        ;the prefixes didn't match - ignore it.
  636. ln_prim_3:
  637.     mov    cx,name_length[bx]    ;get the name length
  638.     push di ! add di,cx ! cmp di,actptr
  639.         pop di ! jb $+5 ! jmp nomem
  640.     rep    movsb            ;move the name in.
  641.     mov    si,bp            ;get the pointer to arg1.
  642.     mov    cx,dx            ;get the size of arg1.
  643.     push di ! add di,cx ! cmp di,actptr
  644.         pop di ! jb $+5 ! jmp nomem
  645.     rep    movsb            ;move it in.
  646. ln_prim_4:
  647.     add    bx,form_length[bx]    ;point to next form.
  648.     jmps    ln_prim_1        ;and continue.
  649. ln_prim_2:
  650.     jmp    return_tos
  651.  
  652.  
  653. dd_prim:
  654.     mov    si,fbgn        ;point si at "dd".
  655.     mov    si,[si]        ;point si at the first arg.
  656. dd_prim_1:
  657.     cmp    si,[si]        ;are we pointing at fend?
  658.     je    dd_prim_3
  659.     push    si        ;save pointer to args.
  660.     mov    cx,[si]        ;compute length of this arg.
  661.     sub    cx,si
  662.     sub    cx,mark_overhead
  663.     add    si,mark_overhead-1    ;make si=> text of argument.
  664.     call    find_form    ;try to find this form.
  665.     jnc    dd_prim_2    ;go if it didn't exist.
  666.     call    delete_form    ;delete the form if it did exist.
  667. dd_prim_2:
  668.     pop    si        ;restore pointer to args.
  669.     mov    si,[si]        ;make it point to next arg.
  670.     jmps    dd_prim_1
  671. dd_prim_3:
  672.     jmp    return_null
  673.  
  674.  
  675. sb_prim:
  676.     call    getarg1_filename
  677.     mov    dx,si
  678.     mov    cx,0
  679. ;    mov    ah,3ch            ;create file.
  680. ;    int    21h
  681.     call ccpm_create_file
  682.     mov    bx,ax            ;remember the handle.
  683.     mov    al,2
  684.     jc    sb_prim_4
  685.     mov    si,fbgn            ;point si at the zeroth arg.
  686.     mov    si,[si]            ;point si at the form name.
  687.     mov    si,[si]            ;point si at the first search string.
  688. sb_prim_1:
  689.     cmp    si,[si]            ;are we pointing at fend?
  690.     je    sb_prim_3
  691.     push    si            ;save pointer to args.
  692.     mov    cx,[si]            ;compute length of this arg.
  693.     sub    cx,si
  694.     sub    cx,mark_overhead
  695.     add    si,mark_overhead-1    ;make si=> text of argument.
  696.     push    bx
  697.     call    find_form
  698.     mov    di,bx            ;remember where the form is.
  699.     pop    bx
  700.     jnc    sb_prim_2        ;go if it isn't there.
  701.     mov    cx,form_length[di]
  702.     mov    dx,di
  703. ;    mov    ah,40h            ;write to a file
  704. ;    int    21h
  705.     call ccpm_write_file
  706.     jnc    sb_prim_2        ;no problem.
  707. ;    mov    ah,3eh            ;disk full - close the file.
  708. ;    int    21h
  709.     call ccpm_close_file
  710.     mov    dx,offset filename    ;delete the file.
  711. ;    mov    ah,41h
  712. ;    int    21h
  713.     call ccpm_delete_file
  714.     mov    al,1
  715.     jmps sb_prim_4
  716. sb_prim_2:
  717.     pop    si        ;restore pointer to args.
  718.     mov    si,[si]        ;make it point to next arg.
  719.     jmps    sb_prim_1
  720. sb_prim_3:
  721. ;    mov    ah,3eh        ;close the file.
  722. ;    int    21h
  723.     call ccpm_close_file
  724.     mov    al,0        ;no problem.
  725. sb_prim_4:
  726.     mov    bx,offset write_errors
  727.     jmp    return_string
  728.  
  729.  
  730. fb_prim:
  731. ;Note that information about the structure 'form' is hard-coded into the
  732. ;  next routine.  We assume that 'form_length' is only two bytes long,
  733. ;  and occurs at the beginning of the structure.
  734.     call    getarg1_filename
  735.     mov    dx,si
  736. ;    mov    ax,3d00h        ;open file for reading.
  737. ;    int    21h
  738.     call ccpm_open_file
  739.     mov    bx,ax            ;remember the handle.
  740.     mov    al,2
  741.     jc    fb_prim_4_j_1
  742.     mov    ax,forme        ;anything loaded yet?
  743.     cmp    ax,formb
  744.     jne    fb_prim_1        ;yes - load one by one.
  745.  
  746.     mov    cx,0
  747.     mov    dx,cx
  748. ;    mov    ax,4202h        ;seek to the end of the file.
  749. ;    int    21h
  750.     mov al,2
  751.     call ccpm_lseek_file
  752.  
  753.     push    ax            ;remember the file size.
  754.     mov    dx,cx            ;zero out dx again.
  755. ;    mov    ax,4200h
  756. ;    int    21h
  757.     mov al,0
  758.     call ccpm_lseek_file
  759.     pop    cx            ;get the file size back again.
  760.  
  761.     mov    ax,forme        ;no - do a bulk load.
  762.     sub    ax,cx            ;see if there is enough room.
  763.     jb    fb_prim_3_j        ;can't possibly be.
  764.     mov    dx,ax
  765.     sub    ax,free_space        ;free_space is the working room.
  766.     cmp    ax,fend
  767.     jb    fb_prim_3_j        ;there isn't.
  768.  
  769.     push cx
  770.     mov    cx,formb        ;compute size of active string.
  771.     sub    cx,actptr
  772.     mov    si,actptr        ;->active string.
  773.     mov    di,dx            ;->new formb.
  774.     sub    di,cx            ;leave room for the active string.
  775.     mov    actptr,di
  776.     rep    movsb
  777.     mov    formb,dx
  778.  
  779.     pop    cx            ;read the whole file in.
  780. ;    mov    ah,3fh            ;read from a file.
  781. ;    int    21h
  782.     call ccpm_read_file
  783.     jc    fb_prim_5        ;trouble reading...
  784.     push    bx            ;preserve handle.
  785.     call    rehash            ;reconstruct the hash links.
  786.     pop    bx
  787. fb_prim_6:
  788. ;    mov    ah,3eh            ;close the file.
  789. ;    int    21h
  790.     call ccpm_close_file
  791.     mov    al,0            ;all ok.
  792.     jmps    fb_prim_4        ;we destroyed the active string.
  793. fb_prim_5:
  794. ;    mov    ah,3eh            ;close the file.
  795. ;    int    21h
  796.     call ccpm_close_file
  797.     mov    al,3            ;read error.
  798. fb_prim_4_j_1:
  799.                     ;we get here if we can't open the file.
  800.     jmps    fb_prim_4        ;we destroyed the active string.
  801. fb_prim_3_j:
  802.     jmps    fb_prim_3
  803. fb_prim_1:
  804.     mov    dx,offset size_buf    ;set disk transfer address
  805.     mov    cx,2
  806. ;    mov    ah,3fh            ;read from a file.
  807. ;    int    21h
  808.     call ccpm_read_file
  809.     jc    fb_prim_5        ;close the file - trouble reading.
  810.  
  811.     cmp    ax,0            ;did we read no bytes at all?
  812.     je    fb_prim_6        ;close and exit.
  813.  
  814.     mov    ax,size_buf        ;we need twice as much memory
  815.     shl    ax,1            ;  as in size_buf.
  816.     add    ax,fend            ;see if there is enough room.
  817.     add    ax,free_space
  818.     cmp    ax,actptr
  819.     jae    fb_prim_3
  820.  
  821.     mov    dx,fend
  822.     add    dx,2
  823.     mov    cx,size_buf
  824.     sub    cx,2            ;transfer two less bytes.
  825. ;    mov    ah,3fh            ;read from a file.
  826. ;    int    21h
  827.     call ccpm_read_file
  828.     jc    fb_prim_5
  829.     cmp    ax,cx
  830.     jne    fb_prim_5        ;trouble reading...
  831.  
  832.     push    bx
  833.     mov    bx,fend            ;don't add 2 like we did before because
  834.     mov    cx,name_length[bx]    ;  we already read form_length.
  835.     mov    dx,data_length[bx]
  836.     lea    si,name_offset[bx]
  837.     mov    di,si
  838.     add    di,cx        ;or [bx].name_length, but cx is cheaper.
  839.     mov    bx,form_pointer[bx]
  840.     call    define_form
  841.     pop    bx
  842.  
  843.     jmps    fb_prim_1
  844. fb_prim_3:
  845. ;    mov    ah,3eh            ;close the file.
  846. ;    int    21h
  847.     call ccpm_close_file
  848.     jmp    nomem
  849. fb_prim_4:
  850.     mov    bx,offset read_errors
  851.     jmp    return_string
  852.  
  853.  
  854. ad_prim:
  855.     call    get_math
  856.     add    ax,bx
  857.     push    si
  858.     jmp    return_number
  859.  
  860.  
  861. su_prim:
  862.     call    get_math
  863.     sub    ax,bx
  864.     push    si
  865.     jmp    return_number
  866.  
  867.  
  868. ml_prim:
  869.     call    get_math
  870.     imul    bx
  871.     push    si
  872.     jmp    return_number
  873.  
  874.  
  875. dv_prim:
  876.     call    get_math
  877.     or    bx,bx
  878.     je    dv_prim_1
  879.     cwd
  880.     idiv    bx
  881. dv_prim_1:
  882.     push    si
  883.     jmp    return_number
  884.  
  885.  
  886. md_prim:
  887.     call    get_math
  888.     or    bx,bx
  889.     je    md_prim_1
  890.     cwd
  891.     idiv    bx
  892.     mov    ax,dx
  893. md_prim_1:
  894.     push    si
  895.     jmp    return_number
  896.  
  897.  
  898. gr_prim:
  899.     call    get_math
  900.     mov    cx,3
  901.     cmp    ax,bx
  902.     jg    gr_prim_1
  903.     mov    cx,4
  904. gr_prim_1:
  905.     jmp    return_arg
  906.  
  907.  
  908. ;primitive externals
  909.     public    dflt
  910.     public    hl_prim
  911.     public    eq_prim
  912.     public    nc_prim
  913.     public    sc_prim
  914.     public    db_prim
  915.     public    dt_prim
  916.     public    tm_prim
  917. ;forms
  918.     public    ds_prim
  919.     public    ss_prim
  920.     public    cl_prim
  921.     public    cc_prim
  922.     public    cn_prim
  923.     public    cr_prim
  924.     public    in_prim
  925.     public    ev_prim
  926.     public    ln_prim
  927.     public    dd_prim
  928.     public    sb_prim
  929.     public    fb_prim
  930.     public    nb_prim
  931. ;math
  932.     public    ad_prim
  933.     public    su_prim
  934.     public    ml_prim
  935.     public    dv_prim
  936.     public    md_prim
  937.     public    gr_prim
  938.  
  939. ;form subroutines
  940.     extrn    define_form: near
  941.     extrn    delete_form: near
  942. ;delete_form deletes the form pointed to by bx.
  943.  
  944.     extrn    rehash: near
  945. ;rehash rebuilds the hashing links.  Used only when a file is bulk loaded.
  946.  
  947.     extrn    find_form: near
  948. ;find_form returns bx pointing to the form whose name is pointed to by si.
  949. ;    The length of the form name is given in cx.
  950. ;    If the form doesn't exist, cy is set, otherwise cy is clear.
  951. ;    di points to the form data after the form pointer, and cx is the
  952. ;    number of chars after the form pointer.
  953.  
  954.     extrn    find_arg1: near
  955. ;find_arg1 returns bx pointing to the form whose name is given in
  956. ;    arg1.  If the form doesn't exist, cy is set, otherwise cy is clear.
  957. ;    di points to the form data after the form pointer, and cx is the
  958. ;    number of chars after the form pointer.
  959.  
  960.     extrn    find_arg: near
  961. ;find_arg returns bx pointing to the form whose name is given in
  962. ;    the arg specified by cx.  If the form doesn't exist, cy is
  963. ;    set, otherwise cy is clear.  di points to the form data
  964. ;    after the form pointer, and cx is the number of chars after
  965. ;    the form pointer.
  966.  
  967.  
  968. ;utility subroutines
  969.  
  970.  
  971.     public    get_math
  972. get_math:
  973. ;exit with ax=first number, bx=second number, si->first arg, di->first number.
  974.     mov    cx,2
  975.     call    get_decimal_arg
  976.     push    ax
  977.     call    getarg1
  978.     push    si
  979.     call    get_decimal
  980.     mov    di,si
  981.     pop    si
  982.     pop    bx        ;pushed as ax
  983.     ret
  984.  
  985.  
  986.     public    get_decimal_arg1
  987. get_decimal_arg1:
  988.     mov    cx,1
  989. ;fall through
  990.     public    get_decimal_arg
  991. get_decimal_arg:
  992.     call    getarg
  993. ;fall through
  994.     public    get_decimal
  995. get_decimal:
  996.     mov    bx,10
  997. ;fall through
  998.     public    get_number
  999. get_number:
  1000. ;enter with si,cx => string containing trailing number, bx=base to convert
  1001. ;  number in.  Return number in ax, si => start of digit string.
  1002.     add    si,cx
  1003.     push    cx
  1004. get_number_1:
  1005.     dec    si
  1006.     mov    al,[si]
  1007.     sub    al,'0'        ;between 0 and "9"?
  1008.     jb    get_number_2    ;no - can't be a digit.
  1009.     cmp    al,'9'-'0'    ;between "0" and "9"?
  1010.     jbe    get_number_6    ;yes - must be a digit.
  1011.     cmp    al,'a'-'0'
  1012.     jb    get_number_8
  1013.     sub    al,'a'-'A'
  1014. get_number_8:
  1015.     cmp    al,'A'-'0'    ;between "A" and "9"?
  1016.     jb    get_number_2    ;yes - can't be a digit.
  1017.     sub    al,'A'-('0'+10)    ;convert "A" to 10
  1018. get_number_6:
  1019.     cmp    al,bl        ;a legal digit in the desired base?
  1020.     jae    get_number_2    ;no.
  1021.     loop    get_number_1
  1022.     dec    si        ;setup for pre-increment.
  1023. get_number_2:
  1024.     mov    dx,cx
  1025.     pop    cx        ;restore count.
  1026.     sub    cx,dx        ;get the actual count of chars into cx.
  1027.     inc    si
  1028.     push    si        ;save a copy of the start of the number.
  1029.     mov    ax,0        ;initially zero.
  1030. ;at this point, si => first digit, cx = count of digits to convert.
  1031.     jcxz    get_number_4    ;if no more chars, we're done.
  1032. get_number_3:
  1033.     mul    bx
  1034.     mov    dx,ax
  1035.     lodsb            ;ax = new ASCII digit.
  1036.     sub    al,'0'        ;make it a number.
  1037.     cmp    al,'9'-'0'
  1038.     jbe    get_number_7
  1039.     cmp    al,'a'-'0'
  1040.     jb    get_number_9
  1041.     sub    al,'a'-'A'
  1042. get_number_9:
  1043.     sub    al,'A'-('0'+10)
  1044. get_number_7:
  1045.     cbw            ;make it a word.
  1046.     add    ax,dx        ;and add in the old value.
  1047.     loop    get_number_3
  1048. get_number_4:
  1049.     pop    si
  1050.     cmp    byte ptr 0ffffh[si],'-'
  1051.     jne    get_number_5
  1052.     dec    si
  1053.     neg    ax
  1054. get_number_5:
  1055.     ret
  1056.  
  1057.  
  1058.     public    return_number
  1059. return_number:
  1060. ;enter with di => place to put string, tos => start of string,
  1061. ;  ax=number.
  1062.     mov    cx,0        ;use only as many digits as is needed.
  1063.     mov    bx,10
  1064.     call    put_number
  1065.     jmp    return_tos
  1066.  
  1067.  
  1068.     public    put_number
  1069. put_number:
  1070. ;enter with di => place to put string, ax = number, cx=minimum number of digits
  1071. ;  bx=base to convert number to.
  1072.     or    ax,ax
  1073.     jge    put_number_1
  1074.     neg    ax
  1075.     mov    byte ptr [di],'-'
  1076.     inc    di
  1077. put_number_1:
  1078.     call    one_digit
  1079.     ret
  1080.  
  1081.  
  1082. one_digit:
  1083.     jcxz    one_digit_3
  1084.     dec    cx
  1085. one_digit_3:
  1086.     cwd
  1087.     div    bx
  1088.     push    dx
  1089.     or    ax,ax
  1090.     jnz    one_digit_1    ;if more digits, do them.
  1091.     jcxz    one_digit_2    ;if count is zero, don't do next digit.
  1092. ;we get here if we have more digits to do, or we have more leading
  1093. ; zeroes to place.
  1094. one_digit_1:
  1095.     call    one_digit
  1096. one_digit_2:
  1097.     pop    ax        ;pushed as dx
  1098.     add    al,'0'
  1099.     cmp    al,'9'
  1100.     jbe    one_digit_4
  1101.     add    al,'A'-('9'+1)    ;the digit above "9" becomes an "A".
  1102. one_digit_4:
  1103.     cmp di,actptr ! jb $+5 ! jmp nomem
  1104.     stosb
  1105.     ret
  1106.  
  1107.  
  1108. string_search:
  1109.  
  1110.     if    1
  1111.  
  1112. ;enter with si,cx => short string, di,dx => long string.
  1113. ;exit with nc if string was found, di,dx => position found.
  1114. ;exit with cy if string was not found.
  1115.     jcxz    string_search_3    ;zero length strings are found immediately
  1116. ;we can get into trouble if cx = 0 after this point.
  1117. string_search_1:
  1118.     cmp    dx,cx
  1119.     jb    string_search_2
  1120.     push    si    ;preserve all the registers.
  1121.     push    di
  1122.     push    cx
  1123.     repe    cmpsb
  1124.     pop    cx
  1125.     pop    di
  1126.     pop    si
  1127.     je    string_search_3
  1128.     dec    dx
  1129.     inc    di
  1130.     jmps    string_search_1
  1131. string_search_3:
  1132.     clc
  1133.     ret
  1134. string_search_2:
  1135.     stc
  1136.     ret
  1137.  
  1138.     else
  1139.  
  1140. ;enter with si,cx => short string, di,dx => long string.
  1141. ;exit with nc if string was found, di,dx => position found.
  1142. ;exit with cy if string was not found.
  1143. ;preserve si,cx, ah.
  1144.     jcxz    string_search_1        ;zero length strings are found immediately
  1145.     mov    bx,cx            ;save search string length.
  1146.     mov    cx,dx            ;get target string length.
  1147.     mov    dx,si            ;save search string pointer.
  1148.     dec    bx
  1149.     sub    cx,bx            ;this many fewer chars to look at.
  1150.     jb    string_search_5        ;string is shorter than search.
  1151. string_search_3:
  1152.     jcxz    string_search_5        ;no chars to look at.
  1153.     mov    si,dx
  1154.     lodsb                ;get the first char.
  1155. string_search_4:
  1156.     scasb                ;look for the first char.
  1157.     loopnz    string_search_4        ;keep looking until we find it.
  1158.     jnz    string_search_5        ;we didn't
  1159.     xchg    cx,bx            ;set the count to the string length.
  1160.     push    cx            ;save the string length
  1161.     push    di            ;save the source position
  1162.     repe    cmpsb            ;is this it?
  1163.     mov    cx,bx            ;restore the search length
  1164.     pop    di            ;restore the source position
  1165.     pop    bx            ;restore the string length
  1166.     jne    string_search_3        ;no match - try at next position.
  1167.     mov    si,dx            ;restore search pointer
  1168.     dec    di            ;make di point to the first char again.
  1169.     mov    dx,cx            ;return the remaining count in dx.
  1170.     mov    cx,bx            ;restore search count
  1171.     inc    cx            ;restore count's original value.
  1172. string_search_1:
  1173.     clc
  1174.     jmps string_search_2
  1175. string_search_5:
  1176.     stc
  1177. string_search_2:
  1178.     ret
  1179.  
  1180.     endif
  1181.  
  1182.  
  1183.     public    getarg1_filename
  1184. getarg1_filename:
  1185.     mov    cx,1
  1186.     public    getarg_filename
  1187. getarg_filename:
  1188.     call    getarg
  1189.     mov    di,offset filename
  1190.     rep    movsb
  1191.     xor    al,al
  1192.     stosb
  1193.     mov    si,offset filename
  1194.     ret
  1195.  
  1196.  
  1197.     extrn    getarg1: near
  1198. ;getarg1 returns si -> the first argument.  cx is set to the size
  1199. ;    of the first argument.
  1200.  
  1201.     extrn    getarg: near
  1202. ;getarg returns si -> the argument given in cx.  cx is set to the size
  1203. ;    of the argument.
  1204.  
  1205. ;code    ends
  1206.  
  1207.     end    init
  1208.  
  1209. turns si -> the argument given in cx.  cx is set to the size
  1210. ;    of the argument.
  1211.  
  1212. ;code    ends
  1213.  
  1214.     end    init
  1215.  
  1216.