/* * coobld - The incredible fortune cookie system database builder */ /* Version T1.00 - 20-Nov-86 - tmk - Initial portable version */ /* Version T1.01 - 05-Jun-87 - tmk - Modify for new header structure, add password, fix -d option which broke on swappped pointer machines like MSDOS, add -o option to specify ouput file name */ /* Version T1.02 - 24-Jun-87 - tmk - Modify for new file structure, get rid of password scheme */ /* Version T1.03 - 30-Jun-87 - tmk - Add help info */ /* Version T1.04 - 02-Jul-87 - tmk - Add support for Turbo C */ /* Version T1.05 - 27-Nov-87 - tmk - Add function prototypes, fix arg type problem with get() and put() */ #define VERSION "T1.05 27-Nov-87 - tmk" /* * Define module ID for VMS (must go for Turbo C, else bogus error) */ #ifdef vms #module coobld VERSION #endif /* vms */ /* * Convince Turbo C it's running under MS-DOS (it isn't sure) */ #ifdef __TURBOC__ #define MSDOS 1 #endif /* __TURBOC__ */ /* * Grab some header files */ #include #include #include #ifndef decus #include #include #endif /* decus */ #ifdef MSDOS #ifndef __TURBOC__ #include #else #include #endif /* __TURBOC__ */ #endif /* MSDOS */ /* * Have a fight about function declarations, names, and file modes */ #ifdef MSDOS #define w_mode "wb" #define r_mode "rb" #endif /* MSDOS */ #ifdef decus #define w_mode "wn" #define r_mode "rn" #define unlink delete #define void #endif /* decus */ #ifdef vms #define w_mode "wb" #define r_mode "rb" #define unlink delete #endif /* vms */ /* * Define some constants */ #define TRUE 1 #define FALSE 0 #define EOS 0 #define SIGNAL '%' #ifdef vms #define exstat 65535 #else #define exstat 0 #endif /* vms */ /* * Global variables */ FILE *indexfp; /* Indices stored here */ FILE *dummyfp; /* Dummy output file */ FILE *outfp; /* Output file (cookie.fil) */ char *dummy_file = "cdummy.tmp"; char *index_file = "cindex.tmp"; char *cookie_file = "cookie.fil"; char *input_file = "cookie.txt"; struct header { #ifdef vms short coover; /* Version of CAM structure */ short spare; /* Spare value (was password) */ long ncookie; /* Number of cookies */ short bcookie; /* Size of largest cookie */ short nindex; /* Dimension of index[] */ short subindex; /* Number of subindex entries */ short sindex; /* Sizeof index for alloc */ #else int coover; /* Version of CAM structure */ int spare; /* Spare value (was password) */ long ncookie; /* Number of cookies */ int bcookie; /* Size of largest cookie */ int nindex; /* Dimension of index[] */ int subindex; /* Number of subindex entries */ int sindex; /* Sizeof index for alloc */ #endif /* vms */ char date[28]; /* Date cookie file built */ } header; char text[513]; /* Working text */ long *sub_index; /* Indices stored here */ long *top_index; /* Top level indices go here */ long firstindex; /* -> top index in indexfp */ long firstcookie; /* -> first cookie in dummyfp */ int debug = 0; /* Debug initally off */ int width = 6; /* Debug width initially 80 */ /* * For 'modern' compilers (all but decus), supply function prototypes */ #ifndef decus extern int main(int, char **); extern void cdelete(FILE *, char *); extern FILE * file_open(char *, char *); extern void maketext(char *); extern void makedummy(char *); extern void makecookie(void); extern void get(long *, int, FILE *, char *); extern void put(long *, int, FILE *, char *); extern void hswap(void); extern void swaplb(long *); extern long swapl(long); extern void dump(long *, char *, int); #else extern long ftell(); /* decus doesn't define??? */ #endif /* decus */ /* * Actual code starts here */ int main(argc, argv) int argc; char *argv[]; { register char *ap; FILE *file_open(); while (argc > 1) { ap = argv[1]; if (*ap != '-') { fprintf(stderr, "?Unknown command \"%s\"\n", ap); fprintf(stderr, " do COOBLD -? for help.\n\n\n"); } else for (ap++; *ap; ap++) { switch (tolower(*ap)) { case 'd': /* Set debug option */ debug++; break; case 'f': /* Use different input file */ if (isgraph(ap[1]) != 0) input_file = &ap[1]; else if (argc > 2) { input_file = argv[2]; argv++; argc--; } else { break; } goto next_arg; case 'o': /* Use different output file */ if (isgraph(ap[1]) != 0) cookie_file = &ap[1]; else if (argc > 2) { cookie_file = argv[2]; argv++; argc--; } else { break; } goto next_arg; case 'w': width = 10; /* Set debug width to 132 */ break; case '?': /* Display help message */ printf("COOBLD %s",VERSION); printf("\n\nUsage is: COOBLD option option...\n"); printf("Options: -d Enable debugging output\n"); printf(" -f fn Read input from file FN\n"); printf(" -o fn Write output to file FN\n"); printf(" -w 132-column debug output\n"); printf(" -? Print this message\n"); exit(exstat); break; default: fprintf(stderr, "?Unknown option '%c'\n", *ap); fprintf(stderr, " do COOBLD -? for help.\n\n\n"); } } next_arg: argc--; argv++; } /* * Copy raw cookies to a temp file. Collect how many and * dimension of indexes. */ maketext(input_file); /* * Build dummy cookie file */ dummyfp = file_open(dummy_file, w_mode); indexfp = file_open(index_file, w_mode); makedummy(input_file); fclose(dummyfp); fclose(indexfp); /* * Build real cookie file */ outfp = file_open(cookie_file, w_mode); dummyfp = file_open(dummy_file, r_mode); indexfp = file_open(index_file, r_mode); makecookie(); fclose(outfp); cdelete(dummyfp, dummy_file); cdelete(indexfp, index_file); printf("Done, %ld cookies in output file %s\n", header.ncookie, cookie_file); } void cdelete(fd, fn) FILE *fd; char *fn; /* * Close or delete the file */ { if (debug) fclose(fd); else { fclose(fd); unlink(fn); } } FILE * file_open(filename, mode) char *filename; char *mode; /* * Open the file, die if failure */ { register FILE *fd; if ((fd = fopen(filename, mode)) == NULL) { perror(filename); exit(exstat); } return (fd); } void maketext(infn) char *infn; /* Input file name */ /* * Read files obtaining the counts. * * Header is set as follows: * * header.coover CAM revision level (1.02) * header.spare Spare value * header.ncookie Number of cookies (long) * header.bcookie Size of largest cookie * header.nindex Index dimension * header.subindex Number of subindex entries * header.sindex Sizeof index[] * header.date ctime() */ { register int len; long subsquare; char *strcpy(); long tvec; FILE *infd; long nrecords; header.bcookie = 0; time(&tvec); strcpy(header.date, ctime(&tvec)); header.coover = 102; header.ncookie = 0; header.nindex = 0; subsquare = 0; len = 0; /* * Read all cookies to count them and get the max. length. */ if ((infd = fopen(infn, "r")) == NULL) { perror(infn); exit(exstat); } { #ifdef MSDOS printf("%s:", infn); /* Print filename and info */ #else fgetname(infd, text); printf("%s:", text); /* Print filename and info */ #endif /* MSDOS */ nrecords = 0; while (!feof(infd)) { fgets(text, sizeof(text), infd); nrecords++; if (feof(infd) || (text[0] == SIGNAL && text[1] == SIGNAL)) { if (len == 0) continue; if (len > header.bcookie) header.bcookie = len; len = 0; header.ncookie++; if (subsquare < header.ncookie) { header.nindex++; subsquare = header.nindex * header.nindex; } } else { len += strlen(text) + 2; } } printf(" %ld lines\n", nrecords); } header.subindex = (header.ncookie + header.nindex - 1) / header.nindex; header.sindex = header.nindex * sizeof(long); printf("%ld cookies read, the longest has %d bytes\n", header.ncookie, header.bcookie); printf("top index = %d, sub index = %d, index area size = %d\n", header.nindex, header.subindex, header.sindex); } void makedummy(infn) char *infn; /* * Build a dummy cookie file in two separate files: * dummyfp Gets the cookie data * indexfp Gets the indices. * * This way, we don't have to reposition the file, nor do we * have to read and write the same file. */ { register int subi; /* Index into sub_index[] */ register int topi; /* Index into top_index[] */ register int len; /* Input record length */ FILE *infd; long count; long dummy_loc; count = 0; top_index = (long *)calloc(header.sindex, 1); sub_index = (long *)calloc(header.sindex, 1); if (top_index == NULL || sub_index == NULL) fprintf(stderr, "Can't allocate index buffers -- %d bytes\n", header.sindex); put((long *)"555-2368", 9, dummyfp, "dummy magic number"); put((long *)"555-2368", 9, indexfp, "index magic number"); put((long *)&header, sizeof(header), dummyfp, "dummy header"); put((long *)&header, sizeof(header), indexfp, "index header"); put(sub_index, header.sindex, dummyfp, "dummy top index"); put(sub_index, header.sindex, indexfp, "index top index"); firstindex = ftell(indexfp); for (subi = header.subindex; --subi >= 0;) { put(sub_index, header.sindex, dummyfp, "dummy sub index"); } dummy_loc = firstcookie = ftell(dummyfp); subi = 0; topi = 0; len = 0; if ((infd = fopen(infn, "r")) == NULL) { perror(infn); exit(exstat); } { while (!feof(infd)) { if (fgets(text, sizeof(text), infd) == NULL || (text[0] == '%' && text[1] == '%')) { if (len == 0) continue; len = 0; count++; if (subi >= header.nindex) { if (topi >= header.nindex) { fprintf(stderr, "Too many cookies, max is %d ** 2\n", header.nindex); } top_index[topi] = ftell(indexfp); topi++; put(sub_index, header.sindex, indexfp, "sub index"); subi = 0; } sub_index[subi] = dummy_loc; subi++; fputs("%%\n", dummyfp); dummy_loc = ftell(dummyfp); } else { fputs(text, dummyfp); len += strlen(text); } if (ferror(dummyfp)) { perror("writing text to temp file"); } } } /* * Put the last subindex record */ while (subi < header.nindex) { sub_index[subi] = -1; subi++; } top_index[topi] = ftell(indexfp); topi++; put(sub_index, header.sindex, indexfp, "last sub index"); while (topi < header.nindex) { top_index[topi] = -1; topi++; } printf("Work files built, %ld cookies, %d index levels\n", count, header.nindex); if (count != header.ncookie) fprintf(stderr, "Expected %ld cookies, read %ld\n", header.ncookie, count); } void makecookie() /* * Write outfp with cookie file, using * * indexfp Index file (has sub-indexes) * dummyfp Cookie work file * */ { register int i; put((long *)"555-2368", 9, outfp, "cookie magic number"); #ifndef decus hswap(); /* Swap to PDP-11 format */ #endif /* decus */ put((long *)&header, sizeof(header), outfp, "cookie header"); #ifndef decus hswap(); /* And back to system format */ swaplb(top_index); /* Swap to PDP-11 format */ #endif /* decus */ put(top_index, header.sindex, outfp, "cookie top index"); #ifndef decus swaplb(top_index); /* And back to system format */ #endif /* decus */ if (debug) dump(top_index, "cookie top index", -1); if (fseek(indexfp, firstindex, 0) != 0) fprintf(stderr, "Can't seek to %ld on index file\n", firstindex); if (fseek(dummyfp, firstcookie, 0) != 0) fprintf(stderr, "Can't seek to %ld on cookie file\n", firstcookie); for (i = 0; i < header.subindex; i++) { get(sub_index, header.sindex, indexfp, "sub index"); #ifndef decus swaplb(sub_index); /* Swap to PDP-11 format */ #endif /* decus */ put(sub_index, header.sindex, outfp, "cookie sub index"); #ifndef decus swaplb(sub_index); /* And back to system format */ #endif /* decus */ if (debug) dump(sub_index, "cookie sub index", i); } printf("%d index records written\n", header.nindex + 1); while (fgets(text, sizeof(text), dummyfp) != NULL) { fputs(text, outfp); } if (ferror(outfp)) { perror("writing output"); } } /* * Raw I/O routines */ void get(whereto, size, fd, why) long *whereto; /* Where to read to */ int size; /* Buffer size */ FILE *fd; /* Input file descriptor */ char *why; /* Who is reading for error */ /* * Read into the buffer. Return the number of bytes read. * All errors are fatal. */ { register int i; if ((i = fread(whereto, size, 1, fd)) != 1 || ferror(fd)) { perror("coobld fread error"); fprintf(stderr, "Reading %s, expected 1 item, %d bytes, read %d items\n", why, size, i); } } void put(wherefrom, size, fd, why) long *wherefrom; /* Where to write from */ int size; /* Number of bytes to write */ FILE *fd; /* Output file descriptor */ char *why; /* Who is writeing for error */ /* * Write from the buffer. All errors are fatal. */ { register int i; if ((i = fwrite(wherefrom, size, 1, fd)) != 1 || ferror(fd)) { perror("coobld fwrite error"); fprintf(stderr, "Error writing 1 item of %d bytes to %s, %d items\n", size, why, i); } } #ifndef decus void hswap() /* * Swap the header.xxx components to/from PDP-11 format */ { header.ncookie = swapl(header.ncookie); } void swaplb(indextable) long indextable[]; /* * Swap an index table to/from PDP-11 format */ { register int i; for (i=0; i < header.nindex; i++) indextable[i] = swapl(indextable[i]); } long swapl(l) /* With thanks to Dennis Bednar */ long l; { register char *sp, *dp; long r; sp = (char *) &l; dp = (char *) &r; *dp++ = sp[2]; /* PDP-11 stores bytes 2,3,0,1 */ *dp++ = sp[3]; *dp++ = sp[0]; *dp = sp[1]; return (r); } #endif /* decus */ /* * For debugging only */ void dump(indextable, why, which) long indextable[]; char *why; int which; { register int i, j; printf("\n%s", why); if (which != -1) printf(" number %d", which); printf(":\n"); for (i = 0; i < header.nindex; i = i+width) { for (j = 0; j < width; j=j+1) { if (i+j >= header.nindex) break; printf("%3d %7ld", i+j, indextable[i+j]); if (i+j == header.nindex-1) break; if (j == width-1) break; printf(", "); } printf("\n"); } }