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