# /* * comm. * */ /*)BUILD $(TKBOPTIONS) = { TASK = ...COM } */ #ifdef DOCUMENTATION title comm Compare Files for Equality index Compare Files for Equality synopsis comm [- [123]] file_1 file_2 [out_file] description Comm prints lines which are common to two files. Lines which are only in file 1 are printed in the leftmost column; those which are only in file 2 are printed indented by one tab; those in both files are printed indented by two tabs. .s Specifying flags 1, 2, or 3 will suppress printing of the indicated column: .lm +16 .s.i -12;comm -12 prints only lines common to both files. .s.i -12;comm -23 prints lines present in the first file, but not in the second. .s.i -12;comm -123 does nothing. .s.lm -16 If the output file argument is not present, output is written to the standard output. diagnostics .lm +8 .s.i -8;No argument .s.i -8;Unknown flag .s.i -8;Two input files needed .s.i -8;Cannot open input file .lm -8 author Martin Minow bugs #endif char *documentation[] = { "comm prints lines common to two files", " comm [- [123]] file_1 file_2 [out_file]", "", "Lines in file 1 only are printed in the leftmost column.", "Lines in file 2 only are printed in the second column.", "Lines in both files are printed in the third column.", "Flags 1, 2, or 3 suprress printing of the corresponding column", " comm -12 prints only lines common to both files", " comm -23 prints lines in the first file, but not the second", " comm -123 does nothing", "", "If the third file is not present, output goes to the standard output", "If using the Decus compiler, output may be redirected:", " comm ... >file.out", "", 0 }; #include #define LINESIZE 512 struct area { FILE *fd; char line[LINESIZE]; } area[2]; FILE *outfd; char *head[3] = { "", "\t", "\t\t" }; /* Heading vector */ int flag[3]; /* What's set */ main(argc, argv) char *argv[]; { register int temp; register int c; register FILE *fdtemp; /* Hide a DECUS C bug */ temp = 0; if (argc <= 1) usage("No arguments"); if (argv[1][0] == '?' && argv[1][1] == 0) { help(); exit(); } if (argv[1][0] == '-' && argv[1][1] != 0) { while ((c = *++argv[1])) { switch (c) { case '1': case '2': case '3': c -= '1'; /* '1..3' => 0..2 */ if (!flag[c]) { flag[c]++; temp++; } break; default: usage("Unknown flag"); } } head[2] = head[2 - temp]; argc--; argv++; } /* * Open files */ if (argc < 3) usage("Two input files needed"); for (temp = 0; temp < 2; temp++) { if ((fdtemp = fopen(argv[1+temp], "r")) == NULL) cant(argv[1+temp]); area[temp].fd = fdtemp; } if (argc > 3) { if ((outfd = fopen(argv[3], "w")) == NULL) cant(argv[3]); } else outfd = stdout; /* * Fill both buffers and off we go */ fillboth(); for (;;) { switch(equals(area[0].line, area[1].line)) { case 0: /* File 1 == file 2 */ output(area[0].line, 2); fillboth(); break; case 1: /* File 1 < file 2 */ output(area[0].line, 0); fill(0); break; case 2: /* File 1 > file 2 */ output(area[1].line, 1); fill(1); break; } } } fill(into) int into; /* Fill this buffer */ /* * buffer filler. Just does one of them. */ { if (input(into)) flushout(1 - into); } fillboth() /* * Fill both buffers */ { if (input(0)) { if (input(1)) finis(); /* Both end filed */ else flushout(1); /* Just file 0 */ } if (input(1)) flushout(0); } input(into) int into; /* Read into this buffer */ /* * Read a line into this buffer, return 1 on eof */ { return(fgets(area[into].line, LINESIZE, area[into].fd) == NULL); } flushout(other) int other; /* Flush this one */ { do { output(area[other].line, other); } while (input(other) == 0); finis(); } output(text, which) char *text; /* Line to output */ int which; /* Which side 1, 2, or 3 */ { if (!flag[which]) fprintf(outfd, "%s%s", head[which], text); } equals(str1, str2) char *str1; /* Strings */ char *str2; /* to compare */ { register char *p1; register char *p2; p1 = str1 - 1; p2 = str2 - 1; while (*++p1 == *++p2) { if (*p1 == 0) return(0); } return((p1 < p2) ? 1 : 2); } finis() /* * Exit from comm */ { fflush(outfd); fclose(outfd); fclose(area[0].fd); fclose(area[1].fd); exit(); } cant(s) char *s; { fprintf(stderr, "?COMM-E-input file %s\n", s); usage("cannot open input file"); } help() /* * Give good help */ { register char **dp; for (dp = documentation; *dp; dp++) printf("%s\n", *dp); } usage(s) char *s; { fprintf(stderr, "?COMM-E-%s\n", s); fprintf(stderr, "Usage: comm [-[123]] file1 file2 [out-file]. comm ? for help\n"); exit(1); }