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.5 (Berkeley) 07/15/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 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 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)) == NULL) 179 err("%s: %s", name, strerror(errno)); 180 return(fp); 181 } 182 183 void 184 obsolete(argv) 185 char *argv[]; 186 { 187 int len; 188 char *ap, *p, *start; 189 190 while (ap = *++argv) { 191 /* Return if "--" or not an option of any form. */ 192 if (ap[0] != '-') { 193 if (ap[0] != '+') 194 return; 195 } else if (ap[1] == '-') 196 return; 197 if (!isdigit(ap[1])) 198 continue; 199 /* 200 * Digit signifies an old-style option. Malloc space for dash, 201 * new option and argument. 202 */ 203 len = strlen(ap); 204 if ((start = p = malloc(len + 3)) == NULL) 205 err("%s", strerror(errno)); 206 *p++ = '-'; 207 *p++ = ap[0] == '+' ? 's' : 'f'; 208 (void)strcpy(p, ap + 1); 209 *argv = start; 210 } 211 } 212 213 void 214 usage() 215 { 216 (void)fprintf(stderr, 217 "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n"); 218 exit(1); 219 } 220 221 #if __STDC__ 222 #include <stdarg.h> 223 #else 224 #include <varargs.h> 225 #endif 226 227 void 228 #if __STDC__ 229 err(const char *fmt, ...) 230 #else 231 err(fmt, va_alist) 232 char *fmt; 233 va_dcl 234 #endif 235 { 236 va_list ap; 237 #if __STDC__ 238 va_start(ap, fmt); 239 #else 240 va_start(ap); 241 #endif 242 (void)fprintf(stderr, "uniq: "); 243 (void)vfprintf(stderr, fmt, ap); 244 va_end(ap); 245 (void)fprintf(stderr, "\n"); 246 exit(1); 247 /* NOTREACHED */ 248 } 249