home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast2.iso
/
waffle
/
allfil62.zip
/
ALLFILES.C
next >
Wrap
C/C++ Source or Header
|
1993-03-03
|
18KB
|
690 lines
/*
** Create a set of BBS directory files and summarys from the Waffle
** dirs file and the raw files according to a summary config
**
** Produce extra information on some special file types (gif, jpg, bin)
**
** Otto J. Makela <otto@jyu.fi>, Jyvaskyla, Finland, 1993
** BBS V.32bis/HST +358 41 211 562
** Distributed under the GNU General Public Licence:
** see file COPYING for details
*/
/* Default dirs file name */
#define DIRSFILE "/waffle/system/dirs"
/* Default input and output filenames */
#define RAWINFO "@files.raw"
#define INFO "@files"
#define NOINFO 0
/* Default formats */
#define MASTERFORMAT "%-12f%6L%3d/%02m/%02y %T\n"
#define PLUSFORMAT " Size Updated %t\n"
#define INFOFORMAT "%f\t%T\n"
#define BEGIN "List of %t files on SomeBBS, Somewhere\n" \
"%A, %2d %B %Y %2H:%M\n"
#define HEADER "\n*** %f ***\n\n"
#define NAMEHEADER "\n*** %f (%t) ***\n\n"
#define FOOTER "\nTotal %L in %n files\n"
#define ENDER "\nGrand total %L in %n file%P in %N directories\n" \
"*** End of %t files listing ***\n"
/* Max number of simultaneous summary files */
#define MAXSUMMARY 8
/* Max number of tokens per parsed file line */
#define MAXTOKENS 25
/* Characters verboten in filenames (not including wildcards) */
#define FORBIDDEN ",;:+\"/<=>[\\]|"
#define NONFILENAME(c) (isspace(c) || strchr(FORBIDDEN,c))
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "formatch.h"
#include "wafcfg.h"
/* God, how I hate ANSI C */
#define READ_TEXT "rt"
#define READ_BINARY "rb"
#define WRITE_TEXT "wt"
#define WRITE_BINARY "wb"
/* Some almost-ANSI compilers don't have __DATE__ */
#ifndef __DATE__
#define __DATE__
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#define ever (;;)
#define KILOS(a) ( ((a)>>10) + (((a)&0x3FF)?1L:0L) )
/* Function prototypes */
int showfile(struct file_match *match);
int find_filenames(char *dirfile,FILE *files,int skiplines);
char *fileinfo(char *format,struct file_match *match);
char *string(char *format,...);
int fputs2(char *string);
int specialinfo(char *string,char *filename,char *extension);
int macbinfo(char *string,char *filename);
int gifinfo(char *string,char *filename);
int jfifinfo(char *string,char *filename);
/* Some common variables */
char info[16]=INFO,rawinfo[16]=RAWINFO,dirsfile[80]=DIRSFILE,
masterformat[80]=MASTERFORMAT,plusformat[80]=PLUSFORMAT,
infoformat[80]=INFOFORMAT,begin[BUFSIZ]=BEGIN,header[80]=HEADER,
nameheader[80]=NAMEHEADER,footer[80]=FOOTER,ender[BUFSIZ]=ENDER;
unsigned int summarys=0,scanrom=0,zeros=0,noinfo=NOINFO;
char *description;
unsigned long size,files,number;
FILE *fi,*fo;
/* Summary file information array */
struct {
char dir[65]; /* Directory */
char name[24]; /* Listing name */
char doprint; /* Printing or not ? */
unsigned int dirs; /* How many directories in listing */
unsigned long size; /* How many bytes in listing */
unsigned long files; /* How many files in listing */
FILE *file; /* Output FILE * */
} summary[MAXSUMMARY];
int main(int argc,char *argv[]) {
register char *p,*q;
int i,rom,skip,column,errors=0;
char dirsline[BUFSIZ],line[BUFSIZ];
char *dir;
FILE *config;
struct file_match nonfile;
fprintf(stderr,"%s 6.2 "__DATE__
" by Otto J. Makela (BBS V.32bis/HST +358 41 211 562)\n"
"Distributed under the GNU General Public Licence: "
"see file COPYING for details\n",*argv="allfiles");
if(argc<2) {
fprintf(stderr,"usage: %s config_file [config_params...]\n",
*argv);
exit(2);
}
/* Open configuration file */
if(!(config=fopen(argv[1],READ_TEXT))) {
fprintf(stderr,"%s: can't open configuration file \"%s\"\n",
*argv,argv[1]);
exit(1);
}
/* Parse configuration file lines */
while(fgets(line,sizeof(line),config)) {
parse: if(!parse_line(line)) continue;
if(p=token_value("dirs",NULL)) strcpy(dirsfile,p);
if(p=token_value("masterformat",NULL)) strcpy(masterformat,p);
if(p=token_value("plusformat",NULL)) strcpy(plusformat,p);
if(p=token_value("infoformat",NULL)) strcpy(infoformat,p);
if(p=token_value("info",NULL)) strcpy(info,p);
if(p=token_value("rawinfo",NULL)) strcpy(rawinfo,p);
if(p=token_value("begin",NULL)) strcpy(begin,p);
if(p=token_value("header",NULL)) strcpy(header,p);
if(p=token_value("nameheader",NULL)) strcpy(nameheader,p);
if(p=token_value("footer",NULL)) strcpy(footer,p);
if(p=token_value("end",NULL)) strcpy(ender,p);
if(token_set("rom")!=-1)
scanrom=atoi(token_value("rom","1"));
if(token_set("noinfo")!=-1)
noinfo=atoi(token_value("noinfo","1"))!=0;
if(token_set("zeros")!=-1)
zeros=atoi(token_value("zeros","1"));
if(p=token_value("list",NULL)) {
strcpy(summary[summarys].dir,token_value("dir",""));
strcpy(summary[summarys].name,token_value("name",""));
if(!(summary[summarys].file=fopen(p,WRITE_TEXT))) {
fprintf(stderr,
"%s: can't open summary file \"%s\"\n",
*argv,p);
exit(1);
}
summary[summarys].dirs=0;
summary[summarys].size=0L;
summary[summarys].files=0L;
#ifdef DEBUG
fprintf(stderr,"%s: %s files summary (%s) %s\n",*argv,
summary[summarys].name,summary[summarys].dir,
p);
#endif
summary[summarys++].doprint=1;
}
}
/* If extra arguments are given, fake a line and parse them */
if(argc>2) {
for(p=line, i=2; i<argc; i++)
p+=sprintf(p," %s",argv[i]);
argc=2;
goto parse;
}
fclose(config);
/* Then read Waffle dirs config file for file area info */
if(!(config=fopen(dirsfile,READ_TEXT))) {
fprintf(stderr,"%s: can't open Waffle dirs config file \"%s\"\n",
*argv,dirsfile);
exit(1);
}
/* Load "nonfile" match pattern */
nonfile.attribute=0;
nonfile.filesize=0L;
nonfile.shortname=nonfile.filename;
nonfile.extension=nonfile.filename;
time(&nonfile.filetime);
nonfile.file_tm=*localtime(&nonfile.filetime);
/* Print begin */
for(i=0; i<summarys; i++) {
description=summary[i].name;
strcpy(nonfile.filename,summary[i].dir);
fputs(fileinfo(begin,&nonfile),summary[i].file);
}
/* Loop through each line (directory) of Waffle dirs file */
init_match();
while(fgets(dirsline,sizeof(dirsline),config)) {
if(!parse_line(dirsline)) continue;
if(!(dir=token_value("dir",NULL))) continue;
if(token_set("name")==-1) continue;
if(scanrom<2 && (rom=(token_set("rom")!=-1))!=scanrom)
continue;
skip=atoi(token_value("skip","0"));
column=atoi(token_value("column","0"));
p=dir; if(isalpha(p[0]) && p[1]==':') p+=2;
strcpy(nonfile.filename,p);
printf("%s ",p);
for(i=0; i<summarys; i++)
if(summary[i].doprint =
!strncmp(summary[i].dir,p,strlen(summary[i].dir)))
summary[i].dirs++;
fputs2(fileinfo(*(description=token_value("name",""))?
nameheader:header,&nonfile));
if(rom || noinfo) {
if(!(fi=fopen(strchr(p=token_value("info",info),'/')?
p:(p=string("%s/%s",dir,p)),READ_TEXT))) {
noinput: fprintf(stderr,"%s: can't open input file \"%s\"\n",
*argv,p);
exit(1);
}
for(i=0; i<skip; i++)
fgets(line,sizeof(line),fi);
fo=NULL;
} else {
if(!(fi=fopen(strchr(p=token_value("rawinfo",rawinfo),'/')?
p:(p=string("%s/%s",dir,p)),READ_TEXT)))
goto noinput;
if(!(fo=fopen(strchr(p=token_value("info",info),'/')?
p:(p=string("%s/%s",dir,p)),WRITE_TEXT))) {
fprintf(stderr,"%s: can't open output file \"%s\"\n",
*argv,p);
exit(1);
}
/* It seems a bit silly, but... */
for(i=0; i<skip; i++)
fputc('\n',fo);
}
size=0L; files=0L;
while(fgets(line,sizeof(line),fi)) {
/* Trim trailing whitespace (including \n) */
for(p=line+strlen(line)-1;
p>=line && isspace(*p); *p--='\0');
/* Lines with leading '+' use plusformat */
if(*line=='+') {
description=line+1;
fputs2(fileinfo(plusformat,&nonfile));
continue;
}
/* Null or leading illegal char lines get printed */
if(!*line || NONFILENAME(*line)) {
p=line+strlen(line);
*p++='\n'; *p='\0';
fputs2(line);
continue;
}
/* Normal file description line */
/* Note: column only works if !noinfo */
for(i=strlen(description=line);
*description && !NONFILENAME(*description);
description++);
if(*description) {
*description='\0';
if(column)
description=line+min(i,column);
else
while(isspace(*++description));
}
if(!(i=formatch(p=string("%s/%s",dir,line),
READONLY|DIRECTORY,showfile))) {
putchar('\n');
fprintf(stderr,
"%s: file \"%s\" not found\n",*argv,p);
errors++;
}
}
fclose(fi);
fclose(fo);
if(size)
for(i=0; i<summarys; i++)
if(summary[i].doprint) {
nonfile.filesize=size;
fputs(fileinfo(footer,&nonfile),
summary[i].file);
summary[i].files += files;
summary[i].size += size;
}
printf("\r%-79s\r","");
}
fclose(config);
for(i=0; i<summarys; i++) {
strcpy(nonfile.filename,summary[i].dir);
nonfile.filesize=summary[i].size;
files=summary[i].files;
number=summary[i].dirs;
description=summary[i].name;
fputs(fileinfo(ender,&nonfile),summary[i].file);
fclose(summary[i].file);
}
exit(errors?1:0);
}
/*
** Create a string by the specified sprintf() rules
*/
char *string(char *format,...) {
static char buffer[BUFSIZ];
va_list arg_ptr;
va_start(arg_ptr,format);
vsprintf(buffer,format,arg_ptr);
va_end(arg_ptr);
return buffer;
}
/*
** fputs the given string to all the conditional file handles
*/
int fputs2(char *string) {
register int i;
for(i=0; i<summarys; i++)
if(summary[i].doprint)
fputs(string,summary[i].file);
}
/*
** Display revolving busy symbol to prevent terminal boredom
*/
busy_symbol() {
static unsigned char busy_phase=0;
printf("%c\b","/-\\|"[++busy_phase%4]);
}
/*
** Return character defined by given \escape sequence
*/
char escapechar(char c,struct file_match *match) {
char *p;
switch(c) {
case 'a': return '\a';
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
if(strlen(match->shortname) > c-'1')
return match->shortname[c-'1'];
return ' ';
case 'x': case 'y': case 'z':
if(strlen(match->extension) > c-'x')
return p[c-'x'];
return ' ';
}
return c;
}
/* Conversion utilites: formats and arrays */
char *nformat[4]={"%*ld","%0*ld","%-*ld","%-0*ld"};
char *sformat[2]={"%*.*s","%-*.*s"};
char *wkdays[7]={"Sunday","Monday","Tuesday",
"Wednesday","Thursday","Friday","Saturday"};
char *months[12]={"January","February","March","April","May","June",
"July","August","September","October","November","December"};
#define PRINTNUM(where,number) sprintf(where,nformat[2*justify+zerofill],\
width,number)
#define PRINTSTR(where,string) sprintf(where,sformat[justify],\
width,maxwidth,string)
char *fileinfo(char *format,struct file_match *match) {
char *p,*q,*r,buffer[BUFSIZ];
static char line[BUFSIZ];
int i,justify,zerofill,width,maxwidth;
for(q=line; *format; *format?format++:0) {
if(*format=='\\') {
*q++=escapechar(*++format,match);
continue;
} else if(*format=='%') {
justify=0; zerofill=0; width=0; maxwidth=999;
again: switch(*++format) {
case '-': /* Right justify */
justify=!justify;
goto again;
case '0': /* Zero fill */
if(!width) {
zerofill=!zerofill;
goto again;
}
case '1': case '2': case '3': /* Number */
case '4': case '5': case '6':
case '7': case '8': case '9':
width=width*10+*format-'0';
goto again;
case 'a': /* Abbreviated weekday name */
maxwidth=3;
case 'A': /* Full weekday name */
q+=PRINTSTR(q,wkdays[match->file_tm.tm_wday]);
continue;
case 'b': /* Abbreviated month name */
maxwidth=3;
case 'B': /* Full month name */
q+=PRINTSTR(q,months[match->file_tm.tm_mon]);
continue;
case 'd': /* Day of month */
q+=PRINTNUM(q,(long)match->file_tm.tm_mday);
continue;
case 'f': /* Tail filename */
q+=PRINTSTR(q,match->shortname);
continue;
case 'F': /* Full filename */
q+=PRINTSTR(q,match->filename);
continue;
case 'H': /* Hour in 24-hour clock */
q+=PRINTNUM(q,(long)match->file_tm.tm_hour);
continue;
case 'I': /* Hour in 12-hour clock */
q+=PRINTNUM(q,((i=match->file_tm.tm_hour)>12)?
(long)(i-12):(long)(i));
continue;
case 'L': /* File length either in bytes or k's */
if(match->filesize>=100000L) {
if(width) width--;
q+=PRINTNUM(q,KILOS(match->filesize));
*q++='k';
continue;
}
case 'l': /* File length in bytes */
q+=PRINTNUM(q,match->filesize);
continue;
case 'M': /* Minute */
q+=PRINTNUM(q,(long)match->file_tm.tm_min);
continue;
case 'm': /* Month */
q+=PRINTNUM(q,(long)match->file_tm.tm_mon+1);
continue;
case 'N': /* A number (from somewhere) */
q+=PRINTNUM(q,(long)number);
continue;
case 'n': /* Files */
q+=PRINTNUM(q,(long)files);
continue;
case 'P': /* Plural 's' if files>1 */
if(files>1) *q++='s';
continue;
case 'p': /* "am" or "pm" depending on hour */
*q++=(match->file_tm.tm_hour<12)?'a':'p';
*q++='m';
continue;
case 'S': /* Second */
q+=PRINTNUM(q,(long)match->file_tm.tm_sec);
continue;
case 'T': /* File description with extra info */
if(i=specialinfo(q,match->filename,match->extension)) {
q+=i;
*q++=' ';
}
case 't': /* Basic file description text */
for(p=description, r=buffer; *p; p++)
if(*p=='\\')
*r++=escapechar(*++p,match);
else
*r++=*p;
*r='\0';
q+=PRINTSTR(q,buffer);
continue;
case 'w': /* Week day number, 0=Sunday */
q+=PRINTNUM(q,match->file_tm.tm_wday);
continue;
case 'Y': /* Year with century */
q+=PRINTNUM(q,(long)match->file_tm.tm_year+1900);
continue;
case 'y': /* Year without century */
q+=PRINTNUM(q,(long)match->file_tm.tm_year);
continue;
}
}
*q++=*format;
}
while(q>line && isspace(q[-1]) && q[-1]!='\n') q--;
*q='\0';
return line;
}
/*
** The actual file information display routine
*/
int showfile(struct file_match *match) {
/* Should we give a warning ? */
if(*match->shortname == '@') return 0;
if(!(match->attribute&DIRECTORY)) {
fputs2(fileinfo(masterformat,match));
size+=match->filesize;
files++;
if(!zeros && !match->filesize)
return 0;
}
if(fo) fputs(fileinfo(infoformat,match),fo);
return 0;
}
/*
** Put special information on the given filename to given string; return
** amount of characters put (cache for repeated requests to same file)
*/
int specialinfo(char *string,char *filename,char *extension) {
static int lastlength=0;
static char lastinfo[50],lastfile[64]="";
/* Cache last request */
if(!strcmp(filename,lastfile)) {
strcpy(string,lastinfo);
return lastlength;
}
*lastinfo='\0';
if(!strcmp(extension,"bin")) /* MacBinary files format */
lastlength=macbinfo(lastinfo,filename);
else if(!strcmp(extension,"gif")) /* Compu$erve graphics format */
lastlength=gifinfo(lastinfo,filename);
else if(!strcmp(extension,"jpg")) /* JPEG/JFIF graphics format */
lastlength=jfifinfo(lastinfo,filename);
else
lastlength=0;
strcpy(lastfile,filename);
strcpy(string,lastinfo);
return lastlength;
}
/*
** Show special information on .bin (MacBinary) files: creator info
*/
#define BINSIZE 128
int macbinfo(char *string,char *filename) {
int chs=0;
FILE *f;
char binheader[BINSIZE];
busy_symbol();
if( (f=fopen(filename,READ_BINARY)) &&
(fread(&binheader,1,sizeof(binheader),f)==sizeof(binheader)) &&
(!(binheader[0] || binheader[74] || binheader[82])) ) {
*string++=binheader[65+chs++];
*string++=binheader[65+chs++];
*string++=binheader[65+chs++];
*string++=binheader[65+chs++];
}
fclose(f);
return chs;
}
/*
** Show special information on .gif files: dimensions plus bit planes
*/
int gifinfo(char *string,char *filename) {
int chs=0;
FILE *f;
char buffer[20];
struct {
char version[6];
unsigned int width,heigth;
unsigned char colors,bits,reserved;
} gif_header;
if(!(f=fopen(filename,READ_BINARY))) return 0;
busy_symbol();
if( (fread(&gif_header,1,sizeof(gif_header),f)==sizeof(gif_header)) &&
(!strncmp(gif_header.version,"GIF",3)) &&
(!(gif_header.colors & 8)) &&
(!gif_header.reserved))
chs=sprintf(string,"%ux%ux%u",
gif_header.width,gif_header.heigth,
(gif_header.colors & 7)+1);
fclose(f);
return chs;
}
/*
** Show dimensions and colors of JFIF files
**
** Shamelessly cribbed from code by Charles Hannum (mycroft@ai.mit.edu).
** "You can do whatever you want with this, but I'd appreciate it if you'd
** attribute the original code to me. B-)"
*/
int jfifinfo(char *string,char *filename) {
int chs=0;
unsigned register int i,j;
unsigned long l;
char buffer[20];
FILE *f;
if(!(f=fopen(filename,READ_BINARY))) return 0;
busy_symbol();
for ever {
if((unsigned char)fgetc(f)!=0xFF) break;
if((i=fgetc(f))==-1 || i==0xD9) break;
if(i>=0xD0 && i<0xD9) continue;
if((j=fgetc(f))==-1) break; l=j;
if((j=fgetc(f))==-1) break; l=(l<<8)+j-2;
if(i==0xC0) {
unsigned char sof[5];
if(fread(sof,1,sizeof(sof),f)!=sizeof(sof)) break;
chs=sprintf(string,"%ux%ux%u",
(sof[3]<<8) + sof[4],
(sof[1]<<8) + sof[2],
sof[0] * 3);
break;
}
fseek(f,l,SEEK_CUR);
}
fclose(f);
return chs;
}