home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol068 / unspol33.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  20.2 KB  |  945 lines

  1.      TITLE 'UNSPOOL Disk to device background process'
  2. ;
  3. VERSION    EQU    3$3    ;Version number
  4. ;
  5. ;Author:
  6. ;    Gary P. Novosielski
  7. ;
  8. ;NOTE:    This source file requires MAC for assembly.
  9. ; Due to the complexity of operations performed by
  10. ; the macros which generate the relocation table, the
  11. ; assembly process will be significantly longer than
  12. ; normal for a program of this size.  Be prepared for
  13. ; a long period of no disk activity on each pass before
  14. ; pressing the panic button.
  15. ;
  16. ;Revisions:        (in LIFO order)
  17. ;3.3    82-01-22   
  18. ;       Optional Formfeed simulation for printers
  19. ;       which do not recognize the formfeed character.
  20. ;       Set SIMFF to TRUE for this option.  LPPP
  21. ;       (lines per physical page - normally 66)
  22. ;       added for calculation of  # of linefeeds.
  23. ;       PAGDEF can be set to TRUE to default PAG.
  24. ;       In that case the PAG command parameter will
  25. ;       turn paging OFF.   END can be used instead of
  26. ;    OFF, because I can never remember OFF.  (Jon Tara)
  27. ;
  28. ;3.2    81-12-29
  29. ;    Optional printer paging added. Feature is
  30. ;    invoked by typing "UNSPOOL FN.FT PAG".
  31. ;    In both cases formfeeds in the file will
  32. ;    be passed to the output device.
  33. ;    Note that paging is available only
  34. ;    under default conditions (C. Strom)
  35. ;
  36. ;3.1    81-12-06
  37. ;    Disable DIRECT BIOS call for DISK writes.
  38. ;    Too many application programs which use
  39. ;    direct BIOS calls to access the disk assume
  40. ;    that they have sole control of drive/track/
  41. ;    sector selection. This could be a potential
  42. ;    disaster.  See documentation.
  43. ;
  44. ;3.0    81-11-12
  45. ;    New release.  Relpaces 2.3.
  46. ;Version 3
  47. ;    Now continues to run during direct BIOS input.
  48. ;    The device name "off" has been implemented as
  49. ;    a method of cancelling an already running
  50. ;    UNSPOOL.  It causes a BDOS function 0 reset.
  51. ;    Function 0 reset now trapped.  Prompts operator
  52. ;    with option to cancel.  Optional tab expansion
  53. ;    support at assembly time. Disk reset (login)
  54. ;    occurs during simulated warm-boot.  Various
  55. ;    cosmetic and source revisions.
  56. ;Version 2
  57. ;    Copy BIOS table so application programs will
  58. ;    still have BIOS access by using word at BOOT+1.
  59. ;    Preserve USER and IOBYTE values as of startup.
  60. ;
  61.  
  62. FALSE    EQU    0
  63. TRUE    EQU    NOT FALSE
  64. ?    EQU    -1
  65.  
  66. ;
  67. ; User-settable assembly options
  68. ;
  69. EXPAND    SET    TRUE    ;True to expand tabs
  70.     IF    EXPAND
  71. PHYSBS    SET    TRUE    ;True to recognize backspace
  72.     ENDIF
  73. SIMFF    SET    TRUE    ; Simulate formfeeds with multiple linefeeds.
  74. PAGDEF    SET    TRUE    ; Default PAGing to on.
  75. LPP    SET    60    ; Lines per PRINTED page.
  76. LPPP    SET    66    ; Lines per PHYSICAL page.
  77.  
  78. ;
  79. ; BDOS Functions:
  80. ;
  81. @SYS    SET    0
  82. @KEY    SET    1
  83. @CON    SET    2
  84. @RDR    SET    3
  85. @PUN    SET    4
  86. @LST    SET    5
  87. @DIO    SET    6
  88. @RIO    SET    7
  89. @SIO    SET    8
  90. @MSG    SET    9
  91. @INP    SET    10
  92. @RDY    SET    11
  93. @VER    SET    12
  94. @LOG    SET    13
  95. @DSK    SET    14
  96. @OPN    SET    15
  97. @CLS    SET    16
  98. @DIR    SET    17
  99. @NXT    SET    18
  100. @DEL    SET    19
  101. @FRD    SET    20
  102. @FWR    SET    21
  103. @MAK    SET    22
  104. @REN    SET    23
  105. @CUR    SET    25
  106. @DMA    SET    26
  107. @CHG    SET    30
  108. @USR    SET    32
  109. @RRD    SET    33
  110. @RWR    SET    34
  111. @SIZ    SET    35
  112. @REC    SET    36
  113. ;
  114. ;System equates:
  115. CPMBASE    EQU    0
  116. BOOT    SET    CPMBASE
  117. BDOS    SET    BOOT+5
  118. TFCB    EQU    BOOT+5CH
  119. TFCB1    EQU    TFCB
  120. TFCB2    EQU    TFCB+16
  121. TBUFF    EQU    BOOT+80H
  122. TPA    EQU    BOOT+100H
  123. CTRL    EQU    ' '-1        ;CTRL CHAR MASK
  124. CR    SET    CTRL AND 'M'
  125. LF    SET    CTRL AND 'J'
  126. TAB    SET    CTRL AND 'I'
  127. FF    SET    CTRL AND 'L'
  128. BS    SET    CTRL AND 'H'
  129. EOF    SET    CTRL AND 'Z'
  130. NVECTS    EQU    16;        ;Number of BIOS vectors
  131. FCBLEN    EQU    33        ;Length of input FCB
  132. ;
  133. ;The flag SAVECCP should be made true if
  134. ;the program segment should load below the CCP.
  135. ;If false the segment will load in the extreme
  136. ;top of the Transient Program Area, overlaying
  137. ;the Console Command Processor.
  138. ;
  139. SAVECCP    SET    TRUE    ;MUST remain true for UNSPOOL
  140. OVERLAY    SET    FALSE    ;(initially)
  141. ; Macro Definitions
  142. ;
  143. ;     Perform a standard BIOS function:
  144. CPM    MACRO    FUNC,OPERAND
  145.     IF    NOT NUL OPERAND
  146.     LXI    D,OPERAND
  147.     ENDIF    ;not nul operand
  148.     IF    NOT NUL FUNC
  149.     MVI    C,@&FUNC
  150.     ENDIF    ;not nul func
  151.     CALL    BDOS
  152.     ENDM
  153. ;
  154. ;    Generate a label of the form ??Rnn to tag an
  155. ;    address requiring relocation:
  156. RTAG    MACRO    LBL,VAL
  157. ??R&LBL EQU    VAL
  158.     ENDM
  159. ;
  160. ;    Flag <INST> as a relocatable instruction
  161. ;    <INST> is of the form: <MNE    OP1[,OP2]>
  162. R    MACRO    INST
  163. @RLBL    SET    @RLBL+1
  164.     RTAG    %@RLBL,%2+$-@BASE
  165.     INST-@BASE
  166.     ENDM
  167. ;
  168. ; During bit map construction, get the next R-tagged
  169. ; address value:
  170. NXTRLD    MACRO    NN
  171. @RLD    SET    ??R&NN
  172. @NXTRLD    SET    @NXTRLD + 1
  173.     ENDM
  174. ;
  175. ;
  176. ; Enter here from Console Command Processor (CCP)
  177. ;
  178. CCPIN    ORG    TPA
  179.     JMP    INTRO
  180. ;
  181. SIGNON:
  182.     DB    'UNSPOOL',TAB,TAB,TAB
  183.     DB    'Ver '
  184.     DB    (VERSION/10)+'0'
  185.     DB    '.'
  186.     DB    (VERSION MOD 10)+'0'
  187.     IF    EXPAND
  188.     DB    '/T'
  189.     ENDIF    ;expand
  190.     IF    PAGDEF
  191.     DB    '/P'
  192.     ENDIF
  193.     IF    NOT SIMFF
  194.     DB    '/F'
  195.     ENDIF
  196.     DB    '$'
  197. ;
  198. INTRO:
  199.     CPM    MSG,SIGNON
  200.     CALL    SETUP        ;initialize.
  201.     LXI    H,BDOS+2    ;find top of memory
  202.     MOV    A,M        ;page address
  203.                 ;Form destination...
  204.     SUI    PAGES        ;...address in
  205.     MOV    D,A        ;DE pair.
  206.     MVI    E,0
  207.     PUSH    D        ;save on stack
  208.     LXI    H,@BASE        ;source address
  209.     LXI    B,SEGLEN
  210. ;
  211. MOVLOOP:
  212. ;Move (HL) to (DE) for (BC) bytes
  213.     MOV    A,B
  214.     ORA    C        ;test for (BC) = 0
  215.     JZ    MOVDONE
  216.     DCX    B        ;count down
  217.     MOV    A,M        ;move a byte
  218.     STAX    D
  219.     INX    D        ;bump the pointers
  220.     INX    H
  221.     JMP    MOVLOOP
  222. ;
  223. MOVDONE:
  224. ;The segment is now moved to high memory, but not
  225. ;properly relocated.  The bit table which specifies
  226. ;which addresses need to be adjusted is located
  227. ;just after the last byte of the source segment,
  228. ;so (HL) is now pointing at it.
  229.     POP    D    ;beginning of newly moved code.
  230.     LXI    B,SEGLEN;length of segment
  231.     PUSH    H    ;save pointer to reloc info
  232.     MOV    H,D    ;offset page address
  233. ;
  234. FIXLOOP:
  235. ;Scan through the newly moved code, and adjust any
  236. ;page addresses by adding (H) to them.  The word on
  237. ;top of the stack points to the next byte of the
  238. ;relocation bit table.  Each bit in the table
  239. ;corresponds to one byte in the destination code.
  240. ;A value of 1 indicates the byte is to be adjusted.
  241. ;A value of 0 indicates the byte is to be unchanged.
  242. ;
  243. ;Thus one byte of relocation information serves to
  244. ;mark 8 bytes of object code.  The bits which have
  245. ;not been used yet are saved in L until all 8
  246. ;are used.
  247. ;
  248.     MOV    A,B
  249.     ORA    C        ;test if finished
  250.     JZ    FIXDONE
  251.     DCX    B        ;count down
  252.     MOV    A,E
  253.     ANI    07H        ;on 8-byte boundry?
  254.     JNZ    NEXTBIT
  255. ;
  256. NEXTBYT:
  257. ;Get another byte of relocation bits
  258.     XTHL
  259.     MOV    A,M
  260.     INX    H
  261.     XTHL
  262.     MOV    L,A        ;save in register L
  263. ;
  264. NEXTBIT    MOV    A,L        ;remaining bits from L
  265.     RAL            ;next bit to CARRY
  266.     MOV    L,A        ;save the rest
  267.     JNC    NEXTADR
  268. ;
  269. ;CARRY was = 1.  Fix this byte.
  270.     LDAX    D
  271.     ADD    H        ;(H) is the page offset
  272.     STAX    D
  273. ;
  274. NEXTADR    INX    D
  275.     JMP    FIXLOOP
  276. ;
  277. FIXDONE:
  278. ;Finished.  Jump to the first address in the new
  279. ;segment in high memory.
  280. ;
  281. ;First adjust the stack.  One garbage word was
  282. ;left by fixloop.
  283.     INX    SP
  284.     INX    SP
  285. ;
  286. ;(HL) still has the page address
  287.     MOV    L,A    ;move zero to l
  288.     PCHL        ;Top-of-stack is CCP return
  289. SETUP:
  290. ;First, check environment to see if BIOS vectors
  291. ;are accessible.
  292.     LDA    BOOT        ;Location BOOT should
  293.     CPI    ( JMP )        ;have a JMP instruction
  294.     JNZ    VECTERR
  295.     LHLD    BOOT+1        ;Location one points
  296.     MVI    C,NVECTS    ;to the table of jumps 
  297.                 ;which we move into
  298.                 ;the code.
  299.     LXI    D,BIOSV
  300.     XCHG
  301. VLOOP:
  302.     LDAX    D
  303.     CMP    M        ;another JMP?
  304.     JNZ    VECTERR
  305.     INX    D
  306.     INX    H
  307.     LDAX    D
  308.     MOV    M,A
  309.     INX    D
  310.     INX    H
  311.     LDAX    D
  312.     MOV    M,A
  313.     INX    H
  314.     INX    D
  315.     DCR    C
  316.     JNZ    VLOOP
  317. ; Save old vectors and CCP return address
  318. ;Patch up new vectors as required.
  319.     LHLD    BOOT+1
  320.     SHLD    OLDBOOT;    Save the BOOT vector
  321. ;
  322.     LXI    H,2;        Retrieve the CCP
  323.     DAD    SP;        return address from
  324.     MOV    A,M;        down the stack a ways.
  325.     INX    H
  326.     MOV    H,M
  327.     MOV    L,A
  328.     SHLD    CCPRET+1;    Save the CCP re-entry
  329. ;                point.
  330. ;
  331.     LHLD    BDOS+1
  332.     SHLD    GOBDOS+1;    Save the BDOS entry
  333. ;                point.
  334. ;
  335.     LHLD    CONIN+1;    Save the direct call
  336.     SHLD    REALCON+1;    to console input.
  337. SETUPDEV:
  338.     LXI    D,TFCB2+1
  339.     LDAX    D
  340.     CPI    ' '
  341.     JZ    SETUPFIL
  342. ;
  343.     LXI    H,LSTLIT
  344.     MVI    B,4
  345.     CALL    SCOMP
  346.     JZ    SETUPFIL;    Use default
  347. ;
  348.     LXI    D,TFCB2+1
  349.     LXI    H,PUNLIT
  350.     MVI    B,4
  351.     CALL    SCOMP
  352.     JNZ    CKPAG
  353.     MVI    A,@PUN
  354.     STA    DEVICE
  355.     JMP    SETUPFIL
  356. ;
  357. CKPAG:
  358.     LXI    D,TFCB2+1
  359.     LXI    H,PAGLIT
  360.     MVI    B,4
  361.     CALL    SCOMP
  362.     JNZ    CKSYS
  363.     LDA    PAGFLG        ; Get initial default value.
  364.     XRI    0FFH            ; Flip it.
  365.     STA    PAGFLG        ; Store new value.    
  366.     JMP    SETUPFIL
  367. ;
  368. CKSYS:
  369.     LXI    D,TFCB2+1
  370.     LXI    H,OFFLIT
  371.     MVI    B,4
  372.     CALL    SCOMP
  373.     JZ    RESET 
  374.     LXI    D,TFCB2+1    ; Also check END cause I can never
  375.     LXI    H,ENDLIT    ;  remember ... uh ... uh ..
  376.     MVI    B,4        ;  oh yea - OFF. (JT)
  377.     CALL    SCOMP
  378.     JNZ    DEVERR        ; Didn't match anything - error.
  379. RESET:
  380.     CPM    SYS        ;Request system reset
  381. SETUPFIL:
  382.     LDA    TFCB1
  383.     ORA    A
  384.     JNZ    OPENIT
  385. ;The drive has been defaulted.  Make it explicit
  386. ;in case the default drive is changed while the
  387. ;file is being unspooled.
  388.     CPM    CUR;    Returns A: as 00
  389.     INR    A;    Open needs A: as 01
  390.     STA    TFCB1
  391. OPENIT:
  392.     CPM    OPN,TFCB1
  393.     INR    A
  394.     JNZ    COPYFCB
  395. ;Error.  Can't open input file.
  396.     LXI    H,TBUFF
  397.     MOV    A,M
  398.     ADD    L
  399.     MOV    L,A
  400.     ADC    H
  401.     SUB    L
  402.     MOV    H,A
  403.     INX    H
  404.     MVI    M,'?'
  405.     INX    H
  406.     MVI    M,'$'
  407.     CPM    CON,CR
  408.     CPM    CON,LF
  409.     CPM    MSG,TBUFF+1
  410.     POP    H;    Adjust stack
  411.     RET;        Exit to CCP
  412. ;
  413. COPYFCB:
  414.     LXI    H,TFCB1
  415.     LXI    D,FCB
  416.     MVI    C,FCBLEN
  417. COPY1    MOV    A,M
  418.     STAX    D
  419.     INX    H
  420.     INX    D
  421.     DCR    C
  422.     JNZ    COPY1
  423. ;
  424. SETUPUSR:
  425. ;    Save user number in effect at time of entry
  426.     CPM    USR,?
  427.     STA    ENTUSR
  428. ;
  429. SETUPIOB:
  430. ;    Save IOBYTE in effect at time of entry
  431.     CPM    RIO
  432.     STA    ENTIOB
  433. ;
  434.     RET
  435. ;
  436. SCOMP:
  437.     LDAX    D
  438.     CMP    M
  439.     RNZ
  440.     INX    D
  441.     INX    H
  442.     DCR    B
  443.     JNZ    SCOMP
  444.     RET
  445. ;
  446. DEVERR:
  447.     CPM    MSG,DEVERRMSG
  448.     POP    H;    Adjust stack
  449.     RET;        Exit to CCP
  450. VECTERR:
  451.     CPM    MSG,VCTERRMSG
  452.     JMP    BOOT    ;try re-booting.
  453. ;
  454. LSTLIT:
  455.     DB    'LST '        ;Note trailing blank
  456. ENDLIT:
  457.     DB    'END '
  458. PUNLIT:
  459.     DB    'PUN '        ;Note trailing blank
  460. OFFLIT:
  461.     DB    'OFF '        ;Note trailing blank
  462. PAGLIT:
  463.     DB    'PAG '        ;Note trailing blank
  464. DEVERRMSG:
  465.     DB    CR,LF,'Invalid device.$'
  466. VCTERRMSG:
  467.     DB    CR,LF,'Error in system table.  '
  468.     DB    'Attempting re-boot.$'
  469.     PAGE
  470. ;Align location counter to next page boundry
  471. @BASE    ORG    ($ + 0FFH) AND 0FF00H
  472. @RLBL    SET    0
  473. ;
  474. ; The segment to be relocated goes here.
  475. ; Any position dependent (3-byte) instructions
  476. ; are handled by the "R" macro.
  477. ; For readability, the macro name "R" is placed in
  478. ; column 2.  The preceding blank must be present to
  479. ; distinguish it from a label.
  480. ;*************************************************
  481. BDOSV:
  482. ;During operation, this location will point
  483. ;to INTERCEPT and will be jumped to by BDOS.
  484. ;It must be at the lowest location
  485. ;in the protected segment of code.
  486.  R    <JMP    ONESHOT>    ;complete installation
  487. BIOSV:
  488.     REPT    NVECTS
  489.     JMP    ?
  490.     ENDM
  491. CONSTAT    EQU    BIOSV+(1*3)
  492. CONIN    EQU    BIOSV+(2*3)
  493. WRITE    EQU    BIOSV+(13*3)
  494. LSTSTAT    EQU    BIOSV+(14*3)
  495. ;
  496. INTERCEPT:
  497. ;This routine intercepts all BDOS calls.
  498.     MOV    A,C;        Get function
  499.     CPI    @SYS;        Is it a system reset?
  500.  R    <JZ    SYSREQ>
  501.     CPI    @KEY;    Is it single key input?
  502.  R    <JZ    WAITING>
  503.     CPI    @INP;    or buffered input?
  504.  R    <JNZ    CKDMA>
  505. WAITING:
  506. ;Wait for actual keypress before honoring input
  507. ;request.  Unspool characters in the meantime.
  508.  R    <LDA    ACTIVE>
  509.     ORA    A;    See if finished.
  510.  R    <CNZ    PROCESS>;    Note that A <> 0
  511.  R    <JMP    GOBDOS>;    Honor the input request
  512. ;
  513. CKDMA    CPI    @DMA;    If the DMA address is being
  514.         ;    changed, we have to know.
  515.  R    <JNZ    GOBDOS>
  516.     XCHG
  517.  R    <SHLD    DMAHOLD>
  518.     XCHG
  519. ;
  520. GOBDOS    JMP    ?;        Patched on entry
  521.         ;    points to "real" BDOS routine.
  522. ;
  523. TRAPCON:
  524. ;    The application has done a direct BIOS call for
  525. ;console input.  We can be confident that this was not
  526. ;as a result of a BDOS operation, since BDOS knows
  527. ;nothing about our local jump table.  Thus we will not
  528. ;need to be concerned with the non-reentrancy of BDOS.
  529. ;
  530.  R    <LDA    ACTIVE>
  531.     ORA    A;        See if active.
  532.     MVI    A,0;        Flag BIOS-type request.
  533.  R    <CNZ    PROCESS>;    Unspool a while if so.
  534. REALCON:
  535.     JMP    ?;        Patched during setup.
  536. ;
  537. TRAPWRT:
  538. ;    The application has attempted a direct BIOS
  539. ;    disk write.  This is too dangerous to be
  540. ;    allowed, since the programmer may have made
  541. ;    rash assumptions about the track or sector
  542. ;    which are currently selected.
  543.  R    <LXI    D,OPEXCPT>
  544.      MVI    C,@MSG
  545.  R    <CALL    GOBDOS>;    Give the bad news.
  546.      JMP    BOOT;        Abort the application
  547. OPEXCPT:
  548.     DB    CR,LF
  549.     DB    'Invalid operation attempted under'
  550.     DB    ' UNSPOOL.',CR,LF,'Program aborted.'
  551.     DB    '$'
  552. PROCESS:
  553. ;The application program is now waiting for a key
  554. ;to be input.  We will use this opportunity to print
  555. ;some characters to the device until a key is
  556. ;actually pressed.
  557.  R    <STA    ITYPE>    ;The A register tells type
  558. ;            of input request.
  559.     LXI    H,0
  560.     DAD    SP
  561.  R    <LXI    SP,LCLSTACK>
  562.     PUSH    H;    Save old SP
  563.     PUSH    B
  564.     PUSH    D;    Save entry parameters
  565.     MVI    C,@RIO;    Save old IOBYTE
  566.  R    <CALL    GOBDOS>
  567.  R    <STA    IOBHOLD>
  568. PROC1:
  569.  R    <CALL    CKKEY>;    Check for keypress.
  570.  R    <JNZ    PROCEXIT>
  571.  R    <LDA    DEVICE>        ;Check device being used
  572.     CPI    @LST
  573.  R    <JNZ    PROC2>        ;If it is LST:
  574.  R    <CALL    LSTSTAT>
  575.     ORA    A
  576.  R    <JZ    PROC1>        ;Loop if not ready
  577. ;
  578. PROC2:
  579.     IF    EXPAND
  580.  R    <LDA    TABFLAG>;    In a tab sequence?
  581.      ORA    A
  582.  R    <JZ    NITAB>
  583.  R    <LXI    H,LINEPOS>
  584.     MVI    A,7
  585.     ANA    M;    Check if more blanks needed
  586.  R    <JNZ    SPCOUT>
  587.  R    <STA    TABFLAG>;    Clear the flag
  588.  R    <JMP    PROC1>
  589. NITAB:                ; "Not in Tab"
  590.     ENDIF    ;EXPAND
  591.  
  592.     IF    SIMFF        ; Simulating form-feeds.
  593.  R    <LDA    FFFLG>        ; In a form-feed sequence?
  594.     ORA    A
  595.  R    <JZ    NIFF>        ; Skip if no.
  596.  R    <LXI    H,NBLINS>
  597.     DCR    M        ; Decrement # of linefeeds remaining.
  598.     MVI    A,LF        ; (Preload LF char)
  599.  R    <JNZ    OUTCHR>        ; Output another line-feed.
  600.     XRA    A
  601.  R    <STA    FFFLG>        ; Clear the flag.
  602.  R    <JMP    PROC1>
  603. NIFF:                ; "Not in form feed"
  604.     ENDIF    ; SIMFF
  605.  
  606.  R    <LXI    H,BUFFER>
  607.     MOV    A,M
  608.     ORA    A
  609.  R    <CM    FILLBUFF>
  610.  R    <JC    ENDFILE>
  611.     INR    A
  612.     MOV    M,A
  613.     MOV    C,A
  614.     MVI    B,0
  615.     DAD    B;    Point to the buffered char.
  616.     MOV    A,M
  617.     CPI    EOF
  618.  R    <JZ    ENDFILE>
  619.  
  620.     IF    EXPAND
  621.  R    <LXI    H,LINEPOS>;    Print head position.
  622.     CPI    TAB;        Is this a tab?
  623.  R    <JNZ    NOTTAB>        ; Skip if not.
  624.  R    <STA    TABFLAG>;    Set the flag
  625. SPCOUT:
  626.     MVI    A,' '
  627.  R    <JMP    PROC5>
  628. ;
  629. NOTTAB:
  630.     IF    PHYSBS
  631.     CPI    BS;        Backspace?
  632.  R    <JNZ    PROC3>
  633.     DCR    M;        Back up 1 column
  634.  R    <JMP    PROC9>
  635. PROC3:
  636.     ENDIF    ;PHYSBS
  637.  
  638.     CPI    CR;        End of line?
  639.  R    <JNZ    PROC4>
  640.     MVI    M,0;        Reset column count.
  641.  R    <JMP    PROC9>
  642. PROC4:
  643.     CPI    ' ';        Other ctrl char?
  644.  R    <JC    PROC9>        ; Dont increase column count.
  645. PROC5:
  646.     INR    M        ; Increase column count. 
  647.     ENDIF    ;EXPAND
  648. PROC9:
  649. ;
  650.     PUSH    PSW
  651.  R    <LDA    PAGFLG>;    Paging enabled?
  652.     ORA    A
  653.  R    <JZ    OUTCHR1>;    No, so jump
  654.     POP    PSW;        Yes, so process
  655.     CPI    FF;        Char a formfeed?
  656.  R    <JZ    PG>;        Yes, so process it
  657.     CPI    LF;        Char a lineFEED?
  658.  R    <JZ    LFPROC>;    Yes, so process it
  659.  R    <JMP    OUTCHR>;    Else just output char
  660. LFPROC:
  661.  R    <LDA    LINCNT>;    Get line counter
  662.     INR    A;        Bump it
  663.     CPI    LPP;        Reached limit?
  664.  R    <JZ    PG>;        Yup, so issue formfeed
  665.  R    <STA    LINCNT>;    Nope, so...
  666.     MVI    A,LF;        ...increment the counter and...
  667.  R    <JMP    OUTCHR>;    ...output the linefeed
  668. ;
  669. PG:
  670.     IF    SIMFF
  671.  R    <LDA    LINCNT>        ; Get # of lines already printed.
  672.     ORA    A        ; If we're already at the top of a page,
  673.  R    <JZ    PROC1>        ;  forget it.
  674.     MOV    B,A
  675.     MVI    A,LPPP        ; Lines per physical page.
  676.     SUB    B        ; Compute # of LFs to output.
  677.  R    <STA    NBLINS>        ; Store # of LFs.
  678.     XRA    A        ; Zero the counter.
  679.  R    <STA    LINCNT>
  680.     DCR    A        ; Make an "FF"
  681.  R    <STA    FFFLG>        ; Set the formfeed flag.
  682.     MVI    A,LF        ; Output the first linefeed.
  683.  R    <JMP    OUTCHR>
  684.     ELSE
  685.     XRA    A
  686.  R    <STA    LINCNT>;    zero the counter
  687.     MVI    A,FF;        issue a formfeed
  688.  R    <JMP    OUTCHR>
  689.     ENDIF
  690. OUTCHR1:
  691.     POP    PSW
  692. OUTCHR:
  693. ;
  694.     MOV    E,A
  695.     PUSH    D    ;SAVE CHARACTER
  696. ;Set the IOBYTE as it was when UNSPOOL was
  697. ;started.
  698.  R    <LDA    ENTIOB>
  699.     MOV    E,A
  700.     MVI    C,@SIO
  701.  R    <CALL    GOBDOS>
  702.     POP    D    ;RESTORE CHARACTER
  703.     MVI    C,@LST;        Default
  704. DEVICE    EQU    $-1;        Device code patch
  705.  R    <CALL    GOBDOS>
  706.  R    <LDA    IOBHOLD>;    Restore active IOBYTE
  707.     MOV    E,A
  708.     MVI    C,@SIO
  709.  R    <CALL    GOBDOS>
  710.  R    <JMP    PROC1>
  711. ;
  712.  
  713. ENDFILE:
  714. ;    An EOF has been reached on the input file.
  715. ;Mark this program as inactive, and de-install on
  716. ;the next warm boot.
  717.     XRA    A
  718.  R    <STA    ACTIVE>
  719. ;
  720. PROCEXIT:
  721.     POP    D
  722.     POP    B
  723.     POP    H;    Restore SP
  724.     SPHL
  725.     RET
  726. ;
  727. ;
  728. FILLBUFF:
  729. ;Fill the buffer from the file
  730.     PUSH    H
  731.     INX    H
  732.     XCHG;        Buffer address to DE
  733.      MVI    C,@DMA;    Set DMA address
  734.  R    <CALL    GOBDOS>
  735.     MVI    E,?
  736.     MVI    C,@USR
  737.  R    <CALL    GOBDOS>;    Get current user
  738.  R    <STA    USRHOLD>;    Save it
  739.  R    <LDA    ENTUSR>;    Change to user at entry
  740.     MOV    E,A
  741.     MVI    C,@USR
  742.  R    <CALL    GOBDOS>
  743.  R    <LXI    D,FCB>
  744.     MVI    C,@FRD;        Read a sector
  745.  R    <CALL    GOBDOS>
  746.     PUSH    PSW;    Save read return code
  747.  R    <LHLD    DMAHOLD>
  748.     XCHG;        Restore DMA address
  749.     MVI    C,@DMA;    to old value.
  750.  R    <CALL    GOBDOS>
  751.  R    <LDA    USRHOLD>
  752.     MOV    E,A;    Restore User number
  753.     MVI    C,@USR;    to old value
  754.  R    <CALL    GOBDOS>
  755.     POP    PSW;    Read return code
  756.     POP    H;    Buffer pointer
  757.     ORA    A;    How went the read?
  758.     RZ;        Fine
  759.     STC;        No good. Set CARRY for EOF
  760.     RET
  761. ;
  762. CKKEY:
  763. ;    Return zero flag if key not pressed
  764. ;Two types of status checking are done, depending
  765. ;on the way in which console input was requested.  If
  766. ;via BDOS, a BDOS call is used.  If via direct BIOS, a
  767. ;direct BIOS call is used.  This distinction in made
  768. ;necessary by the one-character input buffer which
  769. ;BDOS may fill during console output. (Yes output.)
  770. ;
  771.  R    <LDA    ITYPE>;        Type of input which
  772.     ORA    A;        was requested.
  773.  R    <JZ    CKKEY0>
  774.     MVI    C,@RDY;        Use BDOS if non-zero
  775.  R    <CALL    GOBDOS>
  776.     ORA    A
  777.     RET
  778. CKKEY0:
  779.  R    <CALL    CONSTAT>;    Use BIOS otherwise
  780.     ORA    A
  781.     RET
  782. ;
  783. SYSREQ:
  784. ;The application process has requested a warm-boot
  785. ;by invoking BDOS function 0.  Inquire whether the
  786. ;spool writer should be terminated.  If not, treat
  787. ;as a normal warm-boot request.
  788. ;
  789.     LXI    SP,CCPIN;    Set up a valid stack
  790.  R    <LDA    ACTIVE>;    If not active
  791.     ORA    A;        then don't ask.
  792.  R    <LXI    D,DONEMSG>
  793.  R    <JZ    SYSRQ9>
  794.  R    <LXI    D,CNCL?>
  795.     MVI    C,@MSG
  796.  R    <CALL    GOBDOS>
  797. ;
  798.     CPM    KEY        ;Get reply
  799.     ORI    'a'-'A'        ;Force lower case
  800.     CPI    'n'        ;Note lower case n.
  801.      JZ    BOOT
  802.     CPI    'y'        ;Note lower case y.
  803.     JNZ    BOOT        ;Default = No
  804. ;
  805. ;    Do a real BDOS function 0 which will terminate
  806. ;    the spool writer.
  807.  R    <LXI    D,CNCLMSG>
  808. SYSRQ9:
  809.     MVI    C,@MSG        ;Inform the operator
  810.  R    <CALL    GOBDOS>
  811. ;
  812.     MVI    C,@SYS
  813.  R    <JMP    GOBDOS>        ;Reset system
  814. BOOTREQ:
  815. ;The application process has requested a reboot
  816. ;by jumping to location 0.  If we are no longer
  817. ;active, we will honor the request by executing
  818. ;the address found in the BOOT vector at entry.
  819. ;Otherwise return to CCP without rebooting.
  820.     LXI    SP,CCPIN    ;set up a valid stack
  821.  R    <LDA    ACTIVE>
  822.     ORA    A
  823.  R    <JNZ    NOTYET>
  824. ;Jump to old boot address as read from memory
  825. ;word 1 before we changed it.
  826.  R    <LXI    D,DONEMSG>
  827.     MVI    C,@MSG
  828.  R    <CALL    GOBDOS>
  829.  R    <LHLD    OLDBOOT>
  830.     PCHL
  831. ;
  832. NOTYET    LXI    H,TBUFF
  833.  R    <SHLD    DMAHOLD>
  834.     MVI    C,@LOG
  835.  R    <CALL    GOBDOS>
  836.  R    <LXI    D,ACTMSG>
  837.     MVI    C,@MSG
  838.  R    <CALL    GOBDOS>
  839.  R    <LXI    H,INTERCEPT>
  840.  R    <SHLD    BDOSV+1>
  841.  R    <LXI    H,BDOSV>
  842.     SHLD    BDOS+1
  843.  R    <LXI    H,BOOTREQ>
  844.  R    <SHLD    BIOSV+1>
  845.  R    <LXI    H,BIOSV>
  846.     SHLD    BOOT+1
  847. CCPRET:
  848.     JMP    ?;    Patched on startup
  849. ;
  850. ACTMSG:    DB    CR,LF
  851.     DB    'Unspooling in progress.'
  852.     DB    '$'
  853. DONEMSG:
  854.     DB    CR,LF,'UNSPOOL Completed.'
  855.     DB    '$'
  856. CNCL?:
  857.     DB    CR,LF,'Do you want to cancel UNSPOOL?'
  858.     DB    CR,LF,'{Y|N} ?>'
  859.     DB    '$'
  860. CNCLMSG:
  861.     DB    CR,LF,'UNSPOOL Cancelled.'
  862.     DB    '$'
  863. OLDBOOT    DW    ?
  864. DMAHOLD    DW    TBUFF
  865. ACTIVE    DB    TRUE
  866.     IF    EXPAND
  867. TABFLAG    DB    FALSE
  868. LINEPOS    DB    0
  869.     ENDIF    ;EXPAND
  870.     IF    SIMFF
  871. FFFLG    DB    FALSE
  872. NBLINS    DB    0
  873.     ENDIF
  874. LINCNT    DB    0;        Linefeed counter
  875. PAGFLG    DB    PAGDEF;        Paging flag (defaulted to PAGDEF)
  876. USRHOLD    DB    ?
  877. ENTUSR    DB    ?
  878. IOBHOLD    DB    ?
  879. ENTIOB    DB    ?
  880. ITYPE    DB    ?
  881. FCB    DS    FCBLEN
  882. BUFFER    DB    ?
  883. ;
  884. ONESHOT:
  885. ; This one-shot code patches the local jump table.
  886. ;It is then overlayed by the file buffer on the first
  887. ;read, so it takes up no extra memory.
  888.  R    <LXI    H,TRAPCON>
  889.  R    <SHLD    CONIN+1>
  890.  R    <LXI    H,TRAPWRT>
  891.  R    <SHLD    WRITE+1>
  892.  R    <JMP    BOOTREQ>;    Start the program.
  893. ;
  894. OVERLAY    SET    $    ;Bit table may start here
  895. ;            Nothing past here but DS's.
  896.     DS    128-$+BUFFER
  897.     DS    32;    LOCAL STACK AT LEAST 16 WORDS
  898. ;            PLUS WHATEVER'S LEFT OVER
  899.     ORG    ($+0FFH) AND 0FF00H    ; Org to next page boundry.
  900. LCLSTACK:
  901. ;*************************************************
  902. ;End of segment to be relocated.
  903.     IF    SAVECCP
  904. PAGES    EQU    ($-@BASE)/256+8;    CCP = 8 pages.
  905.     ELSE
  906. PAGES    EQU    ($-@BASE)/256
  907.     ENDIF    ;saveccp
  908. ;
  909.     IF    OVERLAY NE FALSE
  910.     ;cause relocation map to slide down into
  911.     ;unused DS area:
  912. SEGLEN    EQU    OVERLAY-@BASE
  913.     ORG    @BASE+SEGLEN
  914.     ELSE
  915.     ;relocation bit map starts here:
  916. SEGLEN    EQU    $-@BASE
  917.     ENDIF    ;overlay
  918.     PAGE
  919. ;    Build the relocation information into a
  920. ; bit map following the code.
  921. ;
  922. @X    SET    0
  923. @BITCNT    SET    0
  924. @RLD    SET    ??R1
  925. @NXTRLD SET    2
  926.     RTAG    %@RLBL+1,0FFFFH    ;define one more symbol
  927. ;
  928.     REPT    SEGLEN+8
  929.     IF    @BITCNT>@RLD
  930.     NXTRLD    %@NXTRLD    ;;next value
  931.     ENDIF
  932.     IF    @BITCNT=@RLD
  933. @X    SET    @X OR 1        ;;set low bit
  934.     ENDIF
  935. @BITCNT    SET    @BITCNT + 1
  936.     IF    @BITCNT MOD 8 = 0
  937.     DB    @X        ;;DEFINE THE BYTE
  938. @X    SET    0    ;;clear hold variable for more
  939.     ELSE
  940. @X    SET    @X SHL 1    ;;not 8 yet. move over.
  941.     ENDIF
  942.     ENDM
  943. ;
  944.     END    CCPIN
  945.