xref: /original-bsd/usr.bin/uniq/uniq.c (revision 982436bd)
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