home *** CD-ROM | disk | FTP | other *** search
/ APDL Public Domain 1 / APDL_PD1A.iso / deskutils / _a_l / boota / C-source / c / GetDirs < prev    next >
Encoding:
Text File  |  1993-03-03  |  45.5 KB  |  1,005 lines

  1. /* > c.GetDirs   - (c) Paul Witheridge - Version 2.04 - 03 Mar 1993  */
  2.  
  3. /*===================================================================*/
  4. /*                                                                   */
  5. /*  Getdirentrys                                                     */
  6. /*  ------------                                                     */
  7. /*                                                                   */
  8. /*  Getdirentrys is a function which reads entries from a directory  */
  9. /*  and then invokes a caller-supplied function to process each      */
  10. /*  file-object, passing the directory entry details in a 'direntry' */
  11. /*  structure defined in 'getdirs.h'.                                */ 
  12. /*                                                                   */ 
  13. /*  The caller supplies the name of the directory to be read (plus   */
  14. /*  optionally, a wildcarded or non-wildcarded object name to be     */
  15. /*  matched against objects in the directory), an indicator as to    */
  16. /*  whether any subdirectories found should be read (recursively)    */
  17. /*  and a pointer to the caller's function to process the entries.   */
  18. /*                                                                   */
  19. /*  The global integer variable "getdirentrys_counter" counts the    */
  20. /*  the number of objects passed to the caller's function.           */
  21. /*                                                                   */
  22. /*  The caller's function should return a value of 'TRUE' if it has  */
  23. /*  not encountered any fatal errors, or 'FALSE' if it wants to      */
  24. /*  stop processing of any further directory entries.                */
  25. /*                                                                   */
  26. /*-------------------------------------------------------------------*/
  27. /*                                                                   */
  28. /*  This file includes the following functions:                      */
  29. /*                                                                   */
  30. /*       getdirentrys   -  read and process directory entries        */
  31. /*       buildtree      -  internal (static) recursive function      */
  32. /*       processtree    -  internal (static) recursive function      */
  33. /*       extendpath     -  internal (static) function                */
  34. /*       freetree       -  internal (static) recursive function      */
  35. /*                                                                   */
  36. /*-------------------------------------------------------------------*/
  37. /*                                                                   */
  38. /*  COPYRIGHT NOTICE                                                 */
  39. /*                                                                   */
  40. /*  GetDirs is subject to Copyright.                                 */
  41. /*                                                                   */
  42. /*  Permission is granted by the author to any recipient of this     */
  43. /*  material to use and make/disseminate copies of the application   */
  44. /*  provided that no charges are made for doing so (other than to    */
  45. /*  cover any cost of media or postage) and that this notice is      */
  46. /*  included with all copies.                                        */
  47. /*                                                                   */
  48. /*===================================================================*/
  49.  
  50. #include "kernel.h"                   /* ARC specifics               */
  51. #include <ctype.h>                    /* Character handling          */
  52. #include <limits.h>                   /* Implementation limits       */
  53. #include <stddef.h>                   /* Standard defintions         */
  54. #include <stdio.h>                    /* Input/output                */
  55. #include <stdlib.h>                   /* General utilities           */
  56. #include <string.h>                   /* String handling             */
  57.  
  58. #include "beep.h"                     /* Beep header                 */
  59. #include "getdirs.h"                  /* GetDirs header              */
  60. #include "useful.h"                   /* Useful defns                */
  61.  
  62. /*-------------------------------------------------------------------*/
  63. /* Global data declarations and definitions.                         */
  64. /*-------------------------------------------------------------------*/
  65.  
  66. #define maxpathlen     255            /* Max path length             */
  67. #define maxobjectlen    20            /* Max object length           */
  68. #define maxdirlistlen  850            /* Max directory list length   */
  69.  
  70. struct dirblock                       /* Directory list structure    */
  71. {
  72.   struct dirblock *subdirq ;          /* Ptr to subdirectory tree    */
  73.   struct dirblock *nextptr ;          /* Ptr to next list            */
  74.   struct dirblock *contptr ;          /* Ptr to continuation list    */
  75.   int nobjects ;                      /* No. of objects in this list */
  76.   int handle ;                        /* Handle (id) for this list   */
  77.   char dirlist[maxdirlistlen] ;       /* List of nul-term'd objects  */
  78. } ;
  79.  
  80. int getdirentrys_counter ;            /* Count of files processed    */
  81.  
  82. static enum boolean (*funcptr)(       /* Ptr to function             */
  83.   const char *path,
  84.   direntry *ptr) ;
  85.  
  86. static const char toolong[] =         /* Common error message        */
  87.   "'%s' too long" ;
  88.  
  89. static const char outofmemory[] =     /* Common error message        */
  90.   "out of memory" ;
  91.  
  92. static const char invalidentry[] =    /* Common error message        */
  93.   "Invalid directory entry '%s'\n" ;
  94.  
  95. /*-------------------------------------------------------------------*/
  96. /*  Declare functions local in scope to this file.                   */
  97. /*-------------------------------------------------------------------*/
  98.  
  99. static enum boolean buildtree(        /* Build directory list tree   */
  100.   char *path,
  101.   const char *object,
  102.   const enum recursive recursion,
  103.   const int handle,
  104.   struct dirblock **subdirq) ;
  105.  
  106. static enum boolean processtree(      /* Process directory list tree */
  107.   char *path,
  108.   struct dirblock *dirblkptr) ;
  109.  
  110. static enum boolean extendpath(       /* Add leafname to path        */
  111.   char *path,
  112.   int pathlen,
  113.   const char *leafname) ;
  114.  
  115. static void freetree(                 /* Free directory list tree    */
  116.   struct dirblock **subdirq) ;
  117.  
  118. /*===================================================================*/
  119. /*                                                                   */
  120. /* getdirentrys  -  read directory entries                           */
  121. /* ------------                                                      */
  122. /*                                                                   */
  123. /* This function is called to read entries from a caller-specified   */
  124. /* directory and pass details of any entries for file objects to a   */
  125. /* caller-supplied function. It is intended for use with a non       */
  126. /* multitasking utility, since it may write error messages to the    */
  127. /* standard output stream.                                           */
  128. /*                                                                   */
  129. /* The caller provides three arguments:                              */
  130. /*                                                                   */
  131. /* (1) Directory name and optional object name. This may be a fully  */
  132. /*     qualified name (e.g. 'adfs::IDEDisc4.$.Clib.h') or it may be  */
  133. /*     relative to the currently selected directory (e.g. just 'h'   */
  134. /*     if the CSD is 'adfs::IDEDisc4.$.Clib' or '^.h' if the CSD is  */
  135. /*     'adfs::IDEDisc4.$.Clib.o'). It may end with a wild-carded or  */
  136. /*     non-wildcarded object name which will be used to select       */
  137. /*     objects from the director (e.g. 'h.a*' meaning all file       */
  138. /*     objects beginning with 'a' in directory 'h' which is a sub-   */
  139. /*     directory of the CSD).                                        */
  140. /*                                                                   */
  141. /* (2) A switch indicating whether any subdirectories found in the   */
  142. /*     specified directory are to be processed or not. This can take */
  143. /*     one of three values 'RECURSE_NEVER', 'RECURSE_ONCE' or        */
  144. /*     'RECURSE_ALWAYS'. These are defined in 'getdirs.h'. They have */
  145. /*     the following effect:                                         */
  146. /*                                                                   */
  147. /*     RECURSE_NEVER implies that the caller knows that the first    */
  148. /*     argument is in the form 'directory.object', and that object   */
  149. /*     is a (possibly wildcarded) file leafname. Only file objects   */
  150. /*     in 'directory' are to be processed; any subdirectories are    */
  151. /*     to be ignored. So if 'object' turned out to be a directory    */
  152. /*     name it would be ignored. This value would only be used under */
  153. /*     special circumstances.                                        */
  154. /*                                                                   */
  155. /*     RECURSE_ONCE implies that the caller is unsure whether the    */
  156. /*     first argument is in the form 'directory.object' or just      */
  157. /*     'directory'. If it turns out to be a directory, then all the  */
  158. /*     file objects in that directory are to be processed, but any   */
  159. /*     subdirectories are to be ignored. This would be the normal    */
  160. /*     value to use if subdirectories were not to be processed.      */
  161. /*                                                                   */
  162. /*     RECURSE_ALWAYS implies full recursion. All files matching     */
  163. /*     'object' found in directory will be processed. All sub-       */
  164. /*     directories matching 'object' will be read; all files in them */
  165. /*     will be processed and all subdirectories found will be read   */
  166. /*     recursively.                                                  */
  167. /*                                                                   */
  168. /* (3) A pointer to a function which will process the file-objects.  */
  169. /*     It will be called once for each file-object found in the      */
  170. /*     specified directory (and all subdirectories if argument 2     */
  171. /*     specifies recursive processing of subdirectories). It is      */
  172. /*     passed the name of the directory and a pointer to the details */
  173. /*     from the directory in a 'direntry' structure. These details   */
  174. /*     include the object-name, its load and exec addresses (which   */
  175. /*     may be in the form of file-type and time-stamp), its length,  */
  176. /*     and its attributes. The file-type is extracted from the load  */
  177. /*     address and supplied separately (or as 0xFFFFFFFF if the file */
  178. /*     has no file-type and time-stamp). This function should return */
  179. /*     a value of 'FALSE' to halt further processing, or 'TRUE' to   */
  180. /*     continue processing of the directory entries.                 */
  181. /*                                                                   */
  182. /* Getdirentrys returns a value of TRUE if it encountered no errors  */
  183. /* in reading the directory entries and if the caller-supplied       */
  184. /* function always returns 'TRUE'. Getdirentrys returns a value of   */
  185. /* 'FALSE' if it encountered any errors reading the directory, or if */
  186. /* the caller-supplied function returned a value of FALSE. The       */
  187. /* values 'TRUE' and 'FALSE' are defined in 'useful.h'.              */
  188. /*                                                                   */
  189. /* Two passes are made through the directory (and subdirectories if  */
  190. /* recursive processing required). The first pass is performed by    */
  191. /* calling the internal function 'buildtree' which creates a tree    */
  192. /* of 'dirlist' structures listing the current contents of the       */
  193. /* directories. The second pass is performed by calling the internal */
  194. /* function 'processtree' which checks that each file-object in the  */
  195. /* tree structure is still present, and if so invokes the caller-    */
  196. /* supplied function.                                                */
  197. /*                                                                   */
  198. /* The two passes are made in this way so that the caller-supplied   */
  199. /* function is only invoked for objects that already exist, and not  */
  200. /* for any objects that the caller-supplied function may create.     */
  201. /* Otherwise, potentially infinite loops could occur - not really    */
  202. /* infinite because they would stop when directory of disk full      */
  203. /* conditions occurred.                                              */
  204. /*                                                                   */
  205. /* The internal function 'freetree' is used to free up the memory    */
  206. /* allocated to the tree structure.                                  */
  207. /*                                                                   */
  208. /* The counter 'getdirentrys_counter' is used to count the number of */
  209. /* times the caller-supplied function is invoked. This count is      */
  210. /* available (as an external variable) to the original caller of     */
  211. /* 'getdirentrys' when thus returns.                                 */
  212. /*                                                                   */
  213. /*===================================================================*/
  214.  
  215. enum boolean getdirentrys(
  216.   const char *fname,                  /* Ptr to initial name         */
  217.   const enum recursive recursion,     /* Recursion switch            */
  218.   enum boolean (*func)(               /* Ptr to function             */
  219.     const char *path,
  220.     direntry *ptr))
  221. {
  222.   /*-----------------------------------------------------------------*/
  223.   /* Local definitions.                                              */
  224.   /*-----------------------------------------------------------------*/
  225.  
  226.   char *p ;                           /* Working pointer             */
  227.   int pathlen ;                       /* Path length                 */
  228.   struct dirblock *dirblkptr ;        /* Ptr to directory tree       */
  229.   enum boolean result ;               /* Value to be returned        */
  230.   char path[maxpathlen+1] ;           /* Path work area              */
  231.   char object[maxobjectlen+1] ;       /* Object work area            */
  232.   static char asterisk[] = "*" ;      /* Default object              */
  233.   static const char specials[] =      /* Special directory letters   */
  234.     "@$^\\&%" ;
  235.  
  236.   /*-----------------------------------------------------------------*/
  237.   /* Executable statements                                           */
  238.   /*                                                                 */
  239.   /* First zero counter in case of immediate exit.                   */
  240.   /*-----------------------------------------------------------------*/
  241.   
  242.   getdirentrys_counter = 0 ;
  243.  
  244.   /*-----------------------------------------------------------------*/
  245.   /* Copy argument "fname" to variable "path" where it can be worked */
  246.   /* on. Strip leading blanks and quotes; then copy up to, but not   */
  247.   /* including, first blank or quote (or to end of string). Take     */
  248.   /* FALSE exit immediately if it is too long.                       */
  249.   /*-----------------------------------------------------------------*/
  250.   
  251.   if ( strlen(fname) > maxpathlen - 3 )
  252.   {
  253.     printf(toolong,fname) ;
  254.     beep() ;
  255.     return FALSE ;
  256.   }
  257.  
  258.   strcpy(path,fname + strspn(fname," \"")) ;
  259.   pathlen = strcspn(path," \"") ;
  260.   path[pathlen] = '\0' ;
  261.  
  262.   /*-----------------------------------------------------------------*/
  263.   /* If argument is null then default to current directory.          */
  264.   /*-----------------------------------------------------------------*/
  265.   
  266.   if ( pathlen == 0 )
  267.   {
  268.     strcpy(path,"@") ;
  269.     pathlen = 1 ;
  270.   } 
  271.  
  272.   /*-----------------------------------------------------------------*/
  273.   /* If argument incorporates any periods, split into path and       */
  274.   /* object at last period.                                          */
  275.   /*-----------------------------------------------------------------*/
  276.  
  277.   if ( ( p = strrchr(path,'.') ) != NULL )
  278.   {
  279.     pathlen = p - path ;
  280.     p++ ;
  281.   }
  282.  
  283.   /*-----------------------------------------------------------------*/
  284.   /* If no period, check for a colon which could be either end of a  */
  285.   /* filing system name or start of a disk name.                     */
  286.   /*                                                                 */
  287.   /* If just name of a filing system (e.g. adfs:) then add "@" and   */
  288.   /* set object to "*".                                              */
  289.   /*                                                                 */
  290.   /* If filing system name plus special directory letter or disk     */
  291.   /* name (e.g. adfs:@ or adfs::IDEDisk4) then just set object to    */
  292.   /* "*".                                                            */
  293.   /*                                                                 */
  294.   /* If filing system name plus object name (e.g. adfs:myfile) then  */
  295.   /* split into path and object just after ":" and add "@" to the    */
  296.   /* filing system name.                                             */
  297.   /*-----------------------------------------------------------------*/
  298.  
  299.   else if ( ( p = strchr(path,':') ) != NULL )
  300.   {
  301.     p++ ;
  302.     if ( *p == '\0' )
  303.     {
  304.       path[pathlen++] = '@' ;
  305.       p = asterisk ;
  306.     }
  307.     else if ( ( *(p + 1) == '\0' && strchr(specials,*p) != NULL ) ||
  308.               ( *p == ':' ) )
  309.     {
  310.       p = asterisk ;
  311.     }
  312.     else
  313.     {
  314.       memmove(p + 1,p,strlen(p) + 1) ;
  315.       *p = '@' ;
  316.       p++ ;
  317.       pathlen = p - path ;
  318.     }
  319.   }
  320.  
  321.   /*-----------------------------------------------------------------*/
  322.   /* No period or colon found.                                       */
  323.   /*                                                                 */
  324.   /* If argument is just a directory letter (e.g. @ or $) then just  */
  325.   /* set object to "*".                                              */
  326.   /*                                                                 */
  327.   /* Otherwise treat entire argument as the object name and set the  */
  328.   /* path to "@".                                                    */
  329.   /*-----------------------------------------------------------------*/
  330.  
  331.   else
  332.  {
  333.     if ( pathlen == 1 && strchr(specials,path[0]) != NULL )
  334.     {
  335.       p = asterisk ;
  336.     }
  337.     else
  338.     {
  339.       p = path + 1 ;
  340.       memmove(p,path,strlen(path) + 1) ;
  341.       *p = '@' ;
  342.       pathlen = 1 ;
  343.     }
  344.   }
  345.  
  346.   /*-----------------------------------------------------------------*/
  347.   /* Copy the object to variable "object" and store terminating nul  */
  348.   /* at end of the path. Take FALSE exit if the object name is too   */
  349.   /* long.                                                           */
  350.   /*-----------------------------------------------------------------*/
  351.  
  352.   if ( strlen(p) > maxobjectlen )
  353.   {
  354.     printf(toolong,p) ;
  355.     beep() ;
  356.     return FALSE ;
  357.   }
  358.   strcpy(object,p) ;
  359.   
  360.   path[pathlen] = '\0' ;
  361.  
  362.   /*-----------------------------------------------------------------*/
  363.   /* Copy function pointer to global variable (to avoid need to pass */
  364.   /* same value on when recursing). Set anchor word for directory    */
  365.   /* list tree to NULL. Then invoke buildtree to create directory    */
  366.   /* list tree and processtree to process the entries in the tree.   */
  367.   /*-----------------------------------------------------------------*/
  368.  
  369.   funcptr = func ;
  370.   dirblkptr = NULL ;
  371.  
  372.   if ( ( result = buildtree(path,object,recursion,0,&dirblkptr) ) == TRUE )
  373.   {
  374.     if ( dirblkptr != NULL )
  375.     {
  376.       result = processtree(path,dirblkptr) ;
  377.       freetree(&dirblkptr) ;
  378.     }
  379.   }
  380.  
  381.   /*-----------------------------------------------------------------*/
  382.   /*  Return to caller.                                              */
  383.   /*-----------------------------------------------------------------*/
  384.  
  385.   return result ;
  386. }
  387.  
  388. /*===================================================================*/
  389. /*                                                                   */
  390. /* buildtree  -  build tree of directory entry lists                 */
  391. /* ---------                                                         */
  392. /*                                                                   */
  393. /* This function is called to create a list of entries in the        */
  394. /* target directory that match a (possibly wildcarded) object name.  */
  395. /* This function will also invoke itself recursively, if required,   */
  396. /* to process subdirectories.                                        */
  397. /*                                                                   */
  398. /* The caller provides as arguments:                                 */
  399. /*                                                                   */
  400. /*   path      -  the name of the directory to be searched, must     */
  401. /*                include the path (if any) and leafname             */
  402. /*                                                                   */
  403. /*   object    -  wildcarded object name used in selecting directory */
  404. /*                entries                                            */
  405. /*                                                                   */
  406. /*   recursion -  switch indicating if matching files only are to be */
  407. /*                processed (RECURSE_NEVER), or first dirctory if no */
  408. /*                matching files found (RECURSE_ONCE), or all        */
  409. /*                matching files and directives are to be processed  */
  410. /*                recursively (RECURSE_ALWAYS)                       */
  411. /*                                                                   */
  412. /*   handle    -  identifier used later to identify this entry       */ 
  413. /*                                                                   */
  414. /*   subdirq   -  pointer to anchor word on which to queue the       */
  415. /*                directory list if it is successfully built.        */
  416. /*                                                                   */
  417. /* If the function completes successfully, it returns a value of     */
  418. /* TRUE (and if any matching directory entries were found, it queues */
  419. /* the directory list it has built off the anchor word provided by   */
  420. /* the caller).                                                      */
  421. /*                                                                   */
  422. /* If an error is encountered, it returns FALSE. In this case no     */
  423. /* directory list is built.                                          */
  424. /*                                                                   */
  425. /*===================================================================*/
  426.  
  427. static enum boolean buildtree(
  428.   char *path,                         /* Directory path              */
  429.   const char *object,                 /* Object (wildcarded)         */
  430.   const enum recursive recursion,     /* Recursion switch            */
  431.   int handle,                         /* Id provided by caller       */
  432.   struct dirblock **subdirq)          /* Ptr to subdir queue anchor  */
  433. {
  434.   /*-----------------------------------------------------------------*/
  435.   /* Local definitions                                               */
  436.   /*-----------------------------------------------------------------*/
  437.  
  438.   int pathlen ;                       /* Length of path string       */
  439.   int found ;                         /* Found switch                */
  440.   int result ;                        /* OSGBPB result               */
  441.   int i ;                             /* Working integer             */
  442.   char *dataptr ;                     /* Working pointer             */
  443.   struct dirblock *dirblkptr ;        /* Ptr to directory list block */
  444.   struct dirblock *firstblkptr ;      /* Ptr to 1st block in cont q  */
  445.   struct dirblock *prevblkptr ;       /* Ptr to prev block in cont q */
  446.   _kernel_osgbpb_block gbpbblk ;      /* OS_GBPG parameter block     */
  447.   _kernel_osfile_block fileblk ;      /* OS_File parameter block     */
  448.  
  449.   /*-----------------------------------------------------------------*/
  450.   /* Executable statements                                           */
  451.   /*                                                                 */
  452.   /* First save length of path on entry so that path can be          */
  453.   /* truncated again to this length on exit. Also set found flag to  */
  454.   /* value of FALSE (it will be set to TRUE later if any files found */
  455.   /* to process.                                                     */
  456.   /*-----------------------------------------------------------------*/
  457.  
  458.   pathlen = strlen(path) ;
  459.   found   = FALSE ;
  460.  
  461.   /*-----------------------------------------------------------------*/
  462.   /* Next allocate memory for first block of directory names         */
  463.   /* (continuation blocks may be added later). Take FALSE exit if    */
  464.   /* unable to do so. Otherwise initialise control fields at head of */
  465.   /* block: number of names in block set to zero; anchor field for   */
  466.   /* subdirectory queue, chain pointer for queueing block off parent */
  467.   /* directory block and chain pointer used to queue continuation    */
  468.   /* blocks are set to null, and handle provided by caller is stored */
  469.   /* in header.                                                      */
  470.   /*-----------------------------------------------------------------*/
  471.  
  472.   if ( ( dirblkptr = malloc(sizeof(struct dirblock)) ) == NULL )
  473.   {
  474.     puts(outofmemory) ;
  475.     beep() ;
  476.     goto badbuild3 ;
  477.   }
  478.   dirblkptr->nobjects = 0 ;
  479.   dirblkptr->subdirq  = dirblkptr->nextptr = dirblkptr->contptr = NULL ;
  480.   dirblkptr->handle   = handle ;
  481.   
  482.   firstblkptr = dirblkptr ;
  483.   prevblkptr  = NULL ;
  484.  
  485.   /*-----------------------------------------------------------------*/
  486.   /* Use OS_GBPB to read list of names in directory that match the   */
  487.   /* (possibly wildcarded) object name provided by the caller. This  */
  488.   /* is done as a repetitive process until an OS_GBPB indicates that */
  489.   /* no more entries remain (probably only ever go through loop once */
  490.   /* but the RICS-OS PRM states that not all filing systems may be   */
  491.   /* able to do it in one go). If zero entries are obtained but the  */
  492.   /* returned values indicate that the end of the directory has not  */
  493.   /* been reached, then the buffer is full. In this case get a       */
  494.   /* continuation block and keep going.                              */
  495.   /*-----------------------------------------------------------------*/
  496.  
  497.   gbpbblk.dataptr  = dirblkptr->dirlist ;
  498.   gbpbblk.buf_len  = sizeof(dirblkptr->dirlist) ;
  499.   gbpbblk.fileptr  = 0 ;
  500.   gbpbblk.wild_fld = (char *)object ;
  501.  
  502.   do
  503.   {
  504.     gbpbblk.nbytes  = INT_MAX ;
  505.     if ( ( result = _kernel_osgbpb(9,(unsigned)path,&gbpbblk) )
  506.            == _kernel_ERROR )
  507.     {
  508.       printf("%s\n",_kernel_last_oserror()->errmess) ;
  509.       goto badbuild1 ;
  510.     }
  511.     for ( i = 0 ; i < gbpbblk.nbytes ; i++ )
  512.     {
  513.       gbpbblk.dataptr = (char *)gbpbblk.dataptr +
  514.                         strlen((char *)gbpbblk.dataptr) + 1 ;
  515.     }
  516.     dirblkptr->nobjects += gbpbblk.nbytes ;
  517.     if ( gbpbblk.fileptr == -1 )
  518.     {
  519.       break ;
  520.     }
  521.     gbpbblk.buf_len = dirblkptr->dirlist + sizeof(dirblkptr->dirlist)
  522.                                          - (char *)gbpbblk.dataptr ;
  523.     if ( gbpbblk.nbytes == 0 || gbpbblk.buf_len < maxobjectlen + 1 )
  524.     {
  525.       if ( ( dirblkptr->contptr = malloc(sizeof(struct dirblock)) ) == NULL )
  526.       {
  527.         puts(outofmemory) ;
  528.         goto badbuild1 ;
  529.       }
  530.       prevblkptr = dirblkptr ;
  531.       dirblkptr  = dirblkptr->contptr ;
  532.       dirblkptr->nobjects = 0 ;
  533.       dirblkptr->subdirq  = dirblkptr->nextptr = dirblkptr->contptr = NULL ;
  534.       dirblkptr->handle   = handle ;
  535.       gbpbblk.dataptr     = dirblkptr->dirlist ;
  536.       gbpbblk.buf_len     = sizeof(dirblkptr->dirlist) ;
  537.     }
  538.   } FOREVER ;
  539.  
  540.   /*-----------------------------------------------------------------*/
  541.   /* If no matching entries found in the directory, go take TRUE     */
  542.   /* exit immediately (which will cause directory list block to be   */
  543.   /* freed instead of queued because found flag is not set).         */
  544.   /*-----------------------------------------------------------------*/
  545.  
  546.   if ( firstblkptr->nobjects == 0 )
  547.   {
  548.     goto goodbuild ;
  549.   }
  550.  
  551.   /*-----------------------------------------------------------------*/
  552.   /* Otherwise free unused space at end of the last (or only)        */
  553.   /* directory list block. Allow for possible NULL return from       */
  554.   /* realloc although it does not seem likely since we are           */
  555.   /* shortening the block.                                           */
  556.   /*-----------------------------------------------------------------*/
  557.  
  558.   dirblkptr = realloc(dirblkptr,offsetof(struct dirblock,dirlist) +
  559.                       (char *)gbpbblk.dataptr - dirblkptr->dirlist) ;
  560.   if ( dirblkptr != NULL )
  561.   {
  562.     if ( prevblkptr == NULL )
  563.     {
  564.       firstblkptr = dirblkptr ;
  565.     }
  566.     else
  567.     {
  568.       prevblkptr->contptr = dirblkptr ;
  569.     }
  570.   }
  571.  
  572.   /*-----------------------------------------------------------------*/
  573.   /* Loop through list of directory entries checking which ones are  */
  574.   /* files and which ones are subdirectories using OS_File type 13   */
  575.   /* to read the catalog details for each object (note: a period     */
  576.   /* must be added to the end of the path for OS_File).              */
  577.   /*-----------------------------------------------------------------*/
  578.  
  579.   for ( dirblkptr = firstblkptr ;
  580.         dirblkptr != NULL ;
  581.         dirblkptr = dirblkptr->contptr )
  582.   {
  583.     for ( i = 0 , dataptr = dirblkptr->dirlist ;
  584.           i < dirblkptr->nobjects ;
  585.           i++ , dataptr += strlen(dataptr) + 1 )
  586.     { 
  587.       strcpy(path + pathlen,".") ;
  588.       fileblk.start = (int)path ;
  589.       switch ( _kernel_osfile(13,dataptr,&fileblk) )
  590.       {
  591.         /*-----------------------------------------------------------*/
  592.         /* Returned value = 1 (file found). Set file found flag.     */
  593.         /*-----------------------------------------------------------*/
  594.  
  595.         case 1  :
  596.  
  597.           found = TRUE ;
  598.           break ;
  599.  
  600.         /*-----------------------------------------------------------*/
  601.         /* Returned value = 2 (directory found). If recursion always */
  602.         /* required, call ouselves recursively to build directory    */
  603.         /* list block for the subdirectory. If not just skip the     */
  604.         /* directory.                                                */
  605.         /*                                                           */
  606.         /* Also accept value of 3 since this is returned for a       */
  607.         /* SparkFS archive using the latest version of SparkFS.      */
  608.         /*-----------------------------------------------------------*/
  609.  
  610.         case 2  :
  611.         case 3  :
  612.  
  613.           if ( recursion == RECURSE_ALWAYS )
  614.           {
  615.             if ( !extendpath(path,pathlen,dataptr) )
  616.             {
  617.               goto badbuild2 ;
  618.             }
  619.             if ( !buildtree(path,"*",RECURSE_ALWAYS,
  620.                             (int)dataptr,&firstblkptr->subdirq) )
  621.             {
  622.               goto badbuild2 ;
  623.             }
  624.           }
  625.           break ;
  626.  
  627.         /*-----------------------------------------------------------*/
  628.         /* Returned value = -2 (error occurred). Display error       */
  629.         /* message and go take FALSE exit.                           */
  630.         /*-----------------------------------------------------------*/
  631.  
  632.         case _kernel_ERROR :
  633.  
  634.           printf("%s\n",_kernel_last_oserror()->errmess) ;
  635.           goto badbuild1 ;
  636.  
  637.         /*-----------------------------------------------------------*/
  638.         /* Other value should not occur. Being paranoid, if they do  */
  639.         /* just display a message and go take FALSE exit.            */
  640.         /*-----------------------------------------------------------*/
  641.  
  642.         default :
  643.  
  644.           printf(invalidentry,dataptr) ;
  645.           goto badbuild1 ;
  646.       }
  647.       
  648.       /*-------------------------------------------------------------*/
  649.       /* Truncate path to original length.                           */
  650.       /*-------------------------------------------------------------*/
  651.  
  652.       path[pathlen] = '\0' ;
  653.     }
  654.   }
  655.  
  656.   /*-----------------------------------------------------------------*/
  657.   /* If no files were found then all the entries must have been for  */
  658.   /* subdirectories. If blanket recursion (RECURSE_ALWAYS) was not   */
  659.   /* required, none of them were processed. If RECURSE_ONCE was      */
  660.   /* specified, process the first entry only by invoking ourselves   */
  661.   /* recursively (but prevent any deeper recursion by specifying     */
  662.   /* RECURSE_NEVER).                                                 */
  663.   /*-----------------------------------------------------------------*/
  664.  
  665.   if ( !found && recursion == RECURSE_ONCE )
  666.   {
  667.     freetree(&firstblkptr->contptr) ;
  668.     firstblkptr->nobjects = 1 ;
  669.     dirblkptr = realloc(firstblkptr,offsetof(struct dirblock,dirlist) +
  670.                                     strlen(firstblkptr->dirlist) + 1) ;
  671.     if ( dirblkptr != NULL )
  672.     {
  673.       firstblkptr = dirblkptr ;
  674.     }
  675.     if ( !extendpath(path,pathlen,firstblkptr->dirlist) )
  676.     {
  677.       goto badbuild2 ;
  678.     }
  679.     if ( !buildtree(path,"*",RECURSE_NEVER,(int)firstblkptr->dirlist,
  680.                     &firstblkptr->subdirq) )
  681.     {
  682.       goto badbuild2 ;
  683.     }
  684.     path[pathlen] = '\0' ;
  685.   }
  686.  
  687.   /*-----------------------------------------------------------------*/
  688.   /* Arrive here to take TRUE exit to caller indicating that no      */
  689.   /* error occurred. If no files were found and no subdirectory      */
  690.   /* lists queued, just free the directory list block. Otherwise     */
  691.   /* queue it off the caller's subdirectory queue.                   */
  692.   /*-----------------------------------------------------------------*/
  693.  
  694.   goodbuild:
  695.  
  696.     if ( !found && firstblkptr->subdirq == NULL )
  697.     {
  698.       freetree(&firstblkptr) ;
  699.     }
  700.     else
  701.     {
  702.       firstblkptr->nextptr = *subdirq ;
  703.       *subdirq = firstblkptr ;
  704.     }
  705.     return TRUE ;
  706.  
  707.   /*-----------------------------------------------------------------*/
  708.   /* Arrive here when error occurs to take FALSE exit to caller.     */
  709.   /*-----------------------------------------------------------------*/
  710.  
  711.   badbuild1:
  712.  
  713.     beep() ;
  714.  
  715.   badbuild2:
  716.  
  717.     freetree(&firstblkptr) ;
  718.  
  719.   badbuild3:
  720.  
  721.     path[pathlen] = '\0' ;
  722.     return FALSE ;
  723. }
  724.  
  725. /*===================================================================*/
  726. /*                                                                   */
  727. /* processtree  -  process files in directory list                   */
  728. /* -----------                                                       */
  729. /*                                                                   */
  730. /* This function processes all the files listed in the tree of       */
  731. /* directory lists created by buildtree, by caller a processing      */
  732. /* function pointed to by global variable "funcptr" for each file in */
  733. /* turn. It calls itself recursively to handle subdirectories.       */
  734. /*                                                                   */
  735. /* The caller provides two arguments:                                */
  736. /*                                                                   */
  737. /*   path         -  name of the directory including path (if any)   */
  738. /*                   and leaf-name.                                  */
  739. /*                                                                   */
  740. /*   firstblkptr  -  pointer to first (or only) block of directory   */
  741. /*                   entries (there may be continuation blocks)      */
  742. /*                                                                   */
  743. /*===================================================================*/
  744.  
  745. static enum boolean processtree(
  746.   char *path,                         /* Ptr to path                 */
  747.   struct dirblock *firstblkptr)       /* Ptr to 1st directory block  */
  748. {
  749.   /*-----------------------------------------------------------------*/
  750.   /* Local definitions.                                              */
  751.   /*-----------------------------------------------------------------*/
  752.  
  753.   int pathlen ;                       /* Length of path string       */
  754.   int i ;                             /* Working integer             */
  755.   char *dataptr ;                     /* Working pointer             */
  756.   struct dirblock *dirblkptr ;        /* Ptr to directory block      */
  757.   struct dirblock *subblkptr ;        /* Working dir list block ptr  */
  758.   _kernel_osfile_block fileblk ;      /* OS_File parameter block     */
  759.   direntry direntryblk ;              /* Directory entry data        */
  760.  
  761.   /*-----------------------------------------------------------------*/
  762.   /* Executable statements                                           */
  763.   /*                                                                 */
  764.   /* First save current path length so that path can be truncated    */
  765.   /* to original length after being extending for recursion.         */
  766.   /*-----------------------------------------------------------------*/
  767.  
  768.   pathlen = strlen(path) ;
  769.  
  770.   /*-----------------------------------------------------------------*/
  771.   /* Perform outer loop starting with first block and proceeding     */
  772.   /* through any continuation blocks. Each block contains list of    */
  773.   /* directory entries.                                              */
  774.   /*-----------------------------------------------------------------*/
  775.  
  776.   for ( dirblkptr = firstblkptr ;
  777.         dirblkptr != NULL ;
  778.         dirblkptr = dirblkptr->contptr )
  779.   {
  780.     /*---------------------------------------------------------------*/
  781.     /* Loop through entries in the directory list invoking OS_File   */
  782.     /* to read catalog information for the object.                   */
  783.     /*---------------------------------------------------------------*/
  784.  
  785.     for ( i = 0 , dataptr = dirblkptr->dirlist ;
  786.           i < dirblkptr->nobjects ;
  787.           i++ , dataptr += strlen(dataptr) + 1 )
  788.     {
  789.       strcpy(path + pathlen,".") ;
  790.       fileblk.start = (int)path ;
  791.       switch ( _kernel_osfile(13,dataptr,&fileblk) )
  792.       {
  793.         /*-----------------------------------------------------------*/
  794.         /* Returned value = 0 (not found). This is unlikely, but     */
  795.         /* could occur if the processing function provided by the    */
  796.         /* caller gets up to very funny tricks. Issue message and    */
  797.         /* ignore.                                                   */
  798.         /*-----------------------------------------------------------*/
  799.  
  800.         case 0  :
  801.  
  802.           printf("'%s.%s' not found\n",path,dataptr) ;
  803.  
  804.           break ;
  805.  
  806.         /*-----------------------------------------------------------*/
  807.         /* Returned value = 1 (file). Bump number of files found and */
  808.         /* copy catalog information into a direntry structure        */
  809.         /* (defined in "getdirs.h"). Extract file-type as            */
  810.         /* convenience for the processing function (or use -1 if not */
  811.         /* file-typed). Then call the processing function. Abort     */
  812.         /* further processing if this returns FALSE.                 */
  813.         /*-----------------------------------------------------------*/
  814.  
  815.         case 1  :
  816.  
  817.           getdirentrys_counter++ ;
  818.  
  819.           direntryblk.load   = fileblk.load ;
  820.           direntryblk.exec   = fileblk.exec ;
  821.           direntryblk.length = fileblk.start ;
  822.           direntryblk.attr   = fileblk.end ;
  823.           direntryblk.name   = dataptr ;
  824.  
  825.           if ( ( fileblk.load & 0xfff00000 ) == 0xfff00000 )
  826.           {
  827.             direntryblk.type = ( fileblk.load & 0x000fff00 ) >> 8 ;
  828.           }
  829.           else
  830.           {
  831.             direntryblk.type = -1 ;
  832.           }
  833.  
  834.           if ( !funcptr(path,&direntryblk) )
  835.           {
  836.             goto badprocess ;
  837.           }
  838.  
  839.           break ;
  840.  
  841.         /*-----------------------------------------------------------*/
  842.         /* Returned value = 2 (directory). Search the queue of       */
  843.         /* subdirectory lists using pointer to directory name as     */
  844.         /* handle. If found then invoke ourselves recursively to     */
  845.         /* process. As before, a value of 3 is also accepted since   */
  846.         /* it indicates a SparkFS archive.                           */
  847.         /*-----------------------------------------------------------*/
  848.  
  849.         case 2  :
  850.         case 3  :
  851.  
  852.           for ( subblkptr = firstblkptr->subdirq ;
  853.                 subblkptr != NULL ;
  854.                 subblkptr = subblkptr->nextptr )
  855.           {
  856.             if ( subblkptr->handle == (int)dataptr )
  857.             {
  858.               if ( !extendpath(path,pathlen,dataptr) )
  859.               {
  860.                 goto badprocess ;
  861.               }
  862.               if ( !processtree(path,subblkptr) )
  863.               {
  864.                 goto badprocess ;
  865.               }
  866.             break ;
  867.             }
  868.           }
  869.  
  870.           break ;
  871.  
  872.         /*-----------------------------------------------------------*/
  873.         /* Returned value = -2 (error). Issue error message and      */
  874.         /* abort any further processing.                             */
  875.         /*-----------------------------------------------------------*/
  876.  
  877.         case _kernel_ERROR :
  878.  
  879.           printf("%s\n",_kernel_last_oserror()->errmess) ;
  880.           beep() ;
  881.           goto badprocess ;
  882.  
  883.         /*-----------------------------------------------------------*/
  884.         /* Other values should not occur. Again, being paranoid, if  */
  885.         /* they do, issue warning message and abort any further      */
  886.         /* processing.                                               */
  887.         /*-----------------------------------------------------------*/
  888.  
  889.         default :
  890.  
  891.           printf(invalidentry,dataptr) ;
  892.           beep() ;
  893.           goto badprocess ;
  894.       }
  895.       
  896.       /*-------------------------------------------------------------*/
  897.       /* Truncate path to original length.                           */
  898.       /*-------------------------------------------------------------*/
  899.  
  900.       path[pathlen] = '\0' ;
  901.     }
  902.   }
  903.   
  904.   /*-----------------------------------------------------------------*/
  905.   /* After all files processed without error, return TRUE.           */
  906.   /*-----------------------------------------------------------------*/
  907.  
  908.   return TRUE ;
  909.  
  910.   /*-----------------------------------------------------------------*/
  911.   /* Arrive here on error to return FALSE.                           */
  912.   /*-----------------------------------------------------------------*/
  913.  
  914.   badprocess:
  915.  
  916.     path[pathlen] = '\0' ;
  917.     return FALSE ;
  918. }
  919.  
  920. /*===================================================================*/
  921. /*                                                                   */
  922. /* extendpath  -  add leafname to path                               */
  923. /* ----------                                                        */
  924. /*                                                                   */
  925. /* This function provides common support to both "buildtree" and     */
  926. /* "processtree" for extending the current path name with a further  */
  927. /* leafname when recursion is required to process a subdirectory.    */
  928. /*                                                                   */
  929. /* It returns TRUE if the path could be extended or FALSE if there   */
  930. /* was not enough room.                                              */
  931. /*                                                                   */
  932. /*===================================================================*/
  933.  
  934. static enum boolean extendpath(
  935.   char *path,                         /* Ptr to current path         */
  936.   int pathlen,                        /* Length of current path      */
  937.   const char *leafname)               /* Ptr to leafname to add      */
  938. {
  939.   /*-----------------------------------------------------------------*/
  940.   /* Executable statements                                           */
  941.   /*                                                                 */
  942.   /* If path would become too long issue error message and take      */
  943.   /* FALSE exit (maxpathlen is defined in "getdirs.h").              */
  944.   /*                                                                 */
  945.   /* Otherwise add period plus leafname to end of path and take      */
  946.   /* TRUE exit.                                                      */
  947.   /*-----------------------------------------------------------------*/
  948.  
  949.   if ( pathlen + 1 + strlen(leafname) > maxpathlen )
  950.   {
  951.     printf(toolong,path) ;
  952.     beep() ;
  953.     return FALSE ;
  954.   }
  955.   
  956.   path[pathlen] = '.' ;
  957.   strcpy(path + pathlen + 1,leafname) ;
  958.   
  959.   return TRUE ;
  960. }
  961.  
  962. /*===================================================================*/
  963. /*                                                                   */
  964. /*  freetree  -  free tree of subdirectory lists                     */
  965. /*  --------                                                         */
  966. /*                                                                   */
  967. /*  This function provides common support to "getdirentrys" and to   */
  968. /*  "buildtree". It frees the tree of directory lists queued off     */
  969. /*  the anchor word provided by the caller. It calls itself          */
  970. /*  recursively to process lists for subdirectories.                 */
  971. /*                                                                   */
  972. /*===================================================================*/
  973.  
  974. static void freetree(
  975.   struct dirblock **subdirq)          /* Ptr to sub directory queue  */
  976. {
  977.   /*-----------------------------------------------------------------*/
  978.   /* Local definitions.                                              */
  979.   /*-----------------------------------------------------------------*/
  980.  
  981.   struct dirblock *dirblkptr ;        /* Directory list block ptr    */
  982.   struct dirblock *contptr ;          /* Ptr to continuation block   */
  983.  
  984.   /*-----------------------------------------------------------------*/
  985.   /* Executable statements                                           */
  986.   /*                                                                 */
  987.   /* Run queue of directory lists queued off the anchor word         */
  988.   /* provided by caller, freeing the storage allocated to the lists. */
  989.   /* Invoke ourselves recursively to process subdirectory lists.     */
  990.   /*-----------------------------------------------------------------*/
  991.  
  992.   while ( ( dirblkptr = *subdirq ) != NULL )
  993.   {
  994.     *subdirq = dirblkptr->nextptr ;
  995.     freetree(&dirblkptr->subdirq) ;
  996.     do
  997.     {
  998.        contptr = dirblkptr->contptr ;
  999.        free(dirblkptr) ;
  1000.     } while ( ( dirblkptr = contptr ) != NULL ) ;
  1001.   }
  1002. }
  1003.  
  1004. /*===================================================================*/
  1005.