Annotation of src/usr.bin/uniq/uniq.c, Revision 1.1.1.1
1.1 deraadt 1: /* $NetBSD: uniq.c,v 1.7 1995/08/31 22:03:48 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.3 (Berkeley) 5/4/95";
48: #endif
49: static char rcsid[] = "$NetBSD: uniq.c,v 1.7 1995/08/31 22:03:48 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: #include <unistd.h>
58:
59: #define MAXLINELEN (8 * 1024)
60:
61: int cflag, dflag, uflag;
62: int numchars, numfields, repeats;
63:
64: void err __P((const char *, ...));
65: FILE *file __P((char *, char *));
66: void show __P((FILE *, char *));
67: char *skip __P((char *));
68: void obsolete __P((char *[]));
69: void usage __P((void));
70:
71: int
72: main (argc, argv)
73: int argc;
74: char *argv[];
75: {
76: register char *t1, *t2;
77: FILE *ifp, *ofp;
78: int ch;
79: char *prevline, *thisline, *p;
80:
81: obsolete(argv);
82: while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF)
83: switch (ch) {
84: case '-':
85: --optind;
86: goto done;
87: case 'c':
88: cflag = 1;
89: break;
90: case 'd':
91: dflag = 1;
92: break;
93: case 'f':
94: numfields = strtol(optarg, &p, 10);
95: if (numfields < 0 || *p)
96: err("illegal field skip value: %s", optarg);
97: break;
98: case 's':
99: numchars = strtol(optarg, &p, 10);
100: if (numchars < 0 || *p)
101: err("illegal character skip value: %s", optarg);
102: break;
103: case 'u':
104: uflag = 1;
105: break;
106: case '?':
107: default:
108: usage();
109: }
110:
111: done: argc -= optind;
112: argv +=optind;
113:
114: /* If no flags are set, default is -d -u. */
115: if (cflag) {
116: if (dflag || uflag)
117: usage();
118: } else if (!dflag && !uflag)
119: dflag = uflag = 1;
120:
121: switch(argc) {
122: case 0:
123: ifp = stdin;
124: ofp = stdout;
125: break;
126: case 1:
127: ifp = file(argv[0], "r");
128: ofp = stdout;
129: break;
130: case 2:
131: ifp = file(argv[0], "r");
132: ofp = file(argv[1], "w");
133: break;
134: default:
135: usage();
136: }
137:
138: prevline = malloc(MAXLINELEN);
139: thisline = malloc(MAXLINELEN);
140: if (prevline == NULL || thisline == NULL)
141: err("%s", strerror(errno));
142:
143: if (fgets(prevline, MAXLINELEN, ifp) == NULL)
144: exit(0);
145:
146: while (fgets(thisline, MAXLINELEN, ifp)) {
147: /* If requested get the chosen fields + character offsets. */
148: if (numfields || numchars) {
149: t1 = skip(thisline);
150: t2 = skip(prevline);
151: } else {
152: t1 = thisline;
153: t2 = prevline;
154: }
155:
156: /* If different, print; set previous to new value. */
157: if (strcmp(t1, t2)) {
158: show(ofp, prevline);
159: t1 = prevline;
160: prevline = thisline;
161: thisline = t1;
162: repeats = 0;
163: } else
164: ++repeats;
165: }
166: show(ofp, prevline);
167: exit(0);
168: }
169:
170: /*
171: * show --
172: * Output a line depending on the flags and number of repetitions
173: * of the line.
174: */
175: void
176: show(ofp, str)
177: FILE *ofp;
178: char *str;
179: {
180:
181: if (cflag && *str)
182: (void)fprintf(ofp, "%4d %s", repeats + 1, str);
183: if (dflag && repeats || uflag && !repeats)
184: (void)fprintf(ofp, "%s", str);
185: }
186:
187: char *
188: skip(str)
189: register char *str;
190: {
191: register int infield, nchars, nfields;
192:
193: for (nfields = numfields, infield = 0; nfields && *str; ++str)
194: if (isspace(*str)) {
195: if (infield) {
196: infield = 0;
197: --nfields;
198: }
199: } else if (!infield)
200: infield = 1;
201: for (nchars = numchars; nchars-- && *str; ++str);
202: return(str);
203: }
204:
205: FILE *
206: file(name, mode)
207: char *name, *mode;
208: {
209: FILE *fp;
210:
211: if ((fp = fopen(name, mode)) == NULL)
212: err("%s: %s", name, strerror(errno));
213: return(fp);
214: }
215:
216: void
217: obsolete(argv)
218: char *argv[];
219: {
220: int len;
221: char *ap, *p, *start;
222:
223: while (ap = *++argv) {
224: /* Return if "--" or not an option of any form. */
225: if (ap[0] != '-') {
226: if (ap[0] != '+')
227: return;
228: } else if (ap[1] == '-')
229: return;
230: if (!isdigit(ap[1]))
231: continue;
232: /*
233: * Digit signifies an old-style option. Malloc space for dash,
234: * new option and argument.
235: */
236: len = strlen(ap);
237: if ((start = p = malloc(len + 3)) == NULL)
238: err("%s", strerror(errno));
239: *p++ = '-';
240: *p++ = ap[0] == '+' ? 's' : 'f';
241: (void)strcpy(p, ap + 1);
242: *argv = start;
243: }
244: }
245:
246: void
247: usage()
248: {
249: (void)fprintf(stderr,
250: "usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n");
251: exit(1);
252: }
253:
254: #if __STDC__
255: #include <stdarg.h>
256: #else
257: #include <varargs.h>
258: #endif
259:
260: void
261: #if __STDC__
262: err(const char *fmt, ...)
263: #else
264: err(fmt, va_alist)
265: char *fmt;
266: va_dcl
267: #endif
268: {
269: va_list ap;
270: #if __STDC__
271: va_start(ap, fmt);
272: #else
273: va_start(ap);
274: #endif
275: (void)fprintf(stderr, "uniq: ");
276: (void)vfprintf(stderr, fmt, ap);
277: va_end(ap);
278: (void)fprintf(stderr, "\n");
279: exit(1);
280: /* NOTREACHED */
281: }