home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / list / ep-src.ark / NDEFF.MAC < prev    next >
Text File  |  1988-05-21  |  20KB  |  1,342 lines

  1.  
  2.     include    BDS.LIB
  3.  
  4.  
  5. lod    macro
  6.     mov    e,m
  7.     inx    h
  8.     mov    d,m
  9.     endm
  10.  
  11. sto    macro
  12.     mov    m,e
  13.     inx    h
  14.     mov    m,d
  15.     endm
  16.  
  17. ind    macro
  18.     mov    a,m
  19.     inx    h
  20.     mov    h,m
  21.     mov    l,a
  22.     endm
  23.  
  24.     .comment    `
  25. functions ALLOC, FREE, and FREEALL
  26.  
  27.  
  28. /*
  29.  * Storage allocation data, used by "alloc" and "free"
  30.  */
  31.  
  32. struct _header  {
  33.     struct _header *_ptr;
  34.     unsigned _size;
  35.  };
  36.  
  37. struct _header _base;        /* declare this external data to  */
  38. struct _header *_allocp;    /* be used by alloc() and free()  */
  39.             `
  40. ._ptr    equ    0
  41. ._size    equ    2
  42.  
  43.     .comment    `
  44. /*
  45.     Storage allocation functions:
  46. */
  47.  
  48. char *alloc(nbytes)
  49. unsigned nbytes;
  50. {
  51.     struct _header *p, *q, *cp;
  52.     int nunits; 
  53.     nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
  54.     if ((q = _allocp) == NULL) {
  55.         _base._ptr = _allocp = q = &_base;
  56.         _base._size = 0;
  57.      }
  58.     for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
  59.         if (p -> _size >= nunits) {
  60.             _allocp = q;
  61.             if (p -> _size == nunits)
  62.                 _allocp->_ptr = p->_ptr;
  63.             else {
  64.                 q = _allocp->_ptr = p + nunits;
  65.                 q->_ptr = p->_ptr;
  66.                 q->_size = p->_size - nunits;
  67.                 p -> _size = nunits;
  68.              }
  69.             return p + 1;
  70.          }
  71.         if (p == _allocp) {
  72.             if ((cp = sbrk(nunits *     sizeof (_base))) == ERROR)
  73.                 return NULL;
  74.             cp -> _size = nunits; 
  75.             free(cp+1);    /* remember: pointer arithmetic! */
  76.             p = _allocp;
  77.         }
  78.      }
  79. }
  80.  
  81.  
  82.  
  83.             `
  84.  
  85.  
  86. alloc::
  87. ;    pop    d
  88. ;    pop    h
  89. ;    push    h
  90. ;    push    d
  91.  
  92. ;    push    b    ;(not yet used)
  93.  
  94. ;    shld    nbytes
  95.  
  96. ;    nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base);
  97.  
  98.  
  99. ;    lhld    nbytes
  100. ; + (4 - 1)
  101.     inx    h
  102.     inx    h
  103.     inx    h
  104. ;    lxi    d,4
  105. ;    xchg
  106. ;    call    usdiv
  107.     mvi    e,2
  108.     call    shlrbe
  109.  
  110.     inx    h    ;1 +
  111.     shld    nunits
  112.  
  113. ;    if ((q = _allocp) == NULL) {
  114.     lhld    _allocp
  115.     shld    a$q
  116.     mov    a,h
  117.     ora    l
  118.     jnz    .alc1
  119.  
  120. ;        _base._ptr = _allocp = q = &_base;
  121.  
  122.     lxi    h,_base
  123.     shld    a$q
  124.     shld    _allocp
  125.     shld    _base+._ptr
  126.  
  127. ;        _base._size = 0;
  128. ;     }
  129.     lxi    h,0
  130.     shld    _base+._size
  131.  
  132. ;    for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
  133. .alc1:
  134.     lhld    a$q
  135.     ind
  136.     shld    a$p
  137.  
  138. ;        if (p -> _size >= nunits) {
  139. .alc2:
  140.     lhld    a$p
  141.     inx    h
  142.     inx    h
  143.     lod
  144.  
  145.     lhld    nunits
  146.  
  147.     call    albu
  148.     jc    .alc5
  149.  
  150. ;            _allocp = q;
  151.     lhld    a$q
  152.     shld    _allocp
  153.  
  154. ;            if (p -> _size == nunits)
  155.  
  156.     lhld    a$p
  157.     inx    h
  158.     inx    h
  159.     lod
  160.  
  161.     lhld    nunits
  162.     call    eqwel
  163.     jnz    .alc3
  164.  
  165. ;                _allocp->_ptr = p->_ptr;
  166.  
  167.     lhld    a$p
  168.     lod
  169.  
  170.     lhld    _allocp
  171.     sto
  172.     jmp    .alc4
  173. ;            else {
  174. ;                q = _allocp->_ptr = p + nunits;
  175. .alc3:
  176.  
  177.     lhld    a$p
  178.     xchg
  179.     lhld    nunits
  180.     dad    h
  181.     dad    h    ;4 bytes per _header
  182.     dad    d
  183.  
  184.     shld    a$q    ;q =
  185.  
  186.     xchg        ;_allocp->_ptr =
  187.     lhld    _allocp
  188.     sto
  189.  
  190. ;                q->_ptr = p->_ptr;
  191.  
  192.     lhld    a$p
  193.     lod
  194.     lhld    a$q
  195.     sto
  196. ;                q->_size = p->_size - nunits;
  197.  
  198.     lhld    a$p
  199.     inx    h
  200.     inx    h
  201.     lod
  202.  
  203.     lhld    nunits
  204.     call    cmh
  205.     dad    d
  206.  
  207.     xchg
  208.     lhld    a$q
  209.     inx    h
  210.     inx    h
  211.     sto
  212. ;                p -> _size = nunits;
  213.  
  214.     lhld    nunits
  215.     xchg
  216.  
  217.     lhld    a$p
  218.     inx    h
  219.     inx    h
  220.     sto
  221. ;             }
  222. ;            return p + 1;
  223. ;         }
  224. .alc4:
  225.     lhld    a$p
  226.     inx    h
  227.     inx    h
  228.     inx    h
  229.     inx    h
  230. ;    jmp    .alc8
  231.     ret
  232. ;        if (p == _allocp) {
  233. .alc5:
  234.     lhld    a$p
  235.     xchg
  236.     lhld    _allocp
  237.     call    eqwel
  238.     jnz    .alc7
  239. ;            if ((cp = sbrk(nunits *     sizeof (_base))) == ERROR)
  240.     lhld    nunits
  241. ;*4
  242.     dad    h
  243.     dad    h
  244.  
  245. ;    push    h
  246.     call    sbrk
  247. ;    pop    d
  248.  
  249.     shld    a$cp
  250.  
  251.     inx    h
  252.     mov    a,h
  253.     ora    l
  254.     rz
  255. ;    jnz    .alc6
  256. ;                return NULL;
  257. ;    lxi    h,0
  258. ;    jmp    .alc8
  259. ;            cp -> _size = nunits; 
  260. .alc6:
  261.  
  262.     lhld    nunits
  263.     xchg
  264.     lhld    a$cp
  265.     inx    h
  266.     inx    h
  267.     sto
  268.  
  269. ;            free(cp+1);    /* remember: pointer arithmetic! */
  270.     lhld    a$cp
  271.     inx    h
  272.     inx    h
  273.     inx    h
  274.     inx    h
  275. ;;    push    h
  276.     call    free
  277. ;;    pop    d
  278. ;            p = _allocp;
  279. ;        }
  280. ;     }
  281. ;}
  282.     lhld    _allocp
  283.     shld    a$p
  284.  
  285. ;(end for-loop action)
  286. ;    for (p = q -> _ptr; ; q = p, p = p -> _ptr) {
  287. .alc7:
  288.  
  289.     lhld    a$p
  290.     shld    a$q
  291.  
  292. ;    lhld    a$p
  293.     ind
  294.     shld    a$p
  295.     jmp    .alc2
  296.  
  297. ;.alc8:
  298. ;    pop    b
  299. ;    ret
  300.  
  301.     .comment    `
  302.  
  303. free(ap)
  304. struct _header *ap;
  305. {
  306.     struct _header *p, *q;
  307.  
  308.     p = ap - 1;    /* No need for the cast when "ap" is a struct ptr */
  309.  
  310.     for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
  311.         if (q >= q -> _ptr && (p > q || p < q -> _ptr))
  312.             break;
  313.     if (p + p -> _size == q -> _ptr) {
  314.         p -> _size += q -> _ptr -> _size;
  315.         p -> _ptr = q -> _ptr -> _ptr;
  316.      }
  317.     else p -> _ptr = q -> _ptr;
  318.  
  319.     if (q + q -> _size == p) {
  320.         q -> _size += p -> _size;
  321.         q -> _ptr = p -> _ptr;
  322.      }
  323.     else q -> _ptr = p;
  324.  
  325.     _allocp = q;
  326. }
  327.             `
  328.  
  329. free::
  330. ;    pop    d
  331. ;    pop    h
  332. ;    push    h
  333. ;    push    d
  334.  
  335. ;    shld    f$ap
  336.  
  337. ;    push    b
  338.  
  339.  
  340. ;    p = ap - 1;    /* No need for the cast when "ap" is a struct ptr */
  341.  
  342. ;    lhld    f$ap
  343.     dcx    h
  344.     dcx    h
  345.     dcx    h
  346.     dcx    h
  347.     shld    f$p
  348. ;
  349. ;    for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
  350.  
  351.     lhld    _allocp
  352.     shld    f$q
  353.  
  354. .fr1:
  355.     lhld    f$p
  356.     xchg
  357.     lhld    f$q
  358.     call    agbu
  359.     jnc    .fr2
  360.  
  361.     lhld    f$q
  362.     lod
  363.  
  364.     lhld    f$p
  365.     xchg
  366.     call    albu
  367.     jc    .fr5
  368.  
  369. ;        if (q >= q -> _ptr && (p > q || p < q -> _ptr))
  370. ;            break;
  371. .fr2:
  372.  
  373.     lhld    f$q
  374.     lod
  375.     xchg
  376.     call    albu
  377.     jc    .fr4
  378.  
  379.     lhld    f$p
  380.     xchg
  381.     lhld    f$q
  382.     call    agbu
  383.     jc    .fr5
  384.  
  385.     lhld    f$q
  386.     lod
  387.     lhld    f$p
  388.     xchg
  389.     call    albu
  390. ;    jnc    .fr4
  391. ;
  392. ;.fr3:    jmp    .fr5
  393.     JC    .fr5
  394.  
  395. ;(end for-loop action)
  396. ;    for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr)
  397. .fr4:
  398.     lhld    f$q
  399.     ind
  400.     shld    f$q
  401.     jmp    .fr1
  402.  
  403. ;    if (p + p -> _size == q -> _ptr) {
  404.  
  405. .fr5:
  406.     lhld    f$p
  407.     push    h
  408.  
  409. ;    lhld    f$p
  410.     inx    h
  411.     inx    h
  412.     ind
  413.     dad    h
  414.     dad    h
  415.  
  416.     pop    d
  417.     dad    d
  418.  
  419.     xchg
  420.  
  421.     lhld    f$q
  422.     ind
  423.  
  424.     call    eqwel
  425.     jnz    .fr6
  426. ;        p -> _size += q -> _ptr -> _size;
  427.     lhld    f$p
  428.     inx    h
  429.     inx    h
  430.     push    h
  431.  
  432.     lod
  433.     push    d
  434.  
  435.     lhld    f$q
  436. ;q
  437.     ind
  438. ;q -> _ptr
  439.     inx    h
  440.     inx    h
  441.     ind
  442. ;q -> _ptr -> _size
  443.  
  444.     pop    d
  445.     dad    d
  446.  
  447.     xchg
  448.     pop    h
  449.     sto
  450.  
  451. ;        p -> _ptr = q -> _ptr -> _ptr;
  452. ;     }
  453.  
  454.     lhld    f$q
  455. ;q
  456.     ind
  457. ;q -> _ptr
  458.     ind
  459. ;q -> _ptr -> _ptr
  460.  
  461.     xchg
  462.     lhld    f$p
  463.     sto
  464.     jmp    .fr7
  465.  
  466. ;    else p -> _ptr = q -> _ptr;
  467. .fr6:
  468.  
  469.     lhld    f$q
  470.     lod
  471.     lhld    f$p
  472.     sto
  473. ;
  474. ;    if (q + q -> _size == p) {
  475. .fr7:
  476.     lhld    f$q
  477.     push    h
  478.  
  479. ;    lhld    f$q
  480.     inx    h
  481.     inx    h
  482.     ind
  483.     dad    h
  484.     dad    h
  485.  
  486.     pop    d
  487.     dad    d
  488.  
  489.     xchg
  490.  
  491.     lhld    f$p
  492.     call    eqwel
  493.     jnz    .fr8
  494.  
  495. ;        q -> _size += p -> _size;
  496.  
  497.     lhld    f$q
  498.     inx    h
  499.     inx    h
  500.     push    h
  501.  
  502.     lod
  503.  
  504.     lhld    f$p
  505.     inx    h
  506.     inx    h
  507.     ind
  508.  
  509.     dad    d
  510.  
  511.     xchg
  512.     pop    h
  513.     sto
  514.  
  515. ;        q -> _ptr = p -> _ptr;
  516. ;     }
  517.  
  518.     lhld    f$p
  519.     lod
  520.     lhld    f$q
  521.     sto
  522.  
  523.     jmp    .fr9
  524.  
  525. ;    else q -> _ptr = p;
  526. .fr8:
  527.  
  528.     lhld    f$p
  529.     xchg
  530.     lhld    f$q
  531.     sto
  532. ;
  533. ;    _allocp = q;
  534. ;}
  535. .fr9:
  536.     lhld    f$q
  537.     shld    _allocp
  538.  
  539. ;    pop    b
  540.     ret
  541.  
  542. freeall::
  543.     lxi    h,0
  544.     shld    _allocp
  545.     lhld    freram
  546.     shld    allocp
  547.     ret
  548.  
  549. ;formerly external
  550. _base:        dw    0,0
  551. _allocp:    dw    0
  552.  
  553. ;alloc arg
  554. ;nbytes:    dw    0 not needed
  555. ;alloc locals
  556. a$p:        dw    0
  557. a$q:        dw    0
  558. a$cp:        dw    0
  559. nunits:        dw    0
  560.  
  561. ;free arg
  562. ;f$ap:        dw    0 not needed
  563. ;free locals
  564. f$p:        dw    0
  565. f$q:        dw    0
  566.  
  567.  
  568.  
  569. sbrk::
  570. ;    call    ma1toh    ;get # of bytes needed in HL
  571. ;    xchg        ;put into DE
  572.  
  573. ;    pop    h
  574. ;    pop    d
  575. ;    push    d
  576. ;    push    h
  577.     xchg
  578.  
  579.     lhld    allocp    ;get current allocation pointer
  580.     push    h    ;save it
  581.     dad    d    ;get tentative last address of new segment
  582.     jc    brkerr    ;better not allow it to go over the top!
  583.     dcx    h
  584.     xchg        ; now last addr is in DE
  585.     lhld    alocmx    ;get safety factor
  586.     call    cmh
  587.     dad    sp    ;get HL = (SP - alocmx)
  588.  
  589.     XCHG
  590.     CALL    CMPHD
  591. ;    call    cmpdh    ;is DE less than HL?
  592.     jnc    brkerr    ;if not, can't provide the needed memory.
  593. ;    xchg        ;else OK.
  594.     inx    h
  595.     shld    allocp    ;save start of next area to be allocated
  596.     pop    h    ;get pointer to this area
  597.     ret        ;and return with it.
  598.  
  599. brkerr:    pop    h    ;clean up stack
  600.     jmp    error    ;and return with -1 to indicate can't allocate.
  601.  
  602. ;cmpdh:    mov    a,d
  603. ;    cmp    h
  604. ;    rc
  605. ;    rnz
  606. ;    mov    a,e
  607. ;    cmp    l
  608. ;    ret
  609.  
  610.  
  611.  
  612.     .comment    `
  613. puts(s)
  614. char *s;
  615. {
  616.     while (*s) putchar(*s++);
  617. }
  618.             `
  619. puts::
  620. ;    pop    d
  621. ;    pop    h
  622. ;    push    h
  623. ;    push    d
  624.  
  625. .pts1:
  626.  
  627.     mov    a,m
  628.     ora    a
  629.     rz
  630.  
  631.     push    h
  632. ;    mov    l,a
  633. ;    mvi    h,0
  634. ;    push    h
  635.     call    putchar
  636. ;    pop    d
  637.     pop    h
  638.     inx    h
  639.     jmp    .pts1
  640.  
  641.  
  642.     .comment    `
  643. char *strcat(s1,s2)
  644. char *s1, *s2;
  645. {
  646.     char *temp; temp=s1;
  647.     while(*s1) s1++;
  648.     do *s1++ = *s2; while (*s2++);
  649.     return temp;
  650. }            `
  651.  
  652. strcat::
  653. ;    push    b
  654. ;    pop    b
  655. ;
  656. ;    pop    b
  657. ;    pop    d
  658. ;    pop    b
  659. ;    lxi    h,-8
  660. ;    dad    sp
  661. ;    sphl
  662. ;s1 in DE
  663. ;s2 in BC
  664. ;NO -- now s1 in HL and s2 in DE
  665.  
  666.  
  667. ;    mov    h,d    ;save s1 for return
  668. ;    mov    l,e
  669. ;NO -- no return used
  670.  
  671. .sct1:
  672.     mov    a,m
  673.     inx    h
  674.     ora    a
  675.     jnz    .sct1
  676.     dcx    h
  677.  
  678. ;DE points to 0 at end of s1
  679.  
  680. .sct2:
  681.     ldax    d
  682.     mov    m,a
  683.     inx    d
  684.     inx    h
  685.     ora    a
  686.     jnz    .sct2
  687.     ret
  688.  
  689.  
  690.     .comment    `
  691. int strcmp(s1, s2)
  692. char *s1, *s2;
  693. {
  694.     while (*s1 == *s2++)
  695.         if (*s1++ == '\0')
  696.             return 0;
  697.     return (*s1 - *--s2);
  698. }            `
  699.  
  700. strcmp::
  701.     .comment    `
  702.     push    b
  703.     pop    b
  704.  
  705.     pop    b
  706.     pop    d
  707.     pop    b
  708.     lxi    h,-8
  709.     dad    sp
  710.     sphl
  711. ;s1 in DE
  712. ;s2 in BC
  713.     mov    h,b
  714.     mov    l,c
  715. ;s2 in HL
  716.     pop    b    ;restore mark stack
  717.             `
  718.  
  719.     XCHG
  720.  
  721. .1:
  722.     ldax    d
  723.     ora    a
  724.     jz    .2    ;end of s1?
  725.     cmp    m
  726.     inx    h
  727.     inx    d
  728.     jz    .1
  729. ;here char's differ, and neither is nul
  730. ;A still has current char from s1
  731.     dcx    h    ;back to current char of s2
  732. .2:    sub    m    ;*s1 - *s2
  733.     mov    l,a
  734.     mvi    h,0
  735.     rnc
  736.     dcr    h    ;maybe negative sign
  737.     ret
  738.  
  739.  
  740.     .comment    `
  741. char *strcpy(s1,s2)
  742. char *s1, *s2;
  743. {
  744.     char *temp; temp=s1;
  745.     while (*s1++ = *s2++);
  746.     return temp;
  747. }            `
  748. strcpy::
  749.     .comment    `
  750.     push    b
  751.     pop    b
  752.     pop    b
  753.     pop    d
  754.     pop    b
  755.     lxi    h,-8
  756.     dad    sp
  757.     sphl
  758. ;s1 in DE
  759. ;s2 in BC
  760.             `
  761. ;NO -- s1 in HL, s2 in DE
  762.  
  763.  
  764. ;    push    d    ;for return s1
  765. ;get s1 in HL
  766. ;    xchg
  767. ;NO -- return not used
  768.  
  769. .scpy1:
  770.     ldax    d
  771.     mov    m,a
  772.     inx    d
  773.     inx    h
  774.     ora    a
  775.     jnz    .scpy1
  776.     ret
  777.  
  778. ;
  779. ; Functions appearing in this file:
  780. ;
  781. ;     getchar    kbhit    ungetch    putchar    gets
  782. ;    exit
  783. ;
  784.  
  785.  
  786. getchar::
  787.     lda    ungetl    ;any character pushed back?
  788.     ora    a
  789.     mov    l,a
  790.     jz    gch2
  791.     xra    a    ;yes. return it and clear the pushback
  792.     sta    ungetl    ;byte in C.CCC.
  793.     mvi    h,0
  794.     ret
  795.  
  796. gch2:    push    b
  797.     mvi    c,conin
  798.     call    .bdos
  799.     pop    b
  800.     cpi    cntrlc    ;control-C ?
  801.     jz    .exit    ;if so, exit the program.
  802.     cpi    1ah    ;control-Z ?
  803.     lxi    h,-1    ;if so, return -1.
  804.     rz
  805.     mov    l,a
  806.     cpi    cr    ;carriage return?
  807.     jnz    gch3
  808.     push    b
  809.     mvi    c,conout    ;if so, also echo linefeed
  810.     mvi    e,lf
  811.     call    .bdos
  812.     pop    b
  813.     mvi    l,newlin    ;and return newline (linefeed)..
  814.  
  815. gch3:    mvi    h,0
  816.     ret
  817.  
  818. kbhit::
  819.     lda    ungetl    ;any character ungotten?
  820.     mvi    h,0
  821.     mov    l,a
  822.     ora    a
  823.     rnz        ;if so, return true
  824.  
  825.     push    b
  826.     mvi    c,cstat    ;else interrogate console status
  827.     call    .bdos
  828.     pop    b
  829.  
  830.     ora    a    ;0 returned by BDOS if no character ready
  831.     lxi    h,0
  832.     rz        ;return 0 in HL if no character ready
  833.     inr    l    ;otherwise return 1 in HL
  834.     ret
  835.  
  836. putchar::
  837. ;    call    ma1toh    ;get character in A
  838.  
  839. ;    pop    d
  840. ;    pop    h
  841. ;    push    h
  842. ;    push    d
  843. ;    mov    a,l
  844.  
  845.     push    b
  846.     mvi    c,conout
  847.     cpi    newlin    ;newline?
  848.     jnz    put1    ;if not, just go put out the character
  849.     mvi    e,cr    ;else...put out CR-LF
  850.     call    .bdos
  851.     mvi    c,conout
  852.     mvi    a,lf
  853.  
  854. put1:    mov    e,a
  855.     call    .bdos
  856.  
  857. put2:    mvi    c,cstat    ;now, is input present at the console?
  858.     call    .bdos
  859.     ora    a
  860.     jnz    put3
  861.     pop    b    ;no...all done.
  862.     ret
  863.  
  864. put3:    mvi    c,conin    ;yes. sample it (this will always echo the
  865.     call    .bdos    ;    character to the screen, alas)
  866.     cpi    cntrlc    ;is it control-C?
  867.     jz    .exit    ;if so, abort and reboot
  868.     pop    b    ;else ignore it.
  869.     ret
  870.  
  871. gets::
  872. ;    call    ma1toh    ;get destination address
  873.  
  874. ;    pop    d
  875. ;    pop    h
  876. ;    push    h
  877. ;    push    d
  878.  
  879.     push    b    ;save BC
  880.     push    h
  881.     push    h
  882.     lxi    h,-150    ;use space below stack for reading line
  883.     dad    sp
  884.     push    h    ;save buffer address
  885.     mvi    m,88h    ;Allow a max of about 135 characters
  886.     mvi    c,getlin
  887.     xchg        ;put buffer addr in DE
  888.     call    .bdos    ;get the input line
  889.     mvi    c,conout
  890.     mvi    e,lf    ;put out a LF
  891.     call    .bdos
  892.     pop    h    ;get back buffer address
  893.     inx    h    ;point to returned char count
  894.     mov    b,m    ;set B equal to char count
  895.     inx    h    ;HL points to first char of line
  896.     pop    d    ;DE points to start destination area
  897. copyl:    mov    a,b    ;copy line to start of buffer
  898.     ora    a
  899.     jz    gets2
  900.     mov    a,m
  901.     stax    d
  902.     inx    h
  903.     inx    d
  904.     dcr    b
  905.     jmp    copyl
  906.     
  907. gets2:    xra    a    ;store terminating null
  908.     stax    d
  909.     pop    h    ;return buffer address in HL
  910.     pop    b
  911.     ret
  912.  
  913.  
  914.  
  915. ;exit::
  916. ;    jmp    .exit
  917.  
  918. ;
  919. ; Functions appearing in this file:
  920. ;    open    creat    unlink
  921. ;    read    write    
  922. ;    execl
  923. ;
  924.  
  925.  
  926.  
  927. ;
  928. ; Open:
  929. ;    int open(filename,mode)
  930. ;        char *filename;
  931. ;
  932. ; Open a file for read (mode == 0), write (mode == 1) or both (mode = 2),
  933. ; and detect a user-number prefix. Returns a file descriptor.
  934. ;
  935.  
  936. open::
  937.     call    arghak
  938.     xra    a
  939.     call    fgfcb    ;any fcb's free?
  940.     jnc    open2    ;if not, error
  941.     mvi    a,10    ;"no more file slots"
  942.     jmp    error
  943.  
  944. open2:    sta    tmp
  945.     xchg
  946.     lhld    arg1
  947.     xchg
  948.     push    b
  949.     call    setfcu    ;parse name and set usenum
  950.     lda    usrnum
  951.     call    setusr    ;set new user number
  952.  
  953.     mvi    c,openc
  954.     call    .bdos
  955.     cpi    errorv    ;successful open?
  956.     pop    b
  957.  
  958.     mvi    a,11    ; set error code in case of error
  959.     jz    oerror    ;if error, go abort
  960.  
  961.     lda    tmp
  962.     call    fgfd    ;get HL pointing to fd table entry
  963.     lda    arg2
  964.     ora    a    ;open for read?
  965.     mvi    d,3
  966.     jz    open4
  967.     dcr    a
  968.     mvi    d,5
  969.     jz    open4    ;write?
  970.     dcr    a
  971.     mvi    a,12    ;"bad mode" for open operation...
  972.     jnz    oerror    ;...if not mode 2
  973.     mvi    d,7    ;else must be mode 2.
  974. open4:    lda    usrnum    ;get user number for the file
  975.     add    d    ;add r/w bit codes
  976.     mov    m,a    ;and store in fd table
  977.     inx    h    ;clear max sector number field of fd entry
  978.     xra    a
  979.     mov    m,a
  980.     inx    h
  981.     mov    m,a
  982.     lda    tmp    ;get back fd
  983.     mov    l,a
  984.     mvi    h,0
  985.     call    rstusr    ;reset user number
  986.     ret
  987.  
  988. oerror:    call    rstusr    ;reset user number
  989.     sta    errnum    ;store error code number
  990.     jmp    error    ;and return general error condition
  991.  
  992.  
  993. ;
  994. ; Close:
  995. ;    close(fd);
  996. ;
  997. ; Close a file opened via "open" or "creat":
  998. ;
  999.  
  1000. ;close::
  1001. ;    jmp    .close    ;jump to the close routine in C.CCC
  1002.  
  1003.  
  1004. ;
  1005. ; Creat:
  1006. ;    int creat(filename)
  1007. ;        char *filename;
  1008. ; Creates the named file, first deleting any old versions, and opens it
  1009. ; for both read and write. Returns a file descriptor.
  1010. ;
  1011.  
  1012. ;    ext    unlink,open
  1013. creat::
  1014.     pop    d
  1015.     pop    h
  1016.     push    h
  1017.     push    d
  1018.  
  1019.     push    b
  1020.     push    h
  1021.  
  1022. ;    push    h
  1023.     call    unlink    ;erase any old versions of file
  1024. ;    pop    d
  1025.  
  1026.     lda    usrnum    ;set to appropriate user area computed by "unlink"
  1027.     call    setusr
  1028.     mvi    c,creatc    ;create the file
  1029.     lxi    d,fcb    ;assume fcb has been set by "unlink"
  1030.     call    .bdos
  1031.     call    rstusr    ;restore previous user number
  1032.     cpi    errorv
  1033.     pop    h
  1034.     pop    b
  1035.     jnz    creat0    ;if no error, go open
  1036.     mvi    a,13    ;"can't create file" error code
  1037.     sta    errnum
  1038.     jmp    error
  1039.  
  1040. creat0:    lxi    d,2    ;now open for read/write
  1041.     push    d
  1042. ;    lhld    arg1
  1043.     push    h
  1044.     call    open
  1045.     pop    d
  1046.     pop    d
  1047.     ret
  1048.  
  1049.  
  1050. ;
  1051. ; Unlink:
  1052. ;    unlink(filename)
  1053. ;    char *filename;
  1054. ;
  1055. ; Deletes the named file. User number prefixes are recognized:
  1056. ;
  1057.  
  1058. unlink:
  1059. ;    call    ma1toh
  1060.     push    b
  1061.     xchg    
  1062.     lxi    h,fcb
  1063.     call    setfcu    ;parse for fcb and compute user number
  1064.     lda    usrnum
  1065.     call    setusr    ;set to correct user number
  1066.     mvi    c,delc    ;delete
  1067.     call    .bdos
  1068.     call    rstusr    ;restore original user number
  1069.     lxi    h,0
  1070.     pop    b    ;restore BC
  1071.     cpi    errorv    ;was BDOS able to find the file?
  1072.     rnz        ;if so, all done.
  1073.     mvi    a,11    ;set error code for "file not found"
  1074.     sta    errnum
  1075.     dcx    h    ;return -1
  1076.     ret
  1077.  
  1078.  
  1079. ;
  1080. ; Fabort:
  1081. ;    fabort(fd);
  1082. ; Abort all operations on file fd. Has no effect under MP/M II.
  1083. ;
  1084.  
  1085. fabort::
  1086. ;    pop    d
  1087. ;    pop    h
  1088. ;    push    h
  1089. ;    push    d
  1090. ;    mov    a,l
  1091.  
  1092.     call    fgfd
  1093.     jnc    abrt2    ;legal fd?
  1094.     mvi    a,7
  1095.     sta    errnum    ;set "bad fd" error code
  1096.     jmp    error
  1097.     
  1098. abrt2:
  1099.     IF NOT MPM2
  1100.     mvi    m,0    ;clear entry in fd table
  1101.     ENDIF
  1102.  
  1103.     lxi    h,0
  1104.     ret
  1105.  
  1106.  
  1107. ;
  1108. ; Read:
  1109. ;
  1110. ;    i = read(fd, buf, n);
  1111. ;
  1112. ; Read a number of sectors using random-record I/O.
  1113. ;
  1114. ; The return value is either the number of sectors successfully
  1115. ; read, 0 for EOF, or -1 on error with errno() returning the error
  1116. ; code (or errmsg(n) returning a pointer to an error message).
  1117. ; The Random Record Field is incremented following each successful
  1118. ; sector is read, just as if the normal (sequential) read function
  1119. ; were being used. "seek" must be used to go back to a previous 
  1120. ; sector.
  1121. ;
  1122.  
  1123. read::
  1124.  
  1125.     call    arghak
  1126.     lda    arg1
  1127.     call    fgfd
  1128.     mov    d,m    ;save fdt entry in D
  1129.     mvi    a,7    ;prepare for possible "bad fd"
  1130.     jc    rerror
  1131.  
  1132.     mov    a,d
  1133.     ani    2
  1134.     mvi    a,8    ;prepare for possible "no read permission"
  1135.     jz    rerror
  1136.  
  1137.     push    b
  1138.     mov    a,d    ;get fd table entry
  1139.     call    setusr    ;set user area to that of the file
  1140.  
  1141.     lda    arg1    ;get fd
  1142.     call    fgfcb
  1143.     shld    tmp2    ;save fcb address
  1144.     lxi    h,0    ;clear sector count
  1145.     shld    tmp2a
  1146. r2:    lhld    arg3    ;get countdown
  1147.     mov    a,h
  1148.     ora    l    ;done?
  1149. r2aa:    lhld    tmp2a
  1150.     jnz    r2a
  1151. r2done:    call    rstusr    ;reset user number
  1152.     pop    b    ;yes. return with success count in HL
  1153.     ret
  1154.  
  1155. r2a:    lhld    arg2    ;get transfer addr in DE
  1156.     xchg
  1157.     mvi    c,sdma    ;set DMA there
  1158.     call    .bdos
  1159.  
  1160.     lhld    tmp2
  1161.     xchg
  1162.     mvi    c,readr    ;code for BDOS random read
  1163.     push    d    ;save DE so we can fudge nr field if
  1164.     call    .bdos    ;we stop reading on extent boundary...
  1165.     pop    d
  1166.     ora    a
  1167.     jz    r4    ;go to r4 if no problem
  1168.  
  1169.     sta    errnum    ;otherwise save error code
  1170.  
  1171.     cpi    1    ;ok, we have SOME kind of hangup...
  1172.     jz    r2b    ;check for EOF condition:
  1173.     cpi    4    ;  error codes 1 and 4 both indicate reading
  1174.     jz    r2b    ;  unwritten data..treat as EOF
  1175.  
  1176.     lxi    h,-1    ;put ERROR value in HL
  1177.     jmp    r2done
  1178.  
  1179. r2b:    lhld    tmp2a    ;return count
  1180.     jmp    r2done
  1181.  
  1182. r4:    lhld    arg3    ;decrement countdown
  1183.     dcx    h
  1184.     shld    arg3
  1185.     lhld    arg2    ;bump DMA address
  1186.     lxi    d,128
  1187.     dad    d
  1188.     shld    arg2
  1189.     lhld    tmp2a    ;bump success count
  1190.     inx    h
  1191.     shld    tmp2a
  1192.     lhld    tmp2    ;get address of fcb
  1193.     lxi    b,33    ;get addr of random record field
  1194.     dad    b
  1195.     mov    c,m    ;bump
  1196.     inx    h    ;    value
  1197.     mov    b,m    ;      of 
  1198.     inx    b    ;        random
  1199.     mov    m,b    ;          field
  1200.     dcx    h    ;            by one
  1201.     mov    m,c
  1202.     mov    a,b    ;overflow past 16-bit record count?
  1203.     ora    c
  1204.     jnz    r2    ; go for next sector if no overflow
  1205.     inx    h    ;else set 3rd byte of random sector count
  1206.     inx    h
  1207.     mvi    m,1
  1208.     mvi    a,14    ;"seek past 65536th record of file"
  1209.     sta    errnum
  1210.     jmp    r2aa    ;and don't read any more.
  1211.  
  1212. rerror:    sta    errnum
  1213.     jmp    error
  1214.  
  1215. ;
  1216. ; Write:
  1217. ;    i = write(fd, buf, n);
  1218. ;
  1219. ; The random sector write function. Returns either the number
  1220. ; of sectors successfully written, or -1 on hard error. Any return
  1221. ; value other than n (the third arg) should be considered an error,
  1222. ; after which errno() can tell you the error condition and errmsg() 
  1223. ; can return a pointer to an appropriate error message text.
  1224. ;
  1225.  
  1226. write::
  1227.  
  1228.     call    arghak
  1229.     lda    arg1
  1230.     call    fgfd
  1231.     shld    arg5    ;save pointer to fd table entry
  1232.     mov    d,m    ;save fd table entry in D
  1233.     mvi    a,7    ;prepare for possible "bad fd"
  1234.     jc    werror
  1235.  
  1236.     mov    a,d
  1237.     ani    4
  1238.     mvi    a,9    ;prepare for possible "no write permission"
  1239.     jz    werror
  1240.  
  1241.     push    b
  1242.     mov    a,d    ;set user number
  1243.     call    setusr
  1244.     lda    arg1    ;get fd
  1245.     call    fgfcb    ;compute fcb address
  1246.     shld    tmp2    ;save it away
  1247.     lxi    h,0    ;clear success count
  1248.     shld    tmp2a
  1249.  
  1250. writ1:    lhld    arg3    ;done yet?
  1251.     mov    a,h
  1252.     ora    l
  1253.     jnz    writ2
  1254.  
  1255.             ;take care of maximum sector count for cfsize:
  1256.     lhld    tmp2    ;get fcb address
  1257.     lxi    d,33    ;point to random record field
  1258.     dad    d
  1259.     mov    e,m
  1260.     inx    h
  1261.     mov    d,m    ;DE now holds random record number for next rec
  1262.     push    d    ;save it
  1263.     lhld    arg5    ;get fd table pointer
  1264.     inx    h    ;point to max value
  1265.     mov    e,m    ;get in DE
  1266.     inx    h
  1267.     mov    d,m    ;now DE is old max value, HL points to end of entry
  1268.     xthl        ;DE = old max, HL = current sector, STACK = tab ptr
  1269.     xchg        ;HL = old max, DE = current sector
  1270.     call    cmphd    ;is  old max less than current sector?
  1271.     pop    h    ;get tab ptr in HL
  1272.     jnc    writ1a    ;if old max not < current sector, don't update max
  1273.     mov    m,d    ;else update max value with new sector number
  1274.     dcx    h
  1275.     mov    m,e
  1276.     
  1277. writ1a:    lhld    tmp2a    ;if so, return count
  1278. wrdone:    call    rstusr    ;reset user number
  1279.     pop    b
  1280.     ret
  1281.  
  1282. writ2:    lhld    arg2    ;else get transfer address
  1283.     push    h    ;save on stack
  1284.     xchg        ;put in DE
  1285.     mvi    c,sdma    ;set DMA there
  1286.     call    .bdos
  1287.  
  1288.     pop    h    ;get back transfer address
  1289.     lxi    d,128    ;bump by 128 bytes for next time
  1290.     dad    d
  1291.     shld    arg2    ;save -> to next 128 bytes
  1292.  
  1293.     lhld    tmp2    ;get addr of fcb
  1294.     xchg
  1295.     mvi    c,writr    ;write random sector
  1296.     call    .bdos
  1297.     lhld    tmp2a    ;get success count in HL
  1298.     ora    a    ;error?
  1299.     jz    writ3    ;if not, go do bookkeeping
  1300.     
  1301.     sta    errnum    ;else save error code
  1302.     jmp    wrdone
  1303.         
  1304. writ3:    inx    h    ; else bump successful sector count,
  1305.     shld    tmp2a
  1306.  
  1307.     lhld    arg3    ; debump countdown,
  1308.     dcx    h
  1309.     shld    arg3
  1310.  
  1311.     lhld    tmp2    ; get address of fcb
  1312.     lxi    b,33    ; get address of random field
  1313.     dad    b
  1314.     mov    c,m    ; bump 16-bit value at random
  1315.     inx    h    ; record
  1316.     mov    b,m    ;    field
  1317.     inx    b    ;         of
  1318.     mov    m,b    ;           fcb
  1319.     dcx    h    ;          by one
  1320.     mov    m,c
  1321.  
  1322.     mov    a,b    ;overflow past 16-bit record count?
  1323.     ora    c
  1324.     jnz    writ1    ; go for next sector if no overflow
  1325.     inx    h    ;else set 3rd byte of random sector count
  1326.     inx    h
  1327.     mvi    m,1
  1328.     mvi    a,14    ;set "past 65536th sector" error code
  1329.     sta    errnum
  1330.     jmp    writ1a    ;and don't read any more.
  1331.  
  1332. werror:    sta    errnum
  1333.     jmp    error
  1334.  
  1335.  
  1336.  
  1337.     end
  1338.  
  1339.