home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / tools / Forth / files.fs < prev    next >
Encoding:
FORTH Source  |  2006-10-19  |  16.4 KB  |  1,005 lines

  1.  
  2. \
  3. \    FILE words
  4. \
  5.  
  6. \    ior is the I/O error from 0 to 7
  7. \    fam is 0=update, 1=output, 2=input, 3=append
  8. \    fileid is a PAB addr
  9.  
  10. \
  11. \    VDP allocation --
  12. \    
  13. \    FILES() must be set to less than 3 so that bitmap
  14. \    mode can have space for a pab (>3800...xxx).
  15. \
  16. \    We adjust >8370 to keep track of open files.
  17. \
  18.  
  19. $8380 constant dskws
  20.  
  21. \    DSRLNK is for use with non-bytefiles 
  22.  
  23. Code: (dsrlnk)
  24.     [ dskws ] data
  25.     [ there 2 + ] data
  26.  
  27.     limi 0 #
  28. \    dbg
  29.     mov *R13 , R5        \ offset 8/10
  30.  
  31.     li R6 , $2e00 #
  32.  
  33.     mov    $8356 @> , R0    \ get ptr to name
  34.     mov    R0 , R9                
  35.     ai    R9 , -8 #        \ point to error code
  36.  
  37.     bl    ' vraddr @>
  38.     movb $8800 @> , R1    \ get filename len
  39.     movb R1 , R3        \ save
  40.     srl    R3 , 8 #                
  41.     seto R4                \ # chars
  42.  
  43.     li    R2 , $834a #    \ buffer [in xopws]
  44. 0 $: inc R0                \ move device name
  45.     inc    R4
  46.     c    R4 , R3
  47.     jeq    1 $f
  48.     bl     ' vraddr @>
  49.     movb $8800 @> , R1
  50.     movb R1 , *R2+
  51.     cb    R1 , R6            \ '.'
  52.     jne    0 $b
  53. 1 $: mov R4 , R4            \ any chars read?
  54.     jeq    9 $f
  55.     ci    R4 , 7 #
  56.     jgt    9 $f                \ too many?
  57.     clr    $83d0 @>
  58.     mov    R4 , $8354 @>        \ # chars in device name
  59.     inc    R4
  60.     a    R4 , $8356 @>        \ point to '.' in name
  61.  
  62.     lwpi $83e0 #            \ GPLWS
  63.  
  64.     clr    R1                    \ init card counter
  65.     li    R12 , $f00 #
  66.     li R6 , $aa00 #
  67. 3 $: sbz 0 #
  68.     ai    R12 , $100 #        \ start scan at >1000
  69.     clr    $83d0 @>
  70.     ci    R12 , $2000 #        \ last base?
  71.     jeq    8 $f
  72.     mov    R12 , $83d0 @>        \ store CRU
  73.     sbo    0 #                    \ turn on rom
  74.     li    R2 , $4000 #
  75.     cb    *R2 , R6            \ legal rom?
  76.     jne    3 $b
  77.     a    &10 dskws + @> , R2    \ add offset
  78.     jmp    5 $f
  79. 4 $: mov $83d2 @> , R2
  80.     sbo    0 #
  81. 5 $: mov *R2 , R2            \ any devices?
  82.     jeq    3 $b                \ nope... next rom pleez
  83.     mov    R2 , $83d2 @>        \ save next link
  84.     inct R2
  85.     mov    *R2+ , R9            \ get routine addr
  86.     movb $8355 @> , R4        \ get len of caller
  87.     jeq    7 $f                \ ??? no length?
  88.     cb    R4 , *R2+            \ match name
  89.     jne    4 $b
  90.     srl    R4 , 8 #
  91.     li    R6 , $834a #
  92. 6 $: cb    *R6+ , *R2+
  93.     jne    4 $b
  94.     dec    R4
  95.     jne    6 $b
  96. 7 $: inc R1                    \ increment card #
  97.     bl    *R9                    \ run it
  98.     jmp    4 $b                \ if no error, DSR skips this word
  99.  
  100.     sbz    0 #                    \ turn off rom
  101.     lwpi dskws #
  102.     mov    R9 , R0                \ get error code
  103.     bl ' vraddr @>
  104.     movb $8800 @> , R1
  105.  
  106.     srl    R1 , &13 #
  107.     jeq 9 $f                \ no error
  108.  
  109.     ori R0 , $4000 #
  110.     bl ' vwaddr @>
  111.     mov R1 , R2
  112.     sla R2 , &13 #
  113.     andi R2 , $7fff #
  114.     movb R2 , $8c00 @>        \ clear error (else it will look like binary)
  115.  
  116.     inc R1                    \ bias
  117.     -dbg
  118. 8 $: 
  119.     mov R1 , *R13
  120. \    -dbg
  121.     rtwp
  122. 9 $: clr *R13
  123. \    -dbg
  124.     rtwp
  125. end-code
  126.  
  127. Code dsrlnk    ( pab 8/10 -- ior )
  128.     mov TOS , R0
  129.     mov *SP , R1
  130.     ai R1 , 9 #
  131.     mov R1 , $8356 @>
  132.     blwp ' (dsrlnk) @>
  133.     0POP
  134.     mov R0 , TOS
  135.     NEXT
  136. end-code
  137.  
  138.  
  139. $8370 constant pabtos 
  140.  
  141. \    for PAB files, the record is 9 bytes plus the filename:
  142. \    <1:opcode> <1:flags> <2:vdpbuff> <1:reclen> 
  143. \    <1:curlen> <2:recnum> <1:status> <1:fnlen>
  144. \
  145. \    for byte files, the record is
  146. \    <1:opcode> <1:flags> <2:curoffs> <1:byteoffs> 
  147. \    <1:eof> <2:numsecs> <1:unused> <1:fnlen>
  148.  
  149. : p>buf        ( pab -- buffer )
  150.     \ skip filename to point to buffer space
  151.     9 + dup vc@ &11 + + 
  152. ;
  153.  
  154. : p>fl        ( pab -- @flags )
  155.     1+
  156. ;
  157.  
  158. : p>ad        ( pab -- @vaddr )
  159.     2+
  160. ;
  161.  
  162. : p>len        ( pab -- @len )
  163.     4 +
  164. ;
  165.  
  166. : p>cnt        ( pab -- @cnt )
  167.     5 +
  168. ;
  169.  
  170. : p>rec        ( pab -- @rec )
  171.     6 +
  172. ;
  173.  
  174. \    the filename is a counted string
  175. : p>fn
  176.     9 +
  177. ;
  178.  
  179. : p>bcursec
  180.     2 +
  181. ;
  182.  
  183. : p>bcuroffs
  184.     4 +
  185. ;
  186.  
  187. : p>beofoffs
  188.     5 +
  189. ;
  190.  
  191. : p>beofsec
  192.     6 +
  193. ;
  194.  
  195. \    \\\\\\\\\\\\\\\\\\
  196. \
  197. \    Support for byte files:
  198. \
  199. \    ANS forth requires that files support byte access
  200. \    as a stream.  TI files don't have this.  We need to
  201. \    emulate it by using blocks.
  202. \
  203. \    We use the pab to store the long offset in the file,
  204. \    and set $80 in the flags byte.
  205.  
  206. $80 constant b<fmt        \ binary/bytefile format: 
  207.                         \ on open, !bytefile, after, ==bytefile
  208. $40 constant b<drt        \ dirty buffer
  209.  
  210. : p>bin?
  211.     p>fl vc@ b<fmt AND 0<>
  212. ;
  213.  
  214. \    Query the dirty flag
  215. \
  216. : p>drt?        ( pab -- )
  217.     p>fl vc@ b<drt AND 0<>
  218. ;
  219.  
  220. \    Set the dirty flag
  221. \
  222. : p>drt!        ( pab -- )
  223.     p>fl dup vc@ b<drt OR swap vc!
  224. ;
  225.  
  226. \    Reset the dirty flag
  227. \
  228. : p>drt0        ( pab -- )
  229.     p>fl dup vc@ b<drt invert AND swap vc!
  230. ;
  231.  
  232.  
  233. \    Calculate sector/offset from position
  234. : >s+o                    ( doffs -- sec offs )
  235.     $100 um/mod swap
  236. ;
  237.  
  238. \    Calculate position from sector/offset
  239. : <s+o                    ( sec offs -- doffs )
  240.     >r $100 um* 
  241.     r> s>d d+
  242. ;
  243.  
  244. \    Set new sector/offset
  245. : b>s+o!                ( sec offs pab -- )
  246.     swap over             ( sec pab offs pab )
  247.     p>bcuroffs  vc!        \ offset
  248.     p>bcursec v!        \ sector
  249. ;
  250.  
  251. \    Set new sector/offset filesize
  252. : b>s+o!sz                ( sec offs pab -- )
  253.     swap over             ( sec pab offs pab )
  254.     p>beofoffs  vc!        \ offset
  255.     p>beofsec v!        \ sector
  256. ;
  257.  
  258. \    Set new position
  259. : b>pos!                ( dpos pab -- )
  260.     >r >s+o r> b>s+o! 
  261. ;
  262.  
  263. \    Set new filesize
  264. : b>sz!                    ( dsz pab -- )
  265.     >r >s+o r> b>s+o!sz 
  266. ;
  267.  
  268. \    Get the sector and offset from the pab
  269. : b>s+o@                ( pab -- sec offs )
  270.     dup p>bcursec v@        \ sector
  271.     swap p>bcuroffs vc@        \ offset
  272. ;
  273.  
  274. \    Get the filesize (sector and offset) cached the pab
  275. : b>s+o@sz                ( pab -- sec offs )
  276.     dup p>beofsec v@        \ sector
  277.     swap p>beofoffs vc@        \ offset
  278. ;
  279.  
  280. \    Get the position from the pab
  281. : b>pos@                ( pab -- dpos )
  282.     b>s+o@ <s+o
  283. ;
  284.  
  285. \    Get the filesize from the pab
  286. : b>sz@                ( pab -- dsz )
  287.     b>s+o@sz <s+o
  288. ;
  289.  
  290. \    See if the file is at or past EOF
  291. \
  292. : b>eof?        ( pab -- t|f )
  293.     >r
  294.     r@ b>pos@ 
  295.     r@ b>sz@
  296.     d< 0=
  297.     rdrop
  298. ;
  299.  
  300. \    DSROP is for use with bytefiles
  301. \
  302. \    R0 = 0 for get info, >0 for read/write # sectors
  303. \    ( drv name paramblk sub -- ior )
  304. Code (dsrop)
  305. \    dbg
  306.     mov *SP , R0
  307.     ai R0 , -$8300 #
  308.     swpb R0
  309.     movb R0 , $8350 @>        \ offset to param block
  310.     mov 2 @>(SP) , $834e @>    \ vdp name
  311.     movb 5 @>(SP) , $834c @>
  312.     ori TOS , $0100 #        \ DSR subroutine name
  313.  
  314.     mov TOS , $83e0 &12 + @> \ copy to GPLWS R6
  315.  
  316.     ai SP , 6 #                \ lose args
  317.  
  318.     lwpi $83e0 #
  319.     li R13 , $9800 #
  320.     li R14 , $0100 #
  321.     li R15 , $8c02 #
  322.  
  323.     li R12 , $1000 #        \ our CRU base
  324.     sbo 0 #                    \ turn device on
  325.     li R1 , $400A #            \ subprograms
  326.     mov *R1 , R1
  327.     jeq 0 $f
  328.  
  329. \    only compares 1 char subprogram names
  330. 1 $: c 4 @>(R1) , R6        \ same name?
  331.     jeq 3 $f                \ matched
  332.     mov *R1 , R1            \ next
  333.     jne 1 $b
  334.  
  335. 0 $: seto $8350 #            \ fake error
  336.     jmp 4 $f
  337.     
  338. 3 $: mov 2 @>(R1) , R11        \ addr
  339.     mov R12 , $83D0 @>        \ save CRU addr
  340.     bl    *R11                \ call routine
  341.     jmp 4 $f                \ nop for error
  342.  
  343. 4 $:
  344.     li R12 , $1000 #
  345.     sbo 0 #                    \ turn device off
  346.     lwpi $8300 #
  347.  
  348.     movb $8350 @> , TOS
  349.     srl TOS , 8 #            \ error code
  350. \    -dbg
  351.     NEXT
  352. end-code
  353.  
  354. $8340 constant $i/o
  355.  
  356. \    Read (r/w <> 0) or write (r/w == 0) a sector
  357. \    from a file.
  358.  
  359. : (sec)        ( drv vname #secs sec# vaddr r/w -- ior )
  360. \    ." [sec" .s 
  361.     >r
  362.     $i/o !        \ param block: @0 = buffer addr
  363.     $i/o 2+ !     \ param block: @2 = sector #
  364.     dup $834D c!    \ read # sectors
  365.     r> swap >r
  366.     if $14 else $15 then    ( R: #sec )
  367.     $i/o swap
  368.     (dsrop)
  369.     ?dup 0= if 
  370.         \ did it really read/write all the sectors?
  371.         $834D c@ r> <> if 1 else 0 then
  372.     else
  373.         rdrop
  374.     then
  375. \    .s ." ]"
  376. ;
  377.  
  378. \    Read (r/w <> 0) or write (r/w == 0) DSR info for a file.
  379. \    Always uses $i/o as a buffer.
  380.  
  381. : (hdr)        ( drv vname r/w -- ior )
  382. \    ." [hdr" .s 
  383.     0 $834D c!        \ header action
  384.     $i/o swap        \ drv vname $i/o r/w
  385.     if $14 else $15 then
  386.     (dsrop)
  387.     ?dup 0= if 
  388.         \ did it really read/write the header?
  389.         $8350 c@
  390.     then
  391. \    .s ." ]"
  392. ;
  393.  
  394. \    Get internal DSR idea about filename
  395. \    we always have enough spaces in fname
  396.  
  397. : b>fn        ( pab -- drv vname )
  398.  
  399. [ 0 [if] ]
  400.     \ step through filename
  401.     \ and find last period; after this
  402.     \ is the filename, before it is the drive
  403.     \ (unless jerky used a dsk.name.xxxx thing)
  404.     p>fn dup vc@ over + do
  405.         i vc@ [char] . = if
  406.             i 1- vc@ [char] 0 -
  407.             i 1+ 
  408.             unloop exit
  409.         then
  410.     -1 +loop
  411.  
  412. [ [else] ]
  413.  
  414.     \ assume DSK?.NAME for now
  415.     p>fn 5 + dup 
  416.     1- vc@ [char] 0 - 
  417.     swap 1+
  418.  
  419. [ [then] ]
  420. ;
  421.  
  422.  
  423. \    Write file size into to $i/o header
  424. : s+o>hdr        ( sec offs -- )
  425. \ ." >out" .s
  426.     dup $i/o 6 + c!            \ eof
  427.     if 1+ then 
  428.     $i/o 2+ !    \ round # sectors 
  429. ;
  430.  
  431. \    Get sectors/offset from $i/o
  432. : hdr>s+o        ( -- sec offs )
  433.     $i/o 6 + c@                \ eof
  434.     $i/o 2+ @                \ secsused
  435.     over if 1- then            \ # secs, not counting half-filled one
  436.     swap 
  437. \    .s ." <in"
  438. ;
  439.  
  440. \    Write DSR info for binary file
  441. : b>wrhdr        ( pab -- ior )
  442.     >r
  443.  
  444.     \ setup info block
  445.     r@ b>s+o@sz     cr ." hdr< " 2dup . . ." >"
  446.     s+o>hdr
  447.  
  448.     1 $i/o 4 + c!            \ flags (program)
  449.     0 $i/o 7 + c!            \ reclen
  450.     0 $i/o 8 + !            \ numrecs
  451.     
  452.     r@ b>fn
  453.     0 (hdr)
  454.     rdrop
  455. ;
  456.  
  457.  
  458. \    Read DSR info for binary file
  459. : b>rdhdr        ( pab -- ior )
  460.     >r
  461.  
  462.     r@ b>fn
  463.     1 (hdr)
  464.     dup 0= if
  465.         \ setup info block
  466.         hdr>s+o
  467.         r@ b>s+o!sz 
  468.     then
  469.  
  470.     rdrop
  471. ;
  472.  
  473.  
  474. \    Update file size from position
  475. : b>updsz        ( pab -- ior )
  476.     >r
  477.  
  478.     r@ b>eof?
  479.     if
  480.         r@ b>s+o@ r@ b>s+o!sz        \ update size to position
  481.         r@ b>wrhdr        
  482.     else
  483.         0
  484.     then
  485.  
  486.     rdrop
  487. ;
  488.  
  489. \    Write sector
  490. : b>wrsec        ( pab -- ior )
  491.     >r
  492.     r@ b>fn
  493.     1            ( #sec )
  494.     r@ b>s+o@ drop
  495.     r@ p>buf
  496.     0 (sec)
  497.     rdrop
  498. ;
  499.  
  500. \    Read sector
  501. : b>rdsec        ( pab -- ior )
  502. \    ." [rdsec" .s
  503.     >r
  504.     r@ b>fn
  505.     1            ( #sec )
  506.     r@ b>s+o@ drop
  507.     r@ p>buf
  508.     1 (sec)
  509.     rdrop
  510. \    .s ." ]rdsec"
  511. ;
  512.  
  513. : b>flush?        ( pab -- ior )
  514.     \ dirty?
  515. \ ." [flush]"
  516.     >r
  517.     r@ p>bin?                        \ binary file?
  518.     r@ p>drt?                         \ dirty sector?
  519.     and if
  520.         r@ b>wrhdr                    \ write header
  521.         ?dup 0= if                     ( ior )
  522.             r@ b>wrsec                \ write sector
  523.             r@ p>drt0                 \ clear dirty flag
  524.         then
  525.     else
  526.         0
  527.     then
  528.     rdrop
  529. ;
  530.  
  531. \    Set position, write dirty sector and 
  532. \    retrieve containing sector
  533. \    (don't use unless you want disk activity)
  534. \
  535. : b>seek        ( dpos pab -- ior )
  536. \ ." b>seek: " .s cr
  537.     >r            \ save pab on rstack
  538.  
  539.     \ get new and old sectors
  540.     >s+o swap
  541.     r@ b>s+o@ drop        ( newpos newsec oldsec )
  542.  
  543.     \ only work if they are different
  544.     over <> if            ( newpos newsec )
  545.            \ flush
  546.         r@ b>flush?
  547.         ?dup if nip nip rdrop rdrop exit then
  548.  
  549.         \ set new position
  550.         swap 2dup r@ b>s+o! drop        ( newsec )
  551.  
  552.         \ see if new sector is in the file
  553.         r@ b>s+o@sz if 1+ then            ( newsec #secs )
  554.         <= if
  555.             r@ b>rdsec                    \ read sector ( ior )
  556.         else
  557.             0
  558.         then
  559.     else
  560.         swap r@ b>s+o!
  561.         0
  562.     then
  563.     rdrop
  564. ;
  565.  
  566. \    Seek ahead
  567. \
  568. : b>seek+                ( n pab -- ior )
  569.     >r
  570.     r@ b>pos@ d+
  571.     r> b>seek
  572. ;
  573.  
  574. \ figure how much space is left in the sector
  575. \
  576. : b>spc                ( ur pab -- ur secwrt )
  577.     b>s+o@ nip        ( ur secoffs )
  578.     $100 over -     ( ur secoffs secmax )
  579.     2 pick            ( ur secoffs secmax ur )
  580.     min                ( ur secoffs secwrt )
  581. ;
  582.  
  583. \    Read memory from file
  584. \
  585. : b>read        ( caddr ur pab -- ur-not ior )
  586.     >r
  587.  
  588.     begin
  589.         dup        ( caddr' ur' )
  590.         r@ b>eof? 0= and
  591.     while
  592.  
  593.         \ Try to read a sector at a time
  594.  
  595.         r@ b>spc
  596.  
  597.            swap r@ p>buf +    ( caddr ur secwrt vptr )
  598.         3 pick rot        ( caddr ur vptr cptr secwrt )
  599.         dup >r            \ save # bytes written
  600.         vcmove            ( caddr ur )
  601.  
  602.         r@ /string        ( caddr' ur' )
  603.  
  604.         r> s>d r@ b>seek+    ( caddr ur ior )
  605.         ?dup if
  606.             rdrop rot drop exit
  607.         then
  608.  
  609.     \    .s cr
  610.     repeat
  611.  
  612.     nip 0
  613.     rdrop
  614. ;
  615.  
  616. \    Write memory to file
  617. \
  618. : b>wrt        ( caddr ur pab -- ur-not ior )
  619.     >r
  620.  
  621.     begin
  622.         dup        ( caddr' ur' )
  623.     while
  624.  
  625.         \ Mark dirty
  626.         r@ p>drt!
  627.  
  628.         \ Try to write a whole sector at a time
  629.  
  630.         r@ b>spc
  631.         
  632.            swap r@ p>buf +    ( caddr ur secwrt vptr )
  633.         3 pick rot        ( caddr ur vptr cptr secwrt )
  634.         >r swap r@        \ save # bytes written
  635.         cvmove            ( caddr ur )
  636.  
  637.         r@ /string        ( caddr' ur' )
  638.  
  639.         r> s>d r@ b>seek+    ( caddr ur ior )
  640.         ?dup if
  641.             rdrop rot drop exit
  642.         then
  643.         r@ b>updsz        \ update file size
  644.         ?dup if
  645.             rdrop rot drop exit
  646.         then
  647.  
  648. \        .s cr
  649.     repeat
  650.  
  651.     nip 0
  652.     rdrop
  653. ;
  654.  
  655. : rtest
  656. s" dsk1.forth0" r/o var $50 reclen open-file 0= if
  657. include-file
  658. then
  659. ;
  660.  
  661. \    \\\\\\\\\\\\\\\\\\\
  662.  
  663. \    reclen is needed to get a record buffer;
  664. \    it should be $100 for byte files
  665. : newpab        ( caddr u reclen -- vaddr )
  666.     \ use 10 extra chars for fname
  667.     \ to store spaces at end of fname for
  668.     \ internal DSR routines
  669.     over over &10 +
  670.  
  671.     \ take space from vram
  672.     &10 + + negate pabtos +!
  673.  
  674.     pabtos @ >r
  675.  
  676.     \ clear pab
  677.     r@ &10 0 vfill
  678.  
  679.     \ set record length
  680.     r@ p>len vc!
  681.  
  682.     \ copy filename
  683.     dup r@ p>fn vc!           \ length
  684.     r@ p>fn 1+ swap cvmove 
  685.  
  686.     \ make 10 spaces after fname
  687.     r@ p>fn vc@ r@ &10 + +
  688.     &10 bl vfill
  689.  
  690.     \ set buffer addr
  691.     r@ p>buf r@ p>ad v!
  692.  
  693.     r> 
  694. ;
  695.  
  696. : frepab        ( vaddr -- )
  697.     \ clear opcode to indicate free
  698.     $ff swap vc!            
  699.  
  700.     \ return memory if we can
  701.     begin
  702.         pabtos @ 
  703.         dup vc@ $ff =    ( pabaddr closed? )
  704.     while
  705.         \ get record length... 256 bytes for byte file
  706.         dup p>bin? if 
  707.             $100
  708.         else
  709.             dup p>len vc@
  710.         then
  711.  
  712.         \ pt to buffer
  713.         swap p>buf
  714.         +
  715.  
  716.         pabtos !    ( newaddr -- )
  717.     repeat
  718.     drop    ( pabaddr -- )
  719. ;
  720.  
  721.  
  722. \
  723. \    fam:      high byte is record length
  724. \            low byte is pab flags
  725. \
  726.  
  727. 0 constant R/W
  728. 2 constant W/O
  729. 4 constant R/O
  730. 6 constant &rw    \ mask to determine which mode is set
  731.  
  732. \    Note:  we use TI-FORMAT == $80 to conform with
  733. \    ANS in which "R/O" by itself is a byte file;
  734. \    but internally we use $80 to indicate a byte file.
  735. \
  736. : TI-FORMAT $80 OR ;
  737. : VAR $10 OR TI-FORMAT ;
  738. : FIX TI-FORMAT ;
  739. : INT $8 OR TI-FORMAT  ;
  740. : DIS TI-FORMAT ;
  741. : RELATIVE $1 OR TI-FORMAT ;
  742. : SEQUENTIAL TI-FORMAT ;
  743. : RECLEN 8 lshift OR TI-FORMAT ;
  744. : BIN TI-FORMAT INVERT AND ;
  745.  
  746. : OPEN-FILE        ( caddr u fam -- fileid ior )
  747.     b<fmt xor
  748.     dup 
  749.     8 rshift $ff and 
  750.     ?dup 0= if                
  751.         b<fmt or >r            \ set bytefile flag
  752.         $100 newpab
  753.         r> swap >r 
  754.         r@ p>fl vc!
  755.         0.0 r@ b>pos!        \ seek to 0
  756.         r@ p>fl vc@ 
  757.         &rw and W/O <> if        \ readable?
  758.             r@ b>rdhdr             \ get DSR info
  759.             ?dup 0= if
  760.                 r@ b>rdsec        \ read first sector if not write-only
  761.             then
  762.             dup if r@ frepab then
  763.         else                    \ open or create
  764.             r@ b>rdhdr            \ read header ( ior )
  765.             if
  766.                 r@ b>wrhdr        \ write blank header
  767.             else
  768.                 0
  769.             then
  770.         then
  771.         r> swap                ( pab ior )
  772.     else                     ( caddr u fam' reclen ) 
  773.         swap >r newpab r>    ( pab fam' )
  774.            over p>fl vc!        \ set flags 
  775.         dup 8 dsrlnk        \ opcode is OPEN via newpab
  776.         dup if over frepab then
  777.     then
  778. ;
  779.  
  780. : CLOSE-FILE    ( fileid -- ior )
  781.     >r
  782.     r@ p>bin? if
  783.         r@ b>flush?
  784.     else
  785.         $1 r@ vc!
  786.         r@ 8 dsrlnk
  787.     then
  788.     r> frepab
  789. ;
  790.  
  791. \    Adjust amount read for record files
  792. \
  793. : p>rdadj    ( caddr wanted real -- ior )
  794.     >r
  795.     swap over    ( caddr real wanted real )
  796.     >= if 
  797.         r@ p>ad v@        ( caddr real vaddr )
  798.         rot rot dup >r vcmove r>
  799.         0
  800.     else
  801.         drop 3                 \ "illegal" to want less than you got ;)
  802.     then
  803.     rdrop
  804. ;
  805.  
  806. \    Read from the file:  ur==0, ior==0 means EOF
  807.  
  808. : READ-FILE        ( caddr ur fileid -- ur ior )
  809.     >r
  810.     r@ p>bin? if
  811.         r@ p>fl vc@ &rw AND W/O = if
  812.             2drop 0 3        \ can't read from write-only file
  813.         else
  814.             r@ 
  815.             over >r         \ save original ur
  816.             b>read
  817.             swap r> swap -    \ calc bytes not written
  818.             swap
  819.         then
  820.     else
  821.         $2 r@ vc!                \ READ op
  822.         r@ 8 dsrlnk 
  823.         ?dup 0= if
  824.             r@ p>fl vc@ $10 and if
  825.                 r@ p>cnt vc@ 
  826.             else
  827.                 r@ p>len vc@
  828.             then
  829.             r@ p>rdadj
  830.         else
  831.             nip nip
  832.             dup 6 = if
  833.                 drop 0 0    \ eof code
  834.             else
  835.                 0 swap 
  836.             then
  837.         then
  838.     then
  839.     rdrop
  840. ;
  841.  
  842. [[ $80 checkmemory ]]
  843.  
  844. : WRITE-FILE        ( caddr u fileid -- ior )
  845.     >r
  846.     r@ p>bin? if
  847.         r@ p>fl vc@ &rw AND R/O = if
  848.             2drop 0 3        \ can't write to read-only file
  849.         else
  850.             r@ 
  851.             over >r         \ save original ur
  852.             b>wrt
  853.             swap r> swap -    \ calc bytes not written
  854.             swap
  855.         then
  856.     else
  857.         $3 r@ vc!                \ WRITE op
  858.         r@ p>ad v@ swap dup >r cvmove r>
  859.         r@ p>cnt vc!
  860.         r@ 8 dsrlnk
  861.     then
  862.     rdrop
  863. ;
  864.  
  865. \    Return codes:
  866. \    u2<=u1, flag=true, ior=0: got a line before u1 chars read
  867. \    u1==u2, flag=true, ior=0: eol not reached
  868. \    u2=0, flag=false, ior=0: at EOF
  869. \    u2?, flag=?, ior<>0: i/o error
  870. \
  871. \    file-position points to next available char
  872. \
  873. : READ-LINE            ( caddr u1 fileid -- u2 flag ior )
  874.     dup p>bin? if
  875.         rot    rot    ( fileid caddr u1 ) 
  876.         dup >r
  877.         0 do        ( fileid caddr )
  878.             \ get a char at a time
  879.             2dup 1 rot read-file    ( fileid caddr ur ior )
  880.             ?dup if 
  881. \                ." error!"
  882.                 unloop rdrop exit             \ failed
  883.             then
  884.             if                        ( fileid caddr ur )
  885.                 dup c@ dup &13 = swap &10 = or            \ newline?
  886.                 if
  887.                     drop drop i true 0 
  888.                     unloop rdrop exit        \ got line
  889.                 then
  890.                 1+
  891.             else
  892.                 \ end of file
  893. \                ." eof"
  894.                 drop drop i false 0 unloop rdrop exit
  895.             then
  896.         loop
  897.         r> true 0                 \ got line by exhaustion
  898.     else
  899.         READ-FILE
  900.     
  901.         ?dup if
  902.             0 swap                \ other error
  903.         else
  904.             ?dup if 
  905.                 true 0            \ success
  906.             else
  907.                 0 0 0            \ eof
  908.             then
  909.         then then
  910.     then
  911. ;
  912.  
  913. : INCLUDE-FILE        ( i*x fileid -- j*x )
  914.     <input
  915.     loadfile !
  916.     1 loadline !
  917.     0 blk !
  918.     begin refill while interpret repeat
  919.     \ $8370 ?
  920.     loadfile @ close-file drop
  921.     input>
  922. ;
  923.  
  924. : INCLUDED ( addr c -- )
  925.     r/o open-file ?dup if ." not found: " . cr then
  926.     dup >r include-file
  927.     r> close-file
  928. ;
  929.  
  930. [[ $400 checkmemory ]]
  931.  
  932. : readfile
  933.     s" dsk1.forth0" R/O $50 RECLEN VAR OPEN-FILE
  934.     ?dup 0= IF
  935.         begin
  936.             dup $c000 &80 rot read-file
  937.             ?dup 0= if
  938.                 ?dup if
  939.                     $c000 swap type cr
  940.                 else
  941.                     ." eof" close-file drop exit
  942.                 then
  943.             else
  944.                 ." error:" . drop
  945.                 close-file exit
  946.             then
  947.         again
  948.     ELSE
  949.         ." could not open: " .
  950.     THEN
  951. ;
  952.  
  953. : writefile
  954.     s" dsk1.forth0" R/W $50 RECLEN VAR open-file
  955.     ?dup 0= if
  956.         dup s" : test1 2 3 ; "  rot write-file drop
  957.         dup s" : test2 key * test1 * * . ;  " rot write-file drop
  958.         dup s" : test3 10 0 do i test2 loop ; " rot write-file drop
  959.         dup s" cr [char] > emit test3 " rot write-file drop
  960.         close-file
  961.     else
  962.         ." could not open: " .
  963.     then
  964. ;
  965.  
  966.  
  967. : readall
  968.     s" dsk1.dum" r/o open-file 0= if
  969.     >r
  970.     begin
  971.         here 7 r@ read-file    ( -- ur ior )
  972.         0= over and
  973.     while
  974.         here swap type
  975.     repeat
  976.     rdrop
  977.     else
  978.     ." could not open" 
  979.     then
  980. ;
  981.  
  982. : writeall
  983.     s" dsk1.dum" w/o open-file 0= if
  984.         10 0 do
  985.             dup s" hi there, guacamole hater! " rot write-file . .
  986.         loop
  987.         close-file
  988.         drop
  989.     else
  990.     ." could not create"
  991.     then
  992. ;
  993.  
  994. : rdfile
  995. s" dsk1.file" r/o open-file 0= if
  996.     include-file
  997. then
  998. ;
  999.  
  1000. : rdfile2
  1001. s" dsk1.forth0" r/o var $50 reclen open-file 0= if
  1002.     include-file
  1003. then
  1004. ;
  1005.