home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1714 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  7.5 KB

  1. From: bogatko@lzga.ATT.COM (George Bogatko)
  2. Newsgroups: alt.sources
  3. Subject: tree dumper
  4. Message-ID: <2018@lzga.ATT.COM>
  5. Date: 23 Aug 90 01:21:46 GMT
  6.  
  7.  
  8. HI:
  9.  
  10.     Yeah, I know, another directory tree dumper.  But THIS one is
  11.     smaller, *FAR* less complicated then some that I've seen, and
  12.     did precisely what I wanted, namely generate a directory tree
  13.     that I could then comment into a "where everything is" document.
  14.  
  15. GB
  16.  
  17. ****** CUT HERE ****** CUT HERE ****** CUT HERE ****** CUT HERE ****** CUT HERE
  18.  
  19. /******************************************************************************
  20. *                                                                             *
  21. *                                  tree.c                                     *
  22. *                                                                             *
  23. ******************************************************************************/
  24.  
  25. /*--------------------------  INITIAL CODING DATE -----------------------------
  26. Wed Aug 22 20:03:03 EDT 1990 by George M. Bogatko
  27.  
  28. --------------------------------  HEADER FILES  -----------------------------*/
  29. #include <stdio.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <dirent.h>
  33. #include <string.h>
  34. #include <malloc.h>
  35. #include <errno.h>
  36.  
  37. /*------------------  TYPEDEF'S, DEFINES, STRUCTURE DEF'S  ------------------*/
  38. #define INCR BUFSIZ
  39. #define USAGE fprintf(stderr, usage, argv[0])
  40.  
  41. /*----------------  IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  42. extern char *calloc();
  43. extern char *optarg;
  44. extern int getopt();
  45. extern int optind;
  46. extern char *sys_errlist[];
  47.  
  48. /*----------------  EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  49.  
  50. /*----------------  INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  51. #ident "@(#)tree.c    1.1 8/22/90 - George M. Bogatko -"
  52. char *arg1;
  53. char *seperator="\t";
  54. char *usage = "usage: %s [-t(abstr)] directory\n";
  55. char dirname[BUFSIZ];
  56. char tbuf[BUFSIZ];
  57. extern char **grabmem();
  58. extern int compar();
  59. extern void addmore();
  60. extern void addname();
  61. extern void delname();
  62. extern void tab();
  63. int tlevel = -1;
  64.  
  65. /*-----------------------------------------------------------------------------
  66.  
  67. SYNOPSIS:
  68.     tree [-t(abstr)] directory
  69.  
  70. DESCRIPTION:
  71.     TREE prints a directory tree similar to the one that MS-DOS 
  72.     supplies, with the following additions for UNIX.
  73.  
  74.     When the file name is printed, it is appended with:
  75.  
  76.     ALL SYSTEMS:
  77.         / - if the file is a directory
  78.         * - if the file is a regular file, and is executable
  79.         # - if the file is a FIFO
  80.     BSD SYSTEMS:
  81.         @ - if the file is a symbolic link
  82.         = - if the file is a socket.
  83.  
  84.     If a subdirectory cannot be entered, the directory name will
  85.     be followed with "(cannot open)".  If the directory can
  86.     be entered, but cannot be read, the name will be followed with
  87.     a "(cannot read)".  Following that is the UNIX error.
  88.  
  89. OPTIONS:
  90.     The one option, '-t' allows you to supply a different indent
  91.     string.  The default is a TAB character ("\t").  
  92.  
  93.     One suggestion is "|  ", which will show a visual link with
  94.     the parent directory
  95.  
  96. CAVEATS:
  97.     Compile with -DBSD for BSD systems to get the defines for
  98.     symbolic links and sockets.  Otherwise just compile straight.
  99.  
  100. COMMENTS:
  101.     Suggestions for improvements are welcome as long as they are not
  102.     of the 'kitchen sink' or 'second system' variety.
  103.  
  104.  
  105. =============================================================================*/
  106.  
  107. main(argc, argv)
  108. int argc;
  109. char *argv[];
  110. {
  111. int c;
  112.  
  113.     while( (c = getopt(argc, argv, "t:")) != EOF )
  114.     {
  115.         switch(c)
  116.         {
  117.         case 't':
  118.             seperator = strdup(optarg);
  119.             break;
  120.         case '?':
  121.             USAGE;
  122.             exit(-1);
  123.         }
  124.     }
  125.  
  126.     if(optind == argc) 
  127.     {
  128.         USAGE;
  129.         exit(-1);
  130.     }
  131.  
  132.     arg1=argv[optind];
  133.     if( access(arg1,05) == -1 )
  134.     {
  135.         fprintf(stderr, "%s: %s\n", arg1, sys_errlist[errno]);
  136.         exit(-1);
  137.     }
  138.     chdir(arg1);
  139.     dumpdir();
  140.     return 0;
  141. }
  142.  
  143. int dumpdir()
  144. {
  145. DIR *dirp;
  146. char **dnames;
  147. char **fnames;
  148. char *str;
  149. int dnameoff=0;
  150. int dnamesz=INCR;
  151. int fnameoff=0;
  152. int fnamesz=INCR;
  153. int i;
  154. int tl;
  155. int x = 0;
  156. struct dirent *dp;
  157. struct stat sbuf;
  158.  
  159.     dnames = grabmem(dnamesz);
  160.     fnames = grabmem(fnamesz);
  161. /*
  162.  * increment the tab level (see tab() )
  163.  */
  164.     tlevel++;
  165. /*
  166.  * try to open the directory
  167.  */
  168.     if( (dirp = opendir(".")) == (DIR *)NULL )
  169.         return -1;
  170. /*
  171.  * KLUDGE number 1.  See the line with the printf statement
  172.  * "printf("%s%s/",arg1,dirname);".  This is how we print
  173.  * the (cannot open) statements, and then get a carrage return
  174.  */
  175.     putchar('\n'); 
  176. /*
  177.  * read the directory to the end
  178.  */
  179.     while( (dp = readdir (dirp)) != NULL )
  180.     {
  181. /*
  182.  * gather some file statistics
  183.  */
  184.         if( stat(dp->d_name, &sbuf) == -1 )
  185.         {
  186.             perror("stat");
  187.             return -1;
  188.         }
  189. /*
  190.  * If the file is a directory, remember the name, in the directory
  191.  * names bucket.
  192.  */
  193.         if((sbuf.st_mode & S_IFMT) == S_IFDIR)
  194.         {
  195.             dnames[dnameoff++] = strdup(dp->d_name);
  196.             if( dnameoff > dnamesz )
  197.                 addmore(&dnames, &dnamesz);
  198.             dnames[dnameoff+1] = (char *)NULL;
  199.         }
  200.         else
  201.         {
  202. /*
  203.  * else it is some other file.  Put the name in another bucket.  Add
  204.  * the mneumonic character (#=@*).
  205.  */
  206.             str = "";
  207.             if((sbuf.st_mode & S_IFMT) == S_IFIFO)
  208.                 str = "#";
  209.             else if((sbuf.st_mode & S_IFMT) == S_IFREG)
  210.             {
  211.                 if(sbuf.st_mode & S_IXUSR)
  212.                     str="*";
  213.             }
  214. #if pyr || BSD
  215.             else if((sbuf.st_mode & S_IFMT) == S_IFLNK)
  216.                 str = "@";
  217.             else if((sbuf.st_mode & S_IFMT) == S_IFSOCK)
  218.                 str = "=";
  219. #endif
  220.             sprintf(tbuf, "%s%s",dp->d_name,str);
  221.             fnames[fnameoff++]=strdup(tbuf);
  222.             if( fnameoff >= fnamesz )
  223.                 addmore(&fnames, &fnamesz);
  224.             fnames[fnameoff+1] = (char *)NULL;
  225.         }
  226.     }
  227. /*
  228.  * sort the buckets
  229.  */
  230.     qsort(fnames, fnameoff, sizeof(char *), compar);
  231.     qsort(dnames, dnameoff, sizeof(char *), compar);
  232. /*
  233.  * dump the sorted list of non directory files
  234.  */
  235.     for(i=0; fnames[i] != (char *)NULL; i++)
  236.     {
  237.         tab();
  238.         printf("%s\n",fnames[i]);
  239.         
  240.     }
  241. /*
  242.  * go through the sorted list of directory files. 
  243.  */
  244.     for(i=0; dnames[i] != (char *)NULL; i++)
  245.     {
  246.         if( strcmp(dnames[i], ".") &&
  247.             strcmp(dnames[i], "..") )
  248.         {
  249. /*
  250.  * build up the pathname
  251.  */
  252.             addname(dnames[i]);
  253.             tab();
  254. /*
  255.  * print it out
  256.  */
  257.             printf("%s%s/",arg1,dirname);
  258. /*
  259.  * chdir to the directory, and recurse.
  260.  */
  261.             if( chdir(dnames[i]) == -1 )
  262.             {
  263.                 printf(" (cannot open: %s)\n", sys_errlist[errno]);
  264.                 delname();
  265.             }
  266.             else if( dumpdir() == -1 )
  267.             {
  268.                 printf(" (cannot read: %s)\n", sys_errlist[errno]);
  269.                 tlevel--;
  270.                 chdir("..");
  271.                 delname();
  272.             }
  273.         }
  274.     }
  275. /*
  276.  * cleanup the mallocs, close the files, decrement the tab level, 
  277.  * and go back up a level
  278.  */
  279.     for(i=0; dnames[i] != (char *)NULL; i++)
  280.     {
  281.         free(dnames[i]);
  282.     }
  283.     free(dnames); 
  284.  
  285.     for(i=0; fnames[i] != (char *)NULL; i++)
  286.     {
  287.         free(fnames[i]);
  288.     }
  289.     free(fnames); 
  290.     tlevel--;
  291.     closedir(dirp);
  292.     delname();
  293.     chdir("..");
  294.     return 0;
  295. }
  296.  
  297. /*
  298.  * indent according to current tab level
  299.  */
  300. void tab()
  301. {
  302. int tl = tlevel;
  303.  
  304.     while(tl--)
  305.         printf("%s",seperator);
  306.     return;
  307. }
  308.  
  309. /*
  310.  * add a name to the current path name
  311.  */
  312. void addname(s)
  313. char *s;
  314. {
  315.     strcat(dirname,"/");
  316.     strcat(dirname,s);
  317.     return;
  318. }
  319.  
  320. /*
  321.  * delete a name from the current path name
  322.  */
  323. void delname()
  324. {
  325. char *ps;
  326.  
  327.     if( ps = strrchr(dirname, '/') )
  328.         *ps = '\0';
  329.     return;
  330. }
  331.  
  332. /*
  333.  * allocate memory
  334.  */
  335. char **grabmem(size)
  336. unsigned size;
  337. {
  338. char **s;
  339.  
  340.     if( (s = (char **)calloc((size+2), sizeof(char **))) == (char **)NULL )
  341.     {
  342.         perror("calloc");
  343.         exit(-1);
  344.     }
  345.     return s;
  346. }
  347.  
  348. /*
  349.  * grow memory
  350.  */
  351. void addmore(s, size)
  352. char ***s;
  353. unsigned *size;
  354. {
  355.     *size += INCR;
  356.     if( (*s = (char **)realloc(*s, ((*size+2) * sizeof(char **)) )) == (char **)NULL )
  357.     {
  358.         perror("realloc");
  359.         exit(-1);
  360.     }
  361.     return;
  362. }
  363.  
  364. /*
  365.  * function for qsort
  366.  */
  367. int compar(s1,s2)
  368. char **s1, **s2;
  369. {
  370.     return( strcmp(*s1, *s2) );
  371. }
  372.