home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / tools / pitools / pitool.c < prev    next >
C/C++ Source or Header  |  1994-07-15  |  22KB  |  891 lines

  1. /*
  2.  *    Process Product-Info files.
  3.  *    Written by Fred Fish.
  4.  *    All portions not covered by GNU GPL are public domain.
  5.  *
  6.  *    usage:  pitool [options] file1 file2 file3 ...
  7.  *    Options:
  8.  *
  9.  *    -b    Find Product-Info files and emit information extracted
  10.  *        from each file using the format specified by the -F option.
  11.  *        By default, the information is appended to the file
  12.  *        "files.bbs" in the directory in which the product info
  13.  *        file is found.  See the -f option to use another destination.
  14.  *
  15.  *    -F <s>    Use <s> as a format specifier for writing entries
  16.  *        with -b option.  EX: "%-30.30B %8.8V %4.4KK %-40.40S\n"
  17.  *        Format specs are:
  18.  *
  19.  *        %%    Literal '%' character.
  20.  *        %a    Contents of ".author" field.
  21.  *        %B    Basename of "stored-in" path.
  22.  *        %D    Dirname of "stored-in" path.
  23.  *        %d    Contents of ".description" field.
  24.  *        %F    Contents of ".fullname" (or ".name") field.
  25.  *        %K    Size of the "stored-in" file/directory, in Kb.
  26.  *        %N    Contents of ".name" field.
  27.  *        %P    Full "stored-in" path.
  28.  *        %S    Contents of the ".short" field, 40 chars max.
  29.  *        %V    Version number of the product.
  30.  *        
  31.  *        Other characters are passed through literally, as with
  32.  *        printf.  Note that %D & %B are defined such that
  33.  *        %P=%D%B without having to know what the separator was.
  34.  *
  35.  *    -f <s>    Use <s> as the name of the file to use to write entries
  36.  *        to as a result of using the -b option.  If <s> is "-",
  37.  *        the entries are written to stdout rather than to a file
  38.  *        in each directory containing product info files.
  39.  *
  40.  *    -h    Print help message.
  41.  *
  42.  *    -n    Find Product-Info files and print names to stdout.
  43.  *
  44.  *    -s    Gather product info files and add ".stored-in" fields.
  45.  *
  46.  *    -t    Test Product Info files, report possible problems.
  47.  *
  48.  *    -v    Verbose flag, print name of each Product Info file to
  49.  *        stdout.
  50.  *
  51.  *    Generally, "file1", "file2", etc can be replaced with "-" to
  52.  *    indicate that pitool should operate on a list of files provided
  53.  *    on stdin rather than walking a file tree rooted in the path given
  54.  *    by "file1", "file2", etc.
  55.  *
  56.  */
  57.  
  58. #include <stdio.h>
  59. #include <sys/types.h>
  60. #include <sys/stat.h>
  61. #include "ftw.h"
  62.  
  63. #define STREQ(a,b) ((*(a) == *(b)) && !strcmp ((a),(b)))
  64.  
  65. extern int strlen (const char *);
  66. extern char *strrchr (const char *, char);
  67. extern char *strchr (const char *, char);
  68. extern char *strdup ();
  69.  
  70. static char *format = "%-30.30B %8.8V %4.4KK %-40.40S\n";
  71. static char *bbs_file_name = "files.bbs";
  72. static int verbose;
  73.  
  74. struct pif {
  75.   const char *pi_fname;    /* Name of file containing the product info */
  76.   int pi_line;        /* Current line number being read */
  77.   FILE *pi_fp;        /* "FILE *" pointer to the open file */
  78.   const char *pi_basename;
  79.   int pi_size;
  80.   char *pi_address;
  81.   char *pi_aminet_dir;
  82.   char *pi_author;
  83.   char *pi_construction;
  84.   char *pi_comment;
  85.   char *pi_contents;
  86.   char *pi_date;
  87.   char *pi_described_by;
  88.   char *pi_description;
  89.   char *pi_distribution;
  90.   char *pi_docs;
  91.   char *pi_email;
  92.   char *pi_exectype;
  93.   char *pi_fax;
  94.   char *pi_fullname;
  95.   char *pi_installsize;
  96.   char *pi_keywords;
  97.   char *pi_locale;
  98.   char *pi_name;    /* Contents of the ".name" field */
  99.   char *pi_phone;
  100.   char *pi_price;
  101.   char *pi_reference;
  102.   char *pi_requirements;
  103.   char *pi_restrictions;
  104.   char *pi_run;
  105.   char *pi_short;
  106.   char *pi_source;
  107.   char *pi_stored_in;
  108.   char *pi_submittal;
  109.   char *pi_tested;
  110.   char *pi_type;
  111.   char *pi_version;
  112. };
  113.  
  114. /* Note, we can't use isspace() here, because it counts
  115.    international characters as whitespace.  So just look
  116.    for the characters we are actually concerned about */
  117.  
  118. #define WHITESPACE(a) (((a) == ' ') || ((a) == '\t') || ((a) == '\n'))
  119.  
  120. void
  121. stripwhite (struct pif *pip, char *fieldp)
  122. {
  123.   char *endp;
  124.  
  125.   for (endp = fieldp; *endp != '\000'; endp++) {;}
  126.   endp--;
  127.  
  128.   if (WHITESPACE (*endp))
  129.     {
  130. #if 0    /* Currently there are too many Product Info files where this
  131.        is true, to make this a useful message.  Enable it once
  132.        we have processed all of them to eliminate the whitespace. */
  133.       fprintf (stderr, "%s:%d: extraneous whitespace at end of line\n",
  134.            pip -> pi_fname, pip -> pi_line);
  135. #endif
  136.     }
  137.   while ((endp >= fieldp) && (WHITESPACE (*endp)))
  138.     {
  139.       *endp-- = '\000';
  140.     }
  141. }
  142.  
  143. int
  144. filesize (const char *fname)
  145. {
  146.   struct stat statbuf;
  147.  
  148.   if (stat (fname, &statbuf) == 0)
  149.     {
  150.       return (statbuf.st_size);
  151.     }
  152.   else
  153.     {
  154.       return (0);
  155.     }
  156. }
  157.  
  158. const char *
  159. basename (const char *sp)
  160. {
  161.   const char *bname;
  162.  
  163.   /* Look first for typical Unix or AmigaDOS separator */
  164.  
  165.   bname = strrchr (sp, '/');
  166.  
  167.   /* Look for special AmigaDOS separator */
  168.  
  169. #ifdef __amigados__
  170.   if (bname == NULL)
  171.     {
  172.       bname = strrchr (sp, ':');
  173.     }
  174. #endif
  175.  
  176.   /* If any separator found, skip over it, otherwise the
  177.      basename is just the entire string. */
  178.  
  179.   if (bname == NULL)
  180.     {
  181.       bname = sp;
  182.     }
  183.   else
  184.     {
  185.       bname++;
  186.     }
  187.  
  188.   return (bname);
  189. }
  190.  
  191. /*
  192.  *  Note that dirname is defined such that it *includes* the
  193.  *  separator.  This way you don't need to know whether it 
  194.  *  was a '/' or ':' to reconstruct the full path.  I.E.
  195.  *  %P=%D%B  not %D/%B if '/' or %D%B if ':'
  196.  */
  197.  
  198. const char *
  199. dirname (const char *sp)
  200. {
  201.   char *endp;
  202.   static char buf[256];
  203.  
  204.   strcpy (buf, sp);
  205.  
  206.   /* Look first for typical Unix or AmigaDOS separator */
  207.  
  208.   endp = strrchr (buf, '/');
  209.  
  210.   /* Look for special AmigaDOS separator */
  211.  
  212. #ifdef __amigados__
  213.   if (endp == NULL)
  214.     {
  215.       endp = strrchr (buf, ':');
  216.     }
  217. #endif
  218.  
  219.   /* If there was a separator, set up to zap the next
  220.      character, otherwise the dirname is just the empty
  221.      string. */
  222.  
  223.   if (endp == NULL)
  224.     {
  225.       endp = buf;
  226.     }
  227.   else
  228.     {
  229.       endp++;
  230.     }
  231.   *endp = '\000';
  232.   return ((const char *) buf);
  233. }
  234.  
  235. /*
  236.  *    Given a name of a file that is potentially a product info file,
  237.  *    generate the name of the directory or file that the associated
  238.  *    product is stored in.  By convention, the "stored in" name is
  239.  *    terminated with a '/' if it is a directory.
  240.  *
  241.  *    Returns NULL if the name is not a product info file.
  242.  */
  243.  
  244. char *
  245. stored_in (const char *name)
  246. {
  247.   int length;
  248.   char *namep;
  249.   char *rtnval = NULL;
  250.   static char stored_in_buf[256];
  251.  
  252.   strcpy (stored_in_buf, name);
  253.   length = strlen (stored_in_buf);
  254.   if ((stored_in_buf[length - 1] == 'i') &&
  255.       (stored_in_buf[length - 2] == 'p') &&
  256.       (stored_in_buf[length - 3] == '.'))
  257.     {
  258.       stored_in_buf[length - 3] = '\000';
  259.       rtnval = stored_in_buf;
  260.     }
  261.   else
  262.     {
  263.       namep = strrchr (stored_in_buf, '/');
  264.       if ((namep != NULL) && (STREQ (namep + 1, "Product-Info")))
  265.     {
  266.       *++namep = '\000';
  267.       rtnval = stored_in_buf;
  268.     }
  269.     }
  270.   if (rtnval != NULL)
  271.     {
  272. #ifdef __amigados__
  273.       /* Convert "/path1/path2/file" to "path1:path2/file" */
  274.       if ((*rtnval == '/') &&
  275.       ((namep = strchr (rtnval + 1, '/')) != NULL))
  276.     {
  277.       rtnval++;
  278.       *namep = ':';
  279.     }
  280. #endif
  281.     }
  282.   return (rtnval);
  283. }
  284.  
  285. int
  286. find_pifiles (const char *name, struct stat *statbuf, int flags)
  287. {
  288.   if (stored_in (name) != NULL)
  289.     {
  290.       printf ("%s\n", name);
  291.     }
  292.   return (0);
  293. }
  294.  
  295. void
  296. copy_out (const char *filename)
  297. {
  298.   int ch;
  299.   FILE *fin;
  300.   char buf[256];
  301.   char *endp;
  302.  
  303.   fin = fopen (filename, "r");
  304.   if (fin != NULL)
  305.     {
  306.       while (fgets (buf, 256, fin) != NULL)
  307.     {
  308.       for (endp = buf; *endp != '\000'; endp++) {;}
  309.       endp--;
  310.       while ((endp >= buf) && (WHITESPACE (*endp)))
  311.         {
  312.           *endp-- = '\000';
  313.         }
  314.       puts (buf);
  315.     }
  316.       fclose (fin);
  317.     }
  318. }
  319.  
  320. int
  321. add_stored_in (const char *name, struct stat *statbuf, int flags)
  322. {
  323.   char *sname;
  324.  
  325.   sname = stored_in (name);
  326.   if (sname != NULL)
  327.     {
  328.       copy_out (name);
  329.       printf (".stored-in\n%s\n", sname);
  330.     }
  331.   return (0);
  332. }
  333.  
  334. void
  335. free_pif (struct pif *pip)
  336. {
  337.   if (pip -> pi_fp != NULL)        fclose (pip -> pi_fp);
  338.   if (pip -> pi_stored_in != NULL)    free (pip -> pi_stored_in);
  339.   if (pip -> pi_address != NULL)    free (pip -> pi_address);
  340.   if (pip -> pi_aminet_dir != NULL)    free (pip -> pi_aminet_dir);
  341.   if (pip -> pi_author != NULL)        free (pip -> pi_author);
  342.   if (pip -> pi_construction != NULL)    free (pip -> pi_construction);
  343.   if (pip -> pi_comment != NULL)    free (pip -> pi_comment);
  344.   if (pip -> pi_contents != NULL)    free (pip -> pi_contents);
  345.   if (pip -> pi_date != NULL)        free (pip -> pi_date);
  346.   i