uniq.c revision 1.6 1 /* $NetBSD: uniq.c,v 1.6 1994/12/06 07:51:17 jtc Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Case Larsen.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char copyright[] =
41 "@(#) Copyright (c) 1989, 1993\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)uniq.c 8.1 (Berkeley) 6/6/93";
48 #endif
49 static char rcsid[] = "$NetBSD: uniq.c,v 1.6 1994/12/06 07:51:17 jtc Exp $";
50 #endif /* not lint */
51
52 #include <errno.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 #define MAXLINELEN (8 * 1024)
59
60 int cflag, dflag, uflag;
61 int numchars, numfields, repeats;
62
63 void err __P((const char *, ...));
64 FILE *file __P((char *, char *));
65 void show __P((FILE *, char *));
66 char *skip __P((char *));
67 void obsolete __P((char *[]));
68 void usage __P((void));
69
70 int
71 main (argc, argv)
72 int argc;
73 char *argv[];
74 {
75 register char *t1, *t2;
76 FILE *ifp, *ofp;
77 int ch;
78 char *prevline, *thisline, *p;
79
80 obsolete(argv);
81 while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF)
82 switch (ch) {
83 case '-':
84 --optind;
85 goto done;
86 case 'c':
87 cflag = 1;
88 break;
89 case 'd':
90 dflag = 1;
91 break;
92 case 'f':
93 numfields = strtol(optarg, &p, 10);
94 if (numfields < 0 || *p)
95 err("illegal field skip value: %s", optarg);
96 break;
97 case 's':
98 numchars = strtol(optarg, &p, 10);
99 if (numchars < 0 || *p)
100 err("illegal character skip value: %s", optarg);
101 break;
102 case 'u':
103 uflag = 1;
104 break;
105 case '?':
106 default:
107 usage();
108 }
109
110 done: argc -= optind;
111 argv +=optind;
112
113 /* If no flags are set, default is -d -u. */
114 if (cflag) {
115 if (dflag || uflag)
116 usage();
117 } else if (!dflag && !uflag)
118 dflag = uflag = 1;
119
120 switch(argc) {
121 case 0:
122 ifp = stdin;
123 ofp = stdout;
124 break;
125 case 1:
126 ifp = file(argv[0], "r");
127 ofp = stdout;
128 break;
129 case 2:
130 ifp = file(argv[0], "r");
131 ofp = file(argv[1], "w");
132 break;
133 default:
134 usage();
135 }
136
137 prevline = malloc(MAXLINELEN);
138 thisline = malloc(MAXLINELEN);
139 if (prevline == NULL || thisline == NULL)
140 err("%s", strerror(errno));
141
142 if (fgets(prevline, MAXLINELEN, ifp) == NULL)
143 exit(0);
144
145 while (fgets(thisline, MAXLINELEN, ifp)) {
146 /* If requested get the chosen fields + character offsets. */
147 if (numfields || numchars) {
148 t1 = skip(thisline);
149 t2 = skip(prevline);
150 } else {
151 t1 = thisline;
152 t2 = prevline;
153 }
154
155 /* If different, print; set previous to new value. */
156 if (strcmp(t1, t2)) {
157 show(ofp, prevline);
158 t1 = prevline;
159 prevline = thisline;
160 thisline = t1;
161 repeats = 0;
162 } else
163 ++repeats;
164 }
165 show(ofp, prevline);
166 exit(0);
167 }
168
169 /*
170 * show --
171 * Output a line depending on the flags and number of repetitions
172 * of the line.
173 */
174 void
175 show(ofp, str)
176 FILE *ofp;
177 char *str;
178 {
179 if (cflag)
180 (void)fprintf(ofp, "%4d %s", repeats + 1, str);
181 if (dflag && repeats || uflag && !repeats)
182 (void)fprintf(ofp, "%s", str);
183 }
184
185 char *
186 skip(str)
187 register char *str;
188 {
189 register int infield, nchars, nfields;
190
191 for (nfields = numfields, infield = 0; nfields && *str; ++str)
192 if (isspace(*str)) {
193 if (infield) {
194 infield = 0;
195 --nfields;
196 }
197 } else if (!infield)
198 infield = 1;
199 for (nchars = numchars; nchars-- && *str; ++str);
200 return(str);
201 }
202
203 FILE *
204 file(name, mode)
205 char *name, *mode;
206 {
207 FILE *fp;
208
209 if ((fp = fopen(name, mode)) == NULL)
210 err("%s: %s", name, strerror(errno));
211 return(fp);
212 }
213
214 void
215 obsolete(argv)
216 char *argv[];
217 {
218 int len;
219 char *ap, *p, *start;
220
221 while (ap = *++argv) {
222 /* Return if "--" or not an option of any form. */
223 if (ap[0] != '-') {
224 if (ap[0] != '+')
225 return;
226 } else if (ap[1] == '-')
227 return;
228 if (!isdigit(ap[1]))
229 continue;
230 /*
231 * Digit signifies an old-style option. Malloc space for dash,
232 * new option and argument.
233 */
234 len = strlen(ap);
235 if ((start = p = malloc(len + 3)) == NULL)
236 err("%s", strerror(errno));
237 *p++ = '-';
238 *p++ = ap[0] == '+' ? 's' : 'f';
239 (void)strcpy(p, ap + 1);
240 *argv = start;
241 }
242 }
243
244 void
245 usage()
246 {
247 (void)fprintf(stderr,
248 "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n");
249 exit(1);
250 }
251
252 #if __STDC__
253 #include <stdarg.h>
254 #else
255 #include <varargs.h>
256 #endif
257
258 void
259 #if __STDC__
260 err(const char *fmt, ...)
261 #else
262 err(fmt, va_alist)
263 char *fmt;
264 va_dcl
265 #endif
266 {
267 va_list ap;
268 #if __STDC__
269 va_start(ap, fmt);
270 #else
271 va_start(ap);
272 #endif
273 (void)fprintf(stderr, "uniq: ");
274 (void)vfprintf(stderr, fmt, ap);
275 va_end(ap);
276 (void)fprintf(stderr, "\n");
277 exit(1);
278 /* NOTREACHED */
279 }
280