home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / cshar / part02 / findsrc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-26  |  7.0 KB  |  301 lines

  1. /*
  2. **  FINDSRC
  3. **  Walk directories, trying to find source files.
  4. */
  5. #include "shar.h"
  6. #ifdef    RCSID
  7. static char RCS[] =
  8.     "$Header: findsrc.c,v 2.0 88/05/27 13:26:05 rsalz Exp $";
  9. #endif    /* RCSID */
  10.  
  11.  
  12. /*
  13. **  Global variables.
  14. */
  15. int     DoDOTFILES;            /* Do .newsrc and friends?    */
  16. int     DoRCS;                /* Do RCS and SCCS files?    */
  17. int     Default;            /* Default answer from user    */
  18. int     Verbose;            /* List rejected files, too?    */
  19. char    *Dname;                /* Filename of directory list    */
  20. char    *Fname;                /* Filename of file list    */
  21. FILE    *Dfile;                /* List of directories found    */
  22. FILE    *Ffile;                /* List of files found        */
  23. FILE    *DEVTTY;            /* The tty, if in filter mode    */
  24.  
  25.  
  26. /*
  27. **  Signal handler.  Clean up and die.
  28. */
  29. static sigret_t
  30. Catch(s)
  31.     int         s;
  32. {
  33.     int         e;
  34.  
  35.     e = errno;
  36.     if (Dname)
  37.     (void)unlink(Dname);
  38.     if (Fname)
  39.     (void)unlink(Fname);
  40.     Fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e));
  41.     exit(1);
  42. }
  43.  
  44.  
  45. /*
  46. **  Given a filename, apply heuristics to see if we want it.
  47. */
  48. static int
  49. Wanted(Name)
  50.     REGISTER char    *Name;
  51. {
  52.     REGISTER FILE    *F;
  53.     REGISTER char    *s;
  54.     REGISTER char    *p;
  55.     REGISTER char    *d;
  56.     char         buff[BUFSIZ];
  57.  
  58.     /* Get down to brass tacks. */
  59.     s = (p = RDX(Name, '/')) ? p + 1 : Name;
  60.  
  61.     /* Only do directories other than . and .. and regular files. */
  62.     if ((Ftype(Name) != F_DIR && Ftype(Name) != F_FILE)
  63.      || EQ(s, ".") || EQ(s, ".."))
  64.     return(FALSE);
  65.  
  66.     /* Common cruft we never want. */
  67.     if (EQ(s, "foo") || EQ(s, "core") || EQ(s, "tags") || EQ(s, "lint"))
  68.     return(FALSE);
  69.  
  70.     /* Disregard stuff with bogus suffixes. */
  71.     d = RDX(s, '.');
  72.     if ((p = d)
  73.      && (EQ(++p, "out") || EQ(p, "orig") || EQ(p, "rej") || EQ(p, "BAK")
  74.       || EQ(p, "CKP") || EQ(p, "old") || EQ(p, "o") || EQ(p, "EXE")
  75.       || EQ(p, "OBJ")))
  76.     return(FALSE);
  77.  
  78.     /* Want .cshrc, .newsrc, etc.? */
  79.     if (*s == '.' && isalpha(s[1]))
  80.     return(DoDOTFILES);
  81.  
  82.     /* RCS or SCCS file or directory? */
  83.     if (EQ(s, "RCS")
  84.      || ((p = RDX(s, ',')) && *++p == 'v' && *++p == '\0')
  85.      || EQ(s, "SCCS") || (s[0] == 's' && s[1] == '.'))
  86.     return(DoRCS);
  87.  
  88.     /* Mlisp, m4 (yes to .m? but no to .mo)? */
  89.     /* really, no to .mo but yes to names matching the regexp ".m?" */
  90.     if ((p = d) && *++p == 'm' && p[2] == '\0')
  91.     return(*++p != 'o');
  92.  
  93.     /* Gnu Emacs elisp (yes to .el*, but no to .elc)? */
  94.     if ((p = d) && *++p == 'e' && *++p == 'l')
  95.     return(*++p != 'c' || *++p);
  96.  
  97.     /* C source (*.[ch])? */
  98.     if ((p = d) && (*++p == 'c' || *p == 'h') && *++p == '\0')
  99.  
  100.     /* Manpage (*.[1234567890] or *.man)? */
  101.     if ((p = d) && isdigit(*p))
  102.     return(TRUE);
  103.     if ((p = d) && *++p == 'm' && *++p == 'a' && *++p == 'n')
  104.     return(TRUE);
  105.  
  106.     /* Make control file? */
  107.     if ((*s == 'M' || *s == 'm') && EQ(s + 1, "akefile"))
  108.     return(TRUE);
  109.  
  110.     /* Convert to lowercase, and see if it's a README or MANIFEST. */
  111.     for (p = strcpy(buff, s); *p; p++)
  112.     if (isascii(*p) && isupper(*p))
  113.         *p = tolower(*p);
  114.     if (EQ(buff, "readme") || EQ(buff, "read_me") || EQ(buff, "read-me")
  115.      || EQ(buff, "manifest"))
  116.     return(TRUE);
  117.  
  118.     /* Larry Wall-style template file (*.SH)? */
  119.     if ((p = d) && *++p == 'S' && *++p == 'H')
  120.     return(TRUE);
  121.  
  122.     /* If we have a default, give it back. */
  123.     if (Default)
  124.     return(Default == 'y');
  125.  
  126. #ifdef    CAN_POPEN
  127.     /* See what file(1) has to say; if it says executable, punt. */
  128.     (void)sprintf(buff, "exec file '%s'", Name);
  129.     if (F = popen(buff, "r")) {
  130.     (void)fgets(buff, sizeof buff, F);
  131.     (void)pclose(F);
  132.     for (p = buff; p = IDX(p, 'e'); p++)
  133.         if (PREFIX(p, "executable"))
  134.         return(FALSE);
  135.     (void)fputs(buff, stderr);
  136.     }
  137. #endif    /* CAN_POPEN */
  138.  
  139.     /* Add it? */
  140.     while (TRUE) {
  141.     if (DEVTTY == NULL)
  142.         DEVTTY = fopen(THE_TTY, "r");
  143.     Fprintf(stderr, "Add this one (y or n)[y]?  ");
  144.     (void)fflush(stderr);
  145.     if (fgets(buff, sizeof buff, DEVTTY) == NULL
  146.      || buff[0] == '\n' || buff[0] == 'y' || buff[0] == 'Y')
  147.         break;
  148.     if (buff[0] == 'n' || buff[0] == 'N')
  149.         return(FALSE);
  150.     if (buff[0] == '!' )
  151.         (void)system(&buff[1]);
  152.     Fprintf(stderr, "--------------------\n%s:  ", Name);
  153.     clearerr(DEVTTY);
  154.     }
  155.     return(TRUE);
  156. }
  157.  
  158.  
  159. /*
  160. **  Quick and dirty recursive routine to walk down directory tree.
  161. **  Could be made more general, but why bother?
  162. */
  163. static void
  164. Process(p, level)
  165.     REGISTER char     *p;
  166.     REGISTER int      level;
  167. {
  168.     REGISTER char     *q;
  169.     DIR             *Dp;
  170.     DIRENTRY         *E;
  171.     char          buff[BUFSIZ];
  172.  
  173. #ifdef    MSDOS
  174.     strlwr(p);
  175. #endif    /* MSDOS */
  176.  
  177.     if (!GetStat(p))
  178.     Fprintf(stderr, "Can't walk down %s, %s.\n", Ermsg(errno));
  179.     else {
  180.     /* Skip leading ./ which find(1), e.g., likes to put out. */
  181.     if (p[0] == '.' && p[1] == '/')
  182.         p += 2;
  183.  
  184.     if (Wanted(p))
  185.         Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "%s\n", p);
  186.     else if (Verbose)
  187.         Fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "PUNTED %s\n", p);
  188.  
  189.     if (Ftype(p) == F_DIR)
  190.         if (++level == MAX_LEVELS)
  191.         Fprintf(stderr, "Won't walk down %s -- more than %d levels.\n",
  192.             p, level);
  193.         else if (Dp = opendir(p)) {
  194.         q = buff + strlen(strcpy(buff, p));
  195.         for (*q++ = '/'; E = readdir(Dp); )
  196.             if (!EQ(E->d_name, ".") && !EQ(E->d_name, "..")) {
  197.             (void)strcpy(q, E->d_name);
  198.             Process(buff, level);
  199.             }
  200.         (void)closedir(Dp);
  201.         }
  202.         else
  203.         Fprintf(stderr, "Can't open directory %s, %s.\n",
  204.             p, Ermsg(errno));
  205.     }
  206. }
  207.  
  208.  
  209. main(ac, av)
  210.     REGISTER int     ac;
  211.     REGISTER char    *av[];
  212. {
  213.     REGISTER char    *p;
  214.     REGISTER int     i;
  215.     REGISTER int     Oops;
  216.     char         buff[BUFSIZ];
  217.  
  218.     /* Parse JCL. */
  219.     for (Oops = 0; (i = getopt(ac, av, ".d:o:RSv")) != EOF; )
  220.     switch (i) {
  221.     default:
  222.         Oops++;
  223.         break;
  224.     case '.':
  225.         DoDOTFILES++;
  226.         break;
  227.     case 'd':
  228.         switch (optarg[0]) {
  229.         default:
  230.         Oops++;
  231.         break;
  232.         case 'y':
  233.         case 'Y':
  234.         Default = 'y';
  235.         break;
  236.         case 'n':
  237.         case 'N':
  238.         Default = 'n';
  239.         break;
  240.         }
  241.         break;
  242.     case 'o':
  243.         if (freopen(optarg, "w", stdout) == NULL) {
  244.         Fprintf(stderr, "Can't open %s for output, %s.\n",
  245.             optarg, Ermsg(errno));
  246.         exit(1);
  247.         }
  248.     case 'R':
  249.     case 'S':
  250.         DoRCS++;
  251.         break;
  252.     case 'v':
  253.         Verbose++;
  254.         break;
  255.     }
  256.     if (Oops) {
  257.     Fprintf(stderr, "Usage: findsrc [-d{yn}] [-.] [-{RS}] [-v] files...\n");
  258.     exit(1);
  259.     }
  260.     av += optind;
  261.  
  262.     /* Set signal catcher, open temp files. */
  263.     SetSigs(TRUE, Catch);
  264.     Dname = mktemp("/tmp/findDXXXXXX");
  265.     Fname = mktemp("/tmp/findFXXXXXX");
  266.     Dfile = fopen(Dname, "w");
  267.     Ffile = fopen(Fname, "w");
  268.  
  269.     /* Read list of files, determine their status. */
  270.     if (*av)
  271.     for (DEVTTY = stdin; *av; av++)
  272.         Process(*av, 0);
  273.     else
  274.     while (fgets(buff, sizeof buff, stdin)) {
  275.         if (p = IDX(buff, '\n'))
  276.         *p = '\0';
  277.         else
  278.         Fprintf(stderr, "Warning, line too long:\n\t%s\n", buff);
  279.         Process(buff, 0);
  280.     }
  281.  
  282.     /* First print directories. */
  283.     if (freopen(Dname, "r", Dfile)) {
  284.     while (fgets(buff, sizeof buff, Dfile))
  285.         (void)fputs(buff, stdout);
  286.     (void)fclose(Dfile);
  287.     }
  288.  
  289.     /* Now print regular files. */
  290.     if (freopen(Fname, "r", Ffile)) {
  291.     while (fgets(buff, sizeof buff, Ffile))
  292.         (void)fputs(buff, stdout);
  293.     (void)fclose(Ffile);
  294.     }
  295.  
  296.     /* That's all she wrote. */
  297.     (void)unlink(Dname);
  298.     (void)unlink(Fname);
  299.     exit(0);
  300. }
  301.