home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / ZCPR33 / A-R / LRUNZ302.LBR / LRUNZ302.AZM / LRUNZ302.ASM
Assembly Source File  |  2000-06-30  |  26KB  |  1,149 lines

  1. TITLE    'LRUNZ  Library Run for ZCPR3 -- a utility for .LBR files'
  2. VERSION EQU    3$0    ;82-08-06 Initial source release
  3.     PAGE    60
  4. ;
  5. ; Requires MAC for assembly.  Due to the complexity of
  6. ; the relocation macros, this program may take a while
  7. ; to assemble.    Be prepared for periods of no disk activity
  8. ; on both passes before pressing panic button.    G.P.N.
  9. ;
  10.  
  11. ;--------------------------NOTICE------------------------------
  12. ;
  13. ;   (c) Copyright 1982    Gary P. Novosielski
  14. ;    All rights reserved.
  15. ;    
  16. ;   The following features courtesy of Ron Fowler:
  17. ;    1) command line reparsing and repacking (this allows
  18. ;    the former load-only program to become a load & run
  19. ;    utility).
  20. ;    2) code necessary to actually execute the loaded file
  21. ;    3) the HELP facility (LRUN with no arguments)
  22. ;    4) modified error routines to avoid warm-boot delay
  23. ;       (return to CCP directly instead)
  24. ;    
  25. ;    Permission to distribute this program in source or
  26. ;    object form without prior written aproval is granted
  27. ;    only under the following conditions.
  28. ;
  29. ;        1. No charge is imposed for the program.
  30. ;        2. Charges for incidental costs including
  31. ;           but not limited to media, postage, tele-
  32. ;           communications, and data storage do not
  33. ;           exceed those costs actually incurred.
  34. ;        3. This Notice and any copright notices in
  35. ;           the object code remain intact 
  36. ;
  37. ;            (signed)  Gary P. Novosielski
  38. ;
  39. ;--------------------------------------------------------------
  40. ;
  41. ; LRUN is intended to be used in conjunction with libraries
  42. ; created with LU.COM, a library utility based upon the
  43. ; groundwork laid by Michael Rubenstien, with some additional
  44. ; inspiration from Leor Zolman's CLIB librarian for .CRL files.
  45. ;
  46. ; The user can place the less frequently used command (.COM)
  47. ; files in a library to save space, and  still be able to run
  48. ; them when required, by typing:
  49. ;     LRUN <normal command line>.
  50. ; The name of the library can be specified, but the greatest
  51. ; utility will be achieved by placing all commands in one
  52. ; library called COMMAND.LBR, or some locally defined name,
  53. ; and always letting LRUN use that name as the default.
  54. ;
  55.  
  56. ;Syntax:
  57. ;    LRUN [-<lbrname>] <command> [<parameters>]
  58. ;
  59. ;where:
  60. ;<lbrname>    is the optional library name.  In the
  61. ;        distrubution version, this defaults to
  62. ;        COMMAND.LBR.  If the user wishes to use a
  63. ;        different name for the default, the 8-byte
  64. ;        literal at DFLTNAM below may be changed to
  65. ;        suit local requirements. The current drive
  66. ;        is searched for the .LBR file, and if not
  67. ;        found there, the A: drive is searched.
  68. ;        **Note that the leading minus sign (not a part
  69. ;        of the name) is required to indicate an
  70. ;        override library name is being entered.
  71. ;
  72. ;<command>    is the name of the .COM file in the library
  73. ;
  74. ;<line>        is the (possibly empty) set of parameters
  75. ;        which are to be passed to <command>, as in
  76. ;        normal CP/M syntax.  Notice that if the
  77. ;        library name is defaulted, the syntax is
  78. ;        simply:
  79. ;     LRUN <command line>
  80. ;        which is just the normal command line with
  81. ;        LRUN prefixed to it.
  82. ;
  83. ;Wheel Mod    If the 'CMDRUN' facility of ZCPR3 is enabled
  84. ;        then it is very handy to take all of your less
  85. ;        often used command files and place them in a
  86. ;        'COMMAND.LBR' and rename LRUNZ to CMDRUN.
  87. ;        Then whenever a command is not found by the
  88. ;        CCP if will run 'CMDRUN' (actually LRUNZ3) which
  89. ;        will look in the 'COMMAND.LBR' and run the command.
  90. ;        Furthermore if you enable the 'ROOTONLY' ZCPR3 option
  91. ;        then the CCP will automatically look at A:15 only
  92. ;        for 'CMDRUN' which will then look for 'COMMAND.LBR'
  93. ;        and run the command. This change to enable the 
  94. ;        Wheel Byte is almost an exact copy of PIP-ZCPR by
  95. ;         John D'Amico.
  96. ;
  97. ;                    Richard Cole
  98. ;
  99. ;
  100. ;LRUNZ301    Modified to use ZCPR3 style Environment Pointers.
  101. ;Environment    It will now search the ZCPR3 Path, and check the
  102. ;Mod        Wheel bytes using the Environment Pointer to locate
  103. ;        the neccesary addresses.  The installation is the
  104. ;        same as any other ZCPR3 utility.  The program is
  105. ;        configured for an external Environment, but can
  106. ;        be easily modified for an internal Environment.
  107. ;
  108. ;                    David Miles
  109. ;                    January 18, 1985
  110. ;
  111. ;LRUNZ302    Fixed a bug where LRUN would search odd drives
  112. ;Bug Fix    when it encountered a '$' in the path.
  113. ;
  114. ;                    David Miles
  115. ;                    February 3, 1985
  116. ;                      
  117. ;
  118. ; MACROS TO PROVIDE Z80 EXTENSIONS
  119. ;   MACROS INCLUDE:
  120. ;
  121. $-MACRO         ;FIRST TURN OFF THE EXPANSIONS
  122. ;
  123. ;    JR    - JUMP RELATIVE
  124. ;    JRC    - JUMP RELATIVE IF CARRY
  125. ;    JRNC    - JUMP RELATIVE IF NO CARRY
  126. ;    JRZ    - JUMP RELATIVE IF ZERO
  127. ;    JRNZ    - JUMP RELATIVE IF NO ZERO
  128. ;    DJNZ    - DECREMENT B AND JUMP RELATIVE IF NO ZERO
  129. ;    LDIR    - MOV @HL TO @DE FOR COUNT IN BC
  130. ;    LXXD    - LOAD DOUBLE REG DIRECT
  131. ;    SXXD    - STORE DOUBLE REG DIRECT
  132. ;
  133. ;
  134. ;
  135. ;    @GENDD MACRO USED FOR CHECKING AND GENERATING
  136. ;    8-BIT JUMP RELATIVE DISPLACEMENTS
  137. ;
  138. @GENDD    MACRO    ?DD    ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS
  139.     IF (?DD GT 7FH) AND (?DD LT 0FF80H)
  140.     DB    100H    ;Displacement Range Error on Jump Relative
  141.     ELSE
  142.     DB    ?DD
  143.     ENDIF
  144.     ENDM
  145. ;
  146. ;
  147. ; Z80 MACRO EXTENSIONS
  148. ;
  149. JR    MACRO    ?N    ;;JUMP RELATIVE
  150.     DB    18H
  151.     @GENDD    ?N-$-1
  152.     ENDM
  153. ;
  154. JRC    MACRO    ?N    ;;JUMP RELATIVE ON CARRY
  155.     DB    38H
  156.     @GENDD    ?N-$-1
  157.     ENDM
  158. ;
  159. JRNC    MACRO    ?N    ;;JUMP RELATIVE ON NO CARRY
  160.     DB    30H
  161.     @GENDD    ?N-$-1
  162.     ENDM
  163. ;
  164. JRZ    MACRO    ?N    ;;JUMP RELATIVE ON ZERO
  165.     DB    28H
  166.     @GENDD    ?N-$-1
  167.     ENDM
  168. ;
  169. JRNZ    MACRO    ?N    ;;JUMP RELATIVE ON NO ZERO
  170.     DB    20H
  171.     @GENDD    ?N-$-1
  172.     ENDM
  173. ;
  174. DJNZ    MACRO    ?N    ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
  175.     DB    10H
  176.     @GENDD    ?N-$-1
  177.     ENDM
  178. ;
  179. LDIR    MACRO        ;;LDIR
  180.     DB    0EDH,0B0H
  181.     ENDM
  182. ;
  183. LDED    MACRO    ?N    ;;LOAD DE DIRECT
  184.     DB    0EDH,05BH
  185.     DW    ?N
  186.     ENDM
  187. ;
  188. LBCD    MACRO    ?N    ;;LOAD BC DIRECT
  189.     DB    0EDH,4BH
  190.     DW    ?N
  191.     ENDM
  192. ;
  193. SDED    MACRO    ?N    ;;STORE DE DIRECT
  194.     DB    0EDH,53H
  195.     DW    ?N
  196.     ENDM
  197. ;
  198. SBCD    MACRO    ?N    ;;STORE BC DIRECT
  199.     DB    0EDH,43H
  200.     DW    ?N
  201.     ENDM
  202. ;
  203. ; END OF Z80 MACRO EXTENSIONS
  204. ;
  205.  
  206. @SYS    SET    0
  207. @KEY    SET    1
  208. @CON    SET    2
  209. @RDR    SET    3
  210. @PUN    SET    4
  211. @LST    SET    5
  212. @DIO    SET    6
  213. @RIO    SET    7
  214. @SIO    SET    8
  215. @MSG    SET    9
  216. @INP    SET    10
  217. @RDY    SET    11
  218. @VER    SET    12
  219. @LOG    SET    13
  220. @DSK    SET    14
  221. @OPN    SET    15
  222. @CLS    SET    16
  223. @DIR    SET    17
  224. @NXT    SET    18
  225. @DEL    SET    19
  226. @FRD    SET    20
  227. @FWR    SET    21
  228. @MAK    SET    22
  229. @REN    SET    23
  230. @CUR    SET    25
  231. @DMA    SET    26
  232. @CHG    SET    30
  233. @USR    SET    32
  234. @RRD    SET    33
  235. @RWR    SET    34
  236. @SIZ    SET    35
  237. @REC    SET    36
  238. @LOGV    SET    37    ;2.2 only
  239. @RWR0    SET    40    ;2.2 only
  240. ;
  241. CPMBASE EQU    0
  242. BOOT    SET    CPMBASE
  243. BDOS    SET    BOOT+5
  244. TFCB    EQU    BOOT+5CH
  245. TFCB1    EQU    TFCB
  246. TFCB2    EQU    TFCB+16
  247. TBUFF    EQU    BOOT+80H
  248. TPA    EQU    BOOT+100H
  249. CTRL    EQU    ' '-1        ;Ctrl char mask
  250. CR    SET    CTRL AND 'M'
  251. LF    SET    CTRL AND 'J'
  252. TAB    SET    CTRL AND 'I'
  253. FF    SET    CTRL AND 'L'
  254. BS    SET    CTRL AND 'H'
  255. FALSE    SET    0
  256. TRUE    SET    NOT FALSE
  257. ;
  258. CPM    MACRO    FUNC,OPERAND,CONDTN
  259.     LOCAL    PAST
  260.     IF    NOT NUL CONDTN
  261.     DB    ( J&CONDTN ) XOR 8
  262.     DW    PAST
  263.     ENDIF        ;;of not nul condtn
  264.     IF    NOT NUL OPERAND
  265.     LXI    D,OPERAND
  266.     ENDIF        ;;of not nul operand
  267.     IF    NOT NUL FUNC
  268.     MVI    C,@&FUNC
  269.     ENDIF
  270.     CALL    BDOS
  271. PAST:
  272.     ENDM
  273. ;
  274. BLKMOV    MACRO    DEST,SRCE,LEN,COND
  275.     LOCAL    PAST
  276.     JMP    PAST
  277. @BMVSBR:
  278.     MOV    A,B
  279.     ORA    C
  280.     RZ
  281.     DCX    B
  282.     MOV    A,M
  283.     INX    H
  284.     STAX    D
  285.     INX    D
  286.     JMP    @BMVSBR
  287. BLKMOV    MACRO    DST,SRC,LN,CC
  288.     LOCAL    PST
  289.     IF    NOT NUL CC
  290.     DB    ( J&CC ) XOR 8
  291.     DW    PST
  292.     ENDIF
  293.     IF    NOT NUL DST
  294.     LXI    D,DST
  295.     ENDIF
  296.     IF    NOT NUL SRC
  297.     LXI    H,SRC
  298.     ENDIF
  299.     IF    NOT NUL LN
  300.     LXI    B,LN
  301.     ENDIF
  302.     CALL    @BMVSBR
  303.     IF    NOT NUL CC
  304. PST:
  305.     ENDIF
  306.     ENDM
  307. PAST:    BLKMOV    DEST,SRCE,LEN,COND
  308.     ENDM
  309.  
  310. ;
  311. OVERLAY SET    0
  312. ; Macro Definitions
  313. ;
  314. RTAG    MACRO    LBL
  315. ??R&LBL EQU    $+2-@BASE
  316.     ENDM
  317. ;
  318. RGRND    MACRO    LBL
  319. ??R&LBL EQU    0FFFFH
  320.     ENDM
  321. ;
  322. R    MACRO    INST
  323. @RLBL    SET    @RLBL+1
  324.     RTAG    %@RLBL
  325.     INST-@BASE
  326.     ENDM
  327. ;
  328. NXTRLD    MACRO    NN
  329. @RLD    SET    ??R&NN
  330. @NXTRLD SET    @NXTRLD + 1
  331.     ENDM
  332. ;
  333. ;
  334. ; Enter here from Console Command Processor (CCP)
  335. ;
  336.     ORG    TPA
  337. CCPIN:
  338. ;
  339. ;  Branch to Start of Program
  340. ;
  341.     jmp    start
  342.     DB    'Z3ENV'        ; indicate ZCPR3 utility
  343.     DB    01        ; indicate external environment
  344. ENVPTR:    DW    0000H        ; pointer to environment
  345.  
  346. DFLTNAM:
  347.     DB    'COMMAND '     ; <---change this if you like---
  348. LBRLIT:
  349.     DB    'LBR'
  350. ;
  351. SIGNON:
  352.     DB    'LRUNZ3  Version '    ;Signon message
  353.     DB    VERSION/10+'0'
  354.     DB    '.'
  355.     DB    VERSION MOD 10+'0'
  356.     DB    CR,LF
  357.     DB    '$',CTRL AND 'Z'
  358.     DB    ' Copyright (c) 1982  Gary P. Novosielski '
  359.     DB    CR,LF
  360.     DB    ' Modified for Use Under ZCPR3 by David Miles'
  361.     DB    '$',CTRL AND 'Z'
  362. ;
  363. ;
  364. ;  START OF PROGRAM
  365. ;
  366. START: 
  367.     LHLD    ENVPTR        ;get pointer to environment
  368.     MOV    A,L        ;make sure pointer is installed
  369.     ORA    H
  370.     JRZ    NOTINS        ;warn user LRUNZ3 is not installed
  371.     LXI    D,29H        ;offset to wheel pointer byte
  372.     DAD    D        ;make address of Wheel vector
  373.     MOV    A,M        ;get high address
  374.     INX    H        ;point to low order address
  375.     MOV    H,M        ;get it
  376.     CMP    H        ;verify Wheel is implemented
  377.     JRZ    START1        ;skip Wheel check if not implemented
  378.     MOV    L,A        ;HL now contains pointer to Wheel
  379.     MOV    A,M        ;get the Wheel byte
  380.     ORA    A        ;set flags
  381.     JRNZ    START1        ;jump to lrunz if wheel set
  382.     LXI    D,NOWHL        ;pointer to abort message
  383. MSGOUT:
  384.     MVI    C,09H        ;BDOS conout command
  385.     JMP    05H        ;do it
  386. NOWHL:    
  387.     DB    'Wheel Byte Not Set ==> Aborting $'
  388. NOTINS:
  389.     LXI    D,NOTINM    ;point to not installed message
  390.     JR    MSGOUT        ;print it
  391. NOTINM:
  392.     DB    'LRUNZ3  must be Installed before it is run $'
  393. START1:         
  394.     LXI    H,0        ;get the CCP entry stackpointer
  395.     DAD    SP        ;(used only if HELP request
  396.     SHLD    SPSAVE        ; is encountered)
  397.     CPM    MSG,SIGNON;    ;Display signon
  398.     CALL    SETUP        ;initialize.
  399.     LHLD    BDOS+1        ;find top of memory
  400.     MOV    A,H        ;page address
  401.                 ;Form destination...
  402.     SUI    PAGES         ;...address in
  403.     MOV    D,A        ;DE pair.
  404.     MVI    E,0
  405.     PUSH    D        ;save on stack
  406. ;
  407.     BLKMOV    ,@BASE,SEGLEN    ;Move the active segment.
  408. ;
  409. ;The segment is now moved to high memory, but not
  410. ;properly relocated.  The bit table which specifies
  411. ;which addresses need to be adjusted is located
  412. ;just after the last byte of the source segment,
  413. ;so (HL) is now pointing at it.
  414.     POP    D    ;beginning of newly moved code.
  415.     LXI    B,SEGLEN;length of segment
  416.     PUSH    H    ;save pointer to reloc info
  417.     MOV    H,D    ;offset page address
  418. ;
  419. ;Scan through the newly moved code, and adjust any
  420. ;page addresses by adding (H) to them.    The word on
  421. ;top of the stack points to the next byte of the
  422. ;relocation bit table.    Each bit in the table
  423. ;corresponds to one byte in the destination code.
  424. ;A value of 1 indicates the byte is to be adjusted.
  425. ;A value of 0 indicates the byte is to be unchanged.
  426. ;
  427. ;Thus one byte of relocation information serves to
  428. ;mark 8 bytes of object code.  The bits which have
  429. ;not been used yet are saved in L until all 8
  430. ;are used.
  431. ;
  432. FIXLOOP:
  433.     MOV    A,B
  434.     ORA    C        ;test if finished
  435.     JRZ    FIXDONE
  436.     DCX    B        ;count down
  437.     MOV    A,E
  438.     ANI    07H        ;on 8-byte boundry?
  439.     JRNZ    NEXTBIT
  440. ;
  441. NEXTBYT:
  442. ;Get another byte of relocation bits
  443.     XTHL
  444.     MOV    A,M
  445.     INX    H
  446.     XTHL
  447.     MOV    L,A        ;save in register L
  448. ;
  449. NEXTBIT:
  450.     MOV    A,L        ;remaining bits from L
  451.     RAL            ;next bit to CARRY
  452.     MOV    L,A        ;save the rest
  453.     JRNC    NEXTADR
  454. ;
  455. ;CARRY was = 1.  Fix this byte.
  456.     LDAX    D
  457.     ADD    H        ;(H) is the page offset
  458.     STAX    D
  459. ;
  460. NEXTADR:
  461.     INX    D
  462.     JR    FIXLOOP
  463. ;
  464. ;Finished.  Jump to the first address in the new
  465. ;segment in high memory.
  466. ;
  467. ;First adjust the stack.  One garbage word was
  468. ;left by fixloop.
  469. ;
  470. FIXDONE:
  471.     INX    SP
  472.     INX    SP
  473. ;
  474. ;(HL) still has the page address
  475. ;
  476.     MOV    L,A    ;move zero to l
  477. ;
  478. ;  Set User/Disk for Return
  479. ;
  480.     LDA    CDISK    ;Set Disk
  481.     MOV    B,A
  482.     LDA    CUSER    ;Set User
  483.     MOV    C,A
  484.     PCHL        ;Stack is valid
  485. ;
  486. ;Any one-shot initialization code goes here.
  487. ;
  488. SETUP:
  489.     LXI    H,NOLOAD
  490.     SHLD    CCPIN+1     ;Prevent reentry
  491. ;
  492.     CALL    REPARS        ;Re-parse command line
  493. ;
  494.     LXI    D,MEMBER+9    ;Check member filetype
  495.     LDAX    D
  496.     CPI    ' '        ;If blank,
  497.     BLKMOV    ,COMLIT,3,Z    ; default to COM.
  498. ;
  499.     LXI    D,LBRFIL+9    ;Check library filetype
  500.     LDAX    D
  501.     CPI    ' '        ;If blank,
  502.     BLKMOV    ,LBRLIT,3,Z    ; default to LBR
  503. ;
  504.     LXI    D,LBRFIL+1    ;Check name
  505.     LDAX    D
  506.     CPI    ' '        ;If blank,
  507.     BLKMOV    ,DFLTNAM,8,Z    ; use default name.
  508. ;
  509. ;  Set Current Disk and User and then Search Along ZCPR3 Path for
  510. ;    the Library File
  511. ;
  512.     CPM    CUR        ;Get Current Disk
  513.     STA    CDISK        ;Save It
  514.     CPM    USR,0FFH    ;Get Current User
  515.     STA    CUSER        ;Save It
  516.     CPM    OPN,LBRFIL    ;Try to Open Library File Now
  517.     INR    A        ;Zero Means Not Found
  518.     JRNZ    DIROK        ;Process if Found
  519.     XRA    A        ;Set to Select Current Disk
  520.     STA    LBRFIL
  521.     LHLD    ENVPTR        ;get Environment pointer
  522.     LXI    D,9        ;offset to Path pointer
  523.     DAD    D        ;make pointer to Path
  524.     MOV    A,M        ;get high order address
  525.     INX    H        ;point to low order address
  526.     MOV    H,M
  527.     CMP    H        ;check for implemented path
  528.     JZ    NODIR        ;no path then can't find library
  529.     MOV    L,A        ;HL now contains pointer to base of path
  530. INPATH:
  531.     MOV    A,M        ;Get Drive
  532.     ORA    A        ;0=Command Not Found
  533.     JZ    NODIR        ;Not Found
  534.     ANI    7FH        ;Mask MSB
  535.     MOV    B,A        ;Save in B for a While
  536.     MVI    A,'$'        ;Get Current Indicator
  537.     CMP    B        ;Compare for Current
  538.     JRNZ    INPATH1        ;Good Disk In B
  539.     LDA    CDISK        ;Get Current Disk
  540.     INR    A        ;Add 1 to be good
  541.     MOV    B,A        ;Disk In B
  542. INPATH1:
  543.     DCR    B        ;Disk in Range 0-15
  544.     INX    H        ;Pt to User Number
  545.     MOV    A,M        ;Get User Number
  546.     INX    H        ;Pt to Next Disk
  547.     PUSH    H        ;Save Ptr
  548.     ANI    7FH        ;Mask User Number
  549.     MOV    C,A        ;User in C for now
  550.     MVI    A,'$'        ;Compare to Current Indicator
  551.     CMP    C        ;See if Current User
  552.     JRNZ    INPATH2        ;Good User In C
  553.     LDA    CUSER        ;User Current User
  554.     MOV    C,A        ;User in C
  555. INPATH2:
  556.     MOV    E,B        ;Select Disk
  557.     PUSH    B        ;Save User in C
  558.     CPM    DSK        ;Set Disk
  559.     POP    D        ;Get User in E
  560.     CPM    USR        ;Set User
  561.     CPM    DIR,LBRFIL    ;See if File Exists in this Directory
  562.     POP    H        ;Restore Path Pointer
  563.     INR    A        ;Error Code (Not Found) is Zero
  564.     JRZ    INPATH        ;Continue Thru Path
  565. DIROPN:
  566.     CPM    OPN,LBRFIL    ;Open for directory read.
  567. DIROK:
  568.     CPM    DMA,TBUFF    ;Set DMA for Block Read
  569. FINDMBR:
  570.     CPM    FRD,LBRFIL    ;Read the directory
  571.     ORA    A
  572.     JNZ    FISHY        ;Empty file, Give up.
  573.     LXI    H,TBUFF
  574.     MOV    A,M
  575.     ORA    A
  576.     JNZ    FISHY        ;Directory not active??
  577.     MVI    B,8+3        ;Check for blanks
  578.     MVI    A,' '
  579. VALIDLOOP:
  580.     INX    H
  581.     CMP    M
  582.     JNZ    FISHY
  583.     DCR    B
  584.     JRNZ    VALIDLOOP
  585. ;
  586.     LHLD    TBUFF+1+8+3    ;Index must be 0000
  587.     MOV    A,H
  588.     ORA    L
  589.     JNZ    FISHY
  590. ;
  591.     LHLD    TBUFF+1+8+3+2    ;Get directory size
  592.     DCX    H        ;We already read one.
  593.     PUSH    H        ;Save on stack
  594.     JR    FINDMBRN    ;Jump into loop
  595. FINDMBRL:
  596.     POP    H        ;Read sector count from TOS
  597.     MOV    A,H
  598.     ORA    L        ;0 ?
  599.     JZ    NOMEMB        ;Member not found in library
  600.     DCX    H        ;Count down
  601.     PUSH    H        ;and put it back.
  602.     CPM    FRD,LBRFIL    ;Get next directory sector
  603.     ORA    A
  604.     JNZ    FISHY
  605.  
  606.  
  607. FINDMBRN:
  608.     LXI    H,TBUFF       ;Point to buffer.
  609.     MVI    C,128/32    ;Number of directory entries
  610. ;
  611. FINDMBR1:
  612.     CALL    COMPARE     ;Check if found yet.
  613.     JZ    GETLOC        ;Found member in .DIR
  614.     DCR    C
  615.     JRZ    FINDMBRL
  616. ;
  617.     LXI    D,32        ;No match, point to next one.
  618.     DAD    D
  619.     JR    FINDMBR1
  620. ;
  621. GETLOC:     ;The name was found now get index and length
  622.     POP    B    ;Clear stack garbage
  623.     XCHG        ;Pointer to sector address.
  624.     MOV    E,M    ;Get First
  625.     INX    H
  626.     MOV    D,M
  627.     XCHG
  628.     SHLD    INDEX    ;Save it
  629.     XCHG
  630.     INX    H    ;Get Size to DE
  631.     MOV    E,M
  632.     INX    H
  633.     MOV    D,M
  634.     XCHG        ; Size to HL
  635.     SHLD    LENX
  636.     CALL    PACKUP    ;Repack command line arguments
  637.     CPM    CON,CR    ;do <cr> only (look like CCP)
  638.     RET
  639. ;        End of setup.
  640. ;
  641. ;    Utility subroutines
  642. NEGDE:            ;DE = -DE
  643.     MOV    A,D
  644.     CMA
  645.     MOV    D,A
  646. ;
  647.     MOV    A,E
  648.     CMA
  649.     MOV    E,A
  650.     INX    D
  651.     RET
  652. ;
  653. ;    REPARSE re-parses the fcbs from the command line,
  654. ;    to allow the "-" character to prefix the library name
  655. ;
  656. REPARS:
  657.     LXI    D,MEMBER    ;first reinitialize both fcbs
  658.     CALL    NITF
  659.     LXI    D,LBRFIL
  660.     CALL    NITF
  661.     LXI    H,TBUFF     ;store a null at the end of
  662.     MOV    E,M        ; the command line (this is
  663.     MVI    D,0        ; done by CP/M usually, except
  664.     XCHG            ; in the case of a full com-
  665.     DAD    D        ; mand line
  666.     INX    H
  667.     MVI    M,0
  668.     XCHG            ;tbuff pointer back in hl
  669. SCANBK:
  670.     INX    H        ;bump to next char position
  671.     MOV    A,M        ;fetch next char
  672.     ORA    A        ;reached a null? (no arguments)
  673.     JZ    HELP        ;interpret as a call for help
  674.     CPI    ' '        ;not null, skip blanks
  675.     JRZ    SCANBK
  676.     CPI    '-'        ;library name specifier?
  677.     JRNZ    NOTLBR        ;skip if not
  678.     INX    H        ;it is, skip over flag character
  679.     LXI    D,LBRFIL    ;parse library name into FCB
  680.     CALL    GETFN
  681. NOTLBR:
  682.     LXI    D,MEMBER    ;now parse the command name
  683.     CALL    GETFN
  684.     LXI    D,HOLD+1    ;pnt to temp storage for rest of cmd line
  685.     MVI    B,-1        ;init a counter
  686. CLSAVE:
  687.     INR    B        ;bump up counter
  688.     MOV    A,M        ;fetch a char
  689.     STAX    D        ;move it to hold area
  690.     INX    H        ;bump pointers
  691.     INX    D
  692.     ORA    A        ;test whether char was a terminator
  693.     JRNZ    CLSAVE        ;continue moving line if not
  694.     MOV    A,B        ;it was, get count
  695.     STA    HOLD        ;save it in hold area
  696.     RET
  697. ;
  698. ;    PACKUP retrieves the command line stored at
  699. ;    HOLD and moves it back to tbuff, then reparses
  700. ;    the default file control blocks so the command
  701. ;    will never know it was run from a library
  702. ;
  703. PACKUP:
  704.     LXI    H,HOLD        ;point to length byte of HOLD
  705.     MOV    C,M        ;get length in BC
  706.     MVI    B,0
  707.     INX    B        ;bump up to because length byte doesn't
  708.     INX    B        ;  include itself or null terminator
  709.     BLKMOV    TBUFF        ;moving everybody to Tbuff
  710.     LXI    H,TBUFF+1    ;point to the command tail
  711.     LXI    D,TFCB1     ;first parse out tfcb1
  712.     CALL    GETFN
  713.     LXI    D,TFCB2     ;then tfcb2
  714.     CALL    GETFN
  715.     RET
  716. ;
  717. ;    Here when HELP is requested (indicated
  718. ;    by LRUN with no arguments)
  719. ;
  720. HELP:
  721.     CPM    MSG,HLPMSG    ;print the HELP message
  722. EXIT:
  723.     LHLD    SPSAVE        ;find CCP re-entry adrs
  724.     SPHL            ;fix & return
  725.     RET
  726. ;
  727. ;    the HELP message
  728. ;
  729. HLPMSG:
  730.     DB    CR,LF,'Correct syntax is:'
  731.     DB    CR,LF
  732.     DB    LF,TAB,'LRUN [-<lbrname>] <command line>'
  733.     DB    CR,LF
  734.     DB    LF,'Where <lbrname> is the optional library name'
  735.     DB    CR,LF,'(Note the preceding "-".  ) If omitted,'
  736.     DB    CR,LF,'the default command library is used.'
  737.     DB    LF
  738.     DB    CR,LF,'<command line> is the name and parameters'
  739.     DB    CR,LF,'of the command being run from the library,'
  740.     DB    CR,LF,'just as if a separate .COM file were being run.'
  741.     DB    CR,LF,'$'
  742. ;
  743. ;
  744. COMPARE:        ;Test status, name and type of
  745.     PUSH    H        ;a directory entry.
  746.     MVI    B,1+8+3
  747.     XCHG            ;with the one we're
  748.     LXI    H,MEMBER    ;looking for.
  749. COMPAR1:
  750.     LDAX    D
  751.     CMP    M
  752.     JRNZ    COMPEXIT
  753.     INX    D
  754.     INX    H
  755.     DCR    B
  756.     JRNZ    COMPAR1
  757. COMPEXIT:            ;Return with DE pointing to
  758.     POP    H        ;last match + 1, and HL still
  759.     RET            ;pointing to beginning.
  760. ;
  761. ;
  762. ;    File name parsing subroutines
  763. ;
  764. ; getfn gets a file name from text pointed to by reg hl into
  765. ; an fcb pointed to by reg de.    leading delimeters are 
  766. ; ignored.
  767. ; entry hl    first character to be scanned
  768. ;    de    first byte of fcb
  769. ; exit    hl    character following file name
  770. ;
  771. ;
  772. ;
  773. GETFN:
  774.     CALL    NITF    ;init 1st half of fcb
  775.     CALL    GSTART    ;scan to first character of name
  776.     RZ        ;end of line was found - leave fcb blank
  777.     CALL    GETDRV    ;get drive spec. if present
  778.     CALL    GETPS    ;get primary and secondary name
  779.     RET
  780.  
  781.  
  782. ;
  783. ; nitf fills the fcb with dflt info - 0 in drive field
  784. ; all-blank in name field, and 0 in ex,s1,s2 and rc flds
  785. ;
  786. NITF:
  787.     PUSH    D    ;save fcb loc
  788.     XCHG        ;move it to hl
  789.     MVI    M,0    ;zap dr field
  790.     INX    H    ;bump to name field
  791.     MVI    B,11    ;zap all of name fld
  792. NITLP1:
  793.     MVI    M,' '
  794.     INX    H
  795.     DJNZ    NITLP1
  796.     MVI    B,4    ;zero others
  797. NITLP2:
  798.     MVI    M,0
  799.     INX    H
  800.     DJNZ    NITLP2
  801.     XCHG        ;restore hl
  802.     POP    D    ;restore fcb pointer
  803.     RET
  804. ;
  805. ; gstart advances the text pointer (reg hl) to the first
  806. ; non delimiter character (i.e. ignores blanks).  returns a
  807. ; flag if end of line (00h or ';') is found while scaning.
  808. ; exit    hl    pointing to first non delimiter
  809. ;    a    clobbered
  810. ;    zero    set if end of line was found
  811. ;
  812. GSTART:
  813.     CALL    GETCH    ;see if pointing to delim?
  814.     RNZ        ;nope - return
  815.     CPI    ';'    ;end of line?
  816.     RZ        ;yup - return w/flag
  817.     ORA    A
  818.     RZ        ;yup - return w/flag
  819.     INX    H    ;nope - move over it
  820.     JR    GSTART    ;and try next char
  821. ;
  822. ; getdrv checks for the presence of a drive spec at the text
  823. ; pointer, and if present formats it into the fcb and
  824. ; advances the text pointer over it.
  825. ; entry hl    text pointer
  826. ;    de    pointer to first byte of fcb
  827. ; exit    hl    possibly updated text pointer
  828. ;    de    pointer to second (primary name) byte of fcb
  829. ;
  830. GETDRV:
  831.     INX    D    ;point to name if spec not found
  832.     INX    H    ;look ahead to see if ':' present
  833.     MOV    A,M
  834.     DCX    H    ;put back in case not present
  835.     CPI    ':'    ;is a drive spec present?
  836.     RNZ        ;nope - return
  837.     MOV    A,M    ;yup - get the ascii drive name
  838.     SUI    'A'-1    ;convert to fcb drive spec
  839.     DCX    D    ;point back to drive spec byte
  840.     STAX    D    ;store spec into fcb
  841.     INX    D    ;point back to name
  842.     INX    H    ;skip over drive name
  843.     INX    H    ;and over ':'
  844.     RET
  845. ;
  846. ; getps gets the primary and secondary names into the fcb.
  847. ; entry hl    text pointer
  848. ; exit    hl    character following secondary name (if present)
  849. ;
  850. GETPS:
  851.     MVI    C,8    ;max length of primary name
  852.     CALL    GETNAM    ;pack primary name into fcb
  853.     MOV    A,M    ;see if terminated by a period
  854.     CPI    '.'
  855.     RNZ        ;nope - secondary name not given
  856.             ;return default (blanks)
  857.     INX    H    ;yup - move text pointer over period
  858. FTPOINT:
  859.     MOV    A,C    ;yup - update fcb pointer to secondary
  860.     ORA    A
  861.     JRZ    GETFT
  862.     INX    D
  863.     DCR    C
  864.     JR    FTPOINT
  865. GETFT:
  866.     MVI    C,3    ;max length of secondary name
  867.     CALL    GETNAM    ;pack secondary name into fcb
  868.     RET
  869. ;
  870. ; getnam copies a name from the text pointer into the fcb for
  871. ; a given maximum length or until a delimiter is found, which
  872. ; ever occurs first.  if more than the maximum number of
  873. ; characters is present, characters are ignored until a
  874. ; a delimiter is found.
  875. ; entry hl    first character of name to be scaned
  876. ;    de    pointer into fcb name field
  877. ;    c    maximum length
  878. ; exit    hl    pointing to terminating delimiter
  879. ;    de    next empty byte in fcb name field
  880. ;    c    max length - number of characters transfered
  881. ;
  882. GETNAM:
  883.     CALL    GETCH    ;are we pointing to a delimiter yet?
  884.     RZ        ;if so, name is transfered
  885.     INX    H    ;if not, move over character
  886.     CPI    '*'    ;ambigious file reference?
  887.     JRZ    AMBIG    ;if so, fill the rest of field with '?'
  888.     STAX    D    ;if not, just copy into name field
  889.     INX    D    ;increment name field pointer
  890.     DCR    C    ;if name field full?
  891.     JRNZ    GETNAM    ;nope - keep filling
  892.     JR    GETDEL    ;yup - ignore until delimiter
  893. AMBIG:
  894.     MVI    A,'?'    ;fill character for wild card match
  895. QFILL:
  896.     STAX    D    ;fill until field is full
  897.     INX    D
  898.     DCR    C
  899.     JRNZ    QFILL    ;fall thru to ingore rest of name
  900. GETDEL:
  901.     CALL    GETCH    ;pointing to a delimiter?
  902.     RZ        ;yup - all done
  903.     INX    H    ;nope - ignore antoher one
  904.     JR    GETDEL
  905. ;
  906. ; getch gets the character pointed to by the text pointer
  907. ; and sets the zero flag if it is a delimiter.
  908. ; entry hl    text pointer
  909. ; exit    hl    preserved
  910. ;    a    character at text pointer
  911. ;    z    set if a delimiter
  912. ;
  913. GETCH:
  914.     MOV    A,M    ;get the character
  915.     CPI    '.'
  916.     RZ
  917.     CPI    ','
  918.     RZ      
  919.     CPI    ';'
  920.     RZ
  921.     CPI    ' '
  922.     RZ
  923.     CPI    ':'
  924.     RZ
  925.     CPI    '='
  926.     RZ
  927.     CPI    '<'
  928.     RZ
  929.     CPI    '>'
  930.     RZ
  931.     ORA    A    ;Set zero flag on end of text
  932.     RET
  933. ;
  934. ;
  935. ; Error routines:
  936. ;
  937. NODIR:
  938.     CALL    ABEND
  939.     DB    'Library not found'
  940.     DB    '$'
  941. FISHY:
  942.     CALL    ABEND
  943.     DB    'Name after "-" isn''t a library'
  944.     DB    '$'
  945. NOMEMB:
  946.     LXI    H,MEMBER+1    ;Pt to first char of Command Name
  947.     MVI    B,8        ;Print 8 Chars
  948. NOMEMBL:
  949.     MOV    E,M        ;Print Char
  950.     INX    H        ;Pt to Next
  951.     PUSH    H        ;Save Ptr and Count
  952.     PUSH    B
  953.     CPM    CON
  954.     POP    B
  955.     POP    H
  956.     DJNZ    NOMEMBL
  957.     CALL    ABEND1        ;No Initial New Line
  958.     DB    ' -- Command not in directory'
  959.     DB    '$'
  960. NOLOAD:
  961.     CALL    ABEND
  962.     DB    'No program in memory'
  963.     DB    '$'
  964. NOFIT:
  965.     POP    B    ;Clear Stack
  966.     CALL    ABEND
  967.     DB    'Program too large to load'
  968.     DB    '$'
  969. ;
  970. COMLIT:
  971.     DB    'COM'
  972. ;
  973. ABEND:
  974.     CPM    MSG,NEWLIN
  975. ABEND1:
  976.     POP    D
  977.     CPM    MSG
  978.     CPM    DEL,SUBFILE
  979.     CPM    MSG,ABTMSG
  980.     JMP    EXIT
  981. ABTMSG:
  982.     DB    ' -- Aborting$'
  983. NEWLIN:
  984.     DB    CR,LF,'$'
  985. CDISK:
  986.     DS    1    ;CURRENT DISK BUFFER
  987. CUSER:
  988.     DS    1    ;CURRENT USER BUFFER
  989. SPSAVE:
  990.     DS    2        ;stack pointer save
  991. ;
  992.     PAGE
  993. ;Adjust location counter to next 256-byte boundry
  994. @BASE    ORG    ($ + 0FFH) AND 0FF00H
  995. @RLBL    SET    0
  996. ;
  997. ; The segment to be relocated goes here.
  998. ; Any position dependent (3-byte) instructions
  999. ; are handled by the "R" macro.
  1000. ;*************************************************
  1001. ;
  1002.     PUSH    B    ;Save Original User/Disk
  1003.  R    <LHLD    LENX>    ;Get length of .COM member to load.
  1004.     MVI    A,TPA/128
  1005.     ADD    L    ;Calculate highest address
  1006.     MOV    L,A    ;To see if it will fit in
  1007.     ADC    H    ;available memory
  1008.     SUB    L
  1009.     MOV    H,A
  1010.     REPT    7
  1011.     DAD    H
  1012.     ENDM
  1013.     XCHG    
  1014.     CALL    NEGDE    ;IT'S STILL IN LOW MEMORY
  1015.  R    <LXI    H,PROTECT>
  1016.     DAD    D
  1017.     JNC    NOFIT    ;Haven't overwritten it yet.
  1018. ;
  1019. ; The library file is still open.  The open FCB has been
  1020. ; moved up here into high memory with the loader code.
  1021. ;
  1022. LBROPN:
  1023.  R    <LHLD    INDEX>        ;Set up for random reads
  1024.  R    <SHLD    RANDOM>
  1025.     XRA    A
  1026.  R    <STA    RANDOM+2>
  1027. ;
  1028.     LXI    H,TPA
  1029.  R    <SHLD    LOADDR>
  1030.  
  1031. ;
  1032. ; This high memory address and above, including CCP, must be
  1033. ; protected from being overlaid by loaded program
  1034. ;
  1035. PROTECT:
  1036. ;
  1037. LOADLOOP:            ;Load that sucker.
  1038.  R    <LHLD    LENX>        ;See if done yet.
  1039.     MOV    A,L
  1040.     ORA    H
  1041.     JRZ    LOADED
  1042.     DCX    H
  1043.  R    <SHLD    LENX>
  1044. ;
  1045.  R    <LHLD    LOADDR>     ;Increment for next time
  1046.     MOV    D,H
  1047.     MOV    E,L
  1048.     LXI    B,80H
  1049.     DAD    B
  1050.  R    <SHLD    LOADDR>
  1051.     CPM    DMA        ;but use old value (DE)
  1052. ;
  1053.  R    <LXI    D,LBRFIL>
  1054.     CPM    RRD        ;Read the sector
  1055.     ORA    A        ;Ok?
  1056.     JRNZ    ERR        ;No, bail out.
  1057. ;
  1058.  R    <LHLD    RANDOM>     ;Increment random record field
  1059.     INX    H
  1060.  R    <SHLD    RANDOM>
  1061. ;
  1062.     JR    LOADLOOP    ;Until done.
  1063. ;
  1064. ERR:
  1065.     MVI    A,( JMP )    ;Prevent execution of bad code
  1066.     STA    TPA
  1067.     LXI    H,BOOT
  1068.     SHLD    TPA+1
  1069. ;
  1070.  R    <LXI    D,LDMSG>
  1071.     CPM    MSG
  1072.  R    <LXI    D,SUBFILE>    ;Abort SUBMIT if in progress
  1073.     CPM    DEL
  1074. LOADED:
  1075.     CPM    DMA,TBUFF    ;Restore DMA adrs for user pgm
  1076.     CPM    CON,LF        ;Turn up a new line on console
  1077.     POP    B        ;Restore Current User/Disk
  1078.     PUSH    B        ;Save it again
  1079.     MOV    E,B        ;Restore Disk
  1080.     CPM    DSK        ;Log In Disk
  1081.     POP    D        ;E=USER
  1082.     CPM    USR        ;Log In User
  1083.     JMP    TPA
  1084. ;
  1085. LDMSG:
  1086.     DB    CR,LF,'Bad Load$'
  1087. INDEX:
  1088.     DW    0
  1089. LENX:
  1090.     DW    0
  1091. SUBFILE:
  1092.     DB    1,'$$$     SUB',0,0,0,0
  1093.     ;If used, this FCB will clobber the following one.
  1094.     ;but it's only used on a fatal error, anyway.
  1095. LBRFIL:
  1096.     DS    32        ;Name placed here at setup
  1097.     DB    0        ;Normal FCB plus...
  1098. OVERLAY SET    $        ;(Nothing past here but DS's)
  1099. RANDOM:
  1100.     DS    3        ;...Random access bytes
  1101. MAXMEM:
  1102.     DS    2
  1103. LOADDR:
  1104.     DS    2
  1105. ;*************************************************
  1106. ;End of segment to be relocated.
  1107.     IF    OVERLAY EQ 0
  1108. OVERLAY SET    $
  1109.     ENDIF
  1110. ;
  1111. PAGES    EQU    ($-@BASE+0FFH)/256+8
  1112. ;
  1113. SEGLEN    EQU    OVERLAY-@BASE
  1114.     ORG    @BASE+SEGLEN
  1115.     PAGE
  1116. ;    Build the relocation information into a
  1117. ; bit table immediately following.
  1118. ;
  1119. @X    SET    0
  1120. @BITCNT SET    0
  1121. @RLD    SET    ??R1
  1122. @NXTRLD SET    2
  1123.     RGRND    %@RLBL+1    ;define one more label
  1124. ;
  1125.     REPT    SEGLEN+8
  1126.     IF    @BITCNT>@RLD
  1127.     NXTRLD    %@NXTRLD    ;next value
  1128.     ENDIF
  1129.     IF    @BITCNT=@RLD
  1130. @X    SET    @X OR 1     ;mark a bit
  1131.     ENDIF
  1132. @BITCNT SET    @BITCNT + 1
  1133.     IF    @BITCNT MOD 8 = 0
  1134.     DB    @X
  1135. @X    SET    0    ;clear hold variable for more
  1136.     ELSE
  1137. @X    SET    @X SHL 1    ;not 8 yet. move over.
  1138.     ENDIF
  1139.     ENDM
  1140. ;
  1141.     DB    0
  1142. HOLD:
  1143.     DB    0,0        ;0 length, null terminator
  1144.     DS    128-2        ;rest of HOLD area
  1145. MEMBER:
  1146.     DS    16
  1147. ;
  1148.     END    CCPIN
  1149.