1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. 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 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)uniq.c 8.2 (Berkeley) 04/28/95"; 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 if (prevline == NULL || thisline == NULL) 109 err("%s", strerror(errno)); 110 111 if (fgets(prevline, MAXLINELEN, ifp) == NULL) 112 exit(0); 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 } else 132 ++repeats; 133 } 134 show(ofp, prevline); 135 exit(0); 136 } 137 138 /* 139 * show -- 140 * Output a line depending on the flags and number of repetitions 141 * of the line. 142 */ 143 void 144 show(ofp, str) 145 FILE *ofp; 146 char *str; 147 { 148 149 if (cflag && *str) 150 (void)fprintf(ofp, "%4d %s", repeats + 1, str); 151 if (dflag && repeats || uflag && !repeats) 152 (void)fprintf(ofp, "%s", str); 153 } 154 155 char * 156 skip(str) 157 register char *str; 158 { 159 register int infield, nchars, nfields; 160 161 for (nfields = numfields, infield = 0; nfields && *str; ++str) 162 if (isspace(*str)) { 163 if (infield) { 164 infield = 0; 165 --nfields; 166 } 167 } else if (!infield) 168 infield = 1; 169 for (nchars = numchars; nchars-- && *str; ++str); 170 return(str); 171 } 172 173 FILE * 174 file(name, mode) 175 char *name, *mode; 176 { 177 FILE *fp; 178 179 if ((fp = fopen(name, mode)) == NULL) 180 err("%s: %s", name, strerror(errno)); 181 return(fp); 182 } 183 184 void 185 obsolete(argv) 186 char *argv[]; 187 { 188 int len; 189 char *ap, *p, *start; 190 191 while (ap = *++argv) { 192 /* Return if "--" or not an option of any form. */ 193 if (ap[0] != '-') { 194 if (ap[0] != '+') 195 return; 196 } else if (ap[1] == '-') 197 return; 198 if (!isdigit(ap[1])) 199 continue; 200 /* 201 * Digit signifies an old-style option. Malloc space for dash, 202 * new option and argument. 203 */ 204 len = strlen(ap); 205 if ((start = p = malloc(len + 3)) == NULL) 206 err("%s", strerror(errno)); 207 *p++ = '-'; 208 *p++ = ap[0] == '+' ? 's' : 'f'; 209 (void)strcpy(p, ap + 1); 210 *argv = start; 211 } 212 } 213 214 void 215 usage() 216 { 217 (void)fprintf(stderr, 218 "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n"); 219 exit(1); 220 } 221 222 #if __STDC__ 223 #include <stdarg.h> 224 #else 225 #include <varargs.h> 226 #endif 227 228 void 229 #if __STDC__ 230 err(const char *fmt, ...) 231 #else 232 err(fmt, va_alist) 233 char *fmt; 234 va_dcl 235 #endif 236 { 237 va_list ap; 238 #if __STDC__ 239 va_start(ap, fmt); 240 #else 241 va_start(ap); 242 #endif 243 (void)fprintf(stderr, "uniq: "); 244 (void)vfprintf(stderr, fmt, ap); 245 va_end(ap); 246 (void)fprintf(stderr, "\n"); 247 exit(1); 248 /* NOTREACHED */ 249 } 250