/* * Conversion to BDS C completed 7/3/83 H.R. Moran, Jr. */ /* * * * The information in this document is subject to change * without notice and should not be construed as a commitment * by Digital Equipment Corporation or by DECUS. * * Neither Digital Equipment Corporation, DECUS, nor the authors * assume any responsibility for the use or reliability of this * document or the described software. * * Copyright (C) 1980, DECUS * * * General permission to copy or modify, but not for profit, is * hereby granted, provided that the above copyright notice is * included and reference made to the fact that reproduction * privileges were granted by DECUS. * */ /* * U N I Q . C * * Read a file, outputting unique (or non-unique) lines. * * Usage: * uniq ? for help * uniq [-Mode] [-Nfields] [+Nletters] [infile [outfile]] * * See documentation[] for more information. * * Updated for the new Decus compiler, 28-Apr-80 * */ #include #define stdin 0 #define stdout 1 #define FAST register #define PROC int /* PROCedure i.e. function returns no value */ #define BOOL int /* BOOLean i.e. YES or NO */ #define YES 1 #define NO 0 #define NIL 0 /* pointer to nothing */ #define FOREVER for(;;) #define BUFSIZE 1024 /* Buffer size (max. line) */ int skip_fields; /* Number of fields to skip */ int skip_letters; /* Number of letters to skip */ int linecount; /* How many repetitions */ int mode; /* Mode byte, if any */ char line1[BUFSIZE]; /* Input buffer 1 */ char line2[BUFSIZE]; /* Input buffer 2 */ FILE junk[2]; /* working space for use with FILE pointers */ FILE *infd; /* Input file */ FILE *outfd; /* Output file */ PROC main(argc, argv) int argc; /* Number of arguments */ char *argv[]; /* Argument buffer pointer */ { char *getline(); char *check(); FAST char *argp; /* Argument pointer */ FAST char c; /* Temp character */ FAST char *lp; /* Line buffer pointer */ infd = stdin; outfd = stdout; line1[0] = line2[0] = '\0'; if ( argc <= 1 || argv[1][0] == '?' ) { help(); exit(); } while ( argc > 1 && (c = *(argp = argv[1])) == '-' || c == '+' ) { ++argp; switch (c) { case '+': skip_letters = atoi(argp); break; case '-': if ( (c = *argp) >= '0' && c <= '9' ) skip_fields = atoi(argp); else mode = (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; break; } argc--; argv++; } if ( argc > 1 ) { infd = &junk[0]; if ( fopen(argv[1], infd) < 0 ) { printf("?Can't open input file \"%s\"\n", argv[1]); exit(1); } argc--; argv++; } if ( argc > 1 ) { outfd = &junk[1]; if ( fcreat(argv[1], outfd) < 0 ) { printf("?Can't open output file \"%s\"\n", argv[1]); exit(1); } } /* * Here we go */ if ( (lp = getline(line2)) == NIL ) { /* Prime the pump */ fclose(infd); fclose(outfd); exit(); } FOREVER { lp = check(line1, line2, lp); lp = check(line2, line1, lp); } } /* * Read lines as long as new == old. Return a pointer to the field to * test in new. Exit the program on end of file. */ char * check(new, old, oldpos) char *new; /* New line read here */ char *old; /* Old line resides here */ char *oldpos; /* Start of field in old line */ { FAST char *lp; /* Random line pointer */ char *getline(); linecount = 0; FOREVER { linecount++; if ( (lp = getline(new)) == NIL ) { output(old); fclose(infd); fclose(outfd); exit(); } if ( ! equals(oldpos, lp) ) break; } output(old); return (lp); } /* * Return NO if they don't match. If they do, return YES. */ BOOL equals(old, new) char *old; /* Compare this field */ char *new; /* Against this field */ { FAST char *op; FAST char *np; FAST char c; op = old; np = new; while ( (c = *op++) == *np++ ) { if ( c == '\0' ) { return (YES); } } return (NO); } /* * Output this line. */ PROC output(line) char *line; /* What to output */ { switch (mode) { case 'u': if (linecount > 1) return; break; case 'd': if (linecount > 1) break; return; case 'c': fprintf(outfd, "%4d ", linecount); break; } fprintf(outfd, "%s", line); } /* * Read a line. return NIL on end of file. If not end of file, return * a pointer to the first byte of the field to check. */ char * getline(line) char *line; /* Buffer to read into */ { FAST int count; FAST char c; FAST char *lp; if ( fgets(line, infd) == NIL ) return (NIL); lp = line; for ( count = 0; count++ < skip_fields; ) { while ( (c = *lp) == ' ' || c == '\t' ) lp++; while ( (c = *lp) != ' ' && c != '\t' ) { if ( c == '\0' ) return (lp); else lp++; } } for ( count = 0; count++ < skip_letters; lp++ ) { if ( *lp == '\0' ) break; } return (lp); } /* * Give good help */ PROC help() { #define P putline P("Uniq reads an input file, writing each unique line."); P("Usage: uniq [-Mode] [-N_fields] [+N_letters] [infile [outfile]]"); P(""); P("Where: note: use only ONE of u, d, or c"); P(""); P(" -u Only print unique lines."); P(" -d Only print duplicate lines."); P(" -c Print the # of times each line occurred along with the line."); P(" -N Skip over the first N words before checking for uniqueness"); P(" +N Skip over the first N letters (in the indicated field)"); P(""); P("A word is defined as \"optional spaces or tabs\" "); P("followed by text up to the first space, tab, or end of line."); P(""); P("If no file names are given, input and output are stdin and stdout"); P(""); } PROC putline(s) char *s; { printf("%s\n", s); }