home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 364b.lha / PCQ_v1.1 / Runtime / PCQ / Openers.asm < prev    next >
Encoding:
Assembly Source File  |  1990-04-08  |  8.7 KB  |  304 lines

  1.  
  2. *    Openers.asm (of PCQ Pascal runtime library)
  3. *    Copyright (c) 1989 Patrick Quaid
  4.  
  5. *    This file takes care of opening and closing DOS files.  In
  6. *    much the same way as the memory routines, these routines keep a
  7. *    list of the open files around.  Open() puts the files on the list
  8. *    and Close() takes them off.
  9.  
  10.     SECTION    ONE
  11.  
  12.     XREF    _p%DOSBase
  13.     XREF    _LVOOpen
  14.     XREF    _LVOIsInteractive
  15.     XREF    _LVOIoErr
  16.     XREF    _p%new
  17.     XREF    _p%dispose
  18.     XREF    _p%ExitWithAddr
  19.     XREF    _LVORead
  20.     XREF    _LVOClose
  21.     XREF    _p%IOResult
  22.     XREF    _p%FlushBuffer
  23.     XREF    i_lmul
  24.     XREF    i_ldiv
  25.  
  26.     XDEF    filekey
  27.  
  28. *    algorithm for open:
  29. *
  30. *    HANDLE := DOSOpen handle
  31. *    if then handle = nil
  32. *        return false
  33. *    INTERACTIVE := IsInteractive
  34. *    if INTERACTIVE and (Access = ModeOldFile) then
  35. *        MAX := RECSIZE
  36. *    else
  37. *        MAX := (MAX div RECSIZE) * RECSIZE
  38. *        if MAX = 0 then
  39. *        MAX := RECSIZE
  40. *    Allocate BUFFER of size MAX
  41. *    if BUFFER = nil then
  42. *        close HANDLE
  43. *        return false
  44. *    set MAX := BUFFER (First position) + MAX (buffer size)
  45. *    - thus MAX points to first byte AFTER buffer
  46. *    CURRENT := BUFFER
  47. *    LAST := BUFFER
  48. *    EOF := False
  49. *    if (Access = ModeOldFile) and (not INTERACTIVE) then
  50. *        FillBuffer
  51. *    link into file list
  52. *    return true
  53.  
  54. * Upon entry, the stack looks like:
  55. *
  56. *    4(SP) -> Address of File Record
  57. *    8(SP) -> Address of File Name String
  58. *
  59. *    The File Record is initialized with the following values:
  60. *
  61. *    ACCESS    = either ModeOldFile or ModeNewFile
  62. *    RECSIZE    = the size of a record (1 for Text files)
  63. *    MAX    = the buffer size requested
  64. *
  65.  
  66.     INCLUDE    ":runtime/FileRec.i"
  67.  
  68.     XDEF    _p%Open
  69. _p%Open:
  70.  
  71.  
  72.     move.l    8(sp),d1    ; get file name
  73.     move.l    4(sp),a0    ; get address of FileRec
  74.     moveq.l    #0,d2        ; clear out upper word
  75.     move.w    ACCESS(a0),d2    ; get access mode
  76.     move.l    _p%DOSBase,a6
  77.     jsr    _LVOOpen(a6)    ; open the file
  78.     move.l    4(sp),a0
  79.     move.l    d0,HANDLE(a0)    ; save the file handle
  80.     bne.s    OpenedOK    ; no errors
  81.     jsr    _LVOIoErr(a6)    ; get the error number
  82. *    move.l    d0,_p%IOResult    ; don't set IOResult from Open
  83.     moveq.l    #0,d0
  84.     rts            ; return false
  85. OpenedOK
  86.     move.l    d0,d1        ; set up caller
  87.     jsr    _LVOIsInteractive(a6)    ; is it interactive ?
  88.     move.l    4(sp),a0    ; get file rec
  89.     move.b    d0,INTERACTIVE(a0)    ; set interactive
  90.     beq.s    AdjustBuffer    ; if not interactive, skip this
  91.     cmp.w    #1005,ACCESS(a0) ; is it an input file ?
  92.     bne.s    AdjustBuffer    ; if not, skip
  93.     move.l    RECSIZE(a0),d0    ; d0 := RECSIZE
  94.     move.l    d0,MAX(a0)    ; save size for later
  95.     bra.s    AllocBuffer    ; go to allocate the buffer
  96. AdjustBuffer
  97.     move.l    MAX(a0),d0    ; d0 := Buffer Size requested
  98.     move.l    RECSIZE(a0),d1    ; d1 := record size
  99.     jsr    i_ldiv        ; call 32-bit divide routines. d0/d1 in d0
  100.     tst.l    d0        ; is it zero?
  101.     bne.s    1$        ; if not, skip
  102.     moveq.l    #1,d0        ; at least 1
  103. 1$    move.l    4(sp),a0    ; get file rec
  104.     move.l    RECSIZE(a0),d1    ; d1 := record size again
  105.     jsr    i_lmul        ; d0 := (max div recsize) * recsize
  106.     move.l    4(sp),a0    ; get file rec address
  107.     move.l    d0,MAX(a0)    ; save it for later
  108. AllocBuffer
  109.     jsr    _p%new        ; allocate buffer
  110.     move.l    4(sp),a0    ; a0 := file record address
  111.     move.l    d0,BUFFER(a0)    ; set buffer
  112.     bne.s    InitializeFR    ; if OK, initialize record
  113.     move.l    HANDLE(a0),d1    ; set up for close
  114.     move.l    _p%DOSBase,a6    ; get DOS library base
  115.     jsr    _LVOClose(a6)    ; close the file
  116. *    move.l    #50,_p%IOResult    ; Don't set IOResult
  117.     moveq.l    #0,d0
  118.     rts            ; return false
  119. InitializeFR
  120.     move.l    MAX(a0),a1    ; get buffer size
  121.     adda.l    BUFFER(a0),a1    ; add to first address
  122.     move.l    a1,MAX(a0)    ; set maximum address: last byte + 1
  123.     move.l    BUFFER(a0),a1    ; a1 := first byte
  124.     move.l    a1,CURRENT(a0)    ; CURRENT := BUFFER
  125.     move.l    a1,LAST(a0)    ; LAST := BUFFER
  126.     move.b    #0,EOF(a0)    ; EOF := False
  127.     cmp.w    #1005,ACCESS(a0)    ; is input file ?
  128.     bne.s    LinkFile    ; if not, skip this
  129.     tst.b    INTERACTIVE(a0)    ; is it interactive ?
  130.     bne.s    LinkFile    ; if so, skip this
  131.     jsr    _p%FillBuffer    ; fill the buffer for input file
  132. LinkFile
  133.     move.l    filekey,NEXT(a0) ; a0.Next := filekey
  134.     move.l    a0,filekey    ; filekey := a0 (linked a0 into list)
  135.     moveq.l    #-1,d0        ; return true
  136.     rts
  137.  
  138.     XDEF    _p%FillBuffer
  139. _p%FillBuffer
  140.  
  141. * Read as many bytes as possible into the file's buffer
  142. * on entry, a0 is the address of the file record, which contains
  143. * all the important info.  This routine sets EOF
  144.  
  145. *    Algorithm:
  146. *
  147. *    if IOResult <> 0 then
  148. *        return
  149. *    if EOF then
  150. *        set IOResult and return
  151. *    Read MAX - BUFFER bytes into BUFFER
  152. *    CURRENT := BUFFER
  153. *    LAST := BUFFER + bytes read
  154. *    if LAST = BUFFER then
  155. *        EOF := True
  156. *
  157.  
  158.     tst.l    _p%IOResult    ; is IO OK?
  159.     bne    3$        ; if not, leave now
  160.     tst.b    EOF(a0)        ; at EOF?
  161.     beq.s    1$        ; if not, skip ahead
  162.     move.l    #51,_p%IOResult    ; set IOResult = Access past EOF
  163.     rts
  164. 1$    move.l    a0,-(sp)    ; save the File Rec
  165.     move.l    HANDLE(a0),d1    ; get the file handle
  166.     bne.s    2$        ; if it's open, skip
  167.     jsr    _p%MayOpenInput    ; if not, try to open input
  168.     move.l    HANDLE(a0),d1    ; if we got here, we must be OK
  169. 2$    move.l    BUFFER(a0),d2    ; get first address
  170.     move.l    MAX(a0),d3    ; get last address + 1
  171.     sub.l    d2,d3        ; number of bytes to read
  172.     move.l    _p%DOSBase,a6    ; get dos.library
  173.     jsr    _LVORead(a6)
  174.     move.l    (sp)+,a0    ; get file record back
  175.     move.l    BUFFER(a0),d1    ; get initial position
  176.     move.l    d1,CURRENT(a0)    ; set CURRENT := initial
  177.     add.l    d0,d1        ; get BUFFER + bytes read
  178.     move.l    d1,LAST(a0)    ; LAST := BUFFER + bytes read
  179.     tst.l    d0        ; did we actually read anything?
  180.     bne.s    3$        ; if so, skip
  181.     move.b    #-1,EOF(a0)    ; set EOF := True
  182. 3$    rts
  183.  
  184. *    MayOpenInput
  185. *
  186. *    This routine opens a Standard Input window for programs that
  187. *    may have started from the Workbench.  It gets the window spec
  188. *    from _StdInName, which is defined either in the User program
  189. *    or, by default, in this library.  If the Output file is already
  190. *    open, and it's interactive, that already open file is used.
  191. *
  192. *    Algorithm for MayOpenInput:
  193. *
  194. *    if a0 <> Input then
  195. *        generate a runtime error
  196. *    if Output is open and interactive then
  197. *        Output.Handle := Input.Handle
  198. *    else
  199. *        Open(StdInName, Input)
  200. *        if it did not open OK
  201. *        generate a runtime error
  202. *
  203.  
  204. *    Upon entry to this routine, a0 holds the address of the
  205. *    File Record, which may or may not be Input.
  206.  
  207.     XREF    _p%exit
  208.     XREF    _StdInName
  209.     XREF    _Input
  210.     XREF    _Output
  211.  
  212. _p%MayOpenInput
  213.     cmpa.l    #_Input,a0    ; is it Input?
  214.     beq.s    1$        ; if so, skip this
  215.     move.l    #52,d0        ; runtime error
  216.     jsr    _p%ExitWithAddr    ; generate the error
  217. 1$    move.l    #_Output,a1    ; get Input ptr
  218.     tst.l    HANDLE(a1)    ; is it open?
  219.     beq    2$        ; if not, open a new one
  220.     tst.b    INTERACTIVE(a1)    ; is it interactive?
  221.     bne    2$        ; if not, open a new file
  222.     move.l    HANDLE(a1),a1    ; get the file handle
  223.     move.l    a1,HANDLE(a0)    ; and copy it over
  224.     rts            ; and try that one
  225. 2$    move.l    #80,MAX(a0)    ; set up for Open call
  226.     move.l    #1,RECSIZE(a0)    ; Text file
  227.     move.w    #1005,ACCESS(a0)    ; it's an input file (ModeOldFile)
  228.     move.l    _StdInName,-(sp)    ; push the file name
  229.     move.l    a0,-(sp)    ; push the file record address
  230.     jsr    _p%Open        ; try to open this file
  231.     move.l    (sp)+,a0    ; retrieve file record
  232.     addq.l    #4,sp        ; and fix stack
  233.     tst.b    d0        ; did it go OK?
  234.     bne.s    3$        ; if so, go on
  235.     move.l    #53,d0        ; if not, generate an error
  236.     jsr    _p%ExitWithAddr    ; goodbye
  237. 3$    rts            ; return to sender
  238.  
  239.  
  240. *    Close the file
  241. *
  242. *    This routine unlinks the file from the open-file list, then
  243. *    de-allocates the buffer and closes the file.  If the file
  244. *    is for some reason not on the open-file list, the routine
  245. *    attempts to close it and deallocate its buffer anyway.  Thus
  246. *    you can generate several types of errors by closing a file
  247. *    twice.
  248. *
  249. *    Algorithm:
  250. *
  251. *    if filekey <> nil then
  252. *        if filekey = FileRec then
  253. *        filekey := FileRec.NEXT
  254. *        else
  255. *        a1 := filekey
  256. *        while a1 <> nil do
  257. *            if a1.Next = FileRec then
  258. *            a1.Next := FileRec.Next
  259. *            skip ahead to FlushBuffer business
  260. *            a1 := a1.Next
  261. *    if ACCESS = ModeNewFile then
  262. *        FlushBuffer
  263. *    DOSClose(HANDLE)
  264. *    Dispose(BUFFER)
  265. *
  266. *    Upon entry, a0 holds the address of the file record
  267. *
  268.  
  269.     XDEF    _p%Close
  270. _p%Close:
  271.     move.l    filekey,a1        ; a1 := filekey
  272.     move.l    a1,d0            ; to set flags
  273.     beq    3$            ; if Nil, skip all this
  274.     cmpa.l    a1,a0            ; is a0 = filekey?
  275.     bne.s    1$            ; if not, go to loop
  276.     move.l    NEXT(a1),a1        ; unlink the first file
  277.     move.l    a1,filekey        ; set filekey := filekey.Next
  278.     bra    3$            ; go to flush buffer stuff
  279. 1$    cmpa.l    NEXT(a1),a0        ; a0 = NEXT(a1)
  280.     bne.s    2$            ; if not, skip this
  281.     move.l    a2,-(sp)        ; save a2 for now
  282.     move.l    NEXT(a0),a2        ; a2 := file after a0
  283.     move.l    a2,NEXT(a1)        ; a1.Next := a0.Next (lose a0)
  284.     move.l    (sp)+,a2        ; retrieve a2
  285.     bra.s    3$            ; and do the rest of close
  286. 2$    move.l    NEXT(a1),a1        ; advance file record ptr
  287.     move.l    a1,d0            ; are we at end of list?
  288.     bne.s    1$            ; if not, go on
  289. 3$    move.l    a0,-(sp)        ; save file record
  290.     cmp.w    #1006,ACCESS(a0)    ; was it ModeNewFile ?
  291.     bne.s    4$            ; if not, skip
  292.     jsr    _p%FlushBuffer        ; otherwise flush the buffer
  293. 4$    move.l    HANDLE(a0),d1        ; get handle
  294.     move.l    _p%DOSBase,a6        ; get DOS address
  295.     jsr    _LVOClose(a6)        ; close the file
  296.     move.l    (sp)+,a0        ; get file record back
  297.     move.l    BUFFER(a0),d0        ; get initial address
  298.     jsr    _p%dispose        ; de-allocate it
  299.     rts
  300.  
  301.     SECTION    FileKey
  302. filekey    dc.l    0
  303.     END
  304.