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.4 (Berkeley) 01/09/92"; 19 #endif /* not lint */ 20 21 #include <errno.h> 22 #include <stdio.h> 23 #include <ctype.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #define MAXLINELEN (8 * 1024) 28 29 int cflag, dflag, uflag; 30 int numchars, numfields, repeats; 31 32 void err __P((const char *, ...)); 33 FILE *file __P((char *, char *)); 34 void show __P((FILE *, char *)); 35 char *skip __P((char *)); 36 void obsolete __P((char *[])); 37 void usage __P((void)); 38 39 int 40 main (argc, argv) 41 int argc; 42 char *argv[]; 43 { 44 register char *t1, *t2; 45 FILE *ifp, *ofp; 46 int ch; 47 char *prevline, *thisline, *p; 48 49 obsolete(argv); 50 while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF) 51 switch (ch) { 52 case '-': 53 --optind; 54 goto done; 55 case 'c': 56 cflag = 1; 57 break; 58 case 'd': 59 dflag = 1; 60 break; 61 case 'f': 62 numfields = strtol(optarg, &p, 10); 63 if (numfields < 0 || *p) 64 err("illegal field skip value: %s", optarg); 65 break; 66 case 's': 67 numchars = strtol(optarg, &p, 10); 68 if (numchars < 0 || *p) 69 err("illegal character skip value: %s", optarg); 70 break; 71 case 'u': 72 uflag = 1; 73 break; 74 case '?': 75 default: 76 usage(); 77 } 78 79 done: argc -= optind; 80 argv +=optind; 81 82 /* If no flags are set, default is -d -u. */ 83 if (cflag) { 84 if (dflag || uflag) 85 usage(); 86 } else if (!dflag && !uflag) 87 dflag = uflag = 1; 88 89 switch(argc) { 90 case 0: 91 ifp = stdin; 92 ofp = stdout; 93 break; 94 case 1: 95 ifp = file(argv[0], "r"); 96 ofp = stdout; 97 break; 98 case 2: 99 ifp = file(argv[0], "r"); 100 ofp = file(argv[1], "w"); 101 break; 102 default: 103 usage(); 104 } 105 106 prevline = malloc(MAXLINELEN); 107 thisline = malloc(MAXLINELEN); 108 (void)fgets(prevline, MAXLINELEN, ifp); 109 110 while (fgets(thisline, MAXLINELEN, ifp)) { 111 /* If requested get the chosen fields + character offsets. */ 112 if (numfields || numchars) { 113 t1 = skip(thisline); 114 t2 = skip(prevline); 115 } else { 116 t1 = thisline; 117 t2 = prevline; 118 } 119 120 /* If different, print; set previous to new value. */ 121 if (strcmp(t1, t2)) { 122 show(ofp, prevline); 123 t1 = prevline; 124 prevline = thisline; 125 thisline = t1; 126 repeats = 0; 127 } else 128 ++repeats; 129 } 130 show(ofp, prevline); 131 exit(0); 132 } 133 134 /* 135 * show -- 136 * Output a line depending on the flags and number of repetitions 137 * of the line. 138 */ 139 void 140 show(ofp, str) 141 FILE *ofp; 142 char *str; 143 { 144 if (cflag) 145 (void)fprintf(ofp, "%4d %s", repeats + 1, str); 146 if (dflag && repeats || uflag && !repeats) 147 (void)fprintf(ofp, "%s", str); 148 } 149 150 char * 151 skip(str) 152 register char *str; 153 { 154 register int infield, nchars, nfields; 155 156 for (nfields = numfields, infield = 0; nfields && *str; ++str) 157 if (isspace(*str)) { 158 if (infield) { 159 infield = 0; 160 --nfields; 161 } 162 } else if (!infield) 163 infield = 1; 164 for (nchars = numchars; nchars-- && *str; ++str); 165 return(str); 166 } 167 168 FILE * 169 file(name, mode) 170 char *name, *mode; 171 { 172 FILE *fp; 173 174 if ((fp = fopen(name, mode)) == NULL) 175 err("%s: %s", name, strerror(errno)); 176 return(fp); 177 } 178 179 void 180 obsolete(argv) 181 char *argv[]; 182 { 183 int len; 184 char *ap, *p, *start; 185 186 while (ap = *++argv) { 187 /* Return if "--" or not an option of any form. */ 188 if (ap[0] != '-') { 189 if (ap[0] != '+') 190 return; 191 } else if (ap[1] == '-') 192 return; 193 if (!isdigit(ap[1])) 194 continue; 195 /* 196 * Digit signifies an old-style option. Malloc space for dash, 197 * new option and argument. 198 */ 199 len = strlen(ap); 200 if ((start = p = malloc(len + 3)) == NULL) 201 err("%s", strerror(errno)); 202 *p++ = '-'; 203 *p++ = ap[0] == '+' ? 's' : 'f'; 204 (void)strcpy(p, ap + 1); 205 *argv = start; 206 } 207 } 208 209 void 210 usage() 211 { 212 (void)fprintf(stderr, 213 "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n"); 214 exit(1); 215 } 216 217 #if __STDC__ 218 #include <stdarg.h> 219 #else 220 #include <varargs.h> 221 #endif 222 223 void 224 #if __STDC__ 225 err(const char *fmt, ...) 226 #else 227 err(fmt, va_alist) 228 char *fmt; 229 va_dcl 230 #endif 231 { 232 va_list ap; 233 #if __STDC__ 234 va_start(ap, fmt); 235 #else 236 va_start(ap); 237 #endif 238 (void)fprintf(stderr, "uniq: "); 239 (void)vfprintf(stderr, fmt, ap); 240 va_end(ap); 241 (void)fprintf(stderr, "\n"); 242 exit(1); 243 /* NOTREACHED */ 244 } 245