don't bother resolving onbld python module deps
[unleashed.git] / bin / uniq / uniq.c
blobae5d76cd24e08936688a5141afd19a08e2577402
1 /* $OpenBSD: uniq.c,v 1.26 2017/12/24 00:11:43 tb Exp $ */
2 /* $NetBSD: uniq.c,v 1.7 1995/08/31 22:03:48 jtc Exp $ */
4 /*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Case Larsen.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <locale.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <wchar.h>
46 #include <wctype.h>
48 #define MAXLINELEN (8 * 1024)
50 int cflag, dflag, iflag, uflag;
51 int numchars, numfields, repeats;
53 FILE *file(char *, char *);
54 void show(FILE *, char *);
55 char *skip(char *);
56 void obsolete(char *[]);
57 __dead void usage(void);
59 int
60 main(int argc, char *argv[])
62 char *t1, *t2;
63 FILE *ifp = NULL, *ofp = NULL;
64 int ch;
65 char *prevline, *thisline;
67 setlocale(LC_CTYPE, "");
69 if (pledge("stdio rpath wpath cpath", NULL) == -1)
70 err(1, "pledge");
72 obsolete(argv);
73 while ((ch = getopt(argc, argv, "cdf:is:u")) != -1) {
74 const char *errstr;
76 switch (ch) {
77 case 'c':
78 cflag = 1;
79 break;
80 case 'd':
81 dflag = 1;
82 break;
83 case 'f':
84 numfields = (int)strtonum(optarg, 0, INT_MAX,
85 &errstr);
86 if (errstr)
87 errx(1, "field skip value is %s: %s",
88 errstr, optarg);
89 break;
90 case 'i':
91 iflag = 1;
92 break;
93 case 's':
94 numchars = (int)strtonum(optarg, 0, INT_MAX,
95 &errstr);
96 if (errstr)
97 errx(1,
98 "character skip value is %s: %s",
99 errstr, optarg);
100 break;
101 case 'u':
102 uflag = 1;
103 break;
104 default:
105 usage();
109 argc -= optind;
110 argv += optind;
112 /* If neither -d nor -u are set, default is -d -u. */
113 if (!dflag && !uflag)
114 dflag = uflag = 1;
116 switch(argc) {
117 case 0:
118 ifp = stdin;
119 ofp = stdout;
120 break;
121 case 1:
122 ifp = file(argv[0], "r");
123 ofp = stdout;
124 break;
125 case 2:
126 ifp = file(argv[0], "r");
127 ofp = file(argv[1], "w");
128 break;
129 default:
130 usage();
133 if (pledge("stdio", NULL) == -1)
134 err(1, "pledge");
136 prevline = malloc(MAXLINELEN);
137 thisline = malloc(MAXLINELEN);
138 if (prevline == NULL || thisline == NULL)
139 err(1, "malloc");
141 if (fgets(prevline, MAXLINELEN, ifp) == NULL)
142 exit(0);
144 while (fgets(thisline, MAXLINELEN, ifp)) {
145 /* If requested get the chosen fields + character offsets. */
146 if (numfields || numchars) {
147 t1 = skip(thisline);
148 t2 = skip(prevline);
149 } else {
150 t1 = thisline;
151 t2 = prevline;
154 /* If different, print; set previous to new value. */
155 if ((iflag ? strcasecmp : strcmp)(t1, t2)) {
156 show(ofp, prevline);
157 t1 = prevline;
158 prevline = thisline;
159 thisline = t1;
160 repeats = 0;
161 } else
162 ++repeats;
164 show(ofp, prevline);
165 exit(0);
169 * show --
170 * Output a line depending on the flags and number of repetitions
171 * of the line.
173 void
174 show(FILE *ofp, char *str)
176 if ((dflag && repeats) || (uflag && !repeats)) {
177 if (cflag)
178 (void)fprintf(ofp, "%4d %s", repeats + 1, str);
179 else
180 (void)fprintf(ofp, "%s", str);
184 char *
185 skip(char *str)
187 wchar_t wc;
188 int nchars, nfields;
189 int len;
190 int field_started;
192 for (nfields = numfields; nfields && *str; nfields--) {
193 /* Skip one field, including preceding blanks. */
194 for (field_started = 0; *str != '\0'; str += len) {
195 if ((len = mbtowc(&wc, str, MB_CUR_MAX)) == -1) {
196 (void)mbtowc(NULL, NULL, MB_CUR_MAX);
197 wc = L'?';
198 len = 1;
200 if (iswblank(wc)) {
201 if (field_started)
202 break;
203 } else
204 field_started = 1;
208 /* Skip some additional characters. */
209 for (nchars = numchars; nchars-- && *str != '\0'; str += len)
210 if ((len = mblen(str, MB_CUR_MAX)) == -1)
211 len = 1;
213 return (str);
216 FILE *
217 file(char *name, char *mode)
219 FILE *fp;
221 if (strcmp(name, "-") == 0)
222 return(*mode == 'r' ? stdin : stdout);
223 if ((fp = fopen(name, mode)) == NULL)
224 err(1, "%s", name);
225 return (fp);
228 void
229 obsolete(char *argv[])
231 size_t len;
232 char *ap, *p, *start;
234 while ((ap = *++argv)) {
235 /* Return if "--" or not an option of any form. */
236 if (ap[0] != '-') {
237 if (ap[0] != '+')
238 return;
239 } else if (ap[1] == '-')
240 return;
241 if (!isdigit((unsigned char)ap[1]))
242 continue;
244 * Digit signifies an old-style option. Malloc space for dash,
245 * new option and argument.
247 len = strlen(ap) + 3;
248 if ((start = p = malloc(len)) == NULL)
249 err(1, "malloc");
250 *p++ = '-';
251 *p++ = ap[0] == '+' ? 's' : 'f';
252 (void)strlcpy(p, ap + 1, len - 2);
253 *argv = start;
257 __dead void
258 usage(void)
260 extern char *__progname;
262 (void)fprintf(stderr,
263 "usage: %s [-ci] [-d | -u] [-f fields] [-s chars] [input_file [output_file]]\n",
264 __progname);
265 exit(1);