Annotation of coherent/d/bin/join.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Join -- relational database join operation.
        !             3:  */
        !             4: 
        !             5: #include <stdio.h>
        !             6: 
        !             7: #define        NREC    512                     /* Maximum record length */
        !             8: #define        NFIELD  200                     /* Maximum number of fields */
        !             9: #define        NOFIELD 150                     /* Maximum fields in output list */
        !            10: 
        !            11: typedef        unsigned char   uchar;
        !            12: 
        !            13: /*
        !            14:  * A record that has been split into
        !            15:  * fields.
        !            16:  */
        !            17: typedef        struct  RECORD {
        !            18:        char    r_record[NREC];         /* The text for the whole record */
        !            19:        FILE    *r_fp;                  /* File stream pointer of input */
        !            20:        int     r_jfield;               /* Join field number */
        !            21:        int     r_eof;                  /* EOF flag */
        !            22:        unsigned r_nfield;              /* Number of fields */
        !            23:        char    *r_fields[NFIELD];      /* Field pointers */
        !            24: }      RECORD;
        !            25: 
        !            26: /*
        !            27:  * The indicator for what field is to be
        !            28:  * printed upon output.
        !            29:  * Whhen there is no `-o' list, then
        !            30:  * the default of the key field followed
        !            31:  * by all fields in file1 followed by all
        !            32:  * other fields in file2 is used.
        !            33:  */
        !            34: typedef        struct  FIELD {
        !            35:        char    f_fileno;               /* File number (1,2,or3) */
        !            36:        uchar   f_fieldno;              /* Field number */
        !            37: }      FIELD;
        !            38: 
        !            39: RECORD rec1;
        !            40: RECORD rec2;
        !            41: FIELD  fields[NOFIELD];
        !            42: FIELD  *efp = &fields[0];
        !            43: 
        !            44: char   usemsg[] = "\
        !            45: Usage: join [-a[f]] [-e s] [-j[f] n] [-o f.n ...] [-tc] file1 file2\n\
        !            46: ";
        !            47: 
        !            48: char   tabc;                           /* Tab character -- if null, default */
        !            49: char   otabc = ' ';                    /* Output separator character */
        !            50: int    unpair;                         /* Print unpairable records in these */
        !            51: int    tflag;                          /* Set when -t given */
        !            52: char   *empty = "";                    /* Put out for empty fields */
        !            53: FILE   *jopen();
        !            54: 
        !            55: main(argc, argv)
        !            56: int argc;
        !            57: char *argv[];
        !            58: {
        !            59:        register char *ap;
        !            60:        register int n;
        !            61:        register FIELD *ep = fields;
        !            62: 
        !            63:        rec1.r_jfield = rec2.r_jfield = 1;
        !            64:        while (argc>1 && *argv[1]=='-') {
        !            65:                ap = &argv[1][1];
        !            66:                if (*ap == '\0')
        !            67:                        break;
        !            68:                switch (*ap) {
        !            69:                case 'a':
        !            70:                        if (ap[1] == '\0')
        !            71:                                unpair = 01|02;
        !            72:                        else {
        !            73:                                if (ap[2] != '\0')
        !            74:                                        usage();
        !            75:                                if (ap[1] == '1')
        !            76:                                        unpair = 01;
        !            77:                                else if (ap[1] == '2')
        !            78:                                        unpair = 02;
        !            79:                                else
        !            80:                                        fnusage("-a");
        !            81:                        }
        !            82:                        break;
        !            83: 
        !            84:                case 'e':
        !            85:                        if (argc<2 || ap[1]!='\0')
        !            86:                                usage();
        !            87:                        argv++;
        !            88:                        argc--;
        !            89:                        empty = argv[1];
        !            90:                        break;
        !            91: 
        !            92:                case 'j':
        !            93:                        if (argc < 2)
        !            94:                                usage();
        !            95:                        argv++;
        !            96:                        argc--;
        !            97:                        if ((n = atoi(argv[1])) == 0)
        !            98:                                usage();
        !            99:                        if (ap[1] == '\0')
        !           100:                                rec1.r_jfield = rec2.r_jfield = n;
        !           101:                        else if (ap[1] == '1')
        !           102:                                rec1.r_jfield = n;
        !           103:                        else if (ap[1] == '2')
        !           104:                                rec2.r_jfield = n;
        !           105:                        else
        !           106:                                fnusage("-j");
        !           107:                        break;
        !           108: 
        !           109:                case 'o':
        !           110:                        ep = efp;
        !           111:                        while (argc > 2) {
        !           112:                                if (!addlist(argv[2]))
        !           113:                                        break;
        !           114:                                argv++;
        !           115:                                argc--;
        !           116:                        }
        !           117:                        if (ep==efp || ap[1]!='\0')
        !           118:                                usage();
        !           119:                        break;
        !           120: 
        !           121:                case 't':
        !           122:                        tflag++;
        !           123:                        if ((tabc = otabc = ap[1]) == '\0')
        !           124:                                usage();
        !           125:                        break;
        !           126: 
        !           127:                default:
        !           128:                        usage();
        !           129:                }
        !           130:                argv++;
        !           131:                argc--;
        !           132:        }
        !           133:        if (argc != 3)
        !           134:                usage();
        !           135:        rec1.r_fp = jopen(argv[1]);
        !           136:        rec2.r_fp = jopen(argv[2]);
        !           137:        if (rec1.r_fp==stdin && rec2.r_fp==stdin)
        !           138:                cerr("both files are `-'");
        !           139:        join();
        !           140:        exit(0);
        !           141: }
        !           142: 
        !           143: /*
        !           144:  * Add a new element to the output list for `join'.
        !           145:  * Check for two many elements on the list.
        !           146:  * Return 0 if this isn't a list element type argument.
        !           147:  * Return 1 if added element.
        !           148:  */
        !           149: addlist(s)
        !           150: register char *s;
        !           151: {
        !           152:        register int n;
        !           153:        register int fn;
        !           154: 
        !           155:        fn = 3;
        !           156:        for (n=0; *s>='0' && *s<='9'; )
        !           157:                n = n*10 + *s++-'0';
        !           158:        if (*s == '.') {
        !           159:                s++;
        !           160:                fn = n;
        !           161:                for (n=0; *s>='0' && *s<='9'; )
        !           162:                        n = n*10 + *s++-'0';
        !           163:        }
        !           164:        if (*s!='\0' || fn<1 || fn>3)
        !           165:                return (0);
        !           166:        if (efp >= &fields[NOFIELD-1])
        !           167:                cerr("too many elements for `-o' list");
        !           168:        efp->f_fileno = fn;
        !           169:        efp->f_fieldno = n;
        !           170:        efp++;
        !           171:        return (1);
        !           172: }
        !           173: 
        !           174: /*
        !           175:  * Open one of join's input files.
        !           176:  * Check for the special filename `-'.
        !           177:  */
        !           178: FILE   *
        !           179: jopen(fn)
        !           180: register char *fn;
        !           181: {
        !           182:        register FILE *fp;
        !           183: 
        !           184:        if (fn[0]=='-' && fn[1]=='\0')
        !           185:                fp = stdin;
        !           186:        else if ((fp = fopen(fn, "r")) == NULL)
        !           187:                cerr("cannot open input `%s'", fn);
        !           188:        return (fp);
        !           189: }
        !           190: 
        !           191: /*
        !           192:  * Do the work of joining two files
        !           193:  * containing relations.
        !           194:  * The files should be ordered on
        !           195:  * the selected primary keys.
        !           196:  */
        !           197: join()
        !           198: {
        !           199:        jread(&rec1);
        !           200:        jread(&rec2);
        !           201:        while (!rec1.r_eof && !rec2.r_eof) {
        !           202:                switch (jcmp()) {
        !           203:                case 0:
        !           204:                        jwrite(03);
        !           205:                        jread(&rec2);
        !           206:                        break;
        !           207: 
        !           208:                case -1:        /* file1 < file2 */
        !           209:                        if (unpair & 01)
        !           210:                                jwrite(01);
        !           211:                        jread(&rec1);
        !           212:                        break;
        !           213: 
        !           214:                case 1:         /* file2 < file1 */
        !           215:                        if (unpair & 02)
        !           216:                                jwrite(02);
        !           217:                        jread(&rec2);
        !           218:                        break;
        !           219:                }
        !           220:        }
        !           221:        while (!rec2.r_eof) {
        !           222:                if (unpair & 02)
        !           223:                        jwrite(02);
        !           224:                jread(&rec2);
        !           225:        }
        !           226: 
        !           227:        while (!rec1.r_eof) {
        !           228:                if (unpair & 01)
        !           229:                        jwrite(01);
        !           230:                jread(&rec1);
        !           231:        }
        !           232: }
        !           233: 
        !           234: /*
        !           235:  * Read a record and divide it into fields.
        !           236:  * The argument is a record pointer.
        !           237:  */
        !           238: jread(rp)
        !           239: register RECORD *rp;
        !           240: {
        !           241:        register char *cp;
        !           242:        register int c;
        !           243:        register int nf = 0;
        !           244: 
        !           245:        rp->r_nfield = 0;
        !           246:        if (fgets(rp->r_record, NFIELD, rp->r_fp) == NULL) {
        !           247:                rp->r_eof++;
        !           248:                return;
        !           249:        }
        !           250:        cp = rp->r_record;
        !           251:        if (tflag) {
        !           252:                for (nf=0; ; nf++) {
        !           253:                        if (nf >= NFIELD)
        !           254:                                cerr("too many fields in input");
        !           255:                        rp->r_fields[nf] = cp;
        !           256:                        while ((c = *cp)!='\n' && c!='\0' && c!=tabc)
        !           257:                                cp++;
        !           258:                        *cp++ = '\0';
        !           259:                        if (c != tabc)
        !           260:                                break;
        !           261:                }
        !           262:                rp->r_nfield = nf+1;
        !           263:        } else {
        !           264:                nf = 0;
        !           265:                for (;;) {
        !           266:                        while ((c = *cp)==' ' || c=='\t')
        !           267:                                cp++;
        !           268:                        if (c=='\n' || c=='\0') {
        !           269:                                *cp = '\0';
        !           270:                                break;
        !           271:                        }
        !           272:                        if (nf >= NFIELD)
        !           273:                                cerr("too many field in input");
        !           274:                        rp->r_fields[nf++] = cp;
        !           275:                        while ((c = *cp)!=' ' && c!='\t' && c!='\n' && c!='\0')
        !           276:                                cp++;
        !           277:                        if (c != '\0')
        !           278:                                *cp++ = '\0';
        !           279:                }
        !           280:                rp->r_nfield = nf;
        !           281:        }
        !           282: }
        !           283: 
        !           284: /*
        !           285:  * Output a record for the given file numbers.
        !           286:  * Numbers can be 1, 2, or 3 (for both files).
        !           287:  */
        !           288: jwrite(fn)
        !           289: int fn;
        !           290: {
        !           291:        register int i;
        !           292: 
        !           293:        if (efp > &fields[0]) {
        !           294:                register FIELD *fp;
        !           295: 
        !           296:                for (fp = &fields[0]; fp < efp; fp++) {
        !           297:                        switch (fn & fp->f_fileno) {
        !           298:                        case 1:
        !           299:                                jpfield(&rec1, fp->f_fieldno);
        !           300:                                break;
        !           301: 
        !           302:                        case 2:
        !           303:                                jpfield(&rec2, fp->f_fieldno);
        !           304:                                break;
        !           305: 
        !           306:                        case 3:
        !           307:                                jpfield(&rec1, fp->f_fieldno);
        !           308:                                jpfield(&rec2, fp->f_fieldno);
        !           309:                                break;
        !           310:                        }
        !           311:                }
        !           312:        } else {
        !           313:                register int jf;
        !           314: 
        !           315:                if (fn & 01) {
        !           316:                        jf = rec1.r_jfield;
        !           317:                        jpfield(&rec1, jf);
        !           318:                        for (i=1; i<=rec1.r_nfield; i++)
        !           319:                                if (i != jf)
        !           320:                                        jpfield(&rec1, i);
        !           321:                }
        !           322:                if (fn & 02) {
        !           323:                        jf = rec2.r_jfield;
        !           324:                        if (fn != 03)
        !           325:                                jpfield(&rec2, jf);
        !           326:                        for (i=1; i<=rec2.r_nfield; i++)
        !           327:                                if (i != jf)
        !           328:                                        jpfield(&rec2, i);
        !           329:                }
        !           330:        }
        !           331:        jpfield(NULL, 0);
        !           332: }
        !           333: 
        !           334: /*
        !           335:  * Print out a field.
        !           336:  * When asked to print from record
        !           337:  * `NULL', this signifies the reset at end
        !           338:  * of line.
        !           339:  * Don't print fields that are out of range
        !           340:  * (perhaps these should be considered as NULL fields).
        !           341:  */
        !           342: jpfield(rp, fieldno)
        !           343: register RECORD *rp;
        !           344: int fieldno;
        !           345: {
        !           346:        static int first;
        !           347:        register char *fp;
        !           348: 
        !           349:        if (rp == NULL) {
        !           350:                putchar('\n');
        !           351:                first = 0;
        !           352:                return;
        !           353:        }
        !           354:        if (fieldno > rp->r_nfield)
        !           355:                return;
        !           356:        if (first++ != 0)
        !           357:                putchar(otabc);
        !           358:        fp = rp->r_fields[fieldno-1];
        !           359:        if (*fp == '\0')
        !           360:                fp = empty;
        !           361:        fputs(fp, stdout);
        !           362: }
        !           363: 
        !           364: /*
        !           365:  * Do a comparison of the join fields.
        !           366:  * This has the same return values as
        !           367:  * strcmp.  If the field is missing, complain.
        !           368:  */
        !           369: jcmp()
        !           370: {
        !           371:        if (rec1.r_jfield>rec1.r_nfield || rec2.r_jfield>rec2.r_nfield)
        !           372:                cerr("join field is missing in input");
        !           373:        return (strcmp(rec1.r_fields[rec1.r_jfield-1],
        !           374:                        rec2.r_fields[rec2.r_jfield-1]));
        !           375: }
        !           376: 
        !           377: fnusage(opt)
        !           378: char *opt;
        !           379: {
        !           380:        fprintf(stderr, "join: `%s' file number must be 1 or 2\n", opt);
        !           381:        usage();
        !           382: }
        !           383: 
        !           384: usage()
        !           385: {
        !           386:        fprintf(stderr, usemsg);
        !           387:        exit(1);
        !           388: }
        !           389: 
        !           390: /* VARARGS */
        !           391: cerr(x)
        !           392: {
        !           393:        fprintf(stderr, "join: %r\n", &x);
        !           394:        exit(1);
        !           395: }

unix.superglobalmegacorp.com

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