home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / clib / progs / utilslib / c / Dirscan < prev    next >
Encoding:
Text File  |  1991-04-20  |  4.9 KB  |  240 lines

  1. /* C.Dirscan: Get filenames for a wildcarded value */
  2.  
  3. /* Use as:
  4.  *
  5.  *    for (file = dirscan(wild); file; file = dirscan(0))
  6.  *        ...
  7.  *
  8.  * Specifying an argument other than 0 restarts the scan with the
  9.  * new wildcard value.
  10.  */ 
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "kernel.h"
  16. #include "swis.h"
  17.  
  18. #include "utils.h"
  19.  
  20. /* Constants. The function assumes that a directory can hold no more than
  21.  * MAX_DIR entries, and a filename can be no longer than NAME_LEN characters.
  22.  * It also assumes that OS_GBPB 9 will only ever fail to return all possible
  23.  * filenames on the first call if the supplied buffer becomes full. In this
  24.  * case, dirscan() will ignore any omitted entries. This behaviour is not
  25.  * ideal, but gains significantly in efficiency. (The given buffer size
  26.  * should be easily enough for all normal cases).
  27.  */
  28. #define MAX_DIR        255
  29. #define NAME_LEN    10
  30. #define BUFFER_SIZE    (MAX_DIR * (NAME_LEN + 1))
  31.  
  32. char *dirscan (const char *f)
  33. {
  34.     int len;
  35.     int dot_stripped = 0;
  36.     const char *file;
  37.     _kernel_swi_regs regs;
  38.  
  39.     static char *ptr = NULL;
  40.     static int num_left = 0;
  41.     static char *buffer = NULL;
  42.     static char *name;
  43.     static char res[255];
  44.  
  45.     if (f && *f)
  46.     {
  47.  
  48. #ifdef DEBUG
  49. printf("New call: looking at %s\n", f);
  50. #endif
  51.  
  52.         /* Delete any old buffer */
  53.         if (buffer)
  54.         {
  55.             free (buffer);
  56.             buffer = NULL;
  57.         }
  58.  
  59.         /* Try for a directory prefix */
  60.         file = strrchr (f, '.');
  61.  
  62.         /* If not, try for a filing system prefix */
  63.         if (file == NULL)
  64.         {
  65.             if (*f == '-')
  66.                 file = strchr (f + 1, '-');
  67.             else
  68.                 file = strchr (f, ':');
  69.         }
  70.  
  71.         if (file == NULL)
  72.         {
  73.             /* We have a simple file name, with no directory. So
  74.              * we set name to point to the place to store the
  75.              * file name (ie, res), and we temporarily set res
  76.              * to hold the directory name (ie, ""). We also set
  77.              * file to the file name f.
  78.              */
  79.             name = res;
  80.             file = f;
  81.             name[0] = '\0';
  82.         }
  83.         else
  84.         {
  85.             /* More work to do. Set res up with the directory,
  86.              * as above, and point name to the place to put the
  87.              * file name(s). And set file to the file name.
  88.              */
  89.  
  90.             len = file - f + 1;
  91.  
  92.             /* Do not allow file names over 255 characters
  93.              * (ie, 245 for the directory, and 10 for the
  94.              * base name).
  95.              */
  96.             if (len > 245)
  97.                 return 0;
  98.  
  99.             /* Build the start of the file name to be returned */
  100.             strncpy (res, f, len);
  101.             name = &res[len];
  102.  
  103.             /* Temporarily, put the name of the directory to scan
  104.              * into res. At the moment, res holds "dir." or "FS:"
  105.              * without a NULL terminator. If the former, we must
  106.              * temporarily remove the dot and add a NULL, but if
  107.              * the latter, we must add the current directory
  108.              * name "@".
  109.              */
  110.             if (*file == '.')
  111.             {
  112.                 dot_stripped = name[-1];
  113.                 name[-1] = '\0';
  114.             }
  115.             else
  116.             {
  117.                 name[0] = '@';
  118.                 name[1] = '\0';
  119.             }
  120.  
  121.             /* Now, set file to the base file name */
  122.             ++file;
  123.         }
  124.  
  125. #ifdef DEBUG
  126. printf("Split: dir = %s, file = %s\n", res, file);
  127. #endif
  128.  
  129.         /* Is the file name wildcarded? */
  130.         if (!strchr (file, '*') && !strchr (file, '#'))
  131.         {
  132.             /* If not, we return the name we were handed,
  133.              * and remember not to return any more later.
  134.              */
  135.  
  136.             /* First restore the proper prefix */
  137.             if (dot_stripped)
  138.                 name[-1] = dot_stripped;
  139.  
  140.             strcpy (name, file);
  141.             num_left = 0;
  142.             return res;
  143.         }
  144.         else
  145.         {
  146.             /* OK, this is the big one. We set up a buffer, and
  147.              * read all the names from the selected directory
  148.              * which match the pattern into it.
  149.              */
  150.  
  151.             buffer = malloc (BUFFER_SIZE) ;
  152.             if (buffer == NULL)
  153.                 return 0;
  154.  
  155.             regs.r[0] = 9;
  156.             regs.r[1] = (int) res;
  157.             regs.r[2] = (int) buffer;
  158.             regs.r[3] = BUFFER_SIZE;
  159.             regs.r[4] = 0;
  160.             regs.r[5] = BUFFER_SIZE;
  161.             regs.r[6] = (int) file;
  162.  
  163.             if (_kernel_swi (OS_GBPB, ®s, ®s))
  164.                 return 0;
  165.  
  166. #ifdef DEBUG
  167. printf("Swi call succeeded: %d entries found\n", regs.r[3]);
  168. #endif
  169.  
  170.             /* Now restore the proper prefix */
  171.             if (dot_stripped)
  172.                 name[-1] = dot_stripped;
  173.  
  174.             /* If there were no entries to find, say so */
  175.             if (regs.r[3] == 0)
  176.             {
  177.                 num_left = 0;
  178.                 free (buffer);
  179.                 buffer = NULL;
  180.                 return 0;
  181.             }
  182.  
  183.             /* Remember how many more to return and set ptr
  184.              * ready to return the next one.
  185.              */
  186.             num_left = regs.r[3] - 1;
  187.             ptr = buffer + strlen (buffer) + 1;
  188.  
  189. #ifdef DEBUG
  190. printf("Buffer set up: first = %s, next = %s\n", buffer, ptr);
  191. #endif
  192.  
  193.             /* Return the first one */
  194.             strcpy (name, buffer);
  195.             return res;
  196.         }
  197.     }
  198.  
  199.     /* If we've run out of names to return, free the buffer and stop */
  200.     if (num_left == 0)
  201.     {
  202.         if (buffer)
  203.         {
  204.             free (buffer);
  205.             buffer = NULL;
  206.         }
  207.         return 0;
  208.     }
  209.  
  210.  
  211.     /* Return the next entry in the buffer, and move on in the buffer */
  212.     strcpy (name, ptr);
  213.     ptr += strlen(ptr) + 1;
  214.     --num_left;
  215.  
  216. #ifdef DEBUG
  217. printf("Skipped on to %s\n",ptr);
  218. #endif
  219.  
  220.     return res;
  221. }
  222.  
  223. #ifdef TEST
  224. #include <stdio.h>
  225.  
  226. int main (int argc, char *argv[])
  227. {
  228.     char *name;
  229.  
  230.     while (--argc > 0)
  231.     {
  232.         printf("Scanning %s\n", *++argv);
  233.         for (name = dirscan(*argv); name; name = dirscan(0))
  234.             printf("%s\n", name);
  235.     }
  236.  
  237.     return 0;
  238. }
  239. #endif
  240.