?login_element?

Subversion Repositories NedoOS

Rev

Rev 671 | Blame | Compare with Previous | Last modification | View Log | Download

  1.        
  2. ;
  3. ; clinka.asm:
  4. ;
  5. ; BDS C Linker 3/86
  6. ;
  7. ; Copyright (c) 1980, 1981, 1982, 1986  by Leor Zolman, BD Software, Inc.
  8. ;
  9. ; Added -f option 4/15/81: forces loading all functions in next crl file
  10. ; Added -n option 9/9/82: activates NOBOOT mechandsm in COM file
  11. ; Added defdsk/defusr mechandsm to library file searches 9/12/82
  12. ; Added -z option to inhibit clearing of externals 11/15/82
  13. ;
  14.  
  15. ; MARC-specific features:
  16. ;   Gets deff.crl, deff2.crl and c.ccall c,from /libC unless -c is given
  17. ;   Added -i option to produce absolute image under MARC instead of default
  18. ;          load file formatted output.
  19. ;   Added -m option for MARC: makes c.ccall c,do a "mexmem" call before setting SP
  20. ;       Changed -m to cause NON-maxmem. I.e., replaced "call marc" with "nop"s.
  21.  
  22.  
  23.         ;org tpa
  24.  
  25.         jp clink
  26.  
  27. ;
  28. ; Configuration block:
  29. ;
  30.         if not PREREL
  31. defdsk: db 0ffh         ;default disk for library files (0=A, etc., FF=current)
  32. defusr: db 0ffh         ;default user area for lib files, FF = current
  33.         endif
  34.  
  35.         if PREREL
  36. defdsk: db 0ffh
  37. defusr: db 0ffh
  38.         endif
  39.  
  40. defsub: db 0            ;default submit file on A: for distribution version
  41. conpol: db 1            ;true to poll for console interrupts
  42. wboote: db 0            ;true to perform warm-boot on exit
  43. pstrip: db 1            ;(dummy in CLINK:) parity strip
  44. nouser: db 0            ;true to disable usage of set user area calls
  45.  
  46. ;
  47. ;end configuration block
  48. ;
  49.  
  50. patch:  ds 19           ;reserved for future expansion (adjust when adding
  51.                         ;               bytes above)
  52.  
  53. clink:
  54.         ;OS_HIDEFROMPARENT
  55.         ;ld e,6 ;textmode
  56.         ;OS_SETGFX
  57.         call initstdio
  58.        
  59.         ;shld zenvad    ;save Z environment pointer (if in HL)
  60.         ;ld hl,0                ;save system SP
  61.         ;add hl,sp
  62.         ;shld spsav     ;save system SP
  63.         ld sp,0;stack   ;set up own stack
  64.         ;call zsetup
  65.  
  66.         lhld errbyt
  67.         ld (hl),0               ;no error by default
  68.  
  69.          call copycline
  70. ;TODO options before filename? but the example is "clink $1 -s"
  71.         ld de,cline
  72.         ld hl,fcb+1
  73.         ;OS_PARSEFNAME
  74.         ld b,8
  75. parsefn0
  76.         ld a,(de)
  77.         ld (hl),a
  78.         cp '.'
  79.         jr z,parsefn1
  80.         cp ' '+1
  81.         jr c,parsefn1
  82.         inc hl
  83.         inc de        
  84.         djnz parsefn0
  85.         jr parsefnq
  86. parsefn1
  87.         ld (hl),' '
  88.         inc hl
  89.         djnz parsefn1
  90. parsefnq
  91.  
  92.         call linit      ;initialize linker
  93.  
  94.         ld de,stg0      ;print opening message
  95.         call pstg
  96.  
  97.         xor a
  98.         sta zsysf       ;not zsystems, by default
  99.  
  100.         call comlin     ;process immediate command line options
  101.  
  102.         IF CPM
  103.         lda defdsk      ;set default disk for library files
  104.         inc a
  105.         sta deffs
  106.         sta deff2s
  107.         sta deff3s
  108.         sta ccc
  109.         ENDIF
  110.  
  111.  
  112.         ld de,tab1      ;set code area pointer to
  113.         lhld tb1siz
  114.         push hl         ;save tab1 size
  115.         add hl,de
  116.         dec hl
  117.         shld tb1end     ;save addr of end of tab1
  118.         ld de,100       ;leave some space in case of
  119.         add hl,de               ; tab1 overflow
  120.         shld cda
  121.         shld cdp
  122.  
  123.         ld hl,tab1
  124.         pop bc          ;get tab1 size
  125. c4:     ld (hl),0               ;clear tab1
  126.         inc hl
  127.         dec bc
  128.         ld a,b
  129.         or c
  130.         jp nz,c4                ;if not, keep looping
  131.  
  132.         IF TESTING3     ;print out contents of fcbs
  133.         push af
  134.         call printf
  135.           db 'before reading c.ccc, fcbs is: ',0
  136.         push hl
  137.         ld hl,fcbs
  138.         call pfnamu
  139.         pop hl
  140.         call crlf
  141.         pop af
  142.         ENDIF
  143.  
  144.         IF CPM
  145.         call setdu      ;set up default library file user areas
  146.         ENDIF
  147.  
  148.         call readc      ;read in c.ccc (if not a segment)
  149.  
  150.         IF ZSYS ;had no endif!!!
  151.         lhld cda        ;check load address for consistency
  152.         ld de,0bh       ;offset for load addr in header
  153.         add hl,de
  154.         ld e,(hl)
  155.         inc hl
  156.         ld d,(hl)               ;DE now = load addr from header
  157.         lhld runsat
  158.         call cmphd
  159.         jp z,c400
  160.        
  161.         ld de,stglde
  162.         call pstg
  163.         jp abort
  164. c400:
  165.         ENDIF
  166. ;       IF CPM
  167.         ;lda curusr     ;go back to current user area
  168.         ;ld e,a
  169.         ;ld c,sguser
  170.         ;lda nouser
  171.         ;or a
  172.         ;IF NOT ALPHA
  173.         ;call z,bdos
  174.         ;ENDIF
  175.         ;ENDIF
  176.  
  177.         IF MARC
  178.         ld hl,fcbt      ;put crl extension on main filename
  179.         push hl
  180.         call scrl
  181.         pop hl
  182.         ENDIF
  183.  
  184. c40:
  185.         IF TESTING3     ;print out contents of fcbs
  186.         push af
  187.         call printf
  188.           db 'before reading in main file, fcbs is: ',0
  189.         push hl
  190.         ld hl,fcbs
  191.         call pfnamu
  192.         pop hl
  193.         call crlf
  194.         pop af
  195.         ENDIF
  196.  
  197.         call gnfl       ;open main file and read in directory
  198.         jp c,abort      ;abort if can't find it
  199.  
  200.         IF TESTING
  201.         call printf
  202.            db 'just successfully opened main file',0
  203.         ENDIF
  204.  
  205.         IF CPM
  206.         ld a,4
  207.         sta nr
  208.         call reads      ;get external data area size and exaddr parameters
  209.         ENDIF
  210.  
  211.         IF NOT CPM
  212.         ld hl,tbuff
  213.         ld de,10
  214.         call reads
  215.         ENDIF
  216.  
  217.         lhld tbuff+3    ;get external data size.
  218.         shld smsf
  219.  
  220.         lda tbuff       ;was explicit external area given?
  221.         or a
  222.         jp z,c4a                ;if not, skip setting eaddr
  223.         sta eflag       ;if so, tell that we have an explicit address
  224.         lhld tbuff+1    ;and copy the passed external address into eaddr
  225.         shld eaddr
  226.  
  227. c4a:    ld hl,stgm      ;read in "main" function
  228.         call ft2        ;is it there?
  229.         jp nc,link2
  230.  
  231.         ld hl,stgmn     ;try long version also
  232.         call ft2
  233.         jp nc,link2
  234.  
  235.         ld de,stg6      ;no. can't link.
  236. c2:     call pstg       ;print error message
  237.  
  238.         IF MARC
  239.         ld hl,fcbt
  240.         ENDIF
  241.  
  242.         call pfnamu     ;print file in which error occurred
  243.         jp abort        ;and abort
  244.  
  245. link2:  ld a,255        ;initialize function number to -1
  246.         sta fcnt
  247.         ld hl,stgmn
  248.  
  249.         ld a,1
  250.         sta gotf
  251.  
  252.         call entt1      ;enter "main" function in table
  253.  
  254.         call pre        ;read it in
  255.  
  256.         IF TESTING
  257.         call printf
  258.            db 'returned from ''pre'' call for main function...',0
  259.         ENDIF
  260.  
  261. link3:  call gtfns      ;get all we can from current CRL file
  262.  
  263. link4:
  264. ;       IF CPM
  265.         ld a,1
  266.         sta search      ;search default path unless otherwise set by getfn
  267.  
  268.         ;ld c,sguser    ;set user area back to current
  269.         ;lda curusr
  270.         ;ld e,a
  271.         ;lda nouser
  272.         ;or a
  273.         ;IF NOT ALPHA
  274.         ;call z,bdos
  275.         ;ENDIF
  276.  
  277.         ;lda savdrv     ;any drive number saved?
  278.         ;or a
  279.         ;jp z,link5
  280.         ;dec a          ;if so, change back to it
  281.         ;ld e,a
  282.         ;ld c,select
  283.         ;call bdos     
  284.         ;xor a
  285.         ;sta savdrv     ;and clear saved drive byte
  286. ;       ENDIF
  287.  
  288. link5:  call fungt      ;are there any functions missing?
  289.         jp c,linkd      ;if not, all done
  290.  
  291.         call getfn      ;else get name of new CRL file to search
  292.        
  293.         IF MARC
  294.         ld hl,fcbt      ;get pointer to the just-gotten crl filename
  295.         ENDIF
  296.  
  297.         call gnfl       ;open it and read in directory
  298.  
  299.         jp nc,link3     ;if opened OK, go read in some functions...
  300.  
  301. ;
  302. ; At this point, all files on the command line and all default
  303. ; library files have been loaded...
  304. ;
  305.  
  306.         IF MARC         ;under MARC, set dflag to indicate that all
  307.         ld a,1          ;deff?.crl files have been searched at least once.
  308.         sta dflag
  309.         ENDIF
  310.  
  311.         jp link4        ;go see if there's more linking to do.
  312.  
  313.  
  314. linkd:  ld a,1
  315.         sta donef       ;all done. scan rest of command line
  316.         lda mflag       ;if it hasn't been scanned through
  317.         or a            ;already...
  318.         call nz,getfn
  319.         call reslv      ;resolve function references
  320.  
  321.         call getcdf2    ;get default external address
  322.         push hl         ;save in C.Ccall c,for use by "codend()" function
  323.         lhld cda
  324.         ld de,codend
  325.         add hl,de
  326.         pop de
  327.  
  328.         lda segf        ;if segment, don't write into code!
  329.         or a
  330.         jp nz,linkd0
  331.  
  332.         ld (hl),e
  333.         inc hl
  334.         ld (hl),d
  335.  
  336. linkd0: ex de,hl
  337.  
  338.         lda eflag       ;-e option specified?
  339.         or a
  340.         jp z,linkd1
  341.         lhld eaddr      ;yes. get the value given in -e option instead
  342. linkd1: push hl         ;save as external starting address in C.CCC
  343.         lhld cda        ; for run-time use.
  344.         ld de,extrns
  345.         add hl,de
  346.         pop de
  347.  
  348.         lda segf        ;if segment, don't write into code!
  349.         or a
  350.         jp nz,lnkd1a
  351.  
  352.         ld (hl),e
  353.         inc hl
  354.         ld (hl),d
  355.  
  356. lnkd1a: ex de,hl
  357.  
  358.         shld extadd
  359.         ex de,hl
  360.         lhld smsf       ;get size of external area
  361.         add hl,de               ;add to start of external area
  362.         push hl         ;and store where it'll be available to the
  363.         lhld cda        ;endext library routine
  364.         ld de,freram
  365.         add hl,de
  366.         pop de
  367.  
  368.         lda segf        ;if segment, don't write into code!
  369.         or a
  370.         jp nz,lnkd1b
  371.  
  372.         ld (hl),e
  373.         inc hl
  374.         ld (hl),d
  375.  
  376. lnkd1b:
  377.         lda zflag       ;-z option given?
  378.         or a
  379.         jp z,skip1
  380.  
  381.         lhld cda        ;if so, disable the external clearing subroutine
  382.         ld de,clrex     ;by changing the first byte of the appropriate
  383.         add hl,de               ;jump vector from C3 into C9.
  384.         ld (hl),0c9h
  385.  
  386. skip1:
  387.         lda segf        ;if segment, don't do rest of this kludgery
  388.         or a
  389.         jp nz,linkf
  390.  
  391.         lhld cda        ;get ptr to startup code in HL
  392.  
  393.         IF ZSYS
  394.         ld de,lxiloc
  395.         add hl,de              
  396.         ENDIF
  397.        
  398.         lda taddrf      ; -t option given?     
  399.         or a
  400.         jp nz,linke
  401.  
  402.         if 1==0
  403.        
  404.         lda nflag       ;noboot option given?
  405.         or a
  406.         jp z,linkd2     ;if not, go handle normally
  407.  
  408. ; Configure for NOBOOT:
  409.  
  410.         IF ZSYS
  411.         push hl
  412.         lhld    cda
  413.         ld de,noboot
  414.         add hl,de
  415.         ld (hl),1               ;set noboot flag in runtime
  416.         pop hl
  417.         jp linkf
  418.         ENDIF
  419.  
  420.         IF NOT ZSYS
  421.         ld (hl),0c3h
  422.         inc hl
  423.         ld (hl),(snobsp and 255)        ;low byte of snobsp address
  424.         inc hl
  425.         ld (hl),(snobsp / 255)  ;high byte of snobsp
  426.  
  427.         ld de,8         ;point HL at nobret jump op
  428.         add hl,de
  429.         ld (hl),(nobret and 255)        ;low byte of nobret address
  430.         inc hl
  431.         ld (hl),(nobret / 255)  ;high byte of nobret address
  432.  
  433.         lhld curtop             ;get top of available memory
  434.         shld taddr
  435.         jp linkf
  436.         ENDIF
  437.  
  438. linkd2:                 ;no -n given.
  439.         endif
  440.  
  441.         ;ld (hl),2ah    ;no. generate initial "lhld ram+6, ld sp,hl"
  442.         ;inc hl
  443.  
  444.         ;ld de,bdosp    ;at run time, ram+6 points to base of bdos
  445.         ;ld (hl),e
  446.         ;inc hl
  447.         ;ld (hl),d
  448.         ;inc hl
  449.         ;ld (hl),0f9h   ; ld sp,hl to set SP to top of TPA
  450.         jp linkf
  451.  
  452. linke:
  453.         ex de,hl                ;save code loc in DE
  454.         lhld taddr      ;if -t option given, leave the "ld sp, stack"
  455.         ex de,hl                ; instruction there, and insert given value.
  456.  
  457.         inc hl          ;pass the ld sp op
  458.  
  459.         ld (hl),e               ;store value
  460.         inc hl
  461.         ld (hl),d
  462.  
  463. linkf:
  464.         IF ZSYS         ;handle setup of Z3 Header:
  465.         lhld    runsat
  466.         ex de,hl
  467.         ld hl,tpa
  468.         call cmphd      ;standard load address?
  469.         jp z,linkf2     ;if so, no problem
  470.  
  471.         push de         ;save runsat address
  472.  
  473.         lhld cda        ;make type 3 header
  474.         ld (hl),0c7h    ;RST 0, so won't crash vandlla CP/M
  475.  
  476.         ld de,8         ;offset to Z type
  477.         add hl,de
  478.         ld (hl),3               ;make type 3
  479.  
  480.         inc hl
  481.         inc hl
  482.         inc hl          ;point to load addr
  483.  
  484.         pop de          ;get back runsat address
  485.         ld (hl),e               ;store runsat address in header
  486.         inc hl
  487.         ld (hl),d
  488.         ENDIF
  489.  
  490. linkf2:
  491.         call pstat      ;print out stats
  492.  
  493.         ld de,stgok     ;print completion message
  494.         call pstg       ;and free-ram diagnostic
  495.  
  496.         ld hl,NEDOOSMEMTOP;lhld bdosp   ;protected memory highest available tpa addr
  497.         ld l,0
  498.  
  499.         ex de,hl
  500.         lhld cdp
  501.         call cmh
  502.         add hl,de
  503.         ld a,h
  504.         rra
  505.         rra
  506.         and 3fh
  507.         ld l,a
  508.         ld h,0
  509.         dec hl
  510.         call prhld
  511.         ld de,stglo
  512.         call pstg
  513.  
  514.         IF TESTING3     ;print out contents of fcbs
  515.         push af
  516.         call printf
  517.           db 'right before calling writf, fcbs is: ',0
  518.         push hl
  519.         ld hl,fcbs
  520.         call pfnamu
  521.         pop hl
  522.         call crlf
  523.         pop af
  524.         ENDIF
  525.  
  526.         IF MARC
  527.         call crlf
  528.         ld a,2
  529.         sta consfd      ;route write error messages to stderr
  530.         ENDIF
  531.  
  532.         call writf      ;write out file or execute directly
  533.  
  534.         IF CPM
  535. exit:   QUIT ;lda wboote        ;need to do warm boot?
  536.         ;or a
  537.         ;jp nz,ram              ;if so, go do it
  538.         ;lhld spsav     ;put saved CCP stack pointer in SP
  539.         ;ld sp,hl
  540.         ;lda ccpok      ;CCP still intact?
  541.         ;or a
  542.         ;ret nz         ;if so, return
  543.         ;lda oktort     ;ok to return despite ccpok being false?
  544.         ;or a
  545.         ;ret nz         ;if so, return
  546.         ;jp ram         ;otherwise warm-boot
  547.  
  548. subfile: db 1,'$$$     SUB',0,0,0,0
  549.         ENDIF
  550.  
  551.         IF MARC
  552.         ld hl,0         ;return code: A OK
  553. exit:   ld c,m$exit
  554.         jp msys
  555.  
  556. ferror: ld c,m$error
  557.         call msys
  558.         ld hl,-1
  559.         jp exit
  560.  
  561. putext: ld a,(hl)
  562.         or a
  563.         jp z,putxt2
  564.         inc hl
  565.         jp putext
  566.  
  567. putxt2: pop de          ;get pointer to extension to be put on
  568. putxt3: ld a,(de)
  569.         ld (hl),a
  570.         inc hl
  571.         inc de
  572.         or a
  573.         jp nz,putxt3    ;copy to (HL) until zero encountered
  574.         ex de,hl                ;then jump to byte after the zero byte to return
  575.         pchl
  576.         ENDIF
  577.  
  578.         if 1==0
  579. ;
  580. ; Set up ZCPR3 environment:
  581. ;
  582. zsetup: xor a
  583.         sta zenvf
  584.         inc a           ;ok to return, by default
  585.         sta oktort
  586.  
  587.         ld hl,errdum
  588.         shld errbyt
  589.  
  590.         lhld zenvad
  591.         push hl
  592.  
  593.         ld de,1bh
  594.         add hl,de
  595.         ld e,(hl)
  596.         inc hl
  597.         ld d,(hl)               ;get reflexive env addr from env
  598.         pop hl          ;original Z env value
  599.         call cmphd      ;save as reflexive address?
  600.         jp nz,setp2a    ;if not Z system, go handle
  601.  
  602.         push hl
  603.         ld de,22h       ;point to message buffer address
  604.         add hl,de
  605.         ld a,(hl)
  606.         inc hl
  607.         ld h,(hl)
  608.         ld l,a          ;HL -> message buffer
  609.         ld de,6         ;get address of error byte
  610.         add hl,de
  611.         shld errbyt     ;save the address
  612.         pop hl
  613.  
  614.         ld a,1
  615.         sta zenvf       ;Z system.
  616.         push hl         ;save env pointer
  617.         ld de,3fh       ;get potential ccp address
  618.         add hl,de
  619.         ld a,(hl)
  620.         inc hl
  621.         ld h,(hl)
  622.         ld l,a
  623.         shld ccpad
  624.  
  625.         pop hl          ;get env pointer
  626.         ld de,8         ;get type
  627.         add hl,de
  628.         ld a,(hl)
  629.         sta envtyp
  630.        
  631.         and 80h         ;b7 hi?
  632.         lhld ccpad
  633.         jp nz,setup3    ;if so, use ccpad as ccp address
  634. setp2a: lhld 0001h      ;else calculate the old way
  635.         ld de,-1603h
  636.         add hl,de
  637.  
  638. setup3: xor a           ;clear 'ccp volatile' flag
  639.         sta ccpok      
  640.         ex de,hl                ;put ccp address in DE
  641.         ld hl,NEDOOSMEMTOP;lhld bdosp
  642.         ld l,0          ;zero out low-order byte
  643.         call cmphd      ;set Cy if [BASE+6,7] < CCP
  644.         jp c,setup4     ;if BASE+6 < CCP, use BASE+6 as end of prot mem
  645.         ex de,hl                ;else use CCP as end of prot. mem.
  646.         ld a,1          ;and set ccp volatile flag
  647.         sta ccpok
  648.         xor a           ;NOT ok to return by default!
  649.         sta oktort      ;  (go by value of ccpok)
  650. setup4: shld curtop
  651.         ret
  652.  
  653. envtyp: ds 1
  654. zenvf:  ds 1    ;true if running under ZCPR3
  655. zenvad: ds 2
  656. ccpad:  ds 2    ;address of CCP for type 80h ZCPR3
  657.         endif
  658. oktort: ds 1    ;ok to return despite ccpok being false?
  659. errbyt: dw errdum       ;address of Z3 error byte
  660. errdum: ds 1    ;if CP/M, errbyt points here
  661.  
  662.         IF CPM
  663. fcbt:   db 0
  664.         db '        '
  665.         db '   '
  666.         db 0,0,0,0
  667.         ENDIF
  668.  
  669.         IF CPM
  670. fcbs:   db 0            ;name of output file buffer
  671.         db '        '   ;8 filename spots
  672.         db 'COM'
  673.         db 0,0,0,0
  674.         ENDIF
  675.  
  676.  
  677.         IF NOT ALPHA AND NOT ZSYS
  678. stg0:   db 'BD Software C Linker   v'
  679.         ENDIF
  680.        
  681.         IF NOT ALPHA AND ZSYS
  682. stg0:   db 'BD Software C Linker (for ZCPR3)  vZ'
  683.         ENDIF
  684.  
  685.         IF ALPHA
  686. stg0:   db 'BDS Alpha-C Linker   v'
  687.         ENDIF
  688.  
  689.         IF NOT ZSYS
  690.         db '1.'
  691.         ENDIF
  692.  
  693.         db version
  694.  
  695.         IF ZSYS
  696.         db '.'
  697.         ENDIF
  698.  
  699.         db update
  700.  
  701.         IF PREREL
  702.         db ' (pre-release)'
  703.         ENDIF
  704.  
  705.         IF CPM
  706.         db cr,lf,0
  707.         ENDIF
  708.  
  709.         IF MARC
  710.         db '  for MARC',lf,0
  711.         ENDIF
  712.  
  713. stg2:   db 'Error reading: ',0
  714.  
  715.         IF CPM
  716. stgnua: db 'No user area prefix allowed on main filename',0
  717. stg5:   db lf,'Dir full; ',cr
  718.         ENDIF
  719.  
  720.         IF NOT CPM
  721. stg5:   db lf,'Error creating output file: ',0
  722.         ENDIF
  723.  
  724. stg3:   db lf,'Error writing: ',0
  725. stg4:   db lf,'Can''t close: ',0
  726. stg6:   db 'No main function in ',0
  727. stgas:  db cr,lf,'Missing function(s):',cr,lf,0
  728. stg7:   db lf,'Type the name of a CRL file '
  729.         db 'to scan; ',cr,lf
  730.  
  731.         IF CPM
  732.         db '<CR> to scan all DEFF files, '
  733.         ENDIF
  734.  
  735.         IF NOT CPM
  736.         db '<CR> to scan all deff?.crl files, '
  737.         ENDIF
  738.  
  739.         IF CPM
  740.         db '^Z-<CR> to abort: ',0
  741.         ENDIF
  742.  
  743.         IF NOT CPM
  744.         db 'or your ''quit'' char to abort: ',0
  745.         ENDIF
  746.  
  747. stgm:   db 9dh
  748. stgmn:  db 'MAI','N'+80h,0
  749.  
  750.         IF CPM
  751. deffs:  db 0,'DEFF    CRL',0
  752. deff2s: db 0,'DEFF2   CRL',0
  753. deff3s: db 0,'DEFF3   CRL',0
  754. ccc:    db 0,'C       CCC',0
  755.         ENDIF
  756.  
  757.         IF NOT CPM
  758. deffs:  db '/libC/deff0.crl',0
  759. ccc:    db '/libC/c.ccc',0
  760.         ENDIF
  761.  
  762. stg1:   db 'Can''t find ',0
  763. stglca: db 'Last code address: ',0
  764. stgext: db cr,lf,'Externals start at ',0
  765. stgxt2: db ' occupy ',0
  766. stgxt3: db 'bytes, last byte at ',0
  767. stgtm:  db cr,lf, 'Top of memory: ',0
  768. stgds:  db cr,lf, 'Stack space: ',0
  769. stgabt: db bell,'Link ABORTED',cr,lf,0
  770.  
  771.  
  772.         IF CPM
  773. stgdo:  db bell,cr,lf,'Warning! Externals extend into the BDOS!',cr,lf,0
  774.         ENDIF
  775.  
  776.         IF MARC
  777. stgdo:  db lf,'Warning! Externals extend into system memory!',lf,0
  778.         ENDIF
  779.  
  780.         IF CPM
  781. stgdo2: db bell,lf,'Warning! Externals overlap code!',cr,lf,0
  782.         ENDIF
  783.  
  784.         IF MARC
  785. stgdo2: db lf,'Warning! Externals overlap code!',lf,0
  786.         ENDIF
  787.  
  788. stgom:  db 'Out of memory',0
  789. stglo:  db 'K link space remaining',cr,lf,0;cr,0
  790. stgok:  db 'Writing output...',cr,lf,0
  791. stgserr: db 'Bad symbols',0
  792. stgdeb: db lf,'Executing:',cr,lf,0
  793. stglde: db 'Load Address does not match Z3 Header in Runtime Pkg',cr,lf,0
  794. stgbop: db 'Bad option: -',0
  795. stgt1o: db 'Ref table overflow',0
  796. stgver: db 'Missing arg to -'
  797. stgdps: db 'Symbol re-defined: ',0
  798. stgdpf: db 'Ignoring duplicate function: ',0
  799. stgabo: db '^C',cr,lf,0
  800.  
  801.         IF MARC
  802. stgnof: db 'Usage:  '
  803.  
  804.         db 'clink <main_crl_file> [-cmsvw]'
  805.         db ' [-e <addr>] [-t <addr>] [-l <addr>]'
  806.         db lf
  807.  
  808.         db tab,'[-o <new_name>] [-y <sym_name>]'
  809.         db ' [<crl_file> [<crl_file>] ... ]'
  810.         db 0
  811.         ENDIF
  812.  
  813. opletr: ds 1
  814.         db 0
  815.  
  816. stgtmf: db 'Sorry; 255 funcs max',0
  817.  
  818.  
  819. ;
  820. ; Initialize linker:
  821. ;
  822.  
  823. linit:  ;ld c,sguser    ;get current user area
  824.         ;ld e,0ffh
  825.         ;lda nouser
  826.         ;or a
  827.  
  828.         ;IF NOT ALPHA
  829.         ;call z,bdos
  830.         ;ENDIF
  831.  
  832.         ;IF ALPHA
  833.         ;nop
  834.         ;nop
  835.         ;nop
  836.         ;ENDIF
  837.  
  838.         ;sta curusr     ;save current user area number
  839.         lda defsub
  840.         inc a
  841.         sta subfile
  842.  
  843.         xor a
  844.         sta wrsmf       ; "outch" not to write to SYM file
  845.  
  846.         IF MARC         ;under marc, initialize message output fd
  847.         ld a,1
  848.         sta consfd      ;route first msgs to stdout (1)
  849.         ld hl,0
  850.         shld noffst     ;search /libC by default for deff*.crl & c.ccc
  851.  
  852.         ld c,m$memory   ;get top of memory value before doing maxmem call
  853.         call msys
  854.         ex de,hl
  855.         shld taddr      ;taddr before maxmem call
  856.  
  857.         ld c,m$maxmem   ;do a maxmem call
  858.         call msys
  859.         ld a,1
  860.         sta maxmd       ;note that we've done the maxmem call (once only)
  861.  
  862.         ld c,m$memory   ;get top of memory AFTER maxmem call has been done
  863.         call msys
  864.         ex de,hl
  865.         shld curtop     ;and as physical top of memory for linkage
  866.         ENDIF
  867.  
  868.         IF MARC         ;if MARC version, get argc and argv:
  869.         sta marcfd      ;clear marcfd in case of usage diagnostic
  870.         pop af          ;skip return address
  871.  
  872.         pop hl          ;get argc passed by MARC
  873.         ld a,l          ;set A = argc
  874.         dec a
  875.         ld de,stgnof    ; complain and abort if no filename given
  876.         jp z,stgab
  877.  
  878.         sta argc        ;else save argc for later use
  879.  
  880.         pop hl          ;get argv passed by MARC
  881.         inc hl
  882.         inc hl          ;point argv to main filename pointer
  883.         shld argv       ;save pointer to main filename pointer
  884.  
  885.         ld a,(hl)               ;indirect to get pointer to main filename
  886.         inc hl
  887.         ld h,(hl)
  888.         ld l,a
  889.  
  890.         push hl         ;save it on stack
  891.         ld de,fcbt      ;copy main filename to fcbt for use in reading
  892.         call ldfn       ;   in main crl file
  893.         pop hl          ;and also copy to fcbs for use in writing out file
  894.         ld de,fcbs
  895.         call ldfn
  896.         ENDIF
  897.  
  898.         IF TESTING3     ;print out contents of fcbs
  899.         push af
  900.         call printf
  901.           db 'after first setting fcbs, fcbs is: ',0
  902.         push hl
  903.         ld hl,fcbs
  904.         call pfnamu
  905.         pop hl
  906.         call crlf
  907.         pop af
  908.         ENDIF
  909.  
  910.  
  911.         IF CPM
  912.         ld de,tbuff     ;set DMA address
  913.         ld c,sdma       ;(helps me debug 4200h version
  914.         call bdos       ; on 0-based CP/M system)
  915.  
  916.         ld hl,fcb       ;save filename argument
  917.         ld de,fcbs
  918.         call ldfn       ;lde main filename to fcbs
  919.         ld hl,fcbs+9    ;and give it a COM extension by default
  920.         ld (hl),'C'
  921.         inc hl
  922.         ld (hl),'O'
  923.         inc hl
  924.         ld (hl),'M'
  925.         ENDIF
  926.  
  927.         xor a           ;clear some flags:
  928.         sta segf        ;assume not a segment by default
  929.         sta debugf      ;don't immediately execute file
  930.         sta statf       ;default to no stats
  931.         sta dflag       ;haven't searched DEFF.CRL yet
  932.         sta quietf      ;report unfound files
  933.         sta rdngsm      ;not reading in symbols from disk
  934.         sta taddrf      ;no top of memory address given yet
  935.         sta eflag       ;no external data addr given yet
  936.         sta donef       ;all function references not resolved yet
  937.         sta wflg        ;controls writing of SYM file
  938.  
  939.         IF CPM
  940.         sta zflag       ;don't inhibit clearing of externals
  941.         sta d2flag      ;haven't searched DEFF2.CRL either
  942.         sta d3flag      ;haven't searched DEFF3.CRL either
  943.         sta nflag       ;no noboot option given yet
  944.         sta hflag       ;don't force lhld 4206 unless -h given
  945.         sta savdrv      ;no drive number currently saved
  946.         ENDIF
  947.  
  948.         IF MARC
  949.         sta dlast       ;last DEFF?.CRL searched (0 for none)
  950.         sta marcfd      ;no file open yet
  951.         sta iflag       ;no image mode output file unless -i used
  952.         sta oflag       ;haven't seen -o yet
  953. ;       sta maxmd       ;haven't done maxmem call yet
  954.         ENDIF
  955.  
  956.         IF NOT FORCE
  957.         sta fflag       ;no forced loading of all funcs in crl file
  958.         ENDIF
  959.  
  960.         inc a
  961.         sta mflag       ;more text to process in command line
  962.  
  963.         IF FORCE
  964.         sta fflag       ;force loading of all funcs in crl file
  965.         ENDIF
  966.  
  967.         IF CPM
  968.         lda fcb         ;default disk to get CRL files from
  969.         sta decl        ; is disk where source file came from
  970.  
  971.         lhld curtop     ;set protected memory address
  972.         shld taddr
  973.         ENDIF  
  974.  
  975.         ld hl,dt1siz    ;set default tab1 size
  976.         shld tb1siz
  977.  
  978.         ld hl,tpa       ;default starting address
  979.         shld runsat     ; (alterable only if -l option used)
  980.         ret
  981.  
  982.  
  983. ;
  984. ; Process immediate command line options:
  985. ;
  986.  
  987. copycline
  988.         IF CPM
  989.         ;ld hl,fcb+1    ;see if user area given as part of filename
  990.         ;call gdec
  991.         ;jp c,clink0    ;if not, OK
  992.         ;ld a,(hl)              ;else, followed by slash?
  993.         ;cp '/'
  994.         ;jp nz,clink0   ;if not, no problem
  995.         ;ld de,stgnua   ;else abort with "no user number allowed" message
  996.         ;jp stgab
  997.  
  998. clink0: ld hl,cline     ;copy command line from tbuff to area at cline
  999.         shld cptr       ;under CP/M
  1000.         ld hl,tbuff
  1001. comlin_fspac:
  1002.         ld a,(hl)
  1003.         or a
  1004.         jr z,comlin_fspac_skip
  1005.         inc hl
  1006.         cp ' '
  1007.         jr nz,comlin_fspac
  1008. comlin_fspac_skip
  1009.        
  1010.         ;ld b,(hl)
  1011.         ;inc b
  1012.         ;inc hl
  1013.         ld de,cline
  1014. c0:     ;dec b
  1015.         ;jp z,c0a
  1016.         ld a,(hl)
  1017.         ld (de),a
  1018.         or a
  1019.         inc hl
  1020.         inc de
  1021.         jr nz,c0
  1022.         ENDIF
  1023.         IF NOT CPM
  1024.         ld a,2
  1025.         sta consfd      ;future msgs to go stderr
  1026.  
  1027.         ld hl,cline     ;copy all MARC args into area at cline, emulating
  1028.         shld cptr       ;CP/M command line passage
  1029.         ex de,hl                ;DE is destination area
  1030.         lhld argv       ;HL will point to arg text
  1031. c00a:   lda argc        ;get arg count
  1032.         or a
  1033.         jp z,c0a                ;if done, go process the line
  1034.         dec a
  1035.         sta argc        ;not done. debump argc and copy current arg text
  1036.         push hl         ;save pointer to text address
  1037.         ld a,(hl)
  1038.         inc hl
  1039.         ld h,(hl)
  1040.         ld l,a          ;HL points to actual arg text
  1041.         call ldfn       ;lde it to (DE)
  1042.         dec de          ;stomp on the trailing null from the last arg text
  1043.         ld a,' '        ; (replace it with a space)
  1044.         ld (de),a
  1045.         inc de
  1046.         pop hl          ;restore arg pointer
  1047.         inc hl          ;bump to next pointer
  1048.         inc hl
  1049.         jp c00a ;and go for it
  1050.         ENDIF  
  1051.  
  1052. c0a:    xor a           ;OK, command line has been copied
  1053.         ld (de),a               ;terminate with null byte
  1054.         ret
  1055.  
  1056. comlin:
  1057.  
  1058.         ld hl,cline     ;find first non-space char
  1059.         call igsp
  1060.         or a            ;if end of line,
  1061.         jp z,c1         ; don't pass over main filename
  1062. c0c:    inc hl          ;else do.
  1063.         ld a,(hl)
  1064.         or a
  1065.         jp z,c1
  1066.         call twhite
  1067.         jp nz,c0c
  1068.         call igsp       ;pass space between this and next arg
  1069.  
  1070. c1:     shld cptr       ;save text pointer for getfn routine
  1071.  
  1072. ;
  1073. ; Here process -l and -r and -v; set tb1siz to optional arg of -r,
  1074. ; set runsat to optional arg of -l, and set segf if -v given:
  1075. ; also handle new -c option for MARC
  1076. ; Also handle new -m option to call MEXMEM under MARC...
  1077. ;
  1078.         dec hl
  1079. prep0:  inc hl
  1080. prep:   ld a,(hl)
  1081.         or a            ;done preprocessing command line?
  1082.         ret z           ;if so, return
  1083.  
  1084.         cp '"'          ;possible option to "-d"?
  1085.         jp nz,prep3    
  1086. prep2:  inc hl          ;if so, skip it totally
  1087.         ld a,(hl)
  1088.         or a
  1089.         ret z           ;if null byte, done scanning command line
  1090.         cp '"'
  1091.         jp nz,prep2
  1092.         jp prep0        ;then continue scanning for useful options
  1093.  
  1094. prep3:  cp '-'          ;no. dashed option?
  1095.         jp nz,prep0     ;if not, ignore it
  1096.         shld fargb      ;else save first arg byte
  1097.         inc hl
  1098.         ld a,(hl)               ;get option letter
  1099.         call mapuc
  1100.         sta opletr      ;save for error msg
  1101.         inc hl
  1102.  
  1103.         cp 'C'          ;set disk to get c.ccc and deff*.crl from
  1104.         jp z,copt
  1105.  
  1106.         IF CPM
  1107.         cp 'H'          ;little kludge (for Leo only)
  1108.         jp z,hopt
  1109.         ENDIF
  1110.  
  1111.         IF MARC
  1112.         cp 'I'          ;image mode?
  1113.         jp z,iopt
  1114.         ENDIF
  1115.  
  1116.         cp 'L'          ;set load addr?
  1117.         jp z,lopt
  1118.         cp 'R'          ;set ref table size?
  1119.         jp z,ropt
  1120.         dec hl
  1121.         cp 'V'          ;declare a segment?
  1122.         jp nz,prep
  1123.         inc hl
  1124.         sta segf        ;this one's easy.
  1125. purge:  ex de,hl                ;put current text addr in DE
  1126. purge1: lhld fargb      ;get 1st byte of arg
  1127. purge2: ld (hl),' '     ;clear it to a space
  1128.         inc hl
  1129.         call cmphd      ;done?
  1130.         jp nz,purge2    ;keep blanking till done.
  1131.         jp prep ;and go pre-process some more
  1132.  
  1133. ropt:   call gtaddd     ;get argument
  1134.         ex de,hl
  1135.         ld a,h
  1136.         or a
  1137.         jp z,purge1     ;must be at least 100h to be reasonable!
  1138.         shld tb1siz     ;set tab1 size;
  1139.         jp purge1       ;and go purge text from command line
  1140.  
  1141. copt:
  1142.         IF CPM
  1143.         call igsp
  1144.         call cnvtd      ;get source disk for C.CCC and DEFF*.CRL
  1145.         sta defdsk      ;(under CP/M only; MARC version assumes
  1146.                         ;all this stuff is in /etc)
  1147.         inc hl          ;bump text pointer to possible user area
  1148.         call gdec       ;user area given?
  1149.         jp c,copt9      ;if not, done with -c option
  1150.         sta defusr      ;else user area given. Store it at defusr
  1151.        
  1152. copt9:  ex de,hl
  1153.         jp purge1
  1154.  
  1155. ;
  1156. ; Scan text at HL for a decimal number. If found, return in B and clear Cy.
  1157. ; Return Cy set if no legal decimal number.
  1158. ; Upon exit, HL is left pointing to the first non-decimal-digit character.
  1159. ;
  1160.  
  1161. gdec:   ld b,0
  1162.         call igsp
  1163.         call legdd
  1164.         ld a,0
  1165.         ret c  
  1166. gdec1:  ld a,(hl)
  1167.         call legdd
  1168.         ld a,b
  1169.         ccf
  1170.         ret nc
  1171.         add a           ;get A = 10 * B
  1172.         add a           ;(*4)
  1173.         add a           ;(*8)
  1174.         add b           ;(*9)
  1175.         add b           ;(*10)
  1176.         add c           ;now add new digit value in C
  1177.         ld b,a          ;put into B
  1178.         inc hl
  1179.         jp gdec1        ;and go for more
  1180.  
  1181. ;
  1182. ; Check for legal decimal digit, return Cy set if illegal,
  1183. ; else the binary value of the digit in A:
  1184. ;
  1185.  
  1186. legdd:  call mapuc
  1187.         sub '0'
  1188.         ld c,a
  1189.         ret c
  1190.         cp 10
  1191.         ccf    
  1192.         ret
  1193.         ENDIF
  1194.  
  1195.         IF NOT CPM
  1196.         ex de,hl                ;put text pointer in DE
  1197.         ld hl,6         ;set noffst to 6 so current directory is
  1198.         shld noffst     ;searched for deff*.crl & c.ccc instead of /libC
  1199.         jp purge1
  1200.         ENDIF
  1201.  
  1202.  
  1203.         IF CPM
  1204. hopt:   sta hflag       ;kludge for Leo, under CP/M only
  1205.         ex de,hl
  1206.         jp purge1
  1207.         ENDIF
  1208.  
  1209.         IF MARC
  1210. iopt:   sta iflag       ;set image mode to produce absolute image
  1211.         ex de,hl
  1212.         jp purge1
  1213.         ENDIF
  1214.  
  1215. lopt:   call gtaddd     ;get argument
  1216.         ex de,hl
  1217.         shld runsat     ;set origin address
  1218.         jp purge1       ;and purge from command line   
  1219.  
  1220.  
  1221.  
  1222.  
  1223. ;
  1224. ; Check for user abortion:
  1225. ;TODO
  1226.  
  1227. ckabrt: push af
  1228.         push hl
  1229.         push de
  1230.         push bc
  1231.  
  1232.         IF CPM
  1233.         ;lda conpol     ;are we polling for interrupts?
  1234.         ;or a
  1235.         ;jp z,noabrt    ;if not, ignore console...
  1236.  
  1237.         ;ld c,intcon    ;interrogate console status
  1238.         ;call bdos
  1239.         ;or a
  1240.         ;jp z,noabrt
  1241.         ;ld c,coninp
  1242.         ;call bdos
  1243.         ;cp 3           ;control-C aborts
  1244.         ;jp nz,noabrt
  1245.  
  1246.         ;ld de,stgabo   ;abort.
  1247.         ;jp stgab
  1248.         ENDIF
  1249.  
  1250.         IF NOT CPM
  1251.         ;ld c,m$ichec
  1252.         ;call msys
  1253.         ENDIF
  1254.  
  1255. noabrt: pop bc
  1256.         pop de
  1257.         pop hl
  1258.         pop af
  1259.         ret
  1260.  
  1261.  
  1262. ;
  1263. ; Here is a little routine to take an ASCII char in A that
  1264. ; is either a space or a disk letter, and return the
  1265. ; appropriate code in A to put in the first byte of an
  1266. ; fcb accessing the given disk:
  1267. ;
  1268.  
  1269.         IF CPM
  1270. cnvtd:  call twhite
  1271.         jp nz,cnvtd2
  1272.         xor a           ;if space, return 0
  1273.         ret
  1274.  
  1275. cnvtd2: sub 'A'         ;else return 0 for A, 2 for B, etc.
  1276.         cp 'Z'+1
  1277.         ret c           ;OK if a letter
  1278.         xor a           ;else change to zero
  1279.         ret
  1280.         ENDIF
  1281.  
  1282. ;
  1283. ; Given the address of a function as stored in memory during
  1284. ; the linkage process, this function returns the actual address
  1285. ; that the function will occupy when executing:
  1286. ;
  1287.  
  1288. getcdf: lhld runsat
  1289.         push de
  1290.         ex de,hl
  1291.         lhld cda
  1292.         call cmh
  1293.         add hl,de
  1294.         pop de
  1295.         ret
  1296.  
  1297. getcdf2: call getcdf
  1298.         ex de,hl
  1299.         lhld cdp
  1300.         add hl,de
  1301.         ret
  1302.  
  1303.  
  1304. ;
  1305. ; Print out the contents of register pair HL in ASCII:
  1306. ;  (uses the simple gas-pump algorithm)
  1307. ;
  1308.  
  1309. prhld:  push de
  1310.         push hl
  1311.         ld hl,'  '
  1312.         shld ascb
  1313.         ld hl,' 0'
  1314.         shld ascb+2
  1315.         pop hl
  1316.         inc hl
  1317. prh0:   ld a,h
  1318.         or l
  1319.         jp z,prnt
  1320.         dec hl
  1321.         push hl
  1322.         ld hl,ascb+3
  1323. prh1:   ld a,(hl)
  1324.         call twhite
  1325.         jp nz,prh2
  1326.         ld a,'0'
  1327. prh2:   inc a
  1328.         cp '9'+1
  1329.         jp z,prh4
  1330. prh3:   ld (hl),a
  1331.         pop hl
  1332.         jp prh0
  1333. prh4:   ld (hl),'0'
  1334.         dec hl
  1335.         jp prh1
  1336. prnt:   ld de,ascb
  1337.         call pstg
  1338.         pop de
  1339.         ret
  1340.  
  1341. ;
  1342. ; Print out file name in the fcb, with user number preceding:
  1343. ;
  1344. pfnamu:
  1345.         lda nouser
  1346.         or a
  1347.         jp nz,pfnam     ;if user areas disabled, don't even try
  1348.         ld e,0ffh
  1349.         ld c,32
  1350.         call bdos       ;get current user number
  1351.         call prad       ;print out value of A in decimal
  1352.         ld a,'/'
  1353.         call outch      ;follow with slash, then print rest of filename
  1354.  
  1355. ;
  1356. ; Routine to print out the name of the file
  1357. ; in the fcb:
  1358. ;
  1359.        
  1360.         IF CPM
  1361. pfnam:
  1362.         push de
  1363.         push bc
  1364.         lda fcb
  1365.         or a            ;if no special disk, don't print a letter
  1366.         jp nz,pfnam1
  1367.         ;push de
  1368.         ;push hl
  1369.         ;ld c,gdisk
  1370.         ;call bdos
  1371.         ;inc a 
  1372.         ;pop hl
  1373.         ;pop de
  1374.          xor a ;TODO getpath
  1375. pfnam1: add a,'@'               ;make it into the disk letter
  1376.         call outch
  1377.         ld a,':'
  1378.         call outch
  1379. pfnam2: ld b,8
  1380.         ld de,fcb+1
  1381.         call pnseg      ;print filename
  1382.         ld a,'.'
  1383.         call outch
  1384.         ld b,3
  1385.         call pnseg      ;print extension
  1386.         call crlf
  1387.         pop bc
  1388.         pop de
  1389.         ret
  1390.  
  1391.  
  1392. ;
  1393. ; Print out user number in A in decimal:
  1394. ;
  1395.  
  1396. prad:   push bc
  1397.         call prad2
  1398.         pop bc
  1399.         ret
  1400.  
  1401. prad2:  ld c,0          ;compute first digit
  1402. prad3:  cp 10           ;less than 10?
  1403.         jp c,prfd               ;if so, print first digit
  1404.         sub 10          ;else subtract 10
  1405.         inc c           ;bump tens digit
  1406.         jp prad3
  1407.        
  1408. prfd:   push af ;save last digit
  1409.         ld a,c          ;look at first digit
  1410.         or a            ;zero?
  1411.         call nz,prhd    ;if not, print it
  1412.         pop af          ;get last digit
  1413.         jp prhd ;print it
  1414.  
  1415. ;
  1416. ; print out string at DE, max length B,
  1417. ; delete spaces:
  1418. ;
  1419.  
  1420. pnseg:  ld a,(de)
  1421. pns2:   call outch
  1422.         inc de
  1423.         dec b
  1424.         ret z
  1425.         ld a,(de)
  1426.         call twhite
  1427.         jp nz,pns2
  1428. pns3:   inc de
  1429.         dec b
  1430.         jp nz,pns3
  1431.         ret
  1432.         ENDIF
  1433.  
  1434. ;
  1435. ; Print out statistics in response to -s option:
  1436. ;
  1437.  
  1438. pstat:  call alphab     ;alphabetize symbols
  1439.  
  1440. ;       lda statf       ;if printing stats, put out a crlf
  1441. ;       or a
  1442. ;       call nz,crlf
  1443.  
  1444. ;       call crlf
  1445.  
  1446.         call wrsmb      ;write symbols to disk and console
  1447.  
  1448. ;       lda statf       ;if stats desired,
  1449. ;       or a            ;print them out
  1450. ;       jp nz,pst00
  1451. ;
  1452. ;       call ovrlap     ;check for code/externals overlap
  1453. ;
  1454. ;       lhld smsf       ;and check for external area overflow into system
  1455. ;       ex de,hl
  1456. ;       lhld extadd
  1457. ;       add hl,de
  1458. ;       jp c,exovfl     ;if carry, REAL overflow!
  1459. ;       ex de,hl                ;DE holds end of external area
  1460. ;       lhld taddr      ;get end of TPA address
  1461. ;       call cmphd      ;HL better be less than DE....
  1462. ;       ret nc          ;if so, no problem
  1463. ;exovfl:
  1464. ;       ld de,stgdo     ;else trouble!
  1465. ;       call pstg
  1466. ;       ret
  1467.  
  1468. pst00:  ld de,stglca    ; "last code address = ..."
  1469.         call crlf
  1470.         call pstg
  1471.         call getcdf2    ;get last code addr. + 1
  1472.         dec hl
  1473.         call prhls      ;print last code address out
  1474.  
  1475. ;
  1476. ; Print external data stats, but DON'T if linking a segment
  1477. ; and no -e option is given:
  1478. ;
  1479.  
  1480.         lda segf
  1481.         or a
  1482.         jp z,pst00a     ;if not linking a segment, print all stats
  1483.         lda eflag       ;yes, linking a segment. -e option given?
  1484.         or a
  1485.         jp z,pst0               ;if not, skip printing external numbers
  1486.  
  1487. pst00a: ld de,stgext    ;"external data starts at "
  1488.         call pstg
  1489.         lhld extadd
  1490.         push hl
  1491.         call prhlc
  1492.         ld de,stgxt2    ;"occupy "
  1493.         call pstg
  1494.         lhld smsf
  1495.         push hl         ;save size of external data area
  1496.         call prhls
  1497.         ld de,stgxt3    ;" bytes, and and end at"
  1498.         call pstg
  1499.         pop de          ;get size of externals
  1500.         pop hl          ;get start of externals
  1501.         add hl,de               ;get ending address of externals
  1502.         dec hl
  1503.         push hl         ;save for local store calc later
  1504.         ld a,d          ;special case of no externals
  1505.         or e
  1506.         jp nz,skpfdg
  1507.         inc hl
  1508. skpfdg: call prhls
  1509.         pop hl
  1510.  
  1511. pst0:   push hl
  1512.         ld de,stgtm     ;"top of memory=..."
  1513.         call pstg
  1514.         lhld taddr
  1515.         dec hl
  1516.         push hl         ;save top of memory address
  1517.         call prhls
  1518.  
  1519.         lda segf
  1520.         or a
  1521.         jp z,pst1
  1522.  
  1523.         pop de
  1524.         pop de
  1525.         jp crlf
  1526.  
  1527. pst1:   ld de,stgds             ;print data & stack space
  1528.         call pstg               ; only if not a segment
  1529.         pop de                  ;get saved top of memory address in DE
  1530.         pop hl                  ;get external ending address in HL
  1531.         call cmphd              ;check for overflow
  1532.         push af         ;save Cy flag for msg later
  1533.         jp c,pst2                       ;externals end before top of memory?
  1534.         ld a,'-'                ;no-- print a negative sign
  1535.         call outch     
  1536.         ex de,hl                        ;exchange so it'll come out positive
  1537. pst2:   call cmh
  1538.         add hl,de
  1539.         call prhls              ;print out amount of stack space
  1540.         call crlf
  1541.         pop af                  ;check for overflow condition
  1542.         ld de,stgdo             ;data overflow message
  1543.         call nc,pstg
  1544.  
  1545. ovrlap: call getcdf2            ;check for externals/code overlap
  1546.         ex de,hl                        ;put end of code addr in DE
  1547.         lhld extadd             ;get external base address
  1548.         call cmphd              ;is external base < end of code + 1?
  1549.         ld de,stgdo2
  1550.         call c,pstg    
  1551.         ret
  1552.  
  1553. wrsmb:  ld a,4
  1554.         sta gotf        ;init symbols-per-line countdown
  1555.         sta wrsmf       ;and make outch write to disk as well as console
  1556.         lda wflg        ;       (to disk only if wflg is on)
  1557.         or a
  1558.         jp z,wrsm2      ;write symbols to disk?
  1559.  
  1560.         IF CPM
  1561.         ld hl,fcbs
  1562.         ld de,fcb
  1563.         call ldfn
  1564.         ld hl,fcb+9
  1565.         ld (hl),'S'
  1566.         inc hl
  1567.         ld (hl),'Y'
  1568.         inc hl
  1569.         ld (hl),'M'
  1570.         ENDIF
  1571.  
  1572.         IF NOT CPM
  1573.         ld hl,fcbs
  1574.         ld de,fcbt
  1575.         push de
  1576.         push de
  1577.         call ldfn
  1578.         pop hl
  1579.         call putext
  1580.            db '.sym',0
  1581.         pop hl
  1582.         ENDIF
  1583.  
  1584.         call crate2     ;if so, create symbols file
  1585.         ld hl,tbuff     ;init buffer pointer
  1586.         shld bufp
  1587. wrsm2:  lhld nsmbs      ;set BC = countdown of # of symbols
  1588.         ld b,h
  1589.         ld c,l
  1590.         ld de,0         ;while DE will go the other way
  1591. wrsm3:  call wsmb       ;write out a single symbol and address
  1592.         inc de          ;bump pointer to next symbol pointer
  1593.         inc de
  1594.         dec bc          ;de-bump countdown
  1595.         ld a,b          ;done?
  1596.         or c
  1597.         jp nz,wrsm3     ;if not, keep loopin'
  1598.  
  1599.         call crlf       ;done. put out trailing crlf
  1600.  
  1601.         IF CPM
  1602.         ld b,1ah        ;terminating control-Z for CP/M (cough cough)
  1603.         lda wflg        ;were we writing to a file?
  1604.         or a
  1605.         call nz,wrb3    ;(into file only)
  1606.         ENDIF
  1607.  
  1608.         xor a
  1609.         sta wrsmf       ;turn off kludge flag
  1610.         lda wflg
  1611.         or a            ;writing to disk?
  1612.         ret z           ;if not, all done
  1613.  
  1614.         IF CPM
  1615.         ld b,1ah        ;if so, pad file with control-Z's for CP/M
  1616.         lhld bufp
  1617.         ld a,l
  1618.         and 7fh        
  1619.         jp z,wrsm6
  1620. wrsm4:  ld a,l
  1621.         and 7fh
  1622.         jp z,wrsm5
  1623.         ld (hl),b
  1624.         inc hl
  1625.         jp wrsm4
  1626. wrsm5:  ld hl,tbuff
  1627.         call writs
  1628.         ENDIF
  1629.  
  1630.         IF NOT CPM      ;for MARC, just write out rest of the buffer
  1631.         lhld bufp
  1632.         ld a,l
  1633.         and 7fh
  1634.         jp z,wrsm6
  1635.         ld e,a          ;put byte count in DE
  1636.         ld d,0
  1637.         ld hl,tbuff
  1638.         call writs      ;write out remainder of symbol text buffer
  1639.         ENDIF
  1640.  
  1641. wrsm6:  call close
  1642.         ret
  1643.  
  1644. wsmb:   push de         ;write out symbol #DE and its value
  1645.         ld hl,tab2      ;first get value
  1646.         add hl,de
  1647.         ld a,(hl)
  1648.         inc hl
  1649.         ld h,(hl)
  1650.         ld l,a          ;HL = raw value
  1651.         push hl         ;add offset    
  1652.         call getcdf
  1653.         pop de
  1654.         add hl,de
  1655.         call prhls      ;print out value in hex
  1656.         ld hl,wsp       ;now get name
  1657.         pop de
  1658.         add hl,de
  1659.         ld a,(hl)
  1660.         inc hl
  1661.         ld h,(hl)
  1662.         ld l,a
  1663.         call pfnm       ;print out name
  1664.         lda gotf        ;see if we trail with tab or crlf
  1665.         dec a
  1666.         sta gotf
  1667.         jp z,wsmbcr
  1668.         ld a,9          ;tab.
  1669.         call outch
  1670.         ret
  1671. wsmbcr: call crlf       ;crlf
  1672.         ld a,4          ;reset line count
  1673.         sta gotf
  1674.         ret
  1675.  
  1676.        
  1677. ;
  1678. ; Alphabetize symbols for SYM file output and stat printout:
  1679. ;
  1680.  
  1681. alphab: call setwsp     ;set up swp with pointers to symbols in tab1
  1682.         ld bc,0         ;initalize outer loop variable
  1683. ab1:    lhld nsmbs      ;done with outer loop?
  1684.         dec hl
  1685.         call cmpbh
  1686.         ret nc          ;if so, all done sorting
  1687.         ld d,b          ;else initialize inner loop
  1688.         ld e,c
  1689.         inc de
  1690. ab2:    lhld nsmbs      ;done with inner iteration?
  1691.         dec hl
  1692.         call cmphd
  1693.         jp c,ab4                ;if so, iterate outer loop
  1694.         call cmptx      ;else compare two symbols
  1695.         jp nc,ab3               ;out of order?
  1696.         ld hl,wsp       ;yes. swap pointers.
  1697.         shld tbase     
  1698.         call swap
  1699.         ld hl,tab2
  1700.         shld tbase
  1701.         call swap
  1702. ab3:    inc de          ;bump inner loop variable
  1703.         jp ab2
  1704. ab4:    inc bc          ;bump outer loop variable
  1705.         jp ab1
  1706.  
  1707. cmpbh:  ld a,b          ;return C set if BC < HL
  1708.         cp h
  1709.         ret nz
  1710.         ld a,c
  1711.         cp l
  1712.         ret
  1713.  
  1714. cmphd:  ld a,h          ;return C set if HL < DE
  1715.         cp d
  1716.         ret nz
  1717.         ld a,l
  1718.         cp e
  1719.         ret
  1720.  
  1721. swap:   lhld tbase      ;switch the 16 bit values at tbase+BC
  1722.         add hl,bc               ;                       and  tbase+DE
  1723.         add hl,bc
  1724.         push bc         ;save BC
  1725.         push hl         ;save tbase+BC
  1726.         ld c,(hl)               ; BC := (tbase+BC)
  1727.         inc hl
  1728.         ld b,(hl)
  1729.         lhld tbase
  1730.         add hl,de
  1731.         add hl,de
  1732.         push de         ;save DE
  1733.         ld e,(hl)               ; DE := (tbase+DE)
  1734.         inc hl
  1735.         ld d,(hl)
  1736.         ld (hl),b               ; (tbase+DE) := (tbase+BC)
  1737.         dec hl
  1738.         ld (hl),c
  1739.         pop hl          ;get back original DE in HL
  1740.         ex de,hl                ;put into DE, and HL:=(tbase+DE)
  1741.         ld b,h          ; BC := (tbase+DE)
  1742.         ld c,l
  1743.         pop hl          ;get back tbase+BC
  1744.         ld (hl),c               ; tbase+BC := tbase+DE
  1745.         inc hl
  1746.         ld (hl),b
  1747.         pop bc          ;and restore original BC
  1748.         ret             ;oh well, so it isn't documented all that greatly!
  1749.  
  1750. setwsp: ld hl,tab1      ;initialize wsp with pointers to entries in tab1
  1751.         ld bc,0         ;symbol count
  1752.         ld de,wsp       ;destination of pointers
  1753. setw2:  ld a,(hl)               ;end of tab1?
  1754.         or a   
  1755.         jp nz,setw3
  1756.         ld h,b          ;yes. set nsmbs to # of symbols found
  1757.         ld l,c
  1758.         shld nsmbs
  1759.         ret             ;and return.
  1760.  
  1761. setw3:  push hl         ;not done. enter pointer into wsp...
  1762.         cp 9dh          ;"main" is a special code; fudge the pointer
  1763.         jp nz,setw4
  1764.         ld hl,stgmn     ;"MAIN'"
  1765.  
  1766. setw4:  ld a,l
  1767.         ld (de),a
  1768.         inc de
  1769.         ld a,h
  1770.         ld (de),a
  1771.         inc de
  1772.         inc bc          ;bump symbol count
  1773.         pop hl          ;restore pointer into tab1
  1774.  
  1775. setw5:  ld a,(hl)               ;pass over symbol text
  1776.         inc hl 
  1777.         or a
  1778.         jp p,setw5
  1779.  
  1780.         ld a,(hl)               ;and references (if any)
  1781.         and 7fh
  1782.         push de
  1783.         ld d,a
  1784.         inc hl
  1785.         ld e,(hl)
  1786.         inc hl
  1787.         add hl,de
  1788.         add hl,de
  1789.         pop de
  1790.         jp setw2        ;and go to next symbol
  1791.  
  1792. cmptx:  push bc         ;compare two symbols
  1793.         push de         ;return C set if wsp(BC) > wsp(DE)
  1794.         ld hl,wsp
  1795.         add hl,de
  1796.         add hl,de
  1797.         ld e,(hl)
  1798.         inc hl
  1799.         ld d,(hl)               ;DE points to second symbol
  1800.         ld hl,wsp
  1801.         add hl,bc
  1802.         add hl,bc
  1803.         ld c,(hl)
  1804.         inc hl
  1805.         ld b,(hl)               ;BC points to first symbol
  1806.         call cmpt2      ;compare symbols at BC and DE
  1807.         pop de          ;restore registers
  1808.         pop bc
  1809.         ret
  1810.  
  1811. cmpt2:  ld a,(bc)               ;get char
  1812.         and 7fh         ;strip end-of-symbol bit
  1813.         ld h,a          ;save
  1814.         ld a,(de)               ;do same with other symbol
  1815.         and 7fh
  1816.         cp h            ;compare with first one
  1817.         ret nz          ;if not same, all done
  1818.         ld a,(de)               ;else...is 2nd symbol ended?
  1819.         or a
  1820.         jp p,cmpt3
  1821.         ld a,(bc)               ;yes..result depends on whether
  1822.         or a            ;1st symbol is ended...
  1823.         scf
  1824.         ret p
  1825.         ccf
  1826.         ret
  1827.  
  1828. cmpt3:  ld a,(bc)               ;is 1st symbol ended?
  1829.         or a
  1830.         ret m           ;if so, it must be smaller than second.
  1831.         inc bc          ;else check next character...
  1832.         inc de
  1833.         jp cmpt2
  1834.  
  1835. ;
  1836. ; Print out the function name pointed to by HL for the SYM file and
  1837. ; stat report:
  1838. ;
  1839.  
  1840. pfnm:   push bc
  1841.         ld b,0          ;char count
  1842. pfnm1:  inc b
  1843.         ld a,(hl)
  1844.         push af
  1845.         inc hl
  1846.         and 7fh
  1847.         call outch
  1848.         pop af
  1849.         or a
  1850.         jp p,pfnm1
  1851.         ld a,b
  1852.         pop bc
  1853.         cp 3            ;if >= 3 characters, ignore
  1854.         ret nc
  1855.         ld a,9          ;else follow with a tab
  1856.         jp outch
  1857.  
  1858. ;
  1859. ; Print out the value in HL in hex and follow by a space:
  1860. ;
  1861.  
  1862. prhls:  call prhl
  1863.         ld a,' '
  1864.         jp outch
  1865.  
  1866. ;
  1867. ; Print out the value in HL in hex and follow by a comma:
  1868. ;
  1869.  
  1870. prhlc:  call prhl
  1871.         ld a,','
  1872.         jp outch
  1873.  
  1874. ;
  1875. ; Print out the value in HL in hex:
  1876. ;
  1877.  
  1878. prhl:   ld a,h
  1879.         call pra
  1880.         ld a,l
  1881.         jp pra
  1882.  
  1883. ;
  1884. ; Print out the value in A in hex:
  1885. ;
  1886.  
  1887. pra:    push af
  1888.         rrca
  1889.         rrca
  1890.         rrca
  1891.         rrca
  1892.         call prhd
  1893.         pop af
  1894.  
  1895. ;
  1896. ; Print out the hex digit in A:
  1897. ;
  1898.  
  1899. prhd:   and 15
  1900.         add a,30h
  1901.         cp 3ah
  1902.         jp c,outch
  1903.         add a,7
  1904.         jp outch
  1905.  
  1906. writf:
  1907.         IF 1==0;CPM             ;don't bother with debugging kludge under MARC yet
  1908.         lda debugf      ;debugging before output?
  1909.         or a
  1910.         jp z,writf0     ;if not, go write out CRL file
  1911.  
  1912.         lda nflag       ;don't try it if -n given, though...
  1913.         or a
  1914.         jp nz,writf0
  1915.  
  1916.         ld de,stgdeb    ;yes. tell about debugging
  1917.         call pstg
  1918.  
  1919.         ld b,0          ;first assume no text string
  1920.  
  1921.         lda debugf      ;now, was a text string given?
  1922.         dec a
  1923.         jp z,copybt     ;if not, just go ahead and do the bootstrap
  1924.  
  1925.         lhld argptr     ;else copy the text line down into tbuff
  1926.         ex de,hl                ;DE points to the text
  1927.         ld hl,tbuff+1   ;HL points into tbuff
  1928.         ld (hl),' '     ;stick in a leading space for good measure
  1929.         inc hl
  1930.         inc b
  1931. cpytxt: ld a,(de)               ;get next text character
  1932.         call mapuc      ;map to upper case just like CP/M does
  1933.         cp '"'          ;end of text?
  1934.         jp z,copybt     ;if so, go set line length and copy bootc
  1935.         ld (hl),a               ;else store the character
  1936.         inc hl          ;bump destination ptr
  1937.         inc de          ;bump source ptr
  1938.         inc b           ;bump char count
  1939.         jp cpytxt       ;and loop till done.
  1940.  
  1941. copybt: ld a,b          ;get text line count
  1942.         sta tbuff       ;set it for the argc&argv processor
  1943.  
  1944.         ld hl,boots     ;the bootstrap
  1945.         ld de,bootsa    ;where it's going
  1946.         ld b,bbytes     ;length of it
  1947. bootlp: ld a,(hl)
  1948.         ld (de),a
  1949.         inc hl
  1950.         inc de
  1951.         dec b
  1952.         jp nz,bootlp
  1953.  
  1954.         jp bootsa       ;and go copy the program and run it
  1955.  
  1956. ;
  1957. ; This is the bootstrap code, to copy the linked COM file down
  1958. ; into the tpa and run it.
  1959. ;
  1960.  
  1961. bootsa: equ tbuff+90    ;where this boot will reside
  1962.  
  1963. boots:  lhld cda        ;source addr.
  1964.         ex de,hl                ;  into DE
  1965.         lhld cdp        ;last addr. of code + 1
  1966.         ld b,h
  1967.         ld c,l          ;put last addr. in BC
  1968.         ld hl,tpa       ;destination (start of TPA)
  1969. boots1: ld a,(de)               ;copy a byte
  1970.         ld (hl),a
  1971.         inc hl
  1972.         inc de
  1973.         ld a,d          ;done yet?
  1974.         cp b
  1975.         jp nz,bootsa+12 ;jp nz,boots1
  1976.         ld a,e
  1977.         cp c
  1978.         jp nz,bootsa+12
  1979.         jp tpa          ;yes. Go execute code
  1980.  
  1981. bbytes: equ $-boots
  1982.         ENDIF           ;end of CP/M-only debugging hack, 4 the time being
  1983.  
  1984. writf0:
  1985.         IF MARC         ;under MARC, put an ".out" extension by default
  1986.         ld hl,fcbs
  1987.         push hl         ;save for create...
  1988.         push hl         ;save for ldfn...
  1989.         lda oflag       ;was -o option given?
  1990.         or a
  1991.         jp nz,writf1    ;if so, don't append '.out' to filename
  1992.         call putext
  1993.            db '.out',0
  1994. writf1:
  1995.         pop hl
  1996.         ld de,fcbt      ;copy into fcbt for error reporting
  1997.         call ldfn
  1998.  
  1999.         pop hl          ;create new version
  2000.         ld de,755q      ;protection mode allows execution
  2001.         call create
  2002.         ENDIF
  2003.  
  2004.         IF CPM
  2005.         call crate      ;create an output file under CP/M
  2006.         ENDIF
  2007.  
  2008.         lhld cda
  2009.        
  2010.         IF CPM          ;under CP/M, copy and write one sector at a time
  2011. writ2:  call copys
  2012.         push af
  2013.         push hl
  2014.         ld hl,tbuff
  2015.         call writs
  2016.         pop hl
  2017.         pop af
  2018.         jp nc,writ2
  2019.         ENDIF  
  2020.  
  2021.         IF NOT CPM      ;under MARC
  2022.         push hl         ;save starting address
  2023.         call cmh
  2024.         ex de,hl
  2025.         lhld cdp        ;get ending address
  2026.         add hl,de               ;subtract starting address
  2027.         inc hl          ;add one to get length of file to write
  2028.         ex de,hl                ;put length in DE
  2029.         pop hl          ;get back starting address
  2030.                         ;now HL = start, DE = length
  2031.         lda iflag       ;doing image mode?
  2032.         or a
  2033.         jp z,writld     ;if not, go write MARC load format file
  2034.  
  2035.         call writs      ;write it out  
  2036.         jp close
  2037.  
  2038. writld: push hl         ;save object code starting address
  2039.         lhld runsat     ;get load address
  2040.         shld runsav     ;save for load address record at end of write
  2041.         pop hl          ;restore code starting addr
  2042.  
  2043. wrtld1: call doblck     ;set up and write out a block of object file data
  2044.         jp nz,wrtld1    ;keep going till all data has been written
  2045.         ld a,1          ;now write out load address record
  2046.         sta doblck      ;use where "doblck" code was for a buffer
  2047.         lhld runsav     ;get load address
  2048.         shld doblck+1
  2049.  
  2050.         ld hl,0400h     ;this gets stored as "00 04"
  2051.         shld doblck+3
  2052.  
  2053.         ld hl,doblck    ;  as load address.
  2054.         ld de,5         ;four bytes for load address record, plus EOF byte
  2055.         call writs      ;and write out this final record
  2056.         ENDIF
  2057.  
  2058.         jp close
  2059.  
  2060.         IF MARC
  2061. doblck: shld datap      ;save object code pointer for later use
  2062.         dec hl          ;HL--> where length byte goes
  2063.         ld a,d          ;more than 255 bytes left to write?
  2064.         or a
  2065.         sta endtst      ;(save for EOF Test later)
  2066.         ld c,e          ;in case this is the last, put count in c
  2067.         jp z,sets2      ;and go away if this is the last
  2068.  
  2069.         push hl         ;else subtract 255 from DE
  2070.         ld hl,-255
  2071.         add hl,de
  2072.         ex de,hl
  2073.         pop hl
  2074.  
  2075.         ld c,255        ;and set count = 255
  2076. sets2:  ld (hl),c               ;set length count byte for this block
  2077.         dec hl
  2078.  
  2079.         push de         ;C contains byte count; save countDOWN register on stk
  2080.         ex de,hl                ;save memory pointer in DE
  2081.         lhld runsat     ;get load address for this block
  2082.         ex de,hl                ;put into DE
  2083.         ld (hl),d               ;transfer to memory
  2084.         dec hl
  2085.         ld (hl),e
  2086.         dec hl
  2087.         ld (hl),1               ;abs record header byte
  2088.  
  2089.         push hl         ;save start of block for writs
  2090.  
  2091.         ld l,c          ;update load address
  2092.         ld h,0
  2093.         add hl,de               ;by adding byte count to old load address
  2094.         shld runsat     ;and get it ready for the next iteration
  2095.  
  2096.         push bc         ;save C for count total later
  2097.         lhld datap      ;compute checksum. get pointer to start of data
  2098.         xor a           ;clear checksum accumulation
  2099. sets3:  add m           ;add next byte
  2100.         inc hl          ;bump memory pointer
  2101.         dec c           ;de-bump countdown
  2102.         jp nz,sets3     ;keep going till done
  2103.  
  2104.         cpl             ;negate A to acheive actual checksum byte
  2105.         inc a
  2106.         ld b,a          ;save checksum in B
  2107.         ld a,(hl)               ;get byte of data AFTER end of block
  2108.         sta btsav       ;save somewhere for later restortion
  2109.         ld (hl),b               ;replace with checksum (kludge, kludge)
  2110.  
  2111.         pop bc          ;get back byte count in C
  2112.         ld b,0          ;use to compute total size of block to be written
  2113.         ld hl,5         ;fudge factor because of ld format overhead
  2114.         add hl,bc               ;add to byte count to get total # byte to write
  2115.         ex de,hl                ;put into DE for writs routine
  2116.         pop hl          ;get pointer to start of block
  2117.         push de         ;save this stuff
  2118.         push hl
  2119.         call writs      ;write the block
  2120.         pop hl          ;restore this stuff
  2121.         pop de
  2122.         add hl,de               ;get pointer to start of data for NEXT block
  2123.         dec hl          ;point back to checksum byte, which overwrote data
  2124.         lda btsav       ;get back the byte butchered by the checksum byte
  2125.         ld (hl),a               ;restore it to its proper place
  2126.         pop de          ;get back countdown register
  2127.         lda endtst      ;was this the last block? if so, endtst will be zero
  2128.         or a            ;set the Z flag if so, so we don't come here again...
  2129.         ret
  2130.  
  2131.         ENDIF
  2132.  
  2133.  
  2134.  
  2135.         IF CPM          ;only need this sector copy kludge under CP/M
  2136. copys:  ld de,tbuff
  2137.         ld b,80h
  2138. copy1:  ld a,(hl)
  2139.         ld (de),a
  2140.         push de
  2141.         ex de,hl
  2142.         lhld cdp
  2143.         ld a,h
  2144.         cp d
  2145.         jp nz,copy2
  2146.         ld a,l
  2147.         cp e
  2148.         jp z,copy3
  2149. copy2:  ex de,hl
  2150.         pop de
  2151.         inc hl
  2152.         inc de
  2153.         dec b
  2154.         jp nz,copy1
  2155.         xor a
  2156.         ret
  2157.  
  2158. copy3:  pop de
  2159. copy4:  dec b
  2160.         jp z,copy5
  2161.         ld a,1ah
  2162.         ld (de),a
  2163.         inc de
  2164.         jp copy4
  2165. copy5:  scf
  2166.         ret
  2167.         ENDIF           ;end of sector copy kludge
  2168.  
  2169. ;
  2170. ; Open a file. Under CP/M, the default fcb is assumed to have been
  2171. ; set up for a file. Under MARC, a name pointer is passed in HL
  2172. ; and location "marcfd" is set here to the file descriptor returned
  2173. ; by the MARC system call; register A is 0 for opening for READ, or
  2174. ; 1 for WRITE.
  2175. ;
  2176.  
  2177. open:   push bc         ;save registers
  2178.         push de
  2179.         push hl
  2180.  
  2181.         IF TESTING
  2182.         push af
  2183.         call printf
  2184.           db 'trying to open: ',0
  2185.         push hl
  2186.         call pfnamu
  2187.         pop hl
  2188.         pop af
  2189.         ENDIF
  2190.  
  2191.         IF CPM
  2192.          xor a
  2193.          sta fcb+_rrn
  2194.          sta fcb+_rrn+1
  2195.         ld de,fcb
  2196.         ld c,openfil
  2197.         call bdos
  2198.         ENDIF
  2199.  
  2200.         IF NOT CPM
  2201.         ld c,m$open
  2202.         call msys
  2203.         ENDIF
  2204.  
  2205.         IF CPM
  2206.         cp 255          ;return value of 255 from CP/M's 'open' means error
  2207.         jp nz,op2
  2208.         ENDIF
  2209.  
  2210.         IF NOT CPM
  2211.         jp z,op2                ;Z flag under MARC indicates success
  2212.         ENDIF
  2213.  
  2214.         ld de,stg1      ;spew an error.
  2215. op1:    lda quietf      ;be quiet about it?
  2216.         or a
  2217.         call z,pstg
  2218.         ld a,0          ;clear quietf.
  2219.         sta quietf     
  2220.  
  2221.         IF MARC
  2222.         pop hl
  2223.         push hl         ;get filename string for MARC pfnam routine
  2224.         ENDIF
  2225.  
  2226.         call z,pfnamu   ;tell name of file that can't be opened
  2227.         scf             ;set carry to indicate error to calling routine
  2228.         jp op3
  2229.  
  2230. op2:
  2231.         IF CPM
  2232.         xor a
  2233.         sta nr
  2234.         ENDIF
  2235.  
  2236.         IF NOT CPM
  2237.         sta marcfd      ;store fd for file only if it opened correctly
  2238.         ENDIF
  2239.  
  2240.         IF TESTING
  2241.         call printf
  2242.           db '....opened OK',0
  2243.         ENDIF
  2244.  
  2245. op3:    pop hl
  2246.         pop de
  2247.         pop bc
  2248.         ret
  2249.  
  2250.  
  2251. ;
  2252. ; Close a file. Under CP/M, also zero out the extent field so the
  2253. ; next routine to use the default fcb doesn't go apeshit opening
  2254. ; the wrong extent.
  2255. ;
  2256.  
  2257.  
  2258. close:
  2259.         IF TESTING
  2260.         call printf
  2261.            db 'closing...',0
  2262.         ENDIF
  2263.  
  2264.         IF CPM
  2265.         push bc
  2266.         push de
  2267.         push hl
  2268.         ld de,fcb
  2269.         ld c,closefil
  2270.         call bdos
  2271.         ld hl,fcb+12
  2272.         ld (hl),0
  2273.         pop hl
  2274.         pop de
  2275.         pop bc
  2276.         cp 255
  2277.         ret nz
  2278.         ld de,stg4
  2279.         jp c2
  2280.         ENDIF
  2281.  
  2282.         IF NOT CPM
  2283.         lda marcfd
  2284.         ld c,m$close
  2285.         call msys
  2286.         jp nz,ferror
  2287.         ld a,0
  2288.         sta marcfd      ;clear fd byte for error recovery
  2289.         ret
  2290.         ENDIF
  2291.  
  2292.  
  2293. ;
  2294. ; Delete a file. Name is in default fcb for CP/M, or passed in HL
  2295. ; for MARC:
  2296. ;
  2297.  
  2298. delfil:
  2299.         IF CPM
  2300.         ld de,fcb
  2301.         ld hl,fcb+12
  2302.         ld (hl),0
  2303.         ld c,delete
  2304.         jp bdos
  2305.         ENDIF
  2306.  
  2307.         IF NOT CPM
  2308.         ld c,m$unlink
  2309.         call msys
  2310.         jp nz,ferror
  2311.         ret
  2312.         ENDIF
  2313.  
  2314.  
  2315.  
  2316.  
  2317. ;
  2318. ; Create a file and open it, first deleting any old version.
  2319. ; Filename is set up in default fcb under CP/M, or pointed to by
  2320. ; HL under MARC:
  2321. ;
  2322.  
  2323. crate:
  2324.         IF CPM
  2325.         ld hl,fcbs
  2326.         ld de,fcb
  2327.         call ldfn
  2328. crate2: call delfil
  2329.         call create
  2330. ;       call open       ;don't need to call open, since "create" does it for us
  2331.         ret
  2332.         ENDIF
  2333.  
  2334.         IF NOT CPM
  2335. crate2: ld de,644q      ;protection mode
  2336.         jp create
  2337.         ENDIF
  2338.  
  2339.  
  2340. ;
  2341. ; Create a new file. Default fcb is set up under CP/M; name pointer
  2342. ; is passed under MARC along with a protection mode in DE; marcfd
  2343. ; is set to the fd of the file (since the creat call opens it for writing):
  2344. ;
  2345.  
  2346.  
  2347. create:
  2348.         IF CPM
  2349.         ld de,fcb
  2350.         ld hl,fcb+12
  2351.         ld (hl),0
  2352.         ld hl,fcb+32
  2353.         ld (hl),0
  2354.          inc hl
  2355.          ld (hl),0 ;_rrn
  2356.          inc hl
  2357.          ld (hl),0 ;_rrn+1
  2358.         ld c,makfil
  2359.         call bdos
  2360.         cp 255
  2361.         ret nz
  2362.         ld de,stg5
  2363.         jp c2
  2364.         ENDIF
  2365.  
  2366.         IF NOT CPM
  2367.         ld c,m$creat
  2368.         call msys
  2369.         jp nz,ferror
  2370.         sta marcfd      ;save the fd if it got created OK
  2371.         ret
  2372.         ENDIF  
  2373.  
  2374.  
  2375. ;
  2376. ; Under CP/M, reads in a sector of data from the default fcb,
  2377. ; setting the Carry flag on end of file,
  2378. ; and prints something appropriately nasty on error. Under MARC,
  2379. ; reads in DE bytes to memory at HL from the currently open file:
  2380. ;
  2381.  
  2382. reads: 
  2383.         IF CPM
  2384.         push hl         ;under CP/M
  2385.         push de
  2386.         ld de,fcb
  2387.         ld c,CMD_RNDRD;rsequen
  2388.         call bdos       ;read a sector
  2389.          ld hl,(fcb+_rrn) ;ok
  2390.          inc hl
  2391.          ld (fcb+_rrn),hl ;ok
  2392.         pop de
  2393.         pop hl
  2394.         or a
  2395.         ret z           ;error?
  2396.         ;dec a          ;maybe.
  2397.         scf
  2398.         ret ;z          ;return carry if EOF
  2399.         ENDIF           ;else fall through to error reporting routine
  2400.  
  2401.  
  2402.         IF MARC         ;under MARC:
  2403.         lda marcfd
  2404.         ld c,m$read
  2405.         push de         ;save byte count
  2406.         call msys       ;read data
  2407.         pop bc          ;get back byte count in BC
  2408.         jp nz,ferror
  2409.         ld a,d
  2410.         cp b
  2411.         jp nz,reads1
  2412.         ld a,e
  2413.         cp c
  2414.         ret z
  2415.  
  2416. ;       ld a,d
  2417. ;       or e            ;is DE zero? if so, EOF: an error here
  2418. ;       ret nz
  2419.         ENDIF
  2420.  
  2421. reads1: ld de,stg2      ;read error: barfsville
  2422.         jp c2
  2423.  
  2424.  
  2425. ;
  2426. ; Write a sector of data to the file in the default fcb under CP/M;
  2427. ; write DE bytes from memory at HL to the "marcfd" file under MARC:
  2428. ;
  2429.  
  2430. writs:
  2431.         IF CPM
  2432.         push de
  2433.         push hl
  2434.         ld c,wsequen
  2435.         ld de,fcb
  2436.         call bdos
  2437.         pop hl
  2438.         pop de
  2439.         or a
  2440.         ret z
  2441.         ENDIF
  2442.  
  2443.         IF NOT CPM
  2444.         ld c,m$write
  2445.         lda marcfd
  2446.         call msys
  2447.         ret z
  2448.         jp ferror
  2449.         ENDIF  
  2450.  
  2451.         ld de,stg3      ;write error: complain
  2452.         jp c2
  2453.  
  2454. ;
  2455. ; Read a character from the standard input (console only under CP/M):
  2456. ;
  2457.  
  2458. inch:
  2459.         IF CPM
  2460.         push bc
  2461.         push hl
  2462.         ;ld c,coninp
  2463.         ;call bdos
  2464.         call yieldgetkeyloop ;YIELDGETKEYLOOP
  2465.         pop hl
  2466.         pop bc
  2467.         ENDIF
  2468.  
  2469.         IF NOT CPM
  2470.         xor a           ;standard input under MARC
  2471.         ld c,m$getcf
  2472.         call msys
  2473.         jp nz,ferror
  2474.         ENDIF
  2475.  
  2476.         IF CPM
  2477.         call mapuc
  2478.         ENDIF
  2479.  
  2480.         cp key_esc;3
  2481.         jp z,abort
  2482.         ret
  2483.  
  2484. ;
  2485. ; Print a CR-LF onto standard output (console only under CP/M):
  2486. ;
  2487.  
  2488. crlf:   IF CPM
  2489.         ld a,cr
  2490.         call outch
  2491.         ENDIF
  2492.  
  2493.         ld a,lf         ;and fall through to outch
  2494.  
  2495. ;
  2496. ; Write a character to standard output, and to the symbols file
  2497. ; if wrsmf flag is active:
  2498. ;
  2499.  
  2500. outch:
  2501.         IF MARC
  2502.         cp cr           ;ignore CR's under MARC
  2503.         ret z
  2504.         ENDIF
  2505.  
  2506.         push hl
  2507.         push bc
  2508.         push de
  2509.         push af
  2510.         ld b,a
  2511.         lda wrsmf       ;if wrsmf true,
  2512.         or a
  2513.         jp z,outc1
  2514.         ld a,b          ;do it all in wrb
  2515.         call wrb
  2516.         jp outc1a
  2517.  
  2518. outc1:  ld a,b          ;otherwise just put out to the console
  2519.         call outch2
  2520.  
  2521. outc1a: pop af
  2522.         pop de
  2523.         pop bc
  2524.         pop hl
  2525.         ret
  2526.  
  2527.  
  2528. ;
  2529. ; Write the character in A to the standard output (console only under CP/M):
  2530. ;
  2531.  
  2532. outch2:
  2533.         IF CPM
  2534.         push bc
  2535.         ;ld c,conout
  2536.         ;ld e,a
  2537.         ;call bdos
  2538.         PRCHAR_
  2539.         pop bc
  2540.         ret
  2541.         ENDIF
  2542.        
  2543.         IF NOT CPM      ; for MARC:
  2544.         ld b,a          ;put character in B
  2545.         lda consfd      ;stdout or stderr under MARC   
  2546.         ld c,m$putcf
  2547.         call msys
  2548.         jp nz,ferror
  2549.         ret
  2550.         ENDIF
  2551.  
  2552.  
  2553. wrb:    ld b,a          ;write out a byte of symbol table text
  2554.         lda statf       ;displaying symbol values on console?
  2555.         or a
  2556.         jp z,wrb2
  2557.         ld a,b          ;yes. do it.
  2558.         call outch2
  2559. wrb2:   lda wflg        ;writing symbols to disk?
  2560.         or a
  2561.         ret z
  2562. wrb3:   push hl
  2563.         lhld bufp      
  2564.         ld (hl),b
  2565.         inc hl
  2566.         ld a,l
  2567.         and 7fh
  2568.         jp nz,wrb4
  2569.  
  2570.         IF MARC
  2571.         ld de,128
  2572.         ENDIF
  2573.  
  2574.         ld hl,tbuff
  2575.         call writs      ;if buffer full, dump to disk
  2576. wrb4:   shld bufp
  2577.         pop hl
  2578.         ret
  2579.  
  2580.         IF MARC
  2581. pfnam:  ex de,hl                ;for MARC, put name pointer in DE
  2582.         call pstg
  2583.         call crlf
  2584.         ret
  2585.         ENDIF
  2586.  
  2587. pstg:   push af
  2588. pstg1:  ld a,(de)
  2589.         or a
  2590.         jp nz,pstg2
  2591.         pop af
  2592.         ret
  2593. pstg2:  call outch
  2594.         inc de
  2595.         jp pstg1
  2596.  
  2597. gnfl:
  2598.         IF CPM
  2599.         call scrl       ;set CRL extension
  2600.         lda quietf
  2601.         ld b,a
  2602.         ld a,1
  2603.         sta quietf      ;don't complain yet under CP/M
  2604.         ENDIF
  2605.  
  2606.         xor a
  2607.         call open       ;try to open for reading
  2608.  
  2609.         IF CPM
  2610.         ld a,b
  2611.         sta quietf
  2612.         ENDIF  
  2613.  
  2614.         IF MARC
  2615.         ret c           ;don't read in directory if not there
  2616.         ENDIF
  2617.  
  2618. ;       IF CPM
  2619.         jp nc,gnflok    ;found in first path? if so, go process
  2620.  
  2621.         lda search      ;no. should we search default area also?
  2622.         or a
  2623.         jp z,cmpln      ;if not, go complain
  2624.  
  2625.         ;lda defusr     ;now try default disk and user area
  2626.         ;ld e,a
  2627.         ;inc a          ;default user area is current user area?
  2628.         ;jp z,gnfl2     ;if so, don't change
  2629.         ;ld c,sguser
  2630.         ;lda nouser
  2631.         ;or a
  2632.         ;IF NOT ALPHA
  2633.         ;call z,bdos
  2634.         ;ENDIF
  2635.  
  2636. gnfl2:  lda defdsk      ;default disk current disk?
  2637.         ld e,a
  2638.         cp 0ffh ;if so, don't switch
  2639.         jp z,gnfl3
  2640.  
  2641.         ;push de
  2642.         ;ld c,gdisk     ;first get and save currently logged drive
  2643.         ;call bdos
  2644.         ;inc a          ;add 1 so A == 1, and 0 can mean "unused"
  2645.          xor a ;TODO getpath
  2646.         sta savdrv
  2647.         ;pop de         ;get back drive to switch to in E
  2648.         ;ld c,select
  2649.         ;call bdos
  2650.  
  2651. gnfl3:  xor a           ;now try to open in new directory
  2652.         call open
  2653.         jp nc,gnflok    ;and go on processing if we finally found it
  2654.         ret             ;else return, since this time "open" printed an error
  2655.  
  2656. cmpln:  lda quietf      ;do we bitch?
  2657.         or a
  2658.         scf
  2659.         ret nz          ;if quietf set, don't bitch, just set Cy and return
  2660.         ld de,stg1      ;can't find:
  2661.         call pstg
  2662.         call pfnamu     ;print filename
  2663.         scf             ;and return Cy set to indicate failure
  2664.         ret
  2665.  
  2666. gnflok:
  2667. ;       ENDIF
  2668.  
  2669.         ld hl,direc
  2670.  
  2671.         IF CPM          ;read in directory under CP/M one sector at a time
  2672.         call reads
  2673.         call cpys
  2674.         call reads
  2675.         call cpys
  2676.         call reads
  2677.         call cpys
  2678.         call reads
  2679.         call cpys
  2680.         ENDIF
  2681.        
  2682.         IF NOT CPM      ;under MARC  just read in 512 bytes
  2683.         ld de,512
  2684.         call reads
  2685.         ENDIF
  2686.  
  2687.         xor a           ;clear carry
  2688.         ret
  2689.  
  2690. scrl:
  2691.         IF CPM
  2692.         ld hl,fcb+9
  2693.         ld (hl),'C'
  2694.         inc hl
  2695.         ld (hl),'R'
  2696.         inc hl
  2697.         ld (hl),'L'
  2698.         ret
  2699.         ENDIF
  2700.  
  2701.         IF NOT CPM
  2702.         call putext
  2703.            db '.crl',0
  2704.         ret
  2705.         ENDIF
  2706.  
  2707.         IF CPM
  2708. cpys:   ld de,tbuff
  2709.         ld b,80h
  2710. cps2:   ld a,(de)
  2711.         ld (hl),a
  2712.         inc hl
  2713.         inc de
  2714.         dec b
  2715.         jp nz,cps2
  2716.         ret
  2717.         ENDIF           ;end of CP/M-only stuff
  2718.  
  2719.  
  2720.  
  2721.  
  2722. ;
  2723. ; Get any functions out of the currently open CRL file
  2724. ; as may be needed, until the supply is exhausted:
  2725. ;
  2726.  
  2727. gtfns:  lda fflag       ;force loading of all function in this crl file?
  2728.         or a
  2729.         jp z,gtfn0      ;if not, go scan normally for needed functions
  2730.  
  2731. ;
  2732. ; Load in EVERY function in the currently open CRL file. Once this works,
  2733. ; it should also refrain from loading any functions which have already been
  2734. ; loaded...
  2735. ;
  2736.  
  2737.         ld hl,direc     ;and try to get every function we can...
  2738. gtfn00: ld a,(hl)
  2739.         cp 80h          ;end of directory?
  2740.         jp z,gtfn03     ;if so, done with this crl file
  2741.         push hl
  2742.         push hl
  2743.         shld savnam     ;save a pointer to the name for entt1 to bitch with
  2744.         call pb7hi      ;pass name (we don't care about it yet)
  2745.         call ft23a      ;else set function parameters for rdfun
  2746.         pop hl
  2747.         ld a,1          ;say that we got it
  2748.         sta gotf
  2749.         sta rdngsm      ;set this so symbol routine does duplicate checking
  2750.         call entt1      ;enter into tab1 as gotten
  2751.         lda gotf        ;was it a duplicate?
  2752.         cp 81h
  2753.         call nz,pre             ;read it in and process if not a duplicate
  2754. gtfn02: pop hl          ;get back pointer to directory
  2755.         call pb7hi      ;pass over name of the function we just read in
  2756.         inc hl          ;and its address
  2757.         inc hl
  2758.         jp gtfn00       ;and go for the next one.
  2759.  
  2760. gtfn03:
  2761.         IF NOT FORCE
  2762.         xor a
  2763.         sta fflag       ;turn off forcing after this file.
  2764.         ENDIF
  2765.         sta rdngsm      ;and reset this also
  2766.         jp close        ;and go close the current one
  2767.  
  2768. ;
  2769. ; Scan the current CRL file for NEEDED functions only (restarting scan
  2770. ; every time one is loaded, so any local backward-references are
  2771. ; resolved):
  2772. ;
  2773.  
  2774. gtfn0:  ld hl,tab1      ;init needed-function table pointer
  2775.         shld fngtt
  2776. gtfn1:  call fung2      ;any more ungotten functions in the n-f table?
  2777.         jp c,close      ;if not, all done with this crl file
  2778.         push hl
  2779.         call ft2        ;else see if the next needed function is in the
  2780.         pop hl          ;  current CRL file
  2781.         jp c,gtfn1      ;is it?
  2782.         ld a,1          ;yes.
  2783.         sta gotf        ;say that we got it
  2784.         call entt1      ;enter the fact in tab1
  2785.         call pre        ;and actually read it in
  2786.         jp gtfn1        ;and go for more
  2787.  
  2788. ;
  2789. ; This routine scans through the entire needed-function table for
  2790. ; any non-loaded needed function entries. As soon as one is found,
  2791. ; HL is returned with a pointer to the loaded byte for that entry, and
  2792. ; Z is set. Z is returned NOT set if there aren't any more unloaded functions:
  2793. ;
  2794.  
  2795. fungt:  ld hl,tab1      ;start at the beginning
  2796.         shld fngtt
  2797.  
  2798. ;
  2799. ; This routine scans the needed-function table from the current position
  2800. ; of the table pointer (fngtt) to the end, looking for unloaded needed
  2801. ; functions. See above for return values.
  2802. ;
  2803.  
  2804. fung2:  lhld fngtt      ;get pointer into tab1
  2805. fng21:  push hl
  2806.         call past1e
  2807.         shld fngtt
  2808.         pop hl
  2809.         ld a,(hl)
  2810.         or a
  2811.         scf
  2812.         ret z
  2813.         push hl
  2814. fng22:  call pb7hi      ;pass function name
  2815.         ld a,(hl)               ;next byte a zero?
  2816.         or a
  2817.         pop hl
  2818.         jp m,fung2
  2819.         ret             ;no...so
  2820.  
  2821.  
  2822. past1e: call pb7hi
  2823.         push de
  2824.         ld a,(hl)
  2825.         and 7fh
  2826.         ld d,a
  2827.         inc hl
  2828.         ld e,(hl)
  2829.         inc hl
  2830.         ex de,hl
  2831.         add hl,hl
  2832.         add hl,de
  2833.         pop de
  2834.         ret
  2835.  
  2836.  
  2837. pb7hi:  ld a,(hl)
  2838.         inc hl
  2839.         or a
  2840.         jp p,pb7hi
  2841.         ret
  2842.  
  2843.  
  2844. mapuc:  cp 61h
  2845.         ret c
  2846.         cp 7bh
  2847.         ret nc
  2848.         sub 32
  2849.         ret
  2850.  
  2851. ;
  2852. ; This routine scans the current CRL file directory for an occurence of
  2853. ; the function whose name is pointed to by HL. If found, Cy is returned not
  2854. ; set. Cy is returned set if not found, of course:
  2855. ;
  2856.  
  2857. ft2:    push hl         ;save the name pointer
  2858.         ex de,hl                ;and also put in DE
  2859.         ld hl,direc     ;start at the beginning of directory
  2860. ft21:   ld a,(hl)               ;end of directory?
  2861.         cp 80h
  2862.         jp nz,ft22
  2863.         pop hl          ;yes. no match found, so set carry and return
  2864.         scf
  2865.         ret
  2866.  
  2867. ft22:   call stcmp      ;not end of directory. current entry match?
  2868.         jp nz,ft24
  2869.  
  2870. ft23:   call ft23a
  2871.         pop hl          ;all done. Note carry isn't set because of pb7hi
  2872.         ret
  2873.  
  2874. ft23a:  ld a,(hl)               ;yes--next two bytes after name are file address
  2875.         inc hl          ;put the file address in HL
  2876.         push hl
  2877.         ld h,(hl)
  2878.         ld l,a
  2879.         shld enst       ;save for rdfun to use in loading it later
  2880.         pop hl          ;find out what the address after the subsequent
  2881.         inc hl          ;entry is, to get ending address in file...
  2882.         call pb7hi
  2883.         ld a,(hl)               ;here it is. load into HL
  2884.         inc hl
  2885.         ld h,(hl)
  2886.         ld l,a
  2887.         shld enend      ;and save for rdfun
  2888.         ret
  2889.  
  2890. ft24:   call pb7hi      ;no match. go on to next entry
  2891.         inc hl
  2892.         inc hl
  2893.         jp ft21
  2894.  
  2895.         ;IF LASM
  2896.         ;link clinkb
  2897.         ;ENDIF
  2898.