home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 5
/
FreshFish_July-August1994.bin
/
tools
/
pitools
/
pitool.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-15
|
22KB
|
891 lines
/*
* 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.
*
* -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 Contents of the ".short" field, 40 chars max.
* %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 "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 ();
static char *format = "%-30.30B %8.8V %4.4KK %-40.40S\n";
static char *bbs_file_name = "files.bbs";
static int verbose;
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 */
const char *pi_basename;
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;
};
/* 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);
}
}
const char *
basename (const char *sp)
{
const char *bname;
/* Look first for typical Unix or AmigaDOS 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.
*
* Returns NULL if the name is not a product info file.
*/
char *
stored_in (const char *name)
{
int length;
char *namep;
char *rtnval = NULL;
static char stored_in_buf[256];
strcpy (stored_in_buf, name);
length = strlen (stored_in_buf);
if ((stored_in_buf[length - 1] == 'i') &&
(stored_in_buf[length - 2] == 'p') &&
(stored_in_buf[length - 3] == '.'))
{
stored_in_buf[length - 3] = '\000';
rtnval = stored_in_buf;
}
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);
i