Annotation of 43BSD/games/fortune/strfile.c, revision 1.1.1.1

1.1       root        1: # include      <stdio.h>
                      2: # include      <ctype.h>
                      3: # include      "strfile.h"
                      4: 
                      5: /*
                      6:  *     This program takes a file composed of strings seperated by
                      7:  * lines starting with two consecutive delimiting character (default
                      8:  * character is '%') and creates another file which consists of a table
                      9:  * describing the file (structure from "strfile.h"), a table of seek
                     10:  * pointers to the start of the strings, and the strings, each terinated
                     11:  * by a null byte.  Usage:
                     12:  *
                     13:  *     % strfile [ - ] [ -cC ] [ -sv ] [ -oir ] sourcefile [ datafile ]
                     14:  *
                     15:  *     - - Give a usage summary useful for jogging the memory
                     16:  *     c - Change delimiting character from '%' to 'C'
                     17:  *     s - Silent.  Give no summary of data processed at the end of
                     18:  *         the run.
                     19:  *     v - Verbose.  Give summary of data processed.  (Default)
                     20:  *     o - order the strings in alphabetic order
                     21:  *     i - if ordering, ignore case 
                     22:  *     r - randomize the order of the strings
                     23:  *
                     24:  *             Ken Arnold      Sept. 7, 1978 --
                     25:  *
                     26:  *     Added method to indicate dividers.  A "%-" will cause the address
                     27:  * to be added to the structure in one of the pointer elements.
                     28:  *
                     29:  *             Ken Arnold      Nov., 1984 --
                     30:  *
                     31:  *     Added ordering options.
                     32:  */
                     33: 
                     34: # define       TRUE    1
                     35: # define       FALSE   0
                     36: 
                     37: # define       DELIM_CH        '-'
                     38: 
                     39: typedef struct {
                     40:        char    first;
                     41:        long    pos;
                     42: } STR;
                     43: 
                     44: char   *Infile         = NULL,         /* input file name */
                     45:        Outfile[100]    = "",           /* output file name */
                     46:        Delimch         = '%',          /* delimiting character */
                     47:        *Usage[]        = {             /* usage summary */
                     48:        "usage: strfile [ - ] [ -cC ] [ -sv ] [ -oir ] inputfile [ datafile ]",
                     49:        "       - - Give this usage summary",
                     50:        "       c - Replace delimiting character with 'C'",
                     51:        "       s - Silent.  Give no summary",
                     52:        "       v - Verbose.  Give summary.  (default)",
                     53:        "       o - order strings alphabetically",
                     54:        "       i - ignore case in ordering",
                     55:        "       r - randomize the order of the strings",
                     56:        "       Default \"datafile\" is inputfile.dat",
                     57:        NULL
                     58:        };
                     59: 
                     60: int    Sflag           = FALSE;        /* silent run flag */
                     61: int    Oflag           = FALSE;        /* ordering flag */
                     62: int    Iflag           = FALSE;        /* ignore case flag */
                     63: int    Rflag           = FALSE;        /* randomize order flag */
                     64: int    Delim           = 0;            /* current delimiter number */
                     65: 
                     66: long   *Seekpts;
                     67: 
                     68: FILE   *Sort_1, *Sort_2;               /* pointers for sorting */
                     69: 
                     70: STRFILE        Tbl;                            /* statistics table */
                     71: 
                     72: STR    *Firstch;                       /* first chars of each string */
                     73: 
                     74: char   *fgets(), *malloc(), *strcpy(), *strcat();
                     75: 
                     76: long   ftell();
                     77: 
                     78: main(ac, av)
                     79: int    ac;
                     80: char   **av;
                     81: {
                     82:        register char           *sp, dc;
                     83:        register long           *lp;
                     84:        register unsigned int   curseek;        /* number of strings */
                     85:        register long           *seekpts, li;   /* table of seek pointers */
                     86:        register FILE           *inf, *outf;
                     87:        register int            first;
                     88:        register char           *nsp;
                     89:        register STR            *fp;
                     90:        static char             string[257];
                     91: 
                     92:        getargs(ac, av);                /* evalute arguments */
                     93: 
                     94:        /*
                     95:         * initial counting of input file
                     96:         */
                     97: 
                     98:        dc = Delimch;
                     99:        if ((inf = fopen(Infile, "r")) == NULL) {
                    100:                perror(Infile);
                    101:                exit(-1);
                    102:        }
                    103:        for (curseek = 0; (sp = fgets(string, 256, inf)) != NULL; )
                    104:                if (*sp++ == dc && (*sp == dc || *sp == DELIM_CH))
                    105:                        curseek++;
                    106:        curseek++;
                    107: 
                    108:        /*
                    109:         * save space at begginning of file for tables
                    110:         */
                    111: 
                    112:        if ((outf = fopen(Outfile, "w")) == NULL) {
                    113:                perror(Outfile);
                    114:                exit(-1);
                    115:        }
                    116: 
                    117:        /*
                    118:         * Allocate space for the pointers, adding one to the end so the
                    119:         * length of the final string can be calculated.
                    120:         */
                    121:        ++curseek;
                    122:        seekpts = (long *) malloc(sizeof *seekpts * curseek);   /* NOSTRICT */
                    123:        if (seekpts == NULL) {
                    124:                perror("calloc");
                    125:                exit(-1);
                    126:        }
                    127:        if (Oflag) {
                    128:                Firstch = (STR *) malloc(sizeof *Firstch * curseek);
                    129:                if (Firstch == NULL) {
                    130:                        perror("calloc");
                    131:                        exit(-1);
                    132:                }
                    133:        }
                    134: 
                    135:        (void) fseek(outf, (long) (sizeof Tbl + sizeof *seekpts * curseek), 0);
                    136:        (void) fseek(inf, (long) 0, 0);         /* goto start of input */
                    137: 
                    138:        /*
                    139:         * write the strings onto the file
                    140:         */
                    141: 
                    142:        Tbl.str_longlen = 0;
                    143:        Tbl.str_shortlen = (unsigned int) 0xffffffff;
                    144:        lp = seekpts;
                    145:        first = Oflag;
                    146:        *seekpts = ftell(outf);
                    147:        fp = Firstch;
                    148:        do {
                    149:                sp = fgets(string, 256, inf);
                    150:                if (sp == NULL ||
                    151:                    (*sp == dc && (sp[1] == dc || sp[1] == DELIM_CH))) {
                    152:                        putc('\0', outf);
                    153:                        *++lp = ftell(outf);
                    154:                        li = ftell(outf) - lp[-1] - 1;
                    155:                        if (Tbl.str_longlen < li)
                    156:                                Tbl.str_longlen = li;
                    157:                        if (Tbl.str_shortlen > li)
                    158:                                Tbl.str_shortlen = li;
                    159:                        if (sp && sp[1] == DELIM_CH && Delim < MAXDELIMS)
                    160:                                Tbl.str_delims[Delim++] = lp - seekpts;
                    161:                        first = Oflag;
                    162:                }
                    163:                else {
                    164:                        if (first) {
                    165:                                for (nsp = sp; !isalnum(*nsp); nsp++)
                    166:                                        continue;
                    167:                                if (Iflag && isupper(*nsp))
                    168:                                        fp->first = tolower(*nsp);
                    169:                                else
                    170:                                        fp->first = *nsp;
                    171:                                fp->pos = *lp;
                    172:                                fp++;
                    173:                                first = FALSE;
                    174:                        }
                    175:                        fputs(sp, outf);
                    176:                }
                    177:        } while (sp != NULL);
                    178: 
                    179:        /*
                    180:         * write the tables in
                    181:         */
                    182: 
                    183:        (void) fclose(inf);
                    184:        Tbl.str_numstr = curseek - 1;
                    185: 
                    186:        if (Oflag)
                    187:                do_order(seekpts, outf);
                    188:        else if (Rflag)
                    189:                randomize(seekpts);
                    190: 
                    191:        (void) fseek(outf, (long) 0, 0);
                    192:        (void) fwrite((char *) &Tbl, sizeof Tbl, 1, outf);
                    193:        (void) fwrite((char *) seekpts, sizeof *seekpts, curseek, outf);
                    194:        (void) fclose(outf);
                    195: 
                    196:        if (!Sflag) {
                    197:                printf("\"%s\" converted to \"%s\"\n", Infile, Outfile);
                    198:                if (curseek == 0)
                    199:                        puts("There was 1 string");
                    200:                else
                    201:                        printf("There were %u strings\n", curseek - 1);
                    202:                printf("Longest string: %u byte%s\n", Tbl.str_longlen,
                    203:                       Tbl.str_longlen == 1 ? "" : "s");
                    204:                printf("Shortest string: %u byte%s\n", Tbl.str_shortlen,
                    205:                       Tbl.str_shortlen == 1 ? "" : "s");
                    206:        }
                    207:        exit(0);
                    208: }
                    209: 
                    210: /*
                    211:  *     This routine evaluates arguments from the command line
                    212:  */
                    213: getargs(ac, av)
                    214: register int   ac;
                    215: register char  **av;
                    216: {
                    217:        register char   *sp;
                    218:        register int    i;
                    219:        register int    bad, j;
                    220: 
                    221:        bad = 0;
                    222:        for (i = 1; i < ac; i++)
                    223:                if (*av[i] == '-' && av[i][1]) {
                    224:                        for (sp = &av[i][1]; *sp; sp++)
                    225:                                switch (*sp) {
                    226:                                  case 'c': /* new delimiting char */
                    227:                                        if ((Delimch = *++sp) == '\0') {
                    228:                                                --sp;
                    229:                                                Delimch = *av[++i];
                    230:                                        }
                    231:                                        if (Delimch <= 0 || Delimch > '~' ||
                    232:                                            Delimch == DELIM_CH) {
                    233:                                                printf("bad delimiting character: '\\%o\n'",
                    234:                                                       Delimch);
                    235:                                                bad++;
                    236:                                        }
                    237:                                        break;
                    238:                                  case 's':     /* silent */
                    239:                                        Sflag++;
                    240:                                        break;
                    241:                                  case 'v':     /* verbose */
                    242:                                        Sflag = 0;
                    243:                                        break;
                    244:                                  case 'o':     /* order strings */
                    245:                                        Oflag++;
                    246:                                        break;
                    247:                                  case 'i':     /* ignore case in ordering */
                    248:                                        Iflag++;
                    249:                                        break;
                    250:                                  case 'r':     /* ignore case in ordering */
                    251:                                        Rflag++;
                    252:                                        break;
                    253:                                  default:      /* unknown flag */
                    254:                                        bad++;
                    255:                                        printf("bad flag: '%c'\n", *sp);
                    256:                                        break;
                    257:                                }
                    258:                }
                    259:                else if (*av[i] == '-') {
                    260:                        for (j = 0; Usage[j]; j++)
                    261:                                puts(Usage[j]);
                    262:                        exit(0);
                    263:                }
                    264:                else if (Infile)
                    265:                        (void) strcpy(Outfile, av[i]);
                    266:                else
                    267:                        Infile = av[i];
                    268:        if (!Infile) {
                    269:                bad++;
                    270:                puts("No input file name");
                    271:        }
                    272:        if (*Outfile == '\0' && !bad) {
                    273:                (void) strcpy(Outfile, Infile);
                    274:                (void) strcat(Outfile, ".dat");
                    275:        }
                    276:        if (bad) {
                    277:                puts("use \"strfile -\" to get usage");
                    278:                exit(-1);
                    279:        }
                    280: }
                    281: 
                    282: /*
                    283:  * do_order:
                    284:  *     Order the strings alphabetically (possibly ignoring case).
                    285:  */
                    286: do_order(seekpts, outf)
                    287: long   *seekpts;
                    288: FILE   *outf;
                    289: {
                    290:        register int    i;
                    291:        register long   *lp;
                    292:        register STR    *fp;
                    293:        extern int      cmp_str();
                    294: 
                    295:        (void) fflush(outf);
                    296:        Sort_1 = fopen(Outfile, "r");
                    297:        Sort_2 = fopen(Outfile, "r");
                    298:        Seekpts = seekpts;
                    299:        qsort((char *) Firstch, Tbl.str_numstr, sizeof *Firstch, cmp_str);
                    300:        i = Tbl.str_numstr;
                    301:        lp = seekpts;
                    302:        fp = Firstch;
                    303:        while (i--)
                    304:                *lp++ = fp++->pos;
                    305:        (void) fclose(Sort_1);
                    306:        (void) fclose(Sort_2);
                    307:        Tbl.str_flags |= STR_ORDERED;
                    308: }
                    309: 
                    310: /*
                    311:  * cmp_str:
                    312:  *     Compare two strings in the file
                    313:  */
                    314: cmp_str(p1, p2)
                    315: STR    *p1, *p2;
                    316: {
                    317:        register int    c1, c2;
                    318: 
                    319:        c1 = p1->first;
                    320:        c2 = p2->first;
                    321:        if (c1 != c2)
                    322:                return c1 - c2;
                    323: 
                    324:        (void) fseek(Sort_1, p1->pos, 0);
                    325:        (void) fseek(Sort_2, p2->pos, 0);
                    326: 
                    327:        while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0')
                    328:                continue;
                    329:        while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0')
                    330:                continue;
                    331: 
                    332:        while (c1 != '\0' && c2 != '\0') {
                    333:                if (Iflag) {
                    334:                        if (isupper(c1))
                    335:                                c1 = tolower(c1);
                    336:                        if (isupper(c2))
                    337:                                c2 = tolower(c2);
                    338:                }
                    339:                if (c1 != c2)
                    340:                        return c1 - c2;
                    341:                c1 = getc(Sort_1);
                    342:                c2 = getc(Sort_2);
                    343:        }
                    344:        return c1 - c2;
                    345: }
                    346: 
                    347: /*
                    348:  * randomize:
                    349:  *     Randomize the order of the string table.  We must be careful
                    350:  *     not to randomize across delimiter boundaries.  All
                    351:  *     randomization is done within each block.
                    352:  */
                    353: randomize(seekpts)
                    354: register long  *seekpts;
                    355: {
                    356:        register int    cnt, i, j, start;
                    357:        register long   tmp;
                    358:        register long   *origsp;
                    359: 
                    360:        Tbl.str_flags |= STR_RANDOM;
                    361:        srnd(time((long *) NULL) + getpid());
                    362:        origsp = seekpts;
                    363:        for (j = 0; j <= Delim; j++) {
                    364: 
                    365:                /*
                    366:                 * get the starting place for the block
                    367:                 */
                    368: 
                    369:                if (j == 0)
                    370:                        start = 0;
                    371:                else
                    372:                        start = Tbl.str_delims[j - 1];
                    373: 
                    374:                /*
                    375:                 * get the ending point
                    376:                 */
                    377: 
                    378:                if (j == Delim)
                    379:                        cnt = Tbl.str_numstr;
                    380:                else
                    381:                        cnt = Tbl.str_delims[j];
                    382: 
                    383:                /*
                    384:                 * move things around randomly
                    385:                 */
                    386: 
                    387:                for (seekpts = &origsp[start]; cnt > start; cnt--, seekpts++) {
                    388:                        i = rnd(cnt - start);
                    389:                        tmp = seekpts[0];
                    390:                        seekpts[0] = seekpts[i];
                    391:                        seekpts[i] = tmp;
                    392:                }
                    393:        }
                    394: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.