home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Games / fortune / Source / strfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-13  |  9.5 KB  |  443 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Ken Arnold.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley.  The name of the
  14.  * University may not be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. char copyright[] =
  23. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  24.  All rights reserved.\n";
  25. #endif /* not lint */
  26.  
  27. #ifndef lint
  28. static char sccsid[] = "@(#)strfile.c    5.11 (Berkeley) 12/15/89";
  29. #endif /* not lint */
  30.  
  31. #ifndef NeXT
  32. # include    <machine/endian.h>
  33. #endif
  34. # include    <sys/param.h>
  35. # include    <stdio.h>
  36. # include    <ctype.h>
  37. # include    "strfile.h"
  38.  
  39. # ifndef MAXPATHLEN
  40. # define    MAXPATHLEN    1024
  41. # endif    /* MAXPATHLEN */
  42.  
  43. /*
  44.  *    This program takes a file composed of strings seperated by
  45.  * lines starting with two consecutive delimiting character (default
  46.  * character is '%') and creates another file which consists of a table
  47.  * describing the file (structure from "strfile.h"), a table of seek
  48.  * pointers to the start of the strings, and the strings, each terminated
  49.  * by a null byte.  Usage:
  50.  *
  51.  *    % strfile [-iorsx] [ -cC ] sourcefile [ datafile ]
  52.  *
  53.  *    c - Change delimiting character from '%' to 'C'
  54.  *    s - Silent.  Give no summary of data processed at the end of
  55.  *        the run.
  56.  *    o - order the strings in alphabetic order
  57.  *    i - if ordering, ignore case 
  58.  *    r - randomize the order of the strings
  59.  *    x - set rotated bit
  60.  *
  61.  *        Ken Arnold    Sept. 7, 1978 --
  62.  *
  63.  *    Added ordering options.
  64.  */
  65.  
  66. # define    TRUE    1
  67. # define    FALSE    0
  68.  
  69. # define    STORING_PTRS    (Oflag || Rflag)
  70. # define    CHUNKSIZE    512
  71.  
  72. #ifdef lint
  73. # define    ALWAYS    atoi("1")
  74. #else
  75. # define    ALWAYS    1
  76. #endif
  77. # define    ALLOC(ptr,sz)    if (ALWAYS) { \
  78.             if (ptr == NULL) \
  79.                 ptr = malloc((unsigned int) (CHUNKSIZE * sizeof *ptr)); \
  80.             else if (((sz) + 1) % CHUNKSIZE == 0) \
  81.                 ptr = realloc((void *) ptr, ((unsigned int) ((sz) + CHUNKSIZE) * sizeof *ptr)); \
  82.             if (ptr == NULL) { \
  83.                 fprintf(stderr, "out of space\n"); \
  84.                 exit(1); \
  85.             } \
  86.         } else
  87.  
  88. #ifdef NO_VOID
  89. # define    void    char
  90. #endif
  91.  
  92. typedef struct {
  93.     char    first;
  94.     off_t    pos;
  95. } STR;
  96.  
  97. char    *Infile        = NULL,        /* input file name */
  98.     Outfile[MAXPATHLEN] = "",    /* output file name */
  99.     Delimch        = '%';        /* delimiting character */
  100.  
  101. int    Sflag        = FALSE;    /* silent run flag */
  102. int    Oflag        = FALSE;    /* ordering flag */
  103. int    Iflag        = FALSE;    /* ignore case flag */
  104. int    Rflag        = FALSE;    /* randomize order flag */
  105. int    Xflag        = FALSE;    /* set rotated bit */
  106. long    Num_pts        = 0;        /* number of pointers/strings */
  107.  
  108. off_t    *Seekpts;
  109.  
  110. FILE    *Sort_1, *Sort_2;        /* pointers for sorting */
  111.  
  112. STRFILE    Tbl;                /* statistics table */
  113.  
  114. STR    *Firstch;            /* first chars of each string */
  115.  
  116. char    *fgets(), *strcpy(), *strcat();
  117.  
  118. void    *malloc(), *realloc();
  119.  
  120. /*
  121.  * main:
  122.  *    Drive the sucker.  There are two main modes -- either we store
  123.  *    the seek pointers, if the table is to be sorted or randomized,
  124.  *    or we write the pointer directly to the file, if we are to stay
  125.  *    in file order.  If the former, we allocate and re-allocate in
  126.  *    CHUNKSIZE blocks; if the latter, we just write each pointer,
  127.  *    and then seek back to the beginning to write in the table.
  128.  */
  129. main(ac, av)
  130. int    ac;
  131. char    **av;
  132. {
  133.     register char        *sp, dc;
  134.     register FILE        *inf, *outf;
  135.     register off_t        last_off, length, pos, *p;
  136.     register int        first, cnt;
  137.     register char        *nsp;
  138.     register STR        *fp;
  139.     static char        string[257];
  140.  
  141.     getargs(ac, av);        /* evalute arguments */
  142.     dc = Delimch;
  143.     if ((inf = fopen(Infile, "r")) == NULL) {
  144.         perror(Infile);
  145.         exit(1);
  146.     }
  147.  
  148.     if ((outf = fopen(Outfile, "w")) == NULL) {
  149.         perror(Outfile);
  150.         exit(1);
  151.     }
  152.     if (!STORING_PTRS)
  153.         (void) fseek(outf, sizeof Tbl, 0);
  154.  
  155.     /*
  156.      * Write the strings onto the file
  157.      */
  158.  
  159.     Tbl.str_longlen = 0;
  160.     Tbl.str_shortlen = (unsigned int) 0xffffffff;
  161.     Tbl.str_delim = dc;
  162.     Tbl.str_version = VERSION;
  163.     first = Oflag;
  164.     add_offset(outf, ftell(inf));
  165.     last_off = 0;
  166.     do {
  167.         sp = fgets(string, 256, inf);
  168.         if (sp == NULL || sp[0] == dc && sp[1] == '\n') {
  169.             pos = ftell(inf);
  170.             length = pos - last_off - (sp ? strlen(sp) : 0);
  171.             last_off = pos;
  172.             if (!length)
  173.                 continue;
  174.             add_offset(outf, pos);
  175.             if (Tbl.str_longlen < length)
  176.                 Tbl.str_longlen = length;
  177.             if (Tbl.str_shortlen > length)
  178.                 Tbl.str_shortlen = length;
  179.             first = Oflag;
  180.         }
  181.         else if (first) {
  182.             for (nsp = sp; !isalnum(*nsp); nsp++)
  183.                 continue;
  184.             ALLOC(Firstch, Num_pts);
  185.             fp = &Firstch[Num_pts - 1];
  186.             if (Iflag && isupper(*nsp))
  187.                 fp->first = tolower(*nsp);
  188.             else
  189.                 fp->first = *nsp;
  190.             fp->pos = Seekpts[Num_pts - 1];
  191.             first = FALSE;
  192.         }
  193.     } while (sp != NULL);
  194.  
  195.     /*
  196.      * write the tables in
  197.      */
  198.  
  199.     (void) fclose(inf);
  200.  
  201.     if (Oflag)
  202.         do_order();
  203.     else if (Rflag)
  204.         randomize();
  205.  
  206.     if (Xflag)
  207.         Tbl.str_flags |= STR_ROTATED;
  208.  
  209.     if (!Sflag) {
  210.         printf("\"%s\" created\n", Outfile);
  211.         if (Num_pts == 2)
  212.             puts("There was 1 string");
  213.         else
  214.             printf("There were %d strings\n", Num_pts - 1);
  215.         printf("Longest string: %lu byte%s\n", Tbl.str_longlen,
  216.                Tbl.str_longlen == 1 ? "" : "s");
  217.         printf("Shortest string: %lu byte%s\n", Tbl.str_shortlen,
  218.                Tbl.str_shortlen == 1 ? "" : "s");
  219.     }
  220.  
  221.     (void) fseek(outf, (off_t) 0, 0);
  222.     Tbl.str_version = htonl(Tbl.str_version);
  223.     Tbl.str_numstr = htonl(Num_pts - 1);
  224.     Tbl.str_longlen = htonl(Tbl.str_longlen);
  225.     Tbl.str_shortlen = htonl(Tbl.str_shortlen);
  226.     Tbl.str_flags = htonl(Tbl.str_flags);
  227.     (void) fwrite((char *) &Tbl, sizeof Tbl, 1, outf);
  228.     if (STORING_PTRS) {
  229.         for (p = Seekpts, cnt = Num_pts; cnt--; ++p)
  230.             *p = htonl(*p);
  231.         (void) fwrite((char *) Seekpts, sizeof *Seekpts, (int) Num_pts, outf);
  232.     }
  233.     (void) fclose(outf);
  234.     exit(0);
  235. }
  236.  
  237. /*
  238.  *    This routine evaluates arguments from the command line
  239.  */
  240. getargs(argc, argv)
  241. int    argc;
  242. char    **argv;
  243. {
  244.     extern char    *optarg;
  245.     extern int    optind;
  246.     int    ch;
  247.  
  248.     while ((ch = getopt(argc, argv, "c:iorsx")) != EOF)
  249.         switch(ch) {
  250.         case 'c':            /* new delimiting char */
  251.             Delimch = *optarg;
  252.             if (!isascii(Delimch)) {
  253.                 printf("bad delimiting character: '\\%o\n'",
  254.                        Delimch);
  255.             }
  256.             break;
  257.         case 'i':            /* ignore case in ordering */
  258.             Iflag++;
  259.             break;
  260.         case 'o':            /* order strings */
  261.             Oflag++;
  262.             break;
  263.         case 'r':            /* randomize pointers */
  264.             Rflag++;
  265.             break;
  266.         case 's':            /* silent */
  267.             Sflag++;
  268.             break;
  269.         case 'x':            /* set the rotated bit */
  270.             Xflag++;
  271.             break;
  272.         case '?':
  273.         default:
  274.             usage();
  275.         }
  276.     argv += optind;
  277.  
  278.     if (*argv) {
  279.         Infile = *argv;
  280.         if (*++argv)
  281.             (void) strcpy(Outfile, *argv);
  282.     }
  283.     if (!Infile) {
  284.         puts("No input file name");
  285.         usage();
  286.     }
  287.     if (*Outfile == '\0') {
  288.         (void) strcpy(Outfile, Infile);
  289.         (void) strcat(Outfile, ".dat");
  290.     }
  291. }
  292.  
  293. usage()
  294. {
  295.     (void) fprintf(stderr,
  296.         "strfile [-iorsx] [-c char] sourcefile [datafile]\n");
  297.     exit(1);
  298. }
  299.  
  300. /*
  301.  * add_offset:
  302.  *    Add an offset to the list, or write it out, as appropriate.
  303.  */
  304. add_offset(fp, off)
  305. FILE    *fp;
  306. off_t    off;
  307. {
  308.     off_t net;
  309.  
  310.     if (!STORING_PTRS) {
  311.         net = htonl(off);
  312.         fwrite(&net, 1, sizeof net, fp);
  313.     } else {
  314.         ALLOC(Seekpts, Num_pts + 1);
  315.         Seekpts[Num_pts] = off;
  316.     }
  317.     Num_pts++;
  318. }
  319.  
  320. /*
  321.  * do_order:
  322.  *    Order the strings alphabetically (possibly ignoring case).
  323.  */
  324. do_order()
  325. {
  326.     register int    i;
  327.     register off_t    *lp;
  328.     register STR    *fp;
  329.     extern int    cmp_str();
  330.  
  331.     Sort_1 = fopen(Infile, "r");
  332.     Sort_2 = fopen(Infile, "r");
  333.     qsort((char *) Firstch, (int) Tbl.str_numstr, sizeof *Firstch, cmp_str);
  334.     i = Tbl.str_numstr;
  335.     lp = Seekpts;
  336.     fp = Firstch;
  337.     while (i--)
  338.         *lp++ = fp++->pos;
  339.     (void) fclose(Sort_1);
  340.     (void) fclose(Sort_2);
  341.     Tbl.str_flags |= STR_ORDERED;
  342. }
  343.  
  344. /*
  345.  * cmp_str:
  346.  *    Compare two strings in the file
  347.  */
  348. char *
  349. unctrl(c)
  350. char c;
  351. {
  352.     static char    buf[3];
  353.  
  354.     if (isprint(c)) {
  355.         buf[0] = c;
  356.         buf[1] = '\0';
  357.     }
  358.     else if (c == 0177) {
  359.         buf[0] = '^';
  360.         buf[1] = '?';
  361.     }
  362.     else {
  363.         buf[0] = '^';
  364.         buf[1] = c + 'A' - 1;
  365.     }
  366.     return buf;
  367. }
  368.  
  369. cmp_str(p1, p2)
  370. STR    *p1, *p2;
  371. {
  372.     register int    c1, c2;
  373.     register int    n1, n2;
  374.  
  375. # define    SET_N(nf,ch)    (nf = (ch == '\n'))
  376. # define    IS_END(ch,nf)    (ch == Delimch && nf)
  377.  
  378.     c1 = p1->first;
  379.     c2 = p2->first;
  380.     if (c1 != c2)
  381.         return c1 - c2;
  382.  
  383.     (void) fseek(Sort_1, p1->pos, 0);
  384.     (void) fseek(Sort_2, p2->pos, 0);
  385.  
  386.     n1 = FALSE;
  387.     n2 = FALSE;
  388.     while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0')
  389.         SET_N(n1, c1);
  390.     while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0')
  391.         SET_N(n2, c2);
  392.  
  393.     while (!IS_END(c1, n1) && !IS_END(c2, n2)) {
  394.         if (Iflag) {
  395.             if (isupper(c1))
  396.                 c1 = tolower(c1);
  397.             if (isupper(c2))
  398.                 c2 = tolower(c2);
  399.         }
  400.         if (c1 != c2)
  401.             return c1 - c2;
  402.         SET_N(n1, c1);
  403.         SET_N(n2, c2);
  404.         c1 = getc(Sort_1);
  405.         c2 = getc(Sort_2);
  406.     }
  407.     if (IS_END(c1, n1))
  408.         c1 = 0;
  409.     if (IS_END(c2, n2))
  410.         c2 = 0;
  411.     return c1 - c2;
  412. }
  413.  
  414. /*
  415.  * randomize:
  416.  *    Randomize the order of the string table.  We must be careful
  417.  *    not to randomize across delimiter boundaries.  All
  418.  *    randomization is done within each block.
  419.  */
  420. randomize()
  421. {
  422.     register int    cnt, i;
  423.     register off_t    tmp;
  424.     register off_t    *sp;
  425.     extern time_t    time();
  426.  
  427.     srandom((int)(time((time_t *) NULL) + getpid()));
  428.  
  429.     Tbl.str_flags |= STR_RANDOM;
  430.     cnt = Tbl.str_numstr;
  431.  
  432.     /*
  433.      * move things around randomly
  434.      */
  435.  
  436.     for (sp = Seekpts; cnt > 0; cnt--, sp++) {
  437.         i = random() % cnt;
  438.         tmp = sp[0];
  439.         sp[0] = sp[i];
  440.         sp[i] = tmp;
  441.     }
  442. }
  443.