home *** CD-ROM | disk | FTP | other *** search
- /*
- * Process Product-Info files.
- * Written by Fred Fish.
- * All portions not covered by GNU GPL are public domain.
- *
- * usage: pitool [options] file1 file2 file3 ...
- * Options:
- *
- * -b Find Product-Info files and emit information extracted
- * from each file using the format specified by the -F option.
- * By default, the information is appended to the file
- * "files.bbs" in the directory in which the product info
- * file is found. See the -f option to use another destination.
- *
- * -D Enable some special MS-DOS support, such as contructing the
- * "stored in" name from the basename of the product info file,
- * with a few explicit possible extensions added, using a
- * different default format for the files.bbs file, and
- * using a different default name (FILES.BBS).
- *
- * -F <s> Use <s> as a format specifier for writing entries
- * with -b option. EX: "%-30.30B %8.8V %4.4KK %-40.40S\n"
- * Format specs are:
- *
- * %% Literal '%' character.
- * %a Contents of ".author" field.
- * %B Basename of "stored-in" path.
- * %D Dirname of "stored-in" path.
- * %d Contents of ".description" field.
- * %F Contents of ".fullname" (or ".name") field.
- * %K Size of the "stored-in" file/directory, in Kb.
- * %N Contents of ".name" field.
- * %P Full "stored-in" path.
- * %s Size of the "stored-in" file in bytes.
- * %S Contents of the ".short" field, 40 chars max.
- * %T Timestamp of the file or dir, as DD-MMM-YY.
- * %V Version number of the product.
- *
- * Other characters are passed through literally, as with
- * printf. Note that %D & %B are defined such that
- * %P=%D%B without having to know what the separator was.
- *
- * -f <s> Use <s> as the name of the file to use to write entries
- * to as a result of using the -b option. If <s> is "-",
- * the entries are written to stdout rather than to a file
- * in each directory containing product info files.
- *
- * -h Print help message.
- *
- * -n Find Product-Info files and print names to stdout.
- *
- * -s Gather product info files and add ".stored-in" fields.
- *
- * -t Test Product Info files, report possible problems.
- *
- * -v Verbose flag, print name of each Product Info file to
- * stdout.
- *
- * Generally, "file1", "file2", etc can be replaced with "-" to
- * indicate that pitool should operate on a list of files provided
- * on stdin rather than walking a file tree rooted in the path given
- * by "file1", "file2", etc.
- *
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <time.h>
- #include <ctype.h>
- #include "ftw.h"
-
- #define STREQ(a,b) ((*(a) == *(b)) && !strcmp ((a),(b)))
-
- extern int strlen (const char *);
- extern char *strrchr (const char *, char);
- extern char *strchr (const char *, char);
- extern char *strdup ();
-
- #define AMIGA_PRINT_FORMAT "%-30.30B %8.8V %4.4KK %-40.40S\n"
- #define DOS_PRINT_FORMAT "%-18.18B%8s %8.8T %-40.40S\r\n"
- static char *print_format;
-
- #define AMIGA_BBS_FILE_NAME "files.bbs"
- #define DOS_BBS_FILE_NAME "FILES.BBS"
- static char *bbs_file_name;
-
- static int verbose = 0;
- static int dosflag = 0;
-
- struct pif {
- const char *pi_fname; /* Name of file containing the product info */
- int pi_line; /* Current line number being read */
- FILE *pi_fp; /* "FILE *" pointer to the open file */
- int pi_size;
- char *pi_address;
- char *pi_aminet_dir;
- char *pi_author;
- char *pi_construction;
- char *pi_comment;
- char *pi_contents;
- char *pi_date;
- char *pi_described_by;
- char *pi_description;
- char *pi_distribution;
- char *pi_docs;
- char *pi_email;
- char *pi_exectype;
- char *pi_fax;
- char *pi_fullname;
- char *pi_installsize;
- char *pi_keywords;
- char *pi_locale;
- char *pi_name; /* Contents of the ".name" field */
- char *pi_phone;
- char *pi_price;
- char *pi_reference;
- char *pi_requirements;
- char *pi_restrictions;
- char *pi_run;
- char *pi_short;
- char *pi_source;
- char *pi_stored_in;
- char *pi_submittal;
- char *pi_tested;
- char *pi_type;
- char *pi_version;
- };
-
- /* This list of common DOS extensions is used to find the "stored in" name
- for the DOS convention for product info files (where files can only have
- one extension and are length limited). */
-
- static char *dosextens[] =
- {
- ".LHA", /* Lha archive */
- ".ZIP", /* Zip archive */
- ".GZ", /* Gzip compressed file */
- ".TAR", /* Tar archive */
- ".TAZ", /* Gzip compressed tar archive */
- ".JPG", /* Jpeg image */
- ".GIF", /* Gif image */
- ".IFF", /* Amiga IFF format image */
- ".ANM", /* Amiga animation */
- NULL
- };
-
- /* Note, we can't use isspace() here, because it counts
- international characters as whitespace. So just look
- for the characters we are actually concerned about */
-
- #define WHITESPACE(a) (((a) == ' ') || ((a) == '\t') || ((a) == '\n'))
-
- void
- stripwhite (struct pif *pip, char *fieldp)
- {
- char *endp;
-
- for (endp = fieldp; *endp != '\000'; endp++) {;}
- endp--;
-
- if (WHITESPACE (*endp))
- {
- #if 0 /* Currently there are too many Product Info files where this
- is true, to make this a useful message. Enable it once
- we have processed all of them to eliminate the whitespace. */
- fprintf (stderr, "%s:%d: extraneous whitespace at end of line\n",
- pip -> pi_fname, pip -> pi_line);
- #endif
- }
- while ((endp >= fieldp) && (WHITESPACE (*endp)))
- {
- *endp-- = '\000';
- }
- }
-
- int
- filesize (const char *fname)
- {
- struct stat statbuf;
-
- if (stat (fname, &statbuf) == 0)
- {
- return (statbuf.st_size);
- }
- else
- {
- return (0);
- }
- }
-
- char *
- timestamp (const char *fname)
- {
- struct stat statbuf;
- struct tm *fdate;
- static char datebuf[64];
- static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
- if (stat (fname, &statbuf) != 0)
- {
- return ("??-???-??");
- }
- else
- {
- fdate = localtime (&statbuf.st_mtime);
- if (dosflag)
- {
- sprintf (datebuf, "%02d-%02d-%02d", fdate -> tm_mon + 1,
- fdate -> tm_mday, fdate -> tm_year);
- }
- else
- {
- sprintf (datebuf, "%02d-%3s-%2d", fdate -> tm_mday,
- months[fdate -> tm_mon], fdate -> tm_year);
- }
- return (datebuf);
- }
- }
-
- /* Get the basename of a path */
-
- const char *
- basename (const char *sp)
- {
- const char *bname;
-
- /* Look first for typical Unix or AmigaDOS separator, and
- leave bname pointing at the separator. */
-
- bname = strrchr (sp, '/');
-
- /* Look for special AmigaDOS separator */
-
- #ifdef __amigados__
- if (bname == NULL)
- {
- bname = strrchr (sp, ':');
- }
- #endif
-
- /* If any separator found, skip over it, otherwise the
- basename is just the entire string. */
-
- if (bname == NULL)
- {
- bname = sp;
- }
- else
- {
- bname++;
- }
-
- return (bname);
- }
-
- /*
- * Note that dirname is defined such that it *includes* the
- * separator. This way you don't need to know whether it
- * was a '/' or ':' to reconstruct the full path. I.E.
- * %P=%D%B not %D/%B if '/' or %D%B if ':'
- */
-
- const char *
- dirname (const char *sp)
- {
- char *endp;
- static char buf[256];
-
- strcpy (buf, sp);
-
- /* Look first for typical Unix or AmigaDOS separator */
-
- endp = strrchr (buf, '/');
-
- /* Look for special AmigaDOS separator */
-
- #ifdef __amigados__
- if (endp == NULL)
- {
- endp = strrchr (buf, ':');
- }
- #endif
-
- /* If there was a separator, set up to zap the next
- character, otherwise the dirname is just the empty
- string. */
-
- if (endp == NULL)
- {
- endp = buf;
- }
- else
- {
- endp++;
- }
- *endp = '\000';
- return ((const char *) buf);
- }
-
- /*
- * Given a name of a file that is potentially a product info file,
- * generate the name of the directory or file that the associated
- * product is stored in. By convention, the "stored in" name is
- * terminated with a '/' if it is a directory.
- *
- * Normally, the "stored in" name can be generated simply from
- * examination of the name of the product info file, such as deriving
- * "foo/bar/bell.lha" from "foo/bar/bell.lha.pi", or deriving
- * "foo/bar/bell/" from "foo/bar/bell/Product-Info".
- *
- * However, because of the braindead naming conventions of MS-DOS,
- * as a special case for DOS support, the convention of naming the
- * product info file that goes with another file using the basename
- * of the file with '.PI' appended, is supported, as long as there
- * is no ambiguity. I.E., given "FOO/BAR/BELL.LHA", the associated
- * product info file is "FOO/BAR/BELL.PI". In order to discover the
- * correct "stored in" name, it is necessary to actually test for
- * the existance of files with specific name patterns and select
- * the first one that matches. The algorithm is to use the basename
- * of the product info file, with each of the following extensions
- * tested in sequence {LHA, TAR, GZ}. This testing is only done if
- * the "-D" option is used.
- *
- * Returns NULL if the name is not a product info file.
- */
-
- char *
- stored_in (const char *name)
- {
- int length;
- char *namep;
- char *rtnval = NULL;
- char **extp;
- static char stored_in_buf[256];
-
- strcpy (stored_in_buf, name);
- length = strlen (stored_in_buf);
- if ((tolower (stored_in_buf[length - 1]) == 'i') &&
- (tolower (stored_in_buf[length - 2]) == 'p') &&
- (stored_in_buf[length - 3] == '.'))
- {
- if (!dosflag)
- {
- stored_in_buf[length - 3] = '\000';
- rtnval = stored_in_buf;
- }
- else
- {
- for (extp = dosextens; *extp != NULL; extp++)
- {
- strcpy (&stored_in_buf[length - 3], *extp);
- if (filesize (stored_in_buf) != 0)
- {
- rtnval = stored_in_buf;
- break;
- }
- }
- }
- }
- else
- {
- namep = strrchr (stored_in_buf, '/');
- if ((namep != NULL) && (STREQ (namep + 1, "Product-Info")))
- {
- *++namep = '\000';
- rtnval = stored_in_buf;
- }
- }
- if (rtnval != NULL)
- {
- #ifdef __amigados__
- /* Convert "/path1/path2/file" to "path1:path2/file" */
- if ((*rtnval == '/') &&
- ((namep = strchr (rtnval + 1, '/')) != NULL))
- {
- rtnval++;
- *namep = ':';
- }
- #endif
- }
- return (rtnval);
- }
-
- int
- find_pifiles (const char *name, struct stat *statbuf, int flags)
- {
- if (stored_in (name) != NULL)
- {
- printf ("%s\n", name);
- }
- return (0);
- }
-
- void
- copy_out (const char *filename)
- {
- int ch;
- FILE *fin;
- char buf[256];
- char *endp;
-
- fin = fopen (filename, "r");
- if (fin != NULL)
- {
- while (fgets (buf, 256, fin) != NULL)
- {
- for (endp = buf; *endp != '\000'; endp++) {;}
- endp--;
- while ((endp >= buf) && (WHITESPACE (*endp)))
- {
- *endp-- = '\000';
- }
- puts (buf);
- }
- fclose (fin);
- }
- }
-
- int
- add_stored_in (const char *name, struct stat *statbuf, int flags)
- {
- char *sname;
-
- sname = stored_in (name);
- if (sname != NULL)
- {
- copy_out (name);
- printf (".stored-in\n%s\n", sname);
- }
- return (0);
- }
-
- void
- free_pif (struct pif *pip)
- {
- if (pip -> pi_fp != NULL) fclose (pip -> pi_fp);
- if (pip -> pi_stored_in != NULL) free (pip -> pi_stored_in);
- if (pip -> pi_address != NULL) free (pip -> pi_address);
- if (pip -> pi_aminet_dir != NULL) free (pip -> pi_aminet_dir);
- if (pip -> pi_author != NULL) free (pip -> pi_author);
- if (pip -> pi_construction != NULL) free (pip -> pi_construction);
- if (pip -> pi_comment != NULL) free (pip -> pi_comment);
- if (pip -> pi_contents != NULL) free (pip -> pi_contents);
- if (pip -> pi_date != NULL) free (pip -> pi_date);
- if (pip -> pi_described_by != NULL) free (pip -> pi_described_by);
- if (pip -> pi_description != NULL) free (pip -> pi_description);
- if (pip -> pi_distribution != NULL) free (pip -> pi_distribution);
- if (pip -> pi_docs != NULL) free (pip -> pi_docs);
- if (pip -> pi_email != NULL) free (pip -> pi_email);
- if (pip -> pi_exectype != NULL) free (pip -> pi_exectype);
- if (pip -> pi_fax != NULL) free (pip -> pi_fax);
- if (pip -> pi_fullname != NULL) free (pip -> pi_fullname);
- if (pip -> pi_installsize != NULL) free (pip -> pi_installsize);
- if (pip -> pi_keywords != NULL) free (pip -> pi_keywords);
- if (pip -> pi_locale != NULL) free (pip -> pi_locale);
- if (pip -> pi_name != NULL) free (pip -> pi_name);
- if (pip -> pi_phone != NULL) free (pip -> pi_phone);
- if (pip -> pi_price != NULL) free (pip -> pi_price);
- if (pip -> pi_reference != NULL) free (pip -> pi_reference);
- if (pip -> pi_requirements != NULL) free (pip -> pi_requirements);
- if (pip -> pi_restrictions != NULL) free (pip -> pi_restrictions);
- if (pip -> pi_run != NULL) free (pip -> pi_run);
- if (pip -> pi_short != NULL) free (pip -> pi_short);
- if (pip -> pi_source != NULL) free (pip -> pi_source);
- if (pip -> pi_submittal != NULL) free (pip -> pi_submittal);
- if (pip -> pi_tested != NULL) free (pip -> pi_tested);
- if (pip -> pi_type != NULL) free (pip -> pi_type);
- if (pip -> pi_version != NULL) free (pip -> pi_version);
-
- free (pip);
- }
-
- struct pif *
- open_pif (const char *name)
- {
- struct pif *pip;
- extern char *malloc ();
- char *stor;
-
- pip = (struct pif *) malloc (sizeof (struct pif));
- if (pip == NULL)
- {
- fprintf (stderr, "pitool: out of virtual memory\n");
- exit (1);
- }
- memset (pip, 0, sizeof (struct pif));
- pip -> pi_fname = name;
- pip -> pi_line = 0;
- pip -> pi_fp = fopen (pip -> pi_fname, "r");
- stor = stored_in (pip -> pi_fname);
- if (stor != NULL)
- {
- pip -> pi_stored_in = strdup (stor);
- }
- if (pip -> pi_fp == NULL)
- {
- perror (pip -> pi_fname);
- free_pif (pip);
- pip = NULL;
- }
- else if (verbose)
- {
- printf ("%s\n", pip -> pi_fname);
- }
- return (pip);
- }
-
- /* Find next field marker and strip off any whitespace from end of the
- line. */
-
- char *
- next_field (struct pif *pip)
- {
- static char readbuf[256];
- char *bufp;
-
- while (fgets (readbuf, sizeof (readbuf), pip -> pi_fp) != NULL)
- {
- pip -> pi_line++;
- if (readbuf[0] == '.')
- {
- for (bufp = readbuf; *bufp != '\000'; bufp++) {;}
- bufp--;
- while ((bufp >= readbuf) && WHITESPACE (*bufp))
- {
- *bufp-- = '\000';
- }
- return (readbuf);
- }
- }
- return (NULL);
- }
-
- char *
- read_field (struct pif *pip)
- {
- static char readbuf[16 * 1024];
- char *sp = readbuf;
- int ch = '\n'; /* Detect '.' if first char read */
- int prevch = 0;
-
- for (;;)
- {
- prevch = ch;
- ch = getc (pip -> pi_fp);
- if (ch == '\n')
- {
- pip -> pi_line++;
- }
- if (ch == '.')
- {
- if (prevch == '\n')
- {
- ungetc (ch, pip -> pi_fp);
- break;
- }
- }
- else if (ch == EOF)
- {
- if (prevch != '\n')
- {
- fprintf (stderr, "%s:%d: does not end with newline\n",
- pip -> pi_fname, pip -> pi_line);
- *sp++ = '\n';
- }
- break;
- }
- *sp++ = ch;
- }
- if (sp > readbuf)
- {
- sp--;
- }
- *sp = '\000';
- stripwhite (pip, readbuf);
- return (readbuf);
- }
-
- struct pif *
- read_pif (const char *name)
- {
- struct pif *pip;
- char *fieldname;
- char *rawfield;
- char *temp;
-
- pip = open_pif (name);
- if (pip != NULL)
- {
- while ((fieldname = next_field (pip)) != NULL)
- {
- rawfield = read_field (pip);
- if (STREQ (fieldname + 1, "address"))
- { pip -> pi_address = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "aminet-dir"))
- { pip -> pi_aminet_dir = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "author"))
- { pip -> pi_author = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "construction"))
- { pip -> pi_construction = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "comment"))
- { pip -> pi_comment = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "contents"))
- { pip -> pi_contents = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "date"))
- { pip -> pi_date = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "described-by"))
- { pip -> pi_described_by = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "description"))
- { pip -> pi_description = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "distribution"))
- { pip -> pi_distribution = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "docs"))
- { pip -> pi_docs = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "email"))
- { pip -> pi_email = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "exectype"))
- { pip -> pi_exectype = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "fax"))
- { pip -> pi_fax = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "fullname"))
- { pip -> pi_fullname = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "installsize"))
- { pip -> pi_installsize = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "keywords"))
- { pip -> pi_keywords = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "locale"))
- { pip -> pi_locale = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "name"))
- {
- pip -> pi_name = strdup (rawfield);
- if (strchr (rawfield, ' ') || strchr (rawfield, '\t'))
- {
- fprintf (stderr,
- "%s:%d: '.name' field contains whitespace; use '.fullname' instead\n",
- pip -> pi_fname, pip -> pi_line);
- }
- continue;
- }
- if (STREQ (fieldname + 1, "phone"))
- { pip -> pi_phone = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "price"))
- { pip -> pi_price = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "reference"))
- { pip -> pi_reference = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "requirements"))
- { pip -> pi_requirements = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "restrictions"))
- { pip -> pi_restrictions = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "run"))
- { pip -> pi_run = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "short"))
- {
- pip -> pi_short = strdup (rawfield);
- if (strlen (rawfield) > 40)
- {
- fprintf (stderr,
- "%s:%d: '.short' field > 40 characters\n",
- pip -> pi_fname, pip -> pi_line);
- }
- if ((temp = strchr (rawfield, '\n')) != NULL)
- {
- *temp = '\000';
- fprintf (stderr,
- "%s:%d: '.short' field contains newline\n",
- pip -> pi_fname, pip -> pi_line);
- }
- continue;
- }
- if (STREQ (fieldname + 1, "source"))
- { pip -> pi_source = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "submittal"))
- { pip -> pi_submittal = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "tested"))
- { pip -> pi_tested = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "type"))
- { pip -> pi_type = strdup (rawfield); continue; }
- if (STREQ (fieldname + 1, "version"))
- { pip -> pi_version = strdup (rawfield); continue; }
- fprintf (stderr, "%s:%d: unrecognized field '%s'\n",
- pip -> pi_fname, pip -> pi_line, fieldname);
- }
- fclose (pip -> pi_fp);
- pip -> pi_fp = NULL;
- }
- if (pip -> pi_name == NULL)
- {
- fprintf (stderr, "%s:%d: missing '.name' field\n", pip -> pi_fname,
- pip -> pi_line);
- }
- if (pip -> pi_short == NULL)
- {
- fprintf (stderr, "%s:%d: missing '.short' field\n", pip -> pi_fname,
- pip -> pi_line);
- }
- return (pip);
- }
-
- void
- fprintf_pif (FILE *fp, struct pif *pip)
- {
- char pformat[256];
- char *pformatp = pformat;
- char *formatp = print_format;
- int argc = 0;
- int needspec = 0;
- const char *argv[10]; /* FIXME: check for overflow */
- char *B_arg;
- char B_argbuf[256];
- static char sizebuf[16];
- static char sizebufKb[16];
-
- while (*formatp != '\000')
- {
- if (needspec)
- {
- switch (*formatp)
- {
- case 'a': /* Contents of ".author" field. */
- argv[argc++] = pip -> pi_author;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'B': /* Basename of "stored-in" path */
- B_arg = basename (pip -> pi_stored_in);
- if (*B_arg == '\000')
- {
- strcpy (B_argbuf, pip -> pi_stored_in);
- B_argbuf[strlen (B_argbuf) - 1] = '\000';
- B_arg = basename (B_argbuf);
- }
- argv[argc++] = B_arg;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'D': /* Dirname of "stored-in" path */
- argv[argc++] = dirname (pip -> pi_stored_in);
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'd': /* contents of ".description" field */
- argv[argc++] = pip -> pi_description;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'F': /* Contents of ".fullname" or ".name" field. */
- argv[argc++] = pip -> pi_fullname ? pip -> pi_fullname : pip -> pi_name;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'K': /* "Stored-in" filesize in Kb */
- sprintf (sizebufKb, "%d", filesize (pip -> pi_stored_in) / 1024);
- argv[argc++] = sizebufKb;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'N': /* Contents of ".name" field. */
- argv[argc++] = pip -> pi_name;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'P': /* Full "stored-in" path */
- argv[argc++] = pip -> pi_stored_in;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 's': /* "Stored-in" filesize in bytes */
- sprintf (sizebuf, "%d", filesize (pip -> pi_stored_in));
- argv[argc++] = sizebuf;
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'S': /* The ".short" field */
- argv[argc++] = pip -> pi_short ? pip -> pi_short : "<no description avail>";
- *pformatp++ = 's';
- *formatp++;
- needspec = 0;
- break;
- case 'T':
- argv[argc++] = timestamp (pip -> pi_stored_in);
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case 'V': /* Version */
- argv[argc++] = pip -> pi_version ? pip -> pi_version : "?.?";
- *pformatp++ = 's';
- formatp++;
- needspec = 0;
- break;
- case '%':
- if (*(formatp - 1) != '%')
- {
- fprintf (stderr, "bad -F format string, missing spec\n");
- exit (1);
- }
- /* A '%' can quote the following '%' */
- *pformatp++ = *formatp++;
- needspec = 0;
- break;
- default:
- /* Stuff to print verbatum */
- *pformatp++ = *formatp++;
- break;
- }
- }
- else if (*formatp == '%')
- {
- /* We are not looking for a spec because of a previous '%' */
- needspec++;
- *pformatp++ = *formatp++;
- }
- else if (*formatp == '\\')
- {
- /* Simple '\' evaluation, only single chars now. FIXME */
- formatp++;
- switch (*formatp)
- {
- case '\\':
- *pformatp++ = '\\'; /* quoted it */
- break;
- case 't':
- *pformatp++ = '\t';
- break;
- case 'n':
- *pformatp++ = '\n';
- break;
- case 'b':
- *pformatp++ = '\b';
- break;
- case 'r':
- *pformatp++ = '\r';
- break;
- case 'f':
- *pformatp++ = '\f';
- break;
- default:
- *pformatp++ = *formatp;
- break;
- }
- formatp++;
- }
- else
- {
- /* stuff that needs no interpretation */
- *pformatp++ = *formatp++;
- }
- }
- *pformatp++ = '\000';
- fprintf (fp, pformat,
- argv[0], argv[1], argv[2], argv[3], argv[4],
- argv[5], argv[6], argv[7], argv[8], argv[9]);
- }
-
- int
- add_files_bbs (const char *name, struct stat *statbuf, int flags)
- {
- struct pif *pip;
- char bbsfile[256];
- char *scan;
- FILE *bbsfp;
-
- if (stored_in (name) != NULL)
- {
- pip = read_pif (name);
- if (pip != NULL)
- {
- if (STREQ (bbs_file_name, "-"))
- {
- fprintf_pif (stdout, pip);
- }
- else
- {
- strcpy (bbsfile, name);
- scan = strrchr (bbsfile, '/');
- if (scan != NULL)
- {
- scan++;
- strcpy (scan, bbs_file_name);
- bbsfp = fopen (bbsfile, "a");
- if (bbsfp != NULL)
- {
- fprintf_pif (bbsfp, pip);
- fclose (bbsfp);
- }
- }
- }
- free_pif (pip);
- }
- }
- return (0);
- }
-
- int
- test_pifiles (const char *name, struct stat *statbuf, int flags)
- {
- struct pif *pip;
- char bbsfile[256];
- char *scan;
- FILE *bbsfp;
-
- if (stored_in (name) != NULL)
- {
- pip = read_pif (name);
- if (pip != NULL)
- {
- free_pif (pip);
- }
- }
- return (0);
- }
-
- void
- filter_stdin (int (*filter_through) (const char *name, struct stat *statbuf, int flags))
- {
- char buf [256];
-
- while (gets (buf) != NULL)
- {
- /* Note that currently only first arg is used. */
- (*filter_through) ((const char *) buf, NULL, 0);
- }
- }
-
- int
- main (argc, argv)
- int argc;
- char *argv[];
- {
- int ch;
- int action;
- int errflg = 0;
- extern int optind;
- extern char *optarg;
-
- while ((ch = getopt (argc, argv, "DF:f:bfhnstv")) != EOF)
- {
- switch (ch)
- {
- case 'D':
- dosflag++;
- break;
- case 'F':
- print_format = optarg;
- break;
- case 'f':
- bbs_file_name = optarg;
- break;
- case 'h':
- break;
- case 'v':
- verbose++;
- break;
- case '?':
- errflg++;
- break;
- default:
- action = ch;
- break;
- }
- if (errflg)
- {
- fprintf (stderr, "unknown arg, use -h for help\n");
- exit (1);
- }
- }
- if (bbs_file_name == NULL)
- {
- bbs_file_name = dosflag ? DOS_BBS_FILE_NAME : AMIGA_BBS_FILE_NAME;
- }
- if (print_format == NULL)
- {
- print_format = dosflag ? DOS_PRINT_FORMAT : AMIGA_PRINT_FORMAT;
- }
- for ( ; optind < argc; optind++)
- {
- if (STREQ (argv[optind], "-"))
- {
- switch (action)
- {
- case 'b':
- filter_stdin (add_files_bbs);
- break;
- case 'n':
- filter_stdin (find_pifiles);
- break;
- case 's':
- filter_stdin (add_stored_in);
- break;
- case 't':
- filter_stdin (test_pifiles);
- break;
- default:
- fprintf (stderr, "unknown action '%c'\n", action);
- exit (1);
- }
- }
- else
- {
- switch (action)
- {
- case 'b':
- ftw ((const char *) argv[optind], add_files_bbs, 30);
- break;
- case 'n':
- ftw ((const char *) argv[optind], find_pifiles, 30);
- break;
- case 's':
- ftw ((const char *) argv[optind], add_stored_in, 30);
- break;
- case 't':
- ftw ((const char *) argv[optind], test_pifiles, 30);
- break;
- default:
- fprintf (stderr, "unknown action '%c'\n", action);
- exit (1);
- }
- }
- }
- exit (0);
- return (0);
- }
-