home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / newc_dev / dr_15b.lha / FastScan.doc < prev    next >
Text File  |  1992-02-18  |  16KB  |  312 lines

  1.  
  2.                               FASTSCAN.LIBRARY       (version 101.5)
  3.  
  4. The idea here is to provide a shared library which contains two functions
  5. FastExamine() and FastExNext() which are fast replacements for Examine and
  6. ExNext.  Unfortunately, the goal of full compatibility has proven impossible, at
  7. least for me.  But the similarity to the original Examine and ExNext makes it
  8. easy for a program to use either one depending on whether fastscan.library is
  9. installed.  Like, you attempt to open it with
  10.  
  11.     FastScanBase = OpenLibrary ("fastscan.library", 0);
  12.  
  13. and later, instead of ExNext(lock, fib), you use
  14.  
  15.     (FastScanBase ? FastExNext(lock, fib) : ExNext(lock, fib))
  16.  
  17. Using this method, your program will work the same with or without the library,
  18. except for how much time it takes to scan the directory.
  19.  
  20. The differences from the Dos Examine and ExNext functions are:
  21.  
  22.      -- VERY IMPORTANT:  You have to use an extended version of the
  23.         FileInfoBlock struct, with two extra longwords added onto the end.
  24.         Something like this will do:
  25.  
  26.             struct Fib {
  27.                 struct FileInfoBlock f;         /* no "*" */
  28.                 long p;
  29.                 long s;
  30.             };
  31.  
  32.         The last extra field (called s above) MUST be initialized to either zero
  33.         or negative one before calling FastExamine.  Use zero if you are not
  34.         going to do a recursive scan of subdirectories (details below).  If you
  35.         don't initialize it, you'll meditate.  Use this struct as you would
  36.         normally use struct FileInfoBlock:  FastExamine(lock, fib).
  37.  
  38.      -- VERY IMPORTANT:  There's a cleanup function you need to use when you're
  39.         done scanning.  Like this:  FastExCleanup(fib); where fib is the
  40.         extended FileInfoBlock you've been passing to FastExNext.  Otherwise
  41.         memory etc. won't be deallocated, and in the case of a floppy disk, the
  42.         motor won't get turned off until the next disk operation.
  43.  
  44.      -- If you want to do a recursive scan of subdirectories, there is special
  45.         optimization you can use, by setting the last longword of the extended
  46.         FileInfoBlock (the s field of struct Fib above) to -1 instead of 0
  47.         before calling FastExamine for the first time.  This will be referred to
  48.         as using "the deep version" in this document.  This optimization works
  49.         not just for recursive descent, but for any succession of nonrepeating
  50.         multiple scans.  It causes FastExNext to remember extra information, so
  51.         as to reduce the amount of disk reading it has to do.
  52.  
  53.      -- The set of possible error returns might be different.  Details below.
  54.  
  55.      -- You can't start inner FastExNext scans using a copied fib from an outer
  56.         FastExNext instead of FastExamine'ing the new inner directory lock.
  57.         (You're not supposed to do this with Examine and ExNext but you can get
  58.         away with it, at least under 1.x amigados.)  If you are using the
  59.         optimized "deep version", you can't even start the inner FastExamine
  60.         with a blank struct Fib; you must copy at least the two extra fields at
  61.         the end (p and s) from the struct Fib you got back in the previous scan.
  62.         Use the most recent values you have for those two fields.
  63.  
  64.      -- The files may be returned in a different order.
  65.  
  66.      -- Using fastscan.library eats a lot more memory than just using the Dos
  67.         functions.  But if memory is low it won't hog it all; it will sacrifice
  68.         speed for politeness.
  69.  
  70.      -- Since we end-run the dos handler and use the device driver task, any
  71.         data buffered in there won't help; AddBuffers goes to waste.  But
  72.         AddBuffers does work for the Fast File System if you're not using the
  73.         deep version, because end running typically offers no advantage then,
  74.         except with unusually large directories, especially if unfragmented.
  75.  
  76.      -- Examine usually does not need to do any physical IO, but FastExamine
  77.         usually reads one track, and sometimes initiates the reading of another.
  78.         (Disk IO is asynchronous in fastscan.library).
  79.  
  80.      -- FastExNext might return slightly out-of-date information if files are
  81.         being renamed or deleted or whatever during the scan.  Which is
  82.         better than the original functions will do ... if you rename files
  83.         while you're scanning them with regular ExNext, it can get seriously
  84.         confused and forget what directory it's in, at least with some
  85.         file systems such as the Ram-Handler.  If you're renaming or deleting
  86.     files as you scan, just make sure the rename/delete operation lags one
  87.     step behind the ExNext or FastExNext.
  88.  
  89. The cleanup function FastExCleanup() takes as its one parm the pointer to the
  90. extended FileInfoBlock (struct Fib or whatever you want to call it) that you've
  91. been using for the FastExNext scan and returns nothing.  It turns off the disk
  92. motor if necessary, closes everything it opened, and frees all the memory it was
  93. using.  Unless you're using the deep version, this is done automatically when
  94. you get to the last entry in the directory, and is unnecessary if the original
  95. FastExamine hit a file instead of a directory.  If you attempt FastExNext on a
  96. FastExCleanup'ed fib, it will fail with IoErr returning ERROR_NO_MORE_ENTRIES,
  97. even if the scan wasn't finished.  If you use the deep version, call
  98. FastExCleanup only once when the complete scanning operation is finished.  Do
  99. NOT call it when an inner scan is finished but you still want to finish an outer
  100. scan.  Furthermore, FastExCleanup is never automatic with the deep version, you
  101. must call it when you quit scanning for any reason.  Even if the first
  102. FastExamine does not return a directory.
  103.  
  104. The easiest way to handle FastExCleanup is not to test for different error
  105. returns, but simply to call it always whenever you know that the directory
  106. scan you are doing is over, even if it's not actually needed.  This is the
  107. most important change you will have to make to change an ExNext program into
  108. a FastExNext program, besides using the extended FileInfoBlock in place of
  109. the normal one.  It's okay to use FastExCleanup twice on one fib.
  110.  
  111. So the classical way to use fastscan.library is as follows.  If normally you
  112. would do something like this:
  113.  
  114.     struct FileInfoBlock *fibb;
  115.     ...
  116.     fibb = AllocMem(sizeof(*fibb), MEMF_PUBLIC);
  117.     if (!fibb) Bomb();
  118.     Examine(lock, fibb);
  119.     while (ExNext(lock, fibb) {
  120.         DoSomethingWith(fibb);
  121.         ...
  122.     }
  123.     FreeMem(fibb, sizeof(*fibb));
  124.  
  125. the fastscan version, with all the necessary extras, would be:
  126.  
  127.     void *FastScanBase;
  128.     struct Fib {
  129.         struct FileInfoBlock f;
  130.         long p, s;
  131.     } *fibb;
  132.     ...
  133.     FastScanBase = OpenLibrary("fastscan.library", 0);
  134.     fibb = AllocMem(sizeof(*fibb), MEMF_PUBLIC);
  135.     if (!fibb) Bomb();
  136.     fibb->s = 0;                        /* <= important! */
  137.     if (FastScanBase)
  138.         FastExamine(lock, fibb);
  139.     else
  140.         Examine(lock, &fibb->f);
  141.     while (FastScanBase ? FastExNext(lock, fibb) : ExNext(lock, &fibb->f)) {
  142.         DoSomethingWith(&fibb->f);
  143.         ...
  144.     }
  145.     if (FastScanBase) {
  146.         FastExCleanup(fibb);
  147.         CloseLibrary(FastScanBase);
  148.     }
  149.     FreeMem(fibb, sizeof(*fibb))
  150.  
  151. The deep version is designed to be optimal when used in a way so that each inner
  152. directory is scanned as soon as it is encountered during the scan of an outer
  153. directory.  If you save the names of inner directories and scan them afterwards,
  154. it isn't quite as perfectly optimized for that case.  The next release may allow
  155. you to pick which style to optimize maximally for, though it won't really make
  156. much noticeable difference.  In either case, when FastExamining an inner
  157. directory, fill in the two extra fields of the struct Fib (p and s) with the
  158. MOST RECENT values returned in those fields by a previous FastExNext.  If you
  159. just initialize s to -1, the optimization won't work and it won't free all the
  160. memory ... and I won't promise that it doesn't mess up worse than that.
  161.  
  162. There are two other functions in the library:  one is FastExGet80().  It takes
  163. as its arg a fib that has been used with FastExamine, or which just has the most
  164. recent values of p and s in it.  It returns a pointer to 80 bytes of newly
  165. allocated storage.  It may sometimes succeed in cases when a regular AllocMem
  166. would fail.  This is present because Dr had a use for it.  The other is
  167. FSRexxQuery, which at present does nothing and always returns 1 (the ARexx
  168. "program not found" error code).  Someday there might be a fastscan rexx
  169. function library.
  170.  
  171. How to link fastscan.library into your programs:  if using assembly language,
  172. the offsets from the library bases are as follows:
  173.  
  174.     _LVOFSRexxQuery         equ     -30
  175.     _LVOFastExamine         equ     -36
  176.     _LVOFastExNext          equ     -42
  177.     _LVOFastExCleanup       equ     -48
  178.     _LVOFastExGet80         equ     -54
  179.  
  180. The include file "fastscan.i" has these definitions in it.  Lock BPTRs are
  181. passed in d0, all other args are passed in a0 -- unlike the dos Examine and
  182. ExNext functions which use d1 and d2.  If you are using some language like
  183. Basic, you can use the file "fastscan.fd", which contains the following:
  184.  
  185.     ##base _FastScanBase
  186.     ##bias 30
  187.     ##public
  188.     FSRexxQuery(rexxmess)(A0)
  189.     FastExamine(lock,fibb)(D0/A0)
  190.     FastExNext(lock,fibb)(D0/A0)
  191.     FastExCleanup(fibb)(A0)
  192.     FastExGet80(fibb)(A0)
  193.     ##end
  194.  
  195. To call these functions from C, you have two choices.  If you use a modern ANSI
  196. compiler such as Aztec C 5.0 or newer, SAS/Lattice C 5.0 or newer, or any
  197. version of DICE, the include file "fastscan.h" should work.  I think.  Or you
  198. can make your own declarations, something like these:
  199.  
  200.     #include <libraries/dos.h>
  201.  
  202.     struct Fib {
  203.         struct FileInfoBlock f;
  204.         long p, s;
  205.     };
  206.  
  207.     long FastExamine(BPTR lok, struct Fib *fibb);
  208.     long FastExNext(BPTR lok, struct Fib *fibb);
  209.     void FastExCleanup(struct Fib *fibb);
  210.     void *FastExGet80(struct Fib *fibb);
  211.  
  212.     void *FastScanBase;
  213.  
  214.  
  215. If you have a non-ANSI compiler you will have to remove the arguments from the
  216. declarations, substituting simply:
  217.  
  218.     long FastExamine(), FastExNext();
  219.     void FastExCleanup(), FastExGet80();
  220.  
  221. If your compiler does not support inline library calls ("fastscan.h" provides
  222. the correct pragmas for both Aztec and SAS/Lattice), you will have to use glue
  223. routines.  To do this, use an assembler on the file "fastscanglue.asm" to
  224. produce an object file which you then link with your program.  Assemble it with
  225. the small or large data memory model as needed by your program.  Since the
  226. number of different .o files that might be needed is large and I have no means
  227. handy of creating some of them, I am providing only the assembly source, which
  228. should work with most any assembler including PD ones.
  229.  
  230. These functions use regular Examine and ExNext packets (asynchronously) in cases
  231. which they can't optimize with device-level IO.  This happens when it's not a
  232. true AmigaDos disk but instead something like RAM: or a network file system or
  233. an MS-Dos formatted disk, or when the block size is not 512 bytes (I guess I
  234. should fix that someday) (but I heard that the file system itself can't even
  235. handle such yet), also in the case of a null lock (note that if you DupLock a
  236. null you get null, but if you have a null CD and go Lock("", ACCESS_READ), you
  237. get a real non-null lock), or when there's not enough contiguous memory for a
  238. track buffer plus 50K of safety margin.  The performance of this thing is
  239. somewhat better than the Commodore file systems in all cases; in the case of a
  240. non-FFS disk under dos 1.3 and older, it is DRASTICALLY better.  In the most
  241. extreme low-memory conditions, or if it can't allocate a signal bit, it will use
  242. the Examine and ExNext functions synchronously.
  243.  
  244. Note that, like the dos.library functions they replace, the functions in
  245. fastscan.library must be called by a DOS process; calling them from a simple
  246. Exec task will fail, possibly in a damaging way.
  247.  
  248. This version can set the following IoErr codes in addition to 232 (no more
  249. entries):  103 if you run out of memory (or signal bits), 211 if you pass it an
  250. invalid lock (not guaranteed to catch all bad locks), 218 (not mounted) if you
  251. pop the disk out of the drive and cancel the "please replace" requester, and 225
  252. (not a dos disk) if there's a hardware IO error or other general trouble in
  253. reading the disk.  (Why is there no DOS error number for hardware errors??  With
  254. the old file system, the Read function returns error 286 [not documented] in
  255. case of a hard error ... the Write function reports success!)  Also, if
  256. perchance you pass it a null FileInfoBlock pointer, it indicates an error
  257. condition by crashing the system.  I don't know what the full set of possible
  258. error returns from vanilla Examine / ExNext is.
  259.  
  260. When to stop scanning:  Official Amiga programs don't seem to agree whether you
  261. should stop scanning when ExNext returns an error other than 232 (no more
  262. entries).  Dir abandons the scan, List sometimes keeps trying, like when you pop
  263. the disk out, even cancelling the "Please replace" requester doesn't stop it, it
  264. keeps putting out the same output line until the disk goes back in or you use
  265. control-C.  With FastExNext, my goal is that you can continue past error if the
  266. error is 218 (not mounted) or 225 (not a dos disk = device level error).  You
  267. might not get a complete directory list under such conditions, and I'm not
  268. completely sure of its reliability in such cases, so I recommend abandoning the
  269. scan and calling FastExCleanup.  Particularly you should abandon the scan if the
  270. user has clicked Cancel on a "Please replace..." requester, which will have
  271. happened if you get error 218 (not mounted) and your pr_WindowPtr is not -1.
  272. Old ExNext sets IoErr 218 if the disk is out of the drive, but if you pop the
  273. disk out during a hardware read and cancel the "You MUST replace ... in unit N
  274. !!!" requester, it sets IoErr to (of all things) 232 "no more entries".  How
  275. bogus!  And also, how bogus to say "You MUST replace ... !!!" for a read-only
  276. operation that it actually recovers from with no problems, as far as I can tell.
  277.  
  278. A note about System Requests that pop up when there's an error:  in the case of
  279. a hardware error, I had to mimic the official system requester by hand, and I
  280. have discovered that the intuition AutoRequest function is the one part of this
  281. that is capable of guruing when memory is low.  It's supposed to display an
  282. alert under such conditions, but only does so if the memory is just slightly too
  283. low (it needs 6k of contiguous chip ram to DisplayAlert under 1.3).  THANKS TO
  284. JOHN GERLACH JR for AllocMaster, which helped me to make most of this pretty
  285. bulletproof under low memory conditions.  There are two requesters which this
  286. can fire up:  "Please replace volume Xxxxxxxx in any drive" and, depending on
  287. which operating system you are using, "Volume Xxxxxxxxxxx has a read error on
  288. disk block NNNN" (in the case of AmigaDOS 2.0 and newer) or "Volume Xxxxxxxxxxx
  289. has a read/write error" (in the case of 1.3 and older).  This latter does not
  290. necessarily mean a physically defective disk or drive.  Elsewhere in Dos this
  291. can come up if there is simply a bogus block pointer somewhere.  This is used as
  292. a catchall for all device level errors other than popping out the disk.
  293.  
  294. Actually, it is possible to get a "You MUST replace !!!" requester by popping
  295. out a disk during a FastExNext scan.  I think this happens when you interrupt a
  296. Dos operation (such as locking an inner directory) rather than a fastscan
  297. operation (reading a track).  Fastscan now knows not to put up its own requester
  298. once the disk is back in the drive.  After reinserting the disk, you have to
  299. click "Retry" by hand in this case; it does not sense disk insertion.
  300.  
  301. fastscan.library is Copyright © 1992 by Paul Kienitz, and is freely
  302. distributable in unmodified form provided that this copyright notice is visibly
  303. included.  Modified versions of fastscan.library are not to be distributed
  304. unless I have demonstrably ceased to support it myself, or given permission.
  305. Feedback is appreciated.  I can be reached at:
  306.  
  307.                 Paul Kienitz              BBSes: try
  308.                 6430 San Pablo ave.           Winners Circle 415-845-4812
  309.                 Oakland, CA  94608            Triple-A 415-222-9416
  310.                 USA                           FAUG 415-515-2479
  311.  
  312.