home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / arc_lbr / arff.arc / ARFF.C next >
C/C++ Source or Header  |  1988-08-19  |  16KB  |  659 lines

  1. /*title  arff -- archive file finder */
  2.  
  3. /*version 1.0  18 August 1988  by Mark Armbrust */
  4.  
  5. /*    This is a nasty hack that searches through the directory tree looking for
  6.     files that match its arguments.  When it find archives that it knows how to
  7.     deal with (their extensions are defined in a configuration file) it fires up
  8.     the appropriate tool to list the archive to a temporary file which is then
  9.     scanned for matching filenames.  If any matching names are found, their
  10.     entries are reformatted into a more-or-less consistant format and printed.
  11.  
  12.     BE WARNED!  This was hacked out in a couple of after work evenings, using
  13.     bits and pieces of other things, and whole lot of "hammer it til it fits"
  14.     code.
  15.  
  16.  
  17.     Reads a configuration file to learn how to handle archives.  Each line
  18.     describes an archive format.  Example:
  19.  
  20. .ARC "c:\bin\arcv %s" "=" "%s" "%*12c %s" "%*50c%9c" "%*61c%8c" "." "*total"
  21.  
  22.     .ARC                This is the archive identifier, any file encountered
  23.                 with this extension is listed and searched using information
  24.                 from this entry.
  25.  
  26.     "c:\bin\arcv.com %s"    This is command used to list the archive to stdout.
  27.                 The name of the archive is represented by the %s in the string.
  28.                 Use of full path name is required.
  29.  
  30.     "="            This is a string, starting in column one of the listing that
  31.                 identifies the last line of information that preceeds the file
  32.                 names in the archive listing.  If there are no preceeding
  33.                 lines, use "."
  34.  
  35.     "%s"        This is the format used to read the file name from archive
  36.                 listing.  This is passed directly to sscanf().
  37.  
  38.     "%*12c %s"    This is the format used to read the file size from archive
  39.                 listing.  This is passed directly to sscanf().
  40.  
  41.     "%*50c%9c"    This is the format used to read the file date from archive
  42.                 listing.  This is passed directly to sscanf().
  43.  
  44.     "%*61c%8c"    This is the format used to read the file time from archive
  45.                 listing.  This is passed directly to sscanf().  If the time
  46.                 was read as part of the date, use "."
  47.  
  48.     "."            This is the format used to read the file options/attributes
  49.                 from archive listing.  This is passed directly to sscanf().  If
  50.                 there are no options, use "."
  51.  
  52.     "*total"    This is a string, starting in column one of the listing that
  53.                 identifies the first line of information that follows the file
  54.                 names in the archive listing.  If there are no trailing lines,
  55.                 use "."
  56.  
  57.  
  58.  
  59.     It's not copyrighted!  It's not patented!  It's not even shareware!
  60.  
  61.             It's absolutely free!  (and worth every penny)
  62.  
  63. */
  64.  
  65.  
  66. #include <stdio.h>
  67. #include <string.h>
  68. #include <stdlib.h>
  69. #include <dos.h>
  70. #include <fcntl.h>
  71. #include <sys\types.h>
  72. #include <sys\stat.h>
  73. #include <io.h>
  74. #include <process.h>
  75.  
  76.  
  77. typedef struct _arc_info {
  78.                         struct _arc_info *next_arc;
  79.                         char             *ext;
  80.                         char             *list_cmd;
  81.                         char             *start_str;
  82.                         char             *name_fmt;
  83.                         char             *size_fmt;
  84.                         char             *date_fmt;
  85.                         char             *time_fmt;
  86.                         char             *opt_fmt;
  87.                         char             *end_str;
  88.                         }
  89.                     arc_info;
  90.  
  91.  
  92. void main (int, char*[]);
  93. void Read_Config_File (void);
  94. void Print_Usage (void);
  95. void Search_Path (char *);
  96. void Show_Dir (char *, struct find_t*);
  97. int Match (char *, char *);
  98. int WC_Match (char *, char *);
  99. void Search_Arc (arc_info *, char *);
  100. void Abort (char *);
  101. char *Fix_Slant (char *);
  102.  
  103.  
  104. #define H_STDOUT        1
  105.  
  106. #define IS_SLANT(c)        ((c) == '/' || (c) == '\\')
  107. #define IS_FILE_SEP(c)    ( (c) == ':' || (c) == '.' || IS_SLANT(c) )
  108.  
  109.  
  110. char        search_mode = '\0';
  111. arc_info    *arc_list = NULL;
  112. int            num_pat;
  113. char        **patterns;
  114. char        months[12][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  115. int            dos_version;
  116. char        *exe_path;
  117. char        *arff_name;
  118.  
  119.  
  120.  
  121.  
  122. void main (argc, argv)
  123.  
  124.     int                argc;
  125.     char            *argv[];
  126.     {
  127.     register char    *path;
  128.     register char    *p;
  129.  
  130.  
  131.     dos_version = bdos (0x30, 0, 0) & 0xff;
  132.     exe_path = argv[0];
  133.  
  134.     if (dos_version < 3)
  135.         arff_name = "arff";
  136.     else {
  137.         arff_name = strrchr (argv[0], '\\');
  138.         if (arff_name)
  139.             ++arff_name;
  140.         else {
  141.             arff_name = strrchr (argv[0], '/');
  142.             if (arff_name)
  143.                 ++arff_name;
  144.             else
  145.                 arff_name = argv[0];
  146.             }
  147.  
  148.         arff_name = strdup (arff_name);
  149.         *strchr(arff_name, '.') = '\0';
  150.         strlwr(arff_name);
  151.         }
  152.  
  153.     if (argc < 2) {
  154.         Print_Usage ();
  155.         exit (-1);
  156.         }
  157.  
  158.     if (stricmp (argv[1], "-a") == 0) {
  159.         search_mode = 'A';
  160.         ++argv;
  161.         --argc;
  162.         }
  163.  
  164.     else if (stricmp (argv[1], "-n") == 0) {
  165.         search_mode = 'N';
  166.         ++argv;
  167.         --argc;
  168.         }
  169.  
  170.     if (argc < 2) {
  171.         Print_Usage ();
  172.         exit (-1);
  173.         }
  174.  
  175.     path = argv[1];
  176.     while (p = strchr( argv[1], ':')) argv[1] = p+1;
  177.     while (p = strchr( argv[1], '/')) argv[1] = p+1;
  178.     while (p = strchr( argv[1], '\\')) argv[1] = p+1;
  179.  
  180.     if (path != argv[1]) {
  181.         if (argv[1][0] == '\0') {
  182.             ++argv;                        /* argument is only a path */
  183.             --argc;
  184.             }
  185.         else {
  186.             p = malloc (argv[1] - path + 1);
  187.             p[argv[1] - path] = '\0';
  188.             path = strncpy (p, path, argv[1] - path);
  189.             }
  190.         Fix_Slant (path);
  191.         }
  192.     else
  193.         path = "";
  194.  
  195.     if (argc < 2) {
  196.         Print_Usage ();
  197.         exit (-1);
  198.         }
  199.  
  200.     Read_Config_File ();
  201.  
  202.     num_pat = argc - 1;
  203.     patterns = &argv[1];
  204.  
  205.     Search_Path (path);
  206.  
  207.     }
  208.  
  209.  
  210.  
  211.  
  212. void Print_Usage ()
  213.  
  214.     {
  215.     printf ("usage: %s [-an] [path] files ...\n", arff_name);
  216.     printf ("             -a     look in archives only\n");
  217.     printf ("             -n     don't look in archives\n");
  218.     printf ("             path   where to start searching\n");
  219.     printf ("             files  what to look for (*? ok)\n");
  220.     }
  221.  
  222.  
  223.  
  224.  
  225. void Read_Config_File ()
  226.  
  227.     {
  228.     register char        *arff_cfg;
  229.     FILE                *config_file;
  230.     char                ext[21], list_cmd[41], start_str[21], name_fmt[21], size_fmt[21],
  231.                         date_fmt[21], time_fmt[21], opt_fmt[21], end_str[21];
  232.     register arc_info    *this_arc;
  233.     int                    i;
  234.     char                line[200];
  235.  
  236.  
  237.     arff_cfg = getenv ("ARFF.CFG");
  238.     if ( ! arff_cfg && dos_version < 3) {
  239.         arff_cfg = "C:\BIN\ARFF.CFG";
  240.         }
  241.     else {
  242.         arff_cfg = strrchr (exe_path, '.');
  243.         if (arff_cfg && strlen (arff_cfg) == 4) {
  244.             strcpy (arff_cfg, ".CFG");
  245.             arff_cfg = exe_path;
  246.             }
  247.         else {
  248.             fprintf (stderr, "%s: internal error, could not change argv[0] extension\n", arff_name);
  249.             exit (-1);
  250.             }
  251.         }
  252.  
  253.     config_file = fopen (arff_cfg, "r");
  254.     if ( ! config_file) {
  255.         fprintf (stderr, "%s: could not open config file \"%s\".  (Set variable ARFF.CFG)\n", arff_name, arff_cfg);
  256.         exit (-1);
  257.         }
  258.  
  259.     for (;;) {
  260.         fgets (line, 200, config_file);
  261.         if (feof (config_file))
  262.             break;
  263.         if (line[0] == ';')
  264.             continue;
  265.  
  266.         i = sscanf (line,
  267. "%20s \"%40[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \n",
  268.  ext,   list_cmd,    start_str,   name_fmt,    size_fmt,    date_fmt,    time_fmt,    opt_fmt,     end_str);
  269.  
  270.         if (i != 9 || ext[0] != '.') {
  271.             fprintf (stderr, "%s: bad line in config file.\n%s\nformat is:\n", arff_name, line);
  272.             fprintf (stderr, "arc_ext \"list_cmd\" \"start_str\" \"name_fmt\" \"size_fmt\" \"date_fmt\" \"time_fmt\" \"opt_fmt\" \"end_str\"\n");
  273.             exit (-1);
  274.             }
  275.  
  276.         this_arc = (arc_info *) malloc (sizeof (arc_info));
  277.         if ( ! this_arc) Abort ("this_arc malloc failed in Read_Config_File");
  278.  
  279.         if (!strcmp (start_str, ".")) start_str[0] = '\0';
  280.         if (!strcmp (size_fmt, ".")) size_fmt[0] = '\0';
  281.         if (!strcmp (date_fmt, ".")) date_fmt[0] = '\0';
  282.         if (!strcmp (time_fmt, ".")) time_fmt[0] = '\0';
  283.         if (!strcmp (opt_fmt, ".")) opt_fmt[0] = '\0';
  284.         if (!strcmp (end_str, ".")) end_str[0] = '\0';
  285.  
  286.         this_arc->ext       = strdup (strlwr (ext));
  287.         this_arc->list_cmd  = strdup (list_cmd);
  288.         this_arc->start_str = strdup (start_str);
  289.         this_arc->name_fmt  = strdup (name_fmt);
  290.         this_arc->size_fmt  = strdup (size_fmt);
  291.         this_arc->date_fmt  = strdup (date_fmt);
  292.         this_arc->time_fmt  = strdup (time_fmt);
  293.         this_arc->opt_fmt   = strdup (opt_fmt);
  294.         this_arc->end_str   = strdup (end_str);
  295.  
  296.         if ( ! (this_arc->ext && this_arc->list_cmd && this_arc->start_str && this_arc->name_fmt &&
  297.                 this_arc->size_fmt && this_arc->date_fmt && this_arc->time_fmt && this_arc->opt_fmt &&
  298.                 this_arc->end_str))
  299.             Abort ("this_arc strdup failed in Read_Config_file");
  300.  
  301.         this_arc->next_arc = arc_list;
  302.         arc_list = this_arc;
  303.  
  304.         }
  305.  
  306.     fclose (config_file);
  307.     }
  308.  
  309.  
  310.  
  311.  
  312. void Search_Path (path)
  313.  
  314.     char                *path;
  315.     {
  316.     struct find_t        find_buf;
  317.     char                *name;
  318.     int                    i;
  319.     register char        *new_path;
  320.     register arc_info    *this_arc;
  321.  
  322.  
  323.     name = malloc (strlen (path) + 4);
  324.     if (!name) Abort ("name malloc failed in Search_Path");
  325.     strcpy (name, path);
  326.     strcat (name, "*.*");
  327.  
  328.     for (i = _dos_findfirst (name, 0x3F, &find_buf); !i; i = _dos_findnext (&find_buf) ) {
  329.  
  330.         if (find_buf.name[0] == '.' && (find_buf.name[1] == 0 || find_buf.name[1] == '.'))
  331.             continue;
  332.  
  333.         strlwr (find_buf.name);
  334.  
  335.         if (find_buf.attrib & _A_SUBDIR) {
  336.             new_path = malloc (strlen (path) + strlen (find_buf.name) + 2);
  337.             if (!new_path) Abort ("new_path malloc failed in Search_Path(subdir)");
  338.             strcpy (new_path, path);
  339.             strcat (new_path, find_buf.name);
  340.             strcat (new_path, "\\");
  341.             Search_Path (new_path);
  342.             free (new_path);
  343.             continue;
  344.             }
  345.  
  346.  
  347.         if (search_mode != 'A')
  348.             for (i=0; i<num_pat; ++i)
  349.                 if (Match (find_buf.name, patterns[i])) {
  350.                     Show_Dir (path, &find_buf);
  351.                     break;
  352.                     }
  353.  
  354.         if (search_mode != 'N') {        /* see if this in archive we can deal with */
  355.  
  356.             for (this_arc = arc_list; this_arc; this_arc = this_arc->next_arc)
  357.                 if (strstr (find_buf.name, this_arc->ext)) {
  358.                     new_path = malloc (strlen (path) + strlen (find_buf.name) + 2);
  359.                     if (!new_path) Abort ("new_path malloc failed in Search_Path(arc)");
  360.                     strcpy (new_path, path);
  361.                     strcat (new_path, find_buf.name);
  362.                     Search_Arc (this_arc, new_path);
  363.                     free (new_path);
  364.                     }
  365.             }
  366.  
  367.         }
  368.  
  369.     free (name);
  370.     }
  371.  
  372.  
  373.  
  374.  
  375. void Show_Dir (path, find_buf)
  376.  
  377.     char            *path;
  378.     struct find_t    *find_buf;
  379.     {
  380.     int                mo, yr, h, m;
  381.     register int    day, s;
  382.     char            attr[4];
  383.  
  384.  
  385.     s = find_buf->wr_time;
  386.     m = (s & 0x07E0) >> 5;
  387.     h = (s & 0xF800) >> 11;
  388.     s &= 0x001F;
  389.  
  390.     day = find_buf->wr_date;
  391.     mo = (day & 0x01E0) >> 5;
  392.     yr = ((day & 0xFE00) >> 9) + 80;
  393.     if (yr >= 100) yr -= 100;
  394.     day &= 0x001F;
  395.  
  396.     strcpy (attr, "   ");
  397.     if (find_buf->attrib & _A_SYSTEM) attr[0] = 'S';
  398.     if (find_buf->attrib & _A_HIDDEN) attr[1] = 'H';
  399.     if (find_buf->attrib & _A_RDONLY) attr[2] = 'R';
  400.  
  401.     printf ("%8ld  %2d %3s %02d  %02d:%02d:%02d %3s %s%s",
  402.             find_buf->size, day, months[mo-1], yr, h, m, s, attr, path, find_buf->name);
  403.  
  404.     if (find_buf->attrib & _A_SUBDIR)
  405.         printf ("\\\n");
  406.     else
  407.         printf ("\n");
  408.     }
  409.  
  410.  
  411.  
  412.  
  413. void Search_Arc (arc_type, path)
  414.  
  415.     register arc_info    *arc_type;
  416.     char                *path;
  417.     {
  418.     char                *temp_name;
  419.     char                *command;
  420.     char                line[100], name[100], size[20], date[40], time[20], opt[10];
  421.     FILE                *temp_file;
  422.     int                    skipping;
  423.     register int        i;
  424.     char                *exe_path;
  425.     int                    save_stdout, new_stdout, exit_code;
  426.  
  427.     temp_name = tempnam ("\\", "$ARF");
  428.     if (!temp_name) Abort ("tempnam failed in Search_Arc");
  429.  
  430.     command = malloc ( strlen(arc_type->list_cmd) + strlen(path) + 1);
  431.     if (!command) Abort ("command malloc failed in Search_Arc");
  432.  
  433.     sprintf (command, arc_type->list_cmd, path);
  434.  
  435.     exe_path = command;
  436.     command = strpbrk (command, " \t");
  437.     if (!command) {
  438.         fprintf (stderr, "%s: could not parse \"%s\" \nspace required after command name\n", arff_name, arc_type->list_cmd);
  439.         exit (-1);
  440.         }
  441.  
  442.     *(command++) = '\0';
  443.  
  444.     fputs ("*\b", stdout);
  445.     fflush (stdout);
  446.     save_stdout = dup (H_STDOUT);
  447.     new_stdout = open (temp_name, O_CREAT | O_WRONLY, S_IWRITE);
  448.     if (new_stdout == -1) Abort ("Could not open temp file");
  449.     dup2 (new_stdout, H_STDOUT);
  450.  
  451.     exit_code = spawnl (P_WAIT, exe_path, exe_path, command, NULL);
  452.  
  453.     close (new_stdout);
  454.  
  455.     dup2 (save_stdout, H_STDOUT);
  456.     close (save_stdout);
  457.     fputs (" \b", stdout);
  458.  
  459.     if (exit_code) {
  460.         unlink (temp_name);
  461.         switch (exit_code >> 8) {
  462.  
  463.             case -1:
  464.                 fprintf (stderr, "%s: could not execute \"%s %s\" command, errno %#04x\n",
  465.                         arff_name, exe_path, command, errno);
  466.                 break;
  467.  
  468.             case 1:
  469.                 printf ("^C\n");
  470.                 break;
  471.  
  472.             default:
  473.                 fprintf (stderr, "%s: \"%s %s\" command failed, exit code %#04x\n",
  474.                         arff_name, exe_path, command, exit_code);
  475.                 break;
  476.             }
  477.  
  478.         exit (-1);
  479.         }
  480.  
  481.     temp_file = fopen (temp_name, "r");
  482.     if (!temp_file) Abort ("temp_file fopen failed in Search_Arc");
  483.  
  484.     skipping = (arc_type->start_str[0]);
  485.  
  486.     while (!feof(temp_file)) {
  487.         fgets (line, 100, temp_file);
  488.  
  489.         if (line[0] == '\n' || line[0] == '\r')
  490.             continue;
  491.  
  492.         if (skipping) {
  493.             if (!strncmp (line, arc_type->start_str, strlen(arc_type->start_str)) )
  494.                 skipping = 0;
  495.             continue;
  496.             }
  497.  
  498.         if (!skipping && arc_type->end_str[0] && (strncmp (line, arc_type->end_str, strlen(arc_type->end_str)) == 0)) {
  499.             break;
  500.             }
  501.  
  502.         memset (name, 0, 100);
  503.         if (sscanf (line, arc_type->name_fmt, name) != 1)
  504.             break;
  505.  
  506.         for (i=0; i<num_pat; ++i)
  507.             if (Match (name, patterns[i])) {
  508.                 memset (size, 0, 20);
  509.                 memset (date, 0, 20);
  510.                 memset (time, 0, 20);
  511.                 memset (opt, 0, 10);
  512.                 if (arc_type->size_fmt[0]) sscanf (line, arc_type->size_fmt, size);
  513.                 if (arc_type->date_fmt[0]) sscanf (line, arc_type->date_fmt, date);
  514.                 if (arc_type->time_fmt[0]) sscanf (line, arc_type->time_fmt, time);
  515.                 if (arc_type->opt_fmt[0]) sscanf (line, arc_type->opt_fmt, opt);
  516.                 strcat (date, "  ");
  517.                 strcat (date, time);
  518.                 Fix_Slant (strlwr (name));
  519.                 printf ("%8s  %-19s %3s %s:%s\n", size, date, opt, path, name);
  520.                 break;
  521.                 }
  522.  
  523.  
  524.         }
  525.  
  526.  
  527.     fclose (temp_file);
  528.     free (command);
  529.     unlink (temp_name);
  530.     free (temp_name);
  531.     }
  532.  
  533.  
  534.  
  535.  
  536. int Match (file, pattern)
  537.  
  538.     char            *file;
  539.     char            *pattern;
  540.     {
  541.     int                i;
  542.     register char    *filename;
  543.     register char    *s;
  544.  
  545.  
  546. /* strip off the leading path and trailing modifiers (zoo ver. number, etc.) */
  547.  
  548.     filename = file;
  549.     if (s = strrchr (filename, '/')) filename = s+1;
  550.     if (s = strrchr (filename, '\\')) filename = s+1;
  551.     filename = strdup (filename);
  552.     if (!filename) Abort ("filename strdup failed in Match");
  553.     if (s = strpbrk (filename, ";*, ")) *s = '\0';
  554.  
  555.     i = WC_Match (filename, pattern);
  556.     free (filename);
  557.  
  558.     return i;
  559.     }
  560.  
  561.  
  562.  
  563.  
  564. /*    Returns TRUE if s1 and s2 match under modified MSDOS wildcard rules.
  565.  *
  566.  *    Two strings match if all their substrings between : . / and \ match
  567.  *    using * and ? as wildcards in the substrings.
  568.  *
  569.  *    Note that MSDOS is a bit schitzo about matching strings that end in : and .
  570.  *    This code will only match them 1-to-1.  For example 'DIR X' matches X.* or
  571.  *    X\*.* depending on what X is.  We do, however, match 'X' to 'X.' and 'X.*'
  572.  *
  573.  */
  574.  
  575. int WC_Match (s1, s2)
  576.  
  577.     register    char    *s1;
  578.     register    char    *s2;
  579.     {
  580.  
  581.  
  582.     while (1) {
  583.  
  584.         if (*s1 == '*' || *s2 == '*') {
  585.             while (*s1 && ! IS_FILE_SEP (*s1))
  586.                 ++s1;
  587.             while (*s2 && ! IS_FILE_SEP (*s2))
  588.                 ++s2;
  589.             continue;
  590.             }
  591.  
  592.         if (*s1 == '?') {
  593.             if (!*s2 || IS_FILE_SEP (*s2))
  594.                 return 0;
  595.             ++s1;
  596.             ++s2;
  597.             continue;
  598.             }
  599.  
  600.         if (*s2 == '?') {
  601.             if (!*s1 || IS_FILE_SEP (*s1))
  602.                 return 0;
  603.             ++s1;
  604.             ++s2;
  605.             continue;
  606.             }
  607.  
  608.         if (*s1 == 0 && *s2 == '.') {
  609.             ++s2;
  610.             continue;
  611.             }
  612.  
  613.         if (*s2 == 0 && *s1 == '.') {
  614.             ++s1;
  615.             continue;
  616.             }
  617.  
  618.         if (toupper(*s1) != toupper(*s2))
  619.             return 0;
  620.  
  621.         if (*s1 == 0)        /* then (*s2 == 0) as well! */
  622.             break;
  623.  
  624.         ++s1;
  625.         ++s2;
  626.         }
  627.  
  628.     return 1;
  629.     }
  630.  
  631.  
  632.  
  633.  
  634. void Abort (msg)
  635.  
  636.     char    *msg;
  637.     {
  638.  
  639.     fprintf (stderr, "%s: internal error -- %s\n", arff_name, msg);
  640.     exit (-1);
  641.     }
  642.  
  643.  
  644.  
  645.  
  646. char *Fix_Slant (s)
  647.  
  648.     register char    *s;
  649.     {
  650.     register int    i;
  651.  
  652.  
  653.     for (i=0; s[i]; ++i)
  654.         if (s[i] == '/')
  655.             s[i] = '\\';
  656.  
  657.     return s;
  658.     }
  659.