/*--------------------------------------------------------------------*/ /* Program: gensig.c 24 July 1991 */ /* Author: Andrew H. Derbyshire */ /* Address: ahd@kew.com */ /* Function: Append a random quote to an electronic */ /* mail signature file */ /* Language: Borland C++ 2.0 (in ANSI C mode) */ /* Arguments: Name of file with fixed text input */ /* Name of file with variable quotes */ /* Name of file to be written */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* RCS Information */ /*--------------------------------------------------------------------*/ /* * $Id: GENSIG.C 1.3 1993/04/11 00:33:54 ahd Exp $ * * Revision history: * $Log: GENSIG.C $ * Revision 1.3 1993/04/11 00:33:54 ahd * Global edits for year, TEXT, etc. * * Revision 1.2 1993/03/06 23:04:54 ahd * Alter message to include output files * * Revision 1.1 1992/11/15 04:29:22 ahd * Initial revision * */ static char rcsid[] = "$Id: GENSIG.C 1.3 1993/04/11 00:33:54 ahd Exp $"; /*--------------------------------------------------------------------*/ /* Standard include files */ /*--------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /*--------------------------------------------------------------------*/ /* UUPC/extended include files */ /*--------------------------------------------------------------------*/ #include "lib.h" #include "timestmp.h" /*--------------------------------------------------------------------*/ /* Local macros */ /*--------------------------------------------------------------------*/ #define bitsper(s) (8 * (sizeof s)) #define bitflag(x, s) (1 << ((bitsper(s) - 1) - x)) #define biton( s, offset ) \ (( s[ (size_t) (offset / bitsper(*s)) ] ) & \ bitflag(offset % bitsper( *s ), *s)) #define bitoff( s, offset) (!biton(s, offset)) /*--------------------------------------------------------------------*/ /* Internal function prototypes */ /*--------------------------------------------------------------------*/ static void usage( void ); static long chooseit( struct stat *current_status, const char *lookaside, const char *quoteused, const char *fname , const char *target); static long getquote( const char *data, const char *target); static void CopyQuote( const char *fname, long where, FILE *stream); static void CopyFixed( const char *fname, FILE *stream ); static long chooseavailable( const char *quoteused, long quotes ); currentfile(); /*--------------------------------------------------------------------*/ /* m a i n */ /* */ /* main program */ /*--------------------------------------------------------------------*/ void main( int argc, char **argv) { long where; FILE *stream; banner( argv ); /*--------------------------------------------------------------------*/ /* Validate the number of arguments */ /*--------------------------------------------------------------------*/ if ( argc != 4 ) usage(); /*--------------------------------------------------------------------*/ /* Determine the number of the quotes available, and then */ /* select one */ /*--------------------------------------------------------------------*/ where = getquote( argv[2], argv[3] ); /*--------------------------------------------------------------------*/ /* Open up our output file */ /*--------------------------------------------------------------------*/ stream = fopen( argv[3] , "w"); if ( stream == NULL ) { perror( argv[3] ); exit(1); } /*--------------------------------------------------------------------*/ /* Copy the fixed and variable parts of the file */ /*--------------------------------------------------------------------*/ CopyFixed( argv[1], stream ); CopyQuote( argv[2], where, stream ); /*--------------------------------------------------------------------*/ /* Close up and return to caller */ /*--------------------------------------------------------------------*/ fclose( stream ); exit( 0 ); } /* main */ /*--------------------------------------------------------------------*/ /* u s a g e */ /* */ /* Report program usage and then exit */ /*--------------------------------------------------------------------*/ static void usage( void ) { printf("Usage:\tgensig\taddr-file quote-file output-file\n"); printf("\taddr-file\tFixed portion of signature file\n"); printf("\tquote-file\tFile of quotes, separated by delimiter lines\n"); printf("\toutput-file\tOutput file with fixed portion and single quote\n"); exit( 2 ); } /* usage */ /*--------------------------------------------------------------------*/ /* g e t q u o t e */ /* */ /* Select a quote to process */ /*--------------------------------------------------------------------*/ static long getquote( const char *data, const char *target) { struct stat current_status; long where; char lookaside[FILENAME_MAX]; char quoteused[FILENAME_MAX]; char drive[FILENAME_MAX], dir[FILENAME_MAX], file[FILENAME_MAX], ext[FILENAME_MAX]; /*--------------------------------------------------------------------*/ /* Get size and data information on the quotes data file */ /*--------------------------------------------------------------------*/ if(stat((char *) data, ¤t_status ) <0) { perror( data ); /* If no data file, panic gracefully */ exit( 3 ); } /* if */ /*--------------------------------------------------------------------*/ /* Build the lookaside file name from the data file name */ /*--------------------------------------------------------------------*/ #ifdef __TURBOC__ fnsplit( data, drive, dir, file, ext); fnmerge( lookaside, drive, dir, file, ".las"); fnmerge( quoteused, drive, dir, file, ".qus"); #else _splitpath( data, drive, dir, file, ext); _makepath( lookaside, drive, dir, file, ".las"); _makepath( quoteused, drive, dir, file, ".qus"); #endif /* __TURBOC__ */ /*--------------------------------------------------------------------*/ /* Now get the location of the quote; if it fails the first */ /* time, then the lookaside buffer is updated and we can try */ /* again */ /*--------------------------------------------------------------------*/ where = chooseit( ¤t_status, lookaside, quoteused, data , target); if (where == -1 ) { where = chooseit( ¤t_status, lookaside, quoteused, data, target ); if ( where == - 1) { printf("Unable to create lookaside file \"%s\"!\n", lookaside ); exit( 4 ); } /* if ( where == - 1) */ } /* if ( where == - 1) */ /*--------------------------------------------------------------------*/ /* Return to caller */ /*--------------------------------------------------------------------*/ return where; } /* getquote */ /*--------------------------------------------------------------------*/ /* c h o o s e i t */ /* */ /* Returns number of quotes in file */ /*--------------------------------------------------------------------*/ static long chooseit( struct stat *current_status, const char *lookaside, const char *quoteused, const char *fname, const char *target) { FILE *stream; FILE *data; long where; long quotes = 0; long quote; char buf[BUFSIZ]; char delimiter[BUFSIZ]; /*--------------------------------------------------------------------*/ /* Open up the lookaside file and determine if it is up to */ /* date. If so, choose an entry and return it. */ /*--------------------------------------------------------------------*/ stream = fopen( lookaside , "rb" ); if ( stream != NULL ) { struct stat status; fread( &status, sizeof status, 1, stream); if ((status.st_size == current_status->st_size) && (status.st_mtime == current_status->st_mtime)) { /* Lookaside file up to date, use it */ if( stat((char *) lookaside, &status ) < 0) { perror( lookaside ); exit( 5 ); } /* if */ quotes = (status.st_size - sizeof status) / sizeof where; /* Determine number of quote pointers in lookaside file from the file's length */ quote = chooseavailable( quoteused, quotes); fseek( stream, quote * sizeof where , SEEK_CUR ); /* Step required number of quotes into the file */ fread( &where, sizeof where, 1, stream); /* Read offset in data file of quote */ printf("Chose quote %ld of %ld from %s for %s:\n\n", quote + 1 , quotes, fname, target); /* Announce number of quote of the day */ fclose( stream ); /* Done with lookaside file, of course */ return where; /* Return position in file to caller */ } /* if */ else fclose( stream ); } /* if ( stream != NULL ) */ else perror( lookaside ); /*--------------------------------------------------------------------*/ /* We have to rewrite the lookaside file */ /*--------------------------------------------------------------------*/ unlink( quoteused ); /* Make all quotes available */ data = fopen( fname, "rt"); /* Open data file to scan */ if ( data == NULL ) /* Did it open? */ { perror( fname ); /* No --> Error */ exit( 6 ); } stream = fopen( lookaside , "wb" ); /* Open lookaside file */ if ( stream == NULL ) /* Did it open? */ { perror( lookaside ); /* No --> Error */ exit( 7 ); } /*--------------------------------------------------------------------*/ /* Start the new lookaside file with the status of the data */ /* file for later comparisons */ /*--------------------------------------------------------------------*/ fwrite( current_status, sizeof *current_status, 1, stream); /*--------------------------------------------------------------------*/ /* Get the first line of the file, which will contain the */ /* delimiter line */ /*--------------------------------------------------------------------*/ fgets(delimiter, BUFSIZ, data ); where = ftell( data ); /* Get location of possible first quote */ /*--------------------------------------------------------------------*/ /* Now process the rest of the file */ /*--------------------------------------------------------------------*/ while( fgets(buf, BUFSIZ, data ) != NULL ) { if ( strcmp( buf, delimiter )) /* Delimiter line? */ { /* No --> data line */ if ( where != -1L ) /* First line of new quote? */ { /* Yes --> Write location to lookaside */ quotes ++ ; fwrite( &where, sizeof where, 1, stream); where = -1L; } /* if */ } /* if */ else where = ftell( data ); /* Delimiter line, remember location of NEXT line in file */ } /* while */ /*--------------------------------------------------------------------*/ /* Close up shop and return to caller */ /*--------------------------------------------------------------------*/ fclose( stream ); fclose( data ); if ( quotes == 1 ) { printf("Invalid data file; first line not a delimiter line!"); exit( 99 ); } printf("Updated lookaside file %s with %d quotes.\n", lookaside , quotes); return -1; /* Inform caller that lookaside file was updated */ } /* chooseit */ /*--------------------------------------------------------------------*/ /* c h o o s e a v a i l a b l e */ /* */ /* Select a quote from available list */ /*--------------------------------------------------------------------*/ static long chooseavailable( const char *quoteused, long quotes ) { FILE *stream; unsigned char *quotelist; size_t listsize = (size_t) (( quotes + bitsper(*quotelist) - 1 ) / bitsper(*quotelist)); long quote; long available = quotes; long select; /*--------------------------------------------------------------------*/ /* Initialize the bit array of quotes */ /*--------------------------------------------------------------------*/ quotelist = malloc( listsize ); checkref( quotelist ); /*--------------------------------------------------------------------*/ /* Open up the used quoted file, if possible */ /*--------------------------------------------------------------------*/ stream = fopen( quoteused, "rb"); /*--------------------------------------------------------------------*/ /* Determine the number of available quotes */ /*--------------------------------------------------------------------*/ if ( stream != NULL ) { if (fread (&available, sizeof available, 1 , stream) < 1 ) { perror( quoteused ); available = 0; } else if ( quotes <= available ) available = 0; else if (fread (quotelist, sizeof *quotelist, listsize , stream) < listsize) { available = 0; perror( quoteused ); } fclose( stream ); } /* if */ else available = 0; if ( available <= ( quotes / 10 )) { memset( quotelist, '\0', listsize ); printf("Resetting available quotes list\n"); available = quotes; } /*--------------------------------------------------------------------*/ /* Now, choose the quote */ /*--------------------------------------------------------------------*/ srand ( time( NULL )); /* Initialize the generator */ select = rand() % available ; /* ... Lucky seven? */ /*--------------------------------------------------------------------*/ /* end debugging info */ /*--------------------------------------------------------------------*/ quote = 0; while( quote < quotes ) { if ( bitoff( quotelist, quote )) select--; if ( select > 0 ) quote++; else break; } if ( quote == quotes ) /* Did we overflow the array? */ panic(); /* Must have a bug! */ /*--------------------------------------------------------------------*/ /* Now update our data and write it out */ /*--------------------------------------------------------------------*/ stream = fopen( quoteused, "wb"); if ( stream == NULL ) { perror( quoteused ); panic(); } quotelist[ (size_t) (quote / bitsper(*quotelist)) ] |= bitflag( quote % bitsper(*quotelist), *quotelist ); available -= 1; fwrite(&available, sizeof available, 1 , stream); fwrite(quotelist, sizeof *quotelist, listsize , stream); fclose( stream ); /*--------------------------------------------------------------------*/ /* Return the quote to the caller */ /*--------------------------------------------------------------------*/ return quote; } /* chooseavailable */ /*--------------------------------------------------------------------*/ /* C o p y F i x e d */ /* */ /* Copy fixed input text (user name and address) to output file */ /*--------------------------------------------------------------------*/ static void CopyFixed( const char *fname, FILE *stream ) { FILE *input; char buf[BUFSIZ]; /*--------------------------------------------------------------------*/ /* Open input file for copying */ /*--------------------------------------------------------------------*/ input = fopen( fname, "r"); if ( input == NULL ) { perror( fname ); exit ( 8 ); } /*--------------------------------------------------------------------*/ /* Copy the fixed input to the signature file */ /*--------------------------------------------------------------------*/ while( fgets( buf, BUFSIZ, input ) != NULL) fputs( buf, stream ); /*--------------------------------------------------------------------*/ /* Close up shop and return to caller */ /*--------------------------------------------------------------------*/ fclose( input ); } /* CopyFixed */ /*--------------------------------------------------------------------*/ /* C o p y Q u o t e */ /* */ /* Write a quote to the output file */ /*--------------------------------------------------------------------*/ static void CopyQuote( const char *fname, long where, FILE *stream) { FILE *input; char buf[BUFSIZ]; char delimiter[BUFSIZ]; /*--------------------------------------------------------------------*/ /* Open up the quotes file and get the delimiter line */ /*--------------------------------------------------------------------*/ input = fopen( fname, "r"); if ( input == NULL ) { perror( fname ); exit ( 9 ); } fgets(delimiter, BUFSIZ, input ); /*--------------------------------------------------------------------*/ /* Position to the beginning of the actual quote to be processed */ /*--------------------------------------------------------------------*/ fseek( input, where , SEEK_SET ); /*--------------------------------------------------------------------*/ /* Copy the quote to both the signature file and the screen */ /*--------------------------------------------------------------------*/ while( fgets( buf, BUFSIZ, input ) != NULL) { if (!strcmp( delimiter, buf )) /* Delimiter line? */ break; /* Yes --> End of quote */ fputs( buf, stream ); /* Copy quote to signature file */ fputs( buf, stdout ); /* Copy quote to screen */ } /* while( fgets( buf, BUFSIZ, input ) != NULL) */ /*--------------------------------------------------------------------*/ /* Close up shop and return to caller */ /*--------------------------------------------------------------------*/ fclose( input ); } /* CopyQuote */