home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
tools
/
pitools
/
pitool.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-30
|
26KB
|
1,034 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.
*
* -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 f