home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
arc_lbr
/
arff.arc
/
ARFF.C
next >
Wrap
C/C++ Source or Header
|
1988-08-19
|
16KB
|
659 lines
/*title arff -- archive file finder */
/*version 1.0 18 August 1988 by Mark Armbrust */
/* This is a nasty hack that searches through the directory tree looking for
files that match its arguments. When it find archives that it knows how to
deal with (their extensions are defined in a configuration file) it fires up
the appropriate tool to list the archive to a temporary file which is then
scanned for matching filenames. If any matching names are found, their
entries are reformatted into a more-or-less consistant format and printed.
BE WARNED! This was hacked out in a couple of after work evenings, using
bits and pieces of other things, and whole lot of "hammer it til it fits"
code.
Reads a configuration file to learn how to handle archives. Each line
describes an archive format. Example:
.ARC "c:\bin\arcv %s" "=" "%s" "%*12c %s" "%*50c%9c" "%*61c%8c" "." "*total"
.ARC This is the archive identifier, any file encountered
with this extension is listed and searched using information
from this entry.
"c:\bin\arcv.com %s" This is command used to list the archive to stdout.
The name of the archive is represented by the %s in the string.
Use of full path name is required.
"=" This is a string, starting in column one of the listing that
identifies the last line of information that preceeds the file
names in the archive listing. If there are no preceeding
lines, use "."
"%s" This is the format used to read the file name from archive
listing. This is passed directly to sscanf().
"%*12c %s" This is the format used to read the file size from archive
listing. This is passed directly to sscanf().
"%*50c%9c" This is the format used to read the file date from archive
listing. This is passed directly to sscanf().
"%*61c%8c" This is the format used to read the file time from archive
listing. This is passed directly to sscanf(). If the time
was read as part of the date, use "."
"." This is the format used to read the file options/attributes
from archive listing. This is passed directly to sscanf(). If
there are no options, use "."
"*total" This is a string, starting in column one of the listing that
identifies the first line of information that follows the file
names in the archive listing. If there are no trailing lines,
use "."
It's not copyrighted! It's not patented! It's not even shareware!
It's absolutely free! (and worth every penny)
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <process.h>
typedef struct _arc_info {
struct _arc_info *next_arc;
char *ext;
char *list_cmd;
char *start_str;
char *name_fmt;
char *size_fmt;
char *date_fmt;
char *time_fmt;
char *opt_fmt;
char *end_str;
}
arc_info;
void main (int, char*[]);
void Read_Config_File (void);
void Print_Usage (void);
void Search_Path (char *);
void Show_Dir (char *, struct find_t*);
int Match (char *, char *);
int WC_Match (char *, char *);
void Search_Arc (arc_info *, char *);
void Abort (char *);
char *Fix_Slant (char *);
#define H_STDOUT 1
#define IS_SLANT(c) ((c) == '/' || (c) == '\\')
#define IS_FILE_SEP(c) ( (c) == ':' || (c) == '.' || IS_SLANT(c) )
char search_mode = '\0';
arc_info *arc_list = NULL;
int num_pat;
char **patterns;
char months[12][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
int dos_version;
char *exe_path;
char *arff_name;
void main (argc, argv)
int argc;
char *argv[];
{
register char *path;
register char *p;
dos_version = bdos (0x30, 0, 0) & 0xff;
exe_path = argv[0];
if (dos_version < 3)
arff_name = "arff";
else {
arff_name = strrchr (argv[0], '\\');
if (arff_name)
++arff_name;
else {
arff_name = strrchr (argv[0], '/');
if (arff_name)
++arff_name;
else
arff_name = argv[0];
}
arff_name = strdup (arff_name);
*strchr(arff_name, '.') = '\0';
strlwr(arff_name);
}
if (argc < 2) {
Print_Usage ();
exit (-1);
}
if (stricmp (argv[1], "-a") == 0) {
search_mode = 'A';
++argv;
--argc;
}
else if (stricmp (argv[1], "-n") == 0) {
search_mode = 'N';
++argv;
--argc;
}
if (argc < 2) {
Print_Usage ();
exit (-1);
}
path = argv[1];
while (p = strchr( argv[1], ':')) argv[1] = p+1;
while (p = strchr( argv[1], '/')) argv[1] = p+1;
while (p = strchr( argv[1], '\\')) argv[1] = p+1;
if (path != argv[1]) {
if (argv[1][0] == '\0') {
++argv; /* argument is only a path */
--argc;
}
else {
p = malloc (argv[1] - path + 1);
p[argv[1] - path] = '\0';
path = strncpy (p, path, argv[1] - path);
}
Fix_Slant (path);
}
else
path = "";
if (argc < 2) {
Print_Usage ();
exit (-1);
}
Read_Config_File ();
num_pat = argc - 1;
patterns = &argv[1];
Search_Path (path);
}
void Print_Usage ()
{
printf ("usage: %s [-an] [path] files ...\n", arff_name);
printf (" -a look in archives only\n");
printf (" -n don't look in archives\n");
printf (" path where to start searching\n");
printf (" files what to look for (*? ok)\n");
}
void Read_Config_File ()
{
register char *arff_cfg;
FILE *config_file;
char ext[21], list_cmd[41], start_str[21], name_fmt[21], size_fmt[21],
date_fmt[21], time_fmt[21], opt_fmt[21], end_str[21];
register arc_info *this_arc;
int i;
char line[200];
arff_cfg = getenv ("ARFF.CFG");
if ( ! arff_cfg && dos_version < 3) {
arff_cfg = "C:\BIN\ARFF.CFG";
}
else {
arff_cfg = strrchr (exe_path, '.');
if (arff_cfg && strlen (arff_cfg) == 4) {
strcpy (arff_cfg, ".CFG");
arff_cfg = exe_path;
}
else {
fprintf (stderr, "%s: internal error, could not change argv[0] extension\n", arff_name);
exit (-1);
}
}
config_file = fopen (arff_cfg, "r");
if ( ! config_file) {
fprintf (stderr, "%s: could not open config file \"%s\". (Set variable ARFF.CFG)\n", arff_name, arff_cfg);
exit (-1);
}
for (;;) {
fgets (line, 200, config_file);
if (feof (config_file))
break;
if (line[0] == ';')
continue;
i = sscanf (line,
"%20s \"%40[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \"%20[^\"]\" \n",
ext, list_cmd, start_str, name_fmt, size_fmt, date_fmt, time_fmt, opt_fmt, end_str);
if (i != 9 || ext[0] != '.') {
fprintf (stderr, "%s: bad line in config file.\n%s\nformat is:\n", arff_name, line);
fprintf (stderr, "arc_ext \"list_cmd\" \"start_str\" \"name_fmt\" \"size_fmt\" \"date_fmt\" \"time_fmt\" \"opt_fmt\" \"end_str\"\n");
exit (-1);
}
this_arc = (arc_info *) malloc (sizeof (arc_info));
if ( ! this_arc) Abort ("this_arc malloc failed in Read_Config_File");
if (!strcmp (start_str, ".")) start_str[0] = '\0';
if (!strcmp (size_fmt, ".")) size_fmt[0] = '\0';
if (!strcmp (date_fmt, ".")) date_fmt[0] = '\0';
if (!strcmp (time_fmt, ".")) time_fmt[0] = '\0';
if (!strcmp (opt_fmt, ".")) opt_fmt[0] = '\0';
if (!strcmp (end_str, ".")) end_str[0] = '\0';
this_arc->ext = strdup (strlwr (ext));
this_arc->list_cmd = strdup (list_cmd);
this_arc->start_str = strdup (start_str);
this_arc->name_fmt = strdup (name_fmt);
this_arc->size_fmt = strdup (size_fmt);
this_arc->date_fmt = strdup (date_fmt);
this_arc->time_fmt = strdup (time_fmt);
this_arc->opt_fmt = strdup (opt_fmt);
this_arc->end_str = strdup (end_str);
if ( ! (this_arc->ext && this_arc->list_cmd && this_arc->start_str && this_arc->name_fmt &&
this_arc->size_fmt && this_arc->date_fmt && this_arc->time_fmt && this_arc->opt_fmt &&
this_arc->end_str))
Abort ("this_arc strdup failed in Read_Config_file");
this_arc->next_arc = arc_list;
arc_list = this_arc;
}
fclose (config_file);
}
void Search_Path (path)
char *path;
{
struct find_t find_buf;
char *name;
int i;
register char *new_path;
register arc_info *this_arc;
name = malloc (strlen (path) + 4);
if (!name) Abort ("name malloc failed in Search_Path");
strcpy (name, path);
strcat (name, "*.*");
for (i = _dos_findfirst (name, 0x3F, &find_buf); !i; i = _dos_findnext (&find_buf) ) {
if (find_buf.name[0] == '.' && (find_buf.name[1] == 0 || find_buf.name[1] == '.'))
continue;
strlwr (find_buf.name);
if (find_buf.attrib & _A_SUBDIR) {
new_path = malloc (strlen (path) + strlen (find_buf.name) + 2);
if (!new_path) Abort ("new_path malloc failed in Search_Path(subdir)");
strcpy (new_path, path);
strcat (new_path, find_buf.name);
strcat (new_path, "\\");
Search_Path (new_path);
free (new_path);
continue;
}
if (search_mode != 'A')
for (i=0; i<num_pat; ++i)
if (Match (find_buf.name, patterns[i])) {
Show_Dir (path, &find_buf);
break;
}
if (search_mode != 'N') { /* see if this in archive we can deal with */
for (this_arc = arc_list; this_arc; this_arc = this_arc->next_arc)
if (strstr (find_buf.name, this_arc->ext)) {
new_path = malloc (strlen (path) + strlen (find_buf.name) + 2);
if (!new_path) Abort ("new_path malloc failed in Search_Path(arc)");
strcpy (new_path, path);
strcat (new_path, find_buf.name);
Search_Arc (this_arc, new_path);
free (new_path);
}
}
}
free (name);
}
void Show_Dir (path, find_buf)
char *path;
struct find_t *find_buf;
{
int mo, yr, h, m;
register int day, s;
char attr[4];
s = find_buf->wr_time;
m = (s & 0x07E0) >> 5;
h = (s & 0xF800) >> 11;
s &= 0x001F;
day = find_buf->wr_date;
mo = (day & 0x01E0) >> 5;
yr = ((day & 0xFE00) >> 9) + 80;
if (yr >= 100) yr -= 100;
day &= 0x001F;
strcpy (attr, " ");
if (find_buf->attrib & _A_SYSTEM) attr[0] = 'S';
if (find_buf->attrib & _A_HIDDEN) attr[1] = 'H';
if (find_buf->attrib & _A_RDONLY) attr[2] = 'R';
printf ("%8ld %2d %3s %02d %02d:%02d:%02d %3s %s%s",
find_buf->size, day, months[mo-1], yr, h, m, s, attr, path, find_buf->name);
if (find_buf->attrib & _A_SUBDIR)
printf ("\\\n");
else
printf ("\n");
}
void Search_Arc (arc_type, path)
register arc_info *arc_type;
char *path;
{
char *temp_name;
char *command;
char line[100], name[100], size[20], date[40], time[20], opt[10];
FILE *temp_file;
int skipping;
register int i;
char *exe_path;
int save_stdout, new_stdout, exit_code;
temp_name = tempnam ("\\", "$ARF");
if (!temp_name) Abort ("tempnam failed in Search_Arc");
command = malloc ( strlen(arc_type->list_cmd) + strlen(path) + 1);
if (!command) Abort ("command malloc failed in Search_Arc");
sprintf (command, arc_type->list_cmd, path);
exe_path = command;
command = strpbrk (command, " \t");
if (!command) {
fprintf (stderr, "%s: could not parse \"%s\" \nspace required after command name\n", arff_name, arc_type->list_cmd);
exit (-1);
}
*(command++) = '\0';
fputs ("*\b", stdout);
fflush (stdout);
save_stdout = dup (H_STDOUT);
new_stdout = open (temp_name, O_CREAT | O_WRONLY, S_IWRITE);
if (new_stdout == -1) Abort ("Could not open temp file");
dup2 (new_stdout, H_STDOUT);
exit_code = spawnl (P_WAIT, exe_path, exe_path, command, NULL);
close (new_stdout);
dup2 (save_stdout, H_STDOUT);
close (save_stdout);
fputs (" \b", stdout);
if (exit_code) {
unlink (temp_name);
switch (exit_code >> 8) {
case -1:
fprintf (stderr, "%s: could not execute \"%s %s\" command, errno %#04x\n",
arff_name, exe_path, command, errno);
break;
case 1:
printf ("^C\n");
break;
default:
fprintf (stderr, "%s: \"%s %s\" command failed, exit code %#04x\n",
arff_name, exe_path, command, exit_code);
break;
}
exit (-1);
}
temp_file = fopen (temp_name, "r");
if (!temp_file) Abort ("temp_file fopen failed in Search_Arc");
skipping = (arc_type->start_str[0]);
while (!feof(temp_file)) {
fgets (line, 100, temp_file);
if (line[0] == '\n' || line[0] == '\r')
continue;
if (skipping) {
if (!strncmp (line, arc_type->start_str, strlen(arc_type->start_str)) )
skipping = 0;
continue;
}
if (!skipping && arc_type->end_str[0] && (strncmp (line, arc_type->end_str, strlen(arc_type->end_str)) == 0)) {
break;
}
memset (name, 0, 100);
if (sscanf (line, arc_type->name_fmt, name) != 1)
break;
for (i=0; i<num_pat; ++i)
if (Match (name, patterns[i])) {
memset (size, 0, 20);
memset (date, 0, 20);
memset (time, 0, 20);
memset (opt, 0, 10);
if (arc_type->size_fmt[0]) sscanf (line, arc_type->size_fmt, size);
if (arc_type->date_fmt[0]) sscanf (line, arc_type->date_fmt, date);
if (arc_type->time_fmt[0]) sscanf (line, arc_type->time_fmt, time);
if (arc_type->opt_fmt[0]) sscanf (line, arc_type->opt_fmt, opt);
strcat (date, " ");
strcat (date, time);
Fix_Slant (strlwr (name));
printf ("%8s %-19s %3s %s:%s\n", size, date, opt, path, name);
break;
}
}
fclose (temp_file);
free (command);
unlink (temp_name);
free (temp_name);
}
int Match (file, pattern)
char *file;
char *pattern;
{
int i;
register char *filename;
register char *s;
/* strip off the leading path and trailing modifiers (zoo ver. number, etc.) */
filename = file;
if (s = strrchr (filename, '/')) filename = s+1;
if (s = strrchr (filename, '\\')) filename = s+1;
filename = strdup (filename);
if (!filename) Abort ("filename strdup failed in Match");
if (s = strpbrk (filename, ";*, ")) *s = '\0';
i = WC_Match (filename, pattern);
free (filename);
return i;
}
/* Returns TRUE if s1 and s2 match under modified MSDOS wildcard rules.
*
* Two strings match if all their substrings between : . / and \ match
* using * and ? as wildcards in the substrings.
*
* Note that MSDOS is a bit schitzo about matching strings that end in : and .
* This code will only match them 1-to-1. For example 'DIR X' matches X.* or
* X\*.* depending on what X is. We do, however, match 'X' to 'X.' and 'X.*'
*
*/
int WC_Match (s1, s2)
register char *s1;
register char *s2;
{
while (1) {
if (*s1 == '*' || *s2 == '*') {
while (*s1 && ! IS_FILE_SEP (*s1))
++s1;
while (*s2 && ! IS_FILE_SEP (*s2))
++s2;
continue;
}
if (*s1 == '?') {
if (!*s2 || IS_FILE_SEP (*s2))
return 0;
++s1;
++s2;
continue;
}
if (*s2 == '?') {
if (!*s1 || IS_FILE_SEP (*s1))
return 0;
++s1;
++s2;
continue;
}
if (*s1 == 0 && *s2 == '.') {
++s2;
continue;
}
if (*s2 == 0 && *s1 == '.') {
++s1;
continue;
}
if (toupper(*s1) != toupper(*s2))
return 0;
if (*s1 == 0) /* then (*s2 == 0) as well! */
break;
++s1;
++s2;
}
return 1;
}
void Abort (msg)
char *msg;
{
fprintf (stderr, "%s: internal error -- %s\n", arff_name, msg);
exit (-1);
}
char *Fix_Slant (s)
register char *s;
{
register int i;
for (i=0; s[i]; ++i)
if (s[i] == '/')
s[i] = '\\';
return s;
}