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 * Case Larsen. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)uniq.c 5.2 (Berkeley) 06/01/90"; 19 #endif /* not lint */ 20 21 #include <stdio.h> 22 #include <ctype.h> 23 24 int cflag, dflag, uflag; 25 int numchars, numfields, repeats; 26 27 #define MAXLINELEN (2048 + 1) 28 29 main (argc,argv) 30 int argc; 31 char **argv; 32 { 33 extern int optind; 34 FILE *ifp, *ofp, *file(); 35 int ch; 36 register char *t1, *t2; 37 char *prevline, *thisline, *malloc(), *skip(); 38 39 while ((ch = getopt(argc, argv, "-cdu123456789")) != EOF) 40 switch (ch) { 41 case '-': 42 --optind; 43 goto done; 44 case 'c': 45 cflag = 1; 46 break; 47 case 'd': 48 dflag = 1; 49 break; 50 case 'u': 51 uflag = 1; 52 break; 53 /* 54 * since -n is a valid option that could be picked up by 55 * getopt, but is better handled by the +n and -n code, we 56 * break out. 57 */ 58 case '1': case '2': case '3': case '4': 59 case '5': case '6': case '7': case '8': case '9': 60 --optind; 61 goto done; 62 case '?': 63 default: 64 usage(); 65 } 66 67 done: argc -= optind; 68 argv +=optind; 69 70 /* if no flags are set, default is -d -u */ 71 if (cflag) { 72 if (dflag || uflag) 73 usage(); 74 } else if (!dflag && !uflag) 75 dflag = uflag = 1; 76 77 /* because of the +, getopt is messed up */ 78 for (; **argv == '+' || **argv == '-'; ++argv, --argc) 79 switch (**argv) { 80 case '+': 81 if ((numchars = atoi(*argv + 1)) < 0) 82 goto negerr; 83 break; 84 case '-': 85 if ((numfields = atoi(*argv + 1)) < 0) { 86 negerr: (void)fprintf(stderr, 87 "uniq: negative field/char skip value.\n"); 88 usage(); 89 } 90 break; 91 } 92 93 switch(argc) { 94 case 0: 95 ifp = stdin; 96 ofp = stdout; 97 break; 98 case 1: 99 ifp = file(argv[0], "r"); 100 ofp = stdout; 101 break; 102 case 2: 103 ifp = file(argv[0], "r"); 104 ofp = file(argv[1], "w"); 105 break; 106 default: 107 usage(); 108 } 109 110 prevline = malloc(MAXLINELEN); 111 thisline = malloc(MAXLINELEN); 112 (void)fgets(prevline, MAXLINELEN, ifp); 113 114 while (fgets(thisline, MAXLINELEN, ifp)) { 115 /* if requested get the chosen fields + character offsets */ 116 if (numfields || numchars) { 117 t1 = skip(thisline); 118 t2 = skip(prevline); 119 } else { 120 t1 = thisline; 121 t2 = prevline; 122 } 123 124 /* if different, print; set previous to new value */ 125 if (strcmp(t1, t2)) { 126 show(ofp, prevline); 127 t1 = prevline; 128 prevline = thisline; 129 thisline = t1; 130 repeats = 0; 131 } 132 else 133 ++repeats; 134 } 135 show(ofp, prevline); 136 exit(0); 137 } 138 139 /* 140 * show -- 141 * output a line depending on the flags and number of repetitions 142 * of the line. 143 */ 144 show(ofp, str) 145 FILE *ofp; 146 char *str; 147 { 148 if (cflag) 149 (void)fprintf(ofp, "%4d %s", repeats + 1, str); 150 if (dflag && repeats || uflag && !repeats) 151 (void)fprintf(ofp, "%s", str); 152 } 153 154 char * 155 skip(str) 156 register char *str; 157 { 158 register int infield, nchars, nfields; 159 160 for (nfields = numfields, infield = 0; nfields && *str; ++str) 161 if (isspace(*str)) { 162 if (infield) { 163 infield = 0; 164 --nfields; 165 } 166 } else if (!infield) 167 infield = 1; 168 for (nchars = numchars; nchars-- && *str; ++str); 169 return(str); 170 } 171 172 FILE * 173 file(name, mode) 174 char *name, *mode; 175 { 176 FILE *fp; 177 178 if (!(fp = fopen(name, mode))) { 179 (void)fprintf(stderr, "uniq: can't open %s.\n", name); 180 exit(1); 181 } 182 return(fp); 183 } 184 185 usage() 186 { 187 (void)fprintf(stderr, 188 "usage: uniq [-c | -du] [- #fields] [+ #chars] [input [output]]\n"); 189 exit(1); 190 } 191