home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol119 / lrun20.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  19.9 KB  |  908 lines

  1. TITLE    'LRUN  Library Run--a utility for .LBR files'
  2. VERSION    EQU    2$0    ;82-11-19 Added equates for user
  3. ;             area to search for command.lbr.
  4. ;
  5. ;        1$0    ;82-08-06 Initial source release
  6.     PAGE    60
  7. ;
  8. ; Requires MAC for assembly.  Due to the complexity of
  9. ; the relocation macros, this program may take a while
  10. ; to assemble.    Be prepared for periods of no disk activity
  11. ; on both passes before pressing panic button.    G.P.N.
  12. ;
  13.  
  14. ;--------------------------NOTICE------------------------------
  15. ;
  16. ;   (c) Copyright 1982    Gary P. Novosielski
  17. ;    All rights reserved.
  18. ;    
  19. ;   The following features courtesy of Ron Fowler:
  20. ;    1) command line reparsing and repacking (this allows
  21. ;    the former load-only program to become a load & run
  22. ;    utility).
  23. ;    2) code necessary to actually execute the loaded file
  24. ;    3) the HELP facility (LRUN with no arguments)
  25. ;    4) modified error routines to avoid warm-boot delay
  26. ;       (return to CCP directly instead)
  27. ;    
  28. ;    Permission to distribute this program in source or
  29. ;    object form without prior written aproval is granted
  30. ;    only under the following conditions.
  31. ;
  32. ;        1. No charge is imposed for the program.
  33. ;        2. Charges for incidental costs including
  34. ;           but not limited to media, postage, tele-
  35. ;           communications, and data storage do not
  36. ;           exceed those costs actually incurred.
  37. ;        3. This Notice and any copright notices in
  38. ;           the object code remain intact 
  39. ;
  40. ;            (signed)  Gary P. Novosielski
  41. ;
  42. ;--------------------------------------------------------------
  43. ;
  44. ; LRUN is intended to be used in conjunction with libraries
  45. ; created with LU.COM, a library utility based upon the
  46. ; groundwork laid by Michael Rubenstein, with some additional
  47. ; inspiration from Leor Zolman's CLIB librarian for .CRL files.
  48. ;
  49. ; The user can place the less frequently used command (.COM)
  50. ; files in a library to save space, and  still be able to run
  51. ; them when required, by typing:
  52. ;     LRUN <normal command line>.
  53. ; The name of the library can be specified, but the greatest
  54. ; utility will be achieved by placing all commands in one
  55. ; library called COMMAND.LBR, or some locally defined name,
  56. ; and always letting LRUN use that name as the default.
  57. ;
  58.  
  59. ;Syntax:
  60. ;    LRUN [-<lbrname>] <command> [<parameters>]
  61. ;
  62. ;where:
  63. ;<lbrname>    is the optional library name.  In the
  64. ;        distrubution version, this defaults to
  65. ;        COMMAND.LBR.  If the user wishes to use a
  66. ;        different name for the default, the 8-byte
  67. ;        literal at DFLTNAM below may be changed to
  68. ;        suit local requirements. The current drive
  69. ;        is searched for the .LBR file, and if not
  70. ;        found there, the A: drive is searched.
  71. ;        **Note that the leading minus sign (not a part
  72. ;        of the name) is required to indicate an
  73. ;        override library name is being entered.
  74. ;
  75. ;<command>    is the name of the .COM file in the library
  76. ;
  77. ;<line>        is the (possibly empty) set of parameters
  78. ;        which are to be passed to <command>, as in
  79. ;        normal CP/M syntax.  Notice that if the
  80. ;        library name is defaulted, the syntax is
  81. ;        simply:
  82. ;     LRUN <command line>
  83. ;        which is just the normal command line with
  84. ;        LRUN prefixed to it.
  85. ;
  86. ;--------------------------------------------------------------
  87. ;        USER MODIFIABLE EQUATES
  88. ;
  89. ;    Define a secondary search drive and user if .LBR is
  90. ;    not found after initial search of current area:
  91. ;
  92. SSDRV:    EQU    'A'    ;Valid values are 'A' through 'P'.
  93. SSUSR:    EQU    0    ;Valid values are  0  through 31.
  94. ;
  95. ;Default library may also be modified.  See label DFLTNAM.
  96. ;--------------------------------------------------------------
  97. ;
  98. QUERY    SET    -1
  99. @SYS    SET    0
  100. @KEY    SET    1
  101. @CON    SET    2
  102. @RDR    SET    3
  103. @PUN    SET    4
  104. @LST    SET    5
  105. @DIO    SET    6
  106. @RIO    SET    7
  107. @SIO    SET    8
  108. @MSG    SET    9
  109. @INP    SET    10
  110. @RDY    SET    11
  111. @VER    SET    12
  112. @LOG    SET    13
  113. @DSK    SET    14
  114. @OPN    SET    15
  115. @CLS    SET    16
  116. @DIR    SET    17
  117. @NXT    SET    18
  118. @DEL    SET    19
  119. @FRD    SET    20
  120. @FWR    SET    21
  121. @MAK    SET    22
  122. @REN    SET    23
  123. @CUR    SET    25
  124. @DMA    SET    26
  125. @CHG    SET    30
  126. @USR    SET    32
  127. @RRD    SET    33
  128. @RWR    SET    34
  129. @SIZ    SET    35
  130. @REC    SET    36
  131. @LOGV    SET    37    ;2.2 only
  132. @RWR0    SET    40    ;2.2 only
  133. ;
  134. CPMBASE EQU    0
  135. BOOT    SET    CPMBASE
  136. BDOS    SET    BOOT+5
  137. TFCB    EQU    BOOT+5CH
  138. TFCB1    EQU    TFCB
  139. TFCB2    EQU    TFCB+16
  140. TBUFF    EQU    BOOT+80H
  141. TPA    EQU    BOOT+100H
  142. CTRL    EQU    ' '-1        ;Ctrl char mask
  143. CR    SET    CTRL AND 'M'
  144. LF    SET    CTRL AND 'J'
  145. TAB    SET    CTRL AND 'I'
  146. FF    SET    CTRL AND 'L'
  147. BS    SET    CTRL AND 'H'
  148. FALSE    SET    0
  149. TRUE    SET    NOT FALSE
  150. ;
  151. CPM    MACRO    FUNC,OPERAND,CONDTN
  152.     LOCAL    PAST
  153.     IF    NOT NUL CONDTN
  154.     DB    ( J&CONDTN ) XOR 8
  155.     DW    PAST
  156.     ENDIF        ;;of not nul condtn
  157.     IF    NOT NUL OPERAND
  158.     LXI    D,OPERAND
  159.     ENDIF        ;;of not nul operand
  160.     IF    NOT NUL FUNC
  161.     MVI    C,@&FUNC
  162.     ENDIF
  163.     CALL    BDOS
  164. PAST:
  165.     ENDM
  166. ;
  167. BLKMOV    MACRO    DEST,SRCE,LEN,COND
  168.     LOCAL    PAST
  169.     JMP    PAST
  170. @BMVSBR:
  171.     MOV    A,B
  172.     ORA    C
  173.     RZ
  174.     DCX    B
  175.     MOV    A,M
  176.     INX    H
  177.     STAX    D
  178.     INX    D
  179.     JMP    @BMVSBR
  180. BLKMOV    MACRO    DST,SRC,LN,CC
  181.     LOCAL    PST
  182.     IF    NOT NUL CC
  183.     DB    ( J&CC ) XOR 8
  184.     DW    PST
  185.     ENDIF
  186.     IF    NOT NUL DST
  187.     LXI    D,DST
  188.     ENDIF
  189.     IF    NOT NUL SRC
  190.     LXI    H,SRC
  191.     ENDIF
  192.     IF    NOT NUL LN
  193.     LXI    B,LN
  194.     ENDIF
  195.     CALL    @BMVSBR
  196.     IF    NOT NUL CC
  197. PST:
  198.     ENDIF
  199.     ENDM
  200. PAST:    BLKMOV    DEST,SRCE,LEN,COND
  201.     ENDM
  202.  
  203. ;
  204. OVERLAY SET    0
  205. ; Macro Definitions
  206. ;
  207. RTAG    MACRO    LBL
  208. ??R&LBL EQU    $+2-@BASE
  209.     ENDM
  210. ;
  211. RGRND    MACRO    LBL
  212. ??R&LBL EQU    0FFFFH
  213.     ENDM
  214. ;
  215. R    MACRO    INST
  216. @RLBL    SET    @RLBL+1
  217.     RTAG    %@RLBL
  218.     INST-@BASE
  219.     ENDM
  220. ;
  221. NXTRLD    MACRO    NN
  222. @RLD    SET    ??R&NN
  223. @NXTRLD SET    @NXTRLD + 1
  224.     ENDM
  225. ;
  226. ;
  227. ; Enter here from Console Command Processor (CCP)
  228. ;
  229. CCPIN    ORG    TPA
  230.     JMP    INTRO        ;Jump around signon
  231. ;
  232. SIGNON:
  233.     DB    'LRUN Ver '    ;Signon message
  234.     DB    VERSION/10+'0'
  235.     DB    '.'
  236.     DB    VERSION MOD 10+'0'
  237.     DB    CR,LF
  238.     DB    ' Copyright (c) 1982  Gary P. Novosielski '
  239.     DB    '$',CTRL AND 'Z'
  240. ;
  241. INTRO:
  242.     LXI    H,0        ;get the CCP entry stackpointer
  243.     DAD    SP        ;(used only if HELP request
  244.     SHLD    SPSAVE        ; is encountered)
  245.     CPM    MSG,SIGNON;    ;Display signon
  246.     CALL    SETUP        ;initialize.
  247.     LHLD    BDOS+1        ;find top of memory
  248.     MOV    A,H        ;page address
  249.                 ;Form destination...
  250.     SUI    PAGES         ;...address in
  251.     MOV    D,A        ;DE pair.
  252.     MVI    E,0
  253.     PUSH    D        ;save on stack
  254. ;
  255.     BLKMOV    ,@BASE,SEGLEN    ;Move the active segment.
  256. ;
  257. ;The segment is now moved to high memory, but not
  258. ;properly relocated.  The bit table which specifies
  259. ;which addresses need to be adjusted is located
  260. ;just after the last byte of the source segment,
  261. ;so (HL) is now pointing at it.
  262.     POP    D    ;beginning of newly moved code.
  263.     LXI    B,SEGLEN;length of segment
  264.     PUSH    H    ;save pointer to reloc info
  265.     MOV    H,D    ;offset page address
  266. ;
  267. FIXLOOP:
  268. ;Scan through the newly moved code, and adjust any
  269. ;page addresses by adding (H) to them.    The word on
  270. ;top of the stack points to the next byte of the
  271. ;relocation bit table.    Each bit in the table
  272. ;corresponds to one byte in the destination code.
  273. ;A value of 1 indicates the byte is to be adjusted.
  274. ;A value of 0 indicates the byte is to be unchanged.
  275. ;
  276. ;Thus one byte of relocation information serves to
  277. ;mark 8 bytes of object code.  The bits which have
  278. ;not been used yet are saved in L until all 8
  279. ;are used.
  280. ;
  281.     MOV    A,B
  282.     ORA    C        ;test if finished
  283.     JZ    FIXDONE
  284.     DCX    B        ;count down
  285.     MOV    A,E
  286.     ANI    07H        ;on 8-byte boundry?
  287.     JNZ    NEXTBIT
  288. ;
  289. NEXTBYT:
  290. ;Get another byte of relocation bits
  291.     XTHL
  292.     MOV    A,M
  293.     INX    H
  294.     XTHL
  295.     MOV    L,A        ;save in register L
  296. ;
  297. NEXTBIT MOV    A,L        ;remaining bits from L
  298.     RAL            ;next bit to CARRY
  299.     MOV    L,A        ;save the rest
  300.     JNC    NEXTADR
  301. ;
  302. ;CARRY was = 1.  Fix this byte.
  303.     LDAX    D
  304.     ADD    H        ;(H) is the page offset
  305.     STAX    D
  306. ;
  307. NEXTADR INX    D
  308.     JMP    FIXLOOP
  309. ;
  310. FIXDONE:
  311. ;Finished.  Jump to the first address in the new
  312. ;segment in high memory.
  313. ;
  314. ;First adjust the stack.  One garbage word was
  315. ;left by fixloop.
  316.     INX    SP
  317.     INX    SP
  318. ;
  319. ;(HL) still has the page address
  320.     MOV    L,A    ;move zero to l
  321.     PCHL        ;Stack is valid
  322. SETUP:
  323. ;Any one-shot initialization code goes here.
  324. ;
  325.     LXI    H,NOLOAD
  326.     SHLD    CCPIN+1     ;Prevent reentry
  327. ;
  328. ;
  329.     CPM    VER        ;Test version of CP/M in use
  330.     CPI    20H        ;2.0 or better?
  331.     JC    BADVER        ;No, bitch and quit.
  332. ;
  333.     CPM    USR,QUERY    ;What's the current user area?
  334.     STA    ENTUSR        ;Save for later.
  335. ;
  336.     CALL    REPARS        ;Re-parse command line
  337. ;
  338.     LXI    D,MEMBER+9    ;Check member filetype
  339.     LDAX    D
  340.     CPI    ' '        ;If blank,
  341.     BLKMOV    ,COMLIT,3,Z    ; default to COM.
  342. ;
  343.     LXI    D,LBRFIL+9    ;Check library filetype
  344.     LDAX    D
  345.     CPI    ' '        ;If blank,
  346.     BLKMOV    ,LBRLIT,3,Z    ; default to LBR
  347. ;
  348.     LXI    D,LBRFIL+1    ;Check name
  349.     LDAX    D
  350.     CPI    ' '        ;If blank,
  351.     BLKMOV    ,DFLTNAM,8,Z    ; use default name.
  352. ;
  353. ;
  354. DIROPN: CPM    OPN,LBRFIL    ;Open for directory read.
  355.     INR    A        ;Was it found?
  356.     JNZ    DIROK        ;yes, ok
  357.     LXI    H,LBRFIL    ;No, test drive spec
  358.     MOV    A,M        ; to see if it's
  359.     ORA    A        ; explicit
  360.     JNZ    NODIR        ;It is explicit.  Out of luck
  361.     MVI    M,SSDRV-'@'    ;Look on secondary drive,
  362.     CPM    USR,SSUSR    ; in secondary user.
  363.     JMP    DIROPN        ; before giving up.
  364. ;
  365. DIROK:
  366.     CPM    DMA,TBUFF
  367. FINDMBR:
  368.     CPM    FRD,LBRFIL    ;Read the directory
  369.     ORA    A
  370.     JNZ    FISHY        ;Empty file, Give up.
  371.     LXI    H,TBUFF
  372.     MOV    A,M
  373.     ORA    A
  374.     JNZ    FISHY        ;Directory not active??
  375.     MVI    B,8+3        ;Check for blanks
  376.     MVI    A,' '
  377. VALIDLOOP:
  378.     INX    H
  379.     CMP    M
  380.     JNZ    FISHY
  381.     DCR    B
  382.     JNZ    VALIDLOOP
  383. ;
  384.     LHLD    TBUFF+1+8+3    ;Index must be 0000
  385.     MOV    A,H
  386.     ORA    L
  387.     JNZ    FISHY
  388. ;
  389.     LHLD    TBUFF+1+8+3+2    ;Get directory size
  390.     DCX    H        ;We already read one.
  391.     PUSH    H        ;Save on stack
  392.     JMP    FINDMBRN    ;Jump into loop
  393. FINDMBRL:
  394.     POP    H        ;Read sector count from TOS
  395.     MOV    A,H
  396.     ORA    L        ;0 ?
  397.     JZ    NOMEMB        ;Member not found in library
  398.     DCX    H        ;Count down
  399.     PUSH    H        ;and put it back.
  400.     CPM    FRD,LBRFIL    ;Get next directory sector
  401.     ORA    A
  402.     JNZ    FISHY
  403.  
  404.  
  405. FINDMBRN:
  406.     LXI    H,TBUFF       ;Point to buffer.
  407.     MVI    C,128/32    ;Number of directory entries
  408. ;
  409. FINDMBR1:
  410.     CALL    COMPARE     ;Check if found yet.
  411.     JZ    GETLOC        ;Found member in .DIR
  412.     DCR    C
  413.     JZ    FINDMBRL
  414. ;
  415.     LXI    D,32        ;No match, point to next one.
  416.     DAD    D
  417.     JMP    FINDMBR1
  418. ;
  419. GETLOC:     ;The name was found now get index and length
  420.     POP    B    ;Clear stack garbage
  421.     XCHG        ;Pointer to sector address.
  422.     MOV    E,M    ;Get First
  423.     INX    H
  424.     MOV    D,M
  425.     XCHG
  426.     SHLD    INDEX    ;Save it
  427.     XCHG
  428.     INX    H    ;Get Size to DE
  429.     MOV    E,M
  430.     INX    H
  431.     MOV    D,M
  432.     XCHG        ; Size to HL
  433.     SHLD    LENX
  434.     CALL    PACKUP    ;Repack command line arguments
  435.     CPM    CON,CR    ;do <cr> only (look like CCP)
  436.     RET
  437. ;        End of setup.
  438. ;
  439. ;    Utility subroutines
  440. NEGDE:            ;DE = -DE
  441.     MOV    A,D
  442.     CMA
  443.     MOV    D,A
  444. ;
  445.     MOV    A,E
  446.     CMA
  447.     MOV    E,A
  448.     INX    D
  449.     RET
  450. ;
  451. ;    REPARSE re-parses the fcbs from the command line,
  452. ;    to allow the "-" character to prefix the library name
  453. ;
  454. REPARS: LXI    D,MEMBER    ;first reinitialize both fcbs
  455.     CALL    NITF
  456.     LXI    D,LBRFIL
  457.     CALL    NITF
  458.     LXI    H,TBUFF     ;store a null at the end of
  459.     MOV    E,M        ; the command line (this is
  460.     MVI    D,0        ; done by CP/M usually, except
  461.     XCHG            ; in the case of a full com-
  462.     DAD    D        ; mand line
  463.     INX    H
  464.     MVI    M,0
  465.     XCHG            ;tbuff pointer back in hl
  466. SCANBK: INX    H        ;bump to next char position
  467.     MOV    A,M        ;fetch next char
  468.     ORA    A        ;reached a null? (no arguments)
  469.     JZ    HELP        ;interpret as a call for help
  470.     CPI    ' '        ;not null, skip blanks
  471.     JZ    SCANBK
  472.     CPI    '-'        ;library name specifier?
  473.     JNZ    NOTLBR        ;skip if not
  474.     INX    H        ;it is, skip over flag character
  475.     LXI    D,LBRFIL    ;parse library name into FCB
  476.     CALL    GETFN
  477. NOTLBR: LXI    D,MEMBER    ;now parse the command name
  478.     CALL    GETFN
  479.     LXI    D,HOLD+1    ;pnt to temp storage for rest of cmd line
  480.     MVI    B,-1        ;init a counter
  481. CLSAVE: INR    B        ;bump up counter
  482.     MOV    A,M        ;fetch a char
  483.     STAX    D        ;move it to hold area
  484.     INX    H        ;bump pointers
  485.     INX    D
  486.     ORA    A        ;test whether char was a terminator
  487.     JNZ    CLSAVE        ;continue moving line if not
  488.     MOV    A,B        ;it was, get count
  489.     STA    HOLD        ;save it in hold area
  490.     RET
  491. ;
  492. ;    PACKUP retrieves the command line stored at
  493. ;    HOLD and moves it back to tbuff, then reparses
  494. ;    the default file control blocks so the command
  495. ;    will never know it was run from a library
  496. ;
  497. PACKUP: LXI    H,HOLD        ;point to length byte of HOLD
  498.     MOV    C,M        ;get length in BC
  499.     MVI    B,0
  500.     INX    B        ;bump up to because length byte doesn't
  501.     INX    B        ;  include itself or null terminator
  502.     BLKMOV    TBUFF        ;moving everybody to Tbuff
  503.     LXI    H,TBUFF+1    ;point to the command tail
  504.     LXI    D,TFCB1     ;first parse out tfcb1
  505.     CALL    GETFN
  506.     LXI    D,TFCB2     ;then tfcb2
  507.     CALL    GETFN
  508.     RET
  509. ;
  510. ;    Here when HELP is requested (indicated
  511. ;    by LRUN with no arguments)
  512. ;
  513. HELP:    CPM    MSG,HLPMSG    ;print the HELP message
  514. EXIT:    LHLD    SPSAVE        ;find CCP re-entry adrs
  515.     SPHL            ;fix & return
  516.     RET
  517. ;
  518. ;    the HELP message
  519. ;
  520. HLPMSG: DB    CR,LF,'Correct syntax is:'
  521.     DB    CR,LF
  522.     DB    LF,TAB,'LRUN [-<lbrname>] <command line>'
  523.     DB    CR,LF
  524.     DB    LF,'Where <lbrname> is the optional library name'
  525.     DB    CR,LF,'(Note the preceding "-".  ) If omitted,'
  526.     DB    CR,LF,'the default command library is used.'
  527.     DB    LF
  528.     DB    CR,LF,'<command line> is the name and parameters'
  529.     DB    CR,LF,'of the command being run from the library,'
  530.     DB    CR,LF,'just as if a separate .COM file were being run.'
  531.     DB    CR,LF,'$'
  532. ;
  533. ;
  534. COMPARE:        ;Test status, name and type of
  535.     PUSH    H        ;a directory entry.
  536.     MVI    B,1+8+3
  537.     XCHG            ;with the one we're
  538.     LXI    H,MEMBER    ;looking for.
  539. COMPAR1:
  540.     LDAX    D
  541.     CMP    M
  542.     JNZ    COMPEXIT
  543.     INX    D
  544.     INX    H
  545.     DCR    B
  546.     JNZ    COMPAR1
  547. COMPEXIT:            ;Return with DE pointing to
  548.     POP    H        ;last match + 1, and HL still
  549.     RET            ;pointing to beginning.
  550. ;
  551. ;
  552. ;    File name parsing subroutines
  553. ;
  554. ; getfn gets a file name from text pointed to by reg hl into
  555. ; an fcb pointed to by reg de.    leading delimeters are 
  556. ; ignored.
  557. ; entry hl    first character to be scanned
  558. ;    de    first byte of fcb
  559. ; exit    hl    character following file name
  560. ;
  561. ;
  562. ;
  563. GETFN:    CALL    NITF    ;init 1st half of fcb
  564.     CALL    GSTART    ;scan to first character of name
  565.     RZ        ;end of line was found - leave fcb blank
  566.     CALL    GETDRV    ;get drive spec. if present
  567.     CALL    GETPS    ;get primary and secondary name
  568.     RET
  569.  
  570.  
  571. ;
  572. ; nitf fills the fcb with dflt info - 0 in drive field
  573. ; all-blank in name field, and 0 in ex,s1,s2 and rc flds
  574. ;
  575. NITF:    PUSH    D    ;save fcb loc
  576.     XCHG        ;move it to hl
  577.     MVI    M,0    ;zap dr field
  578.     INX    H    ;bump to name field
  579.     MVI    B,11    ;zap all of name fld
  580. NITLP1: MVI    M,' '
  581.     INX    H
  582.     DCR    B
  583.     JNZ    NITLP1
  584.     MVI    B,4    ;zero others
  585. NITLP2: MVI    M,0
  586.     INX    H
  587.     DCR    B
  588.     JNZ    NITLP2
  589.     XCHG        ;restore hl
  590.     POP    D    ;restore fcb pointer
  591.     RET
  592. ;
  593. ; gstart advances the text pointer (reg hl) to the first
  594. ; non delimiter character (i.e. ignores blanks).  returns a
  595. ; flag if end of line (00h or ';') is found while scaning.
  596. ; exit    hl    pointing to first non delimiter
  597. ;    a    clobbered
  598. ;    zero    set if end of line was found
  599. ;
  600. GSTART: CALL    GETCH    ;see if pointing to delim?
  601.     RNZ        ;nope - return
  602.     CPI    ';'    ;end of line?
  603.     RZ        ;yup - return w/flag
  604.     ORA    A
  605.     RZ        ;yup - return w/flag
  606.     INX    H    ;nope - move over it
  607.     JMP    GSTART    ;and try next char
  608. ;
  609. ; getdrv checks for the presence of a drive spec at the text
  610. ; pointer, and if present formats it into the fcb and
  611. ; advances the text pointer over it.
  612. ; entry hl    text pointer
  613. ;    de    pointer to first byte of fcb
  614. ; exit    hl    possibly updated text pointer
  615. ;    de    pointer to second (primary name) byte of fcb
  616. ;
  617. GETDRV: INX    D    ;point to name if spec not found
  618.     INX    H    ;look ahead to see if ':' present
  619.     MOV    A,M
  620.     DCX    H    ;put back in case not present
  621.     CPI    ':'    ;is a drive spec present?
  622.     RNZ        ;nope - return
  623.     MOV    A,M    ;yup - get the ascii drive name
  624.     SUI    'A'-1    ;convert to fcb drive spec
  625.     DCX    D    ;point back to drive spec byte
  626.     STAX    D    ;store spec into fcb
  627.     INX    D    ;point back to name
  628.     INX    H    ;skip over drive name
  629.     INX    H    ;and over ':'
  630.     RET
  631. ;
  632. ; getps gets the primary and secondary names into the fcb.
  633. ; entry hl    text pointer
  634. ; exit    hl    character following secondary name (if present)
  635. ;
  636. GETPS:    MVI    C,8    ;max length of primary name
  637.     CALL    GETNAM    ;pack primary name into fcb
  638.     MOV    A,M    ;see if terminated by a period
  639.     CPI    '.'
  640.     RNZ        ;nope - secondary name not given
  641.             ;return default (blanks)
  642.     INX    H    ;yup - move text pointer over period
  643. FTPOINT:MOV    A,C    ;yup - update fcb pointer to secondary
  644.     ORA    A
  645.     JZ    GETFT
  646.     INX    D
  647.     DCR    C
  648.     JMP    FTPOINT
  649. GETFT:    MVI    C,3    ;max length of secondary name
  650.     CALL    GETNAM    ;pack secondary name into fcb
  651.     RET
  652. ;
  653. ; getnam copies a name from the text pointer into the fcb for
  654. ; a given maximum length or until a delimiter is found, which
  655. ; ever occurs first.  if more than the maximum number of
  656. ; characters is present, characters are ignored until a
  657. ; a delimiter is found.
  658. ; entry hl    first character of name to be scaned
  659. ;    de    pointer into fcb name field
  660. ;    c    maximum length
  661. ; exit    hl    pointing to terminating delimiter
  662. ;    de    next empty byte in fcb name field
  663. ;    c    max length - number of characters transfered
  664. ;
  665. GETNAM: CALL    GETCH    ;are we pointing to a delimiter yet?
  666.     RZ        ;if so, name is transfered
  667.     INX    H    ;if not, move over character
  668.     CPI    '*'    ;ambigious file reference?
  669.     JZ    AMBIG    ;if so, fill the rest of field with '?'
  670.     STAX    D    ;if not, just copy into name field
  671.     INX    D    ;increment name field pointer
  672.     DCR    C    ;if name field full?
  673.     JNZ    GETNAM    ;nope - keep filling
  674.     JMP    GETDEL    ;yup - ignore until delimiter
  675. AMBIG:    MVI    A,'?'    ;fill character for wild card match
  676. QFILL:    STAX    D    ;fill until field is full
  677.     INX    D
  678.     DCR    C
  679.     JNZ    QFILL    ;fall thru to ingore rest of name
  680. GETDEL: CALL    GETCH    ;pointing to a delimiter?
  681.     RZ        ;yup - all done
  682.     INX    H    ;nope - ignore another one
  683.     JMP    GETDEL
  684. ;
  685. ; getch gets the character pointed to by the text pointer
  686. ; and sets the zero flag if it is a delimiter.
  687. ; entry hl    text pointer
  688. ; exit    hl    preserved
  689. ;    a    character at text pointer
  690. ;    z    set if a delimiter
  691. ;
  692. GETCH:
  693.     MOV    A,M    ;get the character
  694.     CPI    '.'
  695.     RZ
  696.     CPI    ','
  697.     RZ      
  698.     CPI    ';'
  699.     RZ
  700.     CPI    ' '
  701.     RZ
  702.     CPI    ':'
  703.     RZ
  704.     CPI    '='
  705.     RZ
  706.     CPI    '<'
  707.     RZ
  708.     CPI    '>'
  709.     RZ
  710.     ORA    A    ;Set zero flag on end of text
  711.     RET
  712. ;
  713. ;
  714. ; Error routines:
  715. ;
  716. BADVER: 
  717.     CALL    ABEND
  718.     DB    'Can''t run under CP/M 1.4'
  719.     DB    '$'
  720. NODIR:
  721.     CALL    ABEND
  722.     DB    'Library not found'
  723.     DB    '$'
  724. FISHY:
  725.     CALL    ABEND
  726.     DB    'Name after "-" isn''t a library'
  727.     DB    '$'
  728. NOMEMB:
  729.     CALL    ABEND
  730.     DB    'Command not in directory'
  731.     DB    '$'
  732. NOLOAD:
  733.     CALL    ABEND
  734.     DB    'No program in memory'
  735.     DB    '$'
  736. NOFIT:
  737.     CALL    ABEND
  738.     DB    'Program too large to load'
  739.     DB    '$'
  740. ;
  741. COMLIT: DB    'COM'
  742. ;
  743. DFLTNAM:DB    'COMMAND ' ; <---change this if you like---
  744. LBRLIT: DB    'LBR'
  745. ;
  746. ABEND:
  747.     LDA    ENTUSR
  748.     MOV    E,A
  749.     CPM    USR        ;Reset to entry user.
  750.     CPM    MSG,NEWLIN
  751.     POP    D
  752.     CPM    MSG
  753.     CPM    DEL,SUBFILE
  754.     CPM    MSG,ABTMSG
  755.     JMP    EXIT
  756. ABTMSG: DB    '...ABORTED.$'
  757. NEWLIN:    DB    CR,LF,'$'
  758. SPSAVE: DS    2        ;stack pointer save
  759. ;
  760.     PAGE
  761. ;Adjust location counter to next 256-byte boundry
  762. @BASE    ORG    ($ + 0FFH) AND 0FF00H
  763. @RLBL    SET    0
  764. ;
  765. ; The segment to be relocated goes here.
  766. ; Any position dependent (3-byte) instructions
  767. ; are handled by the "R" macro.
  768. ;*************************************************
  769.  R    <LHLD    LENX>    ;Get length of .COM member to load.
  770.     MVI    A,TPA/128
  771.     ADD    L    ;Calculate highest address
  772.     MOV    L,A    ;To see if it will fit in
  773.     ADC    H    ;available memory
  774.     SUB    L
  775.     MOV    H,A
  776.     REPT    7
  777.     DAD    H
  778.     ENDM
  779.     XCHG    
  780.     CALL    NEGDE    ;IT'S STILL IN LOW MEMORY
  781.  R    <LXI    H,PROTECT>
  782.     DAD    D
  783.     JNC    NOFIT    ;Haven't overwritten it yet.
  784. LBROPN:
  785. ; The library file is still open.  The open FCB has been
  786. ; moved up here into high memory with the loader code.
  787. ;
  788.  R    <LHLD    INDEX>        ;Set up for random reads
  789.  R    <SHLD    RANDOM>
  790.     XRA    A
  791.  R    <STA    RANDOM+2>
  792. ;
  793.     LXI    H,TPA
  794.  R    <SHLD    LOADDR>
  795.  
  796. ; This high memory address and above, including CCP, must be
  797. ; protected from being overlaid by loaded program
  798. PROTECT:
  799. ;
  800. LOADLOOP:            ;Load that sucker.
  801.  R    <LHLD    LENX>        ;See if done yet.
  802.     MOV    A,L
  803.     ORA    H
  804.  R    <JZ    LOADED>
  805.     DCX    H
  806.  R    <SHLD    LENX>
  807. ;
  808.  R    <LHLD    LOADDR>     ;Increment for next time
  809.     MOV    D,H
  810.     MOV    E,L
  811.     LXI    B,80H
  812.     DAD    B
  813.  R    <SHLD    LOADDR>
  814.     CPM    DMA        ;but use old value (DE)
  815. ;
  816.  R    <LXI    D,LBRFIL>
  817.     CPM    RRD        ;Read the sector
  818.     ORA    A        ;Ok?
  819.  R    <JNZ    ERR>        ;No, bail out.
  820. ;
  821.  R    <LHLD    RANDOM>     ;Increment random record field
  822.     INX    H
  823.  R    <SHLD    RANDOM>
  824. ;
  825.  R    <JMP    LOADLOOP>    ;Until done.
  826. ;
  827. ERR:
  828.     MVI    A,( JMP )    ;Prevent execution of bad code
  829.     STA    TPA
  830.  R    <LXI    H,ERRX>
  831.     SHLD    TPA+1
  832.  R    <JMP    LOADED>        ;Execute dummy program instead
  833. ERRX:
  834.      LXI    H,BOOT        ;One more time, but this time
  835.     SHLD    TPA+1        ;Jump to BOOT
  836. ;
  837.  R    <LXI    D,LDMSG>
  838.     CPM    MSG
  839.  R    <LXI    D,SUBFILE>    ;Abort SUBMIT if in progress
  840.     CPM    DEL
  841. LOADED:
  842.  R    <LDA    ENTUSR>
  843.     MOV    E,A
  844.     CPM    USR        ;Restore USR number from setup.
  845.     CPM    DMA,TBUFF    ;Restore DMA adrs for user pgm
  846.     CPM    CON,LF        ;Turn up a new line on console
  847.     JMP    TPA
  848. ;
  849. LDMSG:
  850.     DB    'BAD LOAD$'
  851. INDEX    DW    0
  852. LENX    DW    0
  853. ENTUSR    DB    0
  854. SUBFILE:
  855.     DB    1,'$$$     SUB',0,0,0,0
  856.     ;If used, this FCB will clobber the following one.
  857.     ;but it's only used on a fatal error, anyway.
  858. LBRFIL:
  859.     DS    32        ;Name placed here at setup
  860.     DB    0        ;Normal FCB plus...
  861. OVERLAY SET    $        ;(Nothing past here but DS's)
  862. RANDOM    DS    3        ;...Random access bytes
  863. MAXMEM    DS    2
  864. LOADDR    DS    2
  865. ;*************************************************
  866. ;End of segment to be relocated.
  867.     IF    OVERLAY EQ 0
  868. OVERLAY SET    $
  869.     ENDIF
  870. ;
  871. PAGES    EQU    ($-@BASE+0FFH)/256+8
  872. ;
  873. SEGLEN    EQU    OVERLAY-@BASE
  874.     ORG    @BASE+SEGLEN
  875.     PAGE
  876. ;    Build the relocation information into a
  877. ; bit table immediately following.
  878. ;
  879. @X    SET    0
  880. @BITCNT SET    0
  881. @RLD    SET    ??R1
  882. @NXTRLD SET    2
  883.     RGRND    %@RLBL+1    ;define one more label
  884. ;
  885.     REPT    SEGLEN+8
  886.     IF    @BITCNT>@RLD
  887.     NXTRLD    %@NXTRLD    ;next value
  888.     ENDIF
  889.     IF    @BITCNT=@RLD
  890. @X    SET    @X OR 1     ;mark a bit
  891.     ENDIF
  892. @BITCNT SET    @BITCNT + 1
  893.     IF    @BITCNT MOD 8 = 0
  894.     DB    @X
  895. @X    SET    0    ;clear hold variable for more
  896.     ELSE
  897. @X    SET    @X SHL 1    ;not 8 yet. move over.
  898.     ENDIF
  899.     ENDM
  900. ;
  901.     DB    0
  902. HOLD:    DB    0,0        ;0 length, null terminator
  903.     DS    128-2        ;rest of HOLD area
  904. MEMBER:
  905.     DS    16
  906. ;
  907.     END    CCPIN
  908.