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