xref: /original-bsd/usr.bin/uniq/uniq.c (revision 50dd0bba)
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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)uniq.c	5.2 (Berkeley) 06/01/90";
19 #endif /* not lint */
20 
21 #include <stdio.h>
22 #include <ctype.h>
23 
24 int cflag, dflag, uflag;
25 int numchars, numfields, repeats;
26 
27 #define	MAXLINELEN	(2048 + 1)
28 
29 main (argc,argv)
30 	int argc;
31 	char **argv;
32 {
33 	extern int optind;
34 	FILE *ifp, *ofp, *file();
35 	int ch;
36 	register char *t1, *t2;
37 	char *prevline, *thisline, *malloc(), *skip();
38 
39 	while ((ch = getopt(argc, argv, "-cdu123456789")) != EOF)
40 		switch (ch) {
41 		case '-':
42 			--optind;
43 			goto done;
44 		case 'c':
45 			cflag = 1;
46 			break;
47 		case 'd':
48 			dflag = 1;
49 			break;
50 		case 'u':
51 			uflag = 1;
52 			break;
53 		/*
54 		 * since -n is a valid option that could be picked up by
55 		 * getopt, but is better handled by the +n and -n code, we
56 		 * break out.
57 		 */
58 		case '1': case '2': case '3': case '4':
59 		case '5': case '6': case '7': case '8': case '9':
60 			--optind;
61 			goto done;
62 		case '?':
63 		default:
64 			usage();
65 	}
66 
67 done:	argc -= optind;
68 	argv +=optind;
69 
70 	/* if no flags are set, default is -d -u */
71 	if (cflag) {
72 		if (dflag || uflag)
73 			usage();
74 	} else if (!dflag && !uflag)
75 		dflag = uflag = 1;
76 
77 	/* because of the +, getopt is messed up */
78 	for (; **argv == '+' || **argv == '-'; ++argv, --argc)
79 		switch (**argv) {
80 		case '+':
81 			if ((numchars = atoi(*argv + 1)) < 0)
82 				goto negerr;
83 			break;
84 		case '-':
85 			if ((numfields = atoi(*argv + 1)) < 0) {
86 negerr:				(void)fprintf(stderr,
87 				    "uniq: negative field/char skip value.\n");
88 				usage();
89 			}
90 			break;
91 		}
92 
93 	switch(argc) {
94 	case 0:
95 		ifp = stdin;
96 		ofp = stdout;
97 		break;
98 	case 1:
99 		ifp = file(argv[0], "r");
100 		ofp = stdout;
101 		break;
102 	case 2:
103 		ifp = file(argv[0], "r");
104 		ofp = file(argv[1], "w");
105 		break;
106 	default:
107 		usage();
108 	}
109 
110 	prevline = malloc(MAXLINELEN);
111 	thisline = malloc(MAXLINELEN);
112 	(void)fgets(prevline, MAXLINELEN, ifp);
113 
114 	while (fgets(thisline, MAXLINELEN, ifp)) {
115 		/* if requested get the chosen fields + character offsets */
116 		if (numfields || numchars) {
117 			t1 = skip(thisline);
118 			t2 = skip(prevline);
119 		} else {
120 			t1 = thisline;
121 			t2 = prevline;
122 		}
123 
124 		/* if different, print; set previous to new value */
125 		if (strcmp(t1, t2)) {
126 			show(ofp, prevline);
127 			t1 = prevline;
128 			prevline = thisline;
129 			thisline = t1;
130 			repeats = 0;
131 		}
132 		else
133 			++repeats;
134 	}
135 	show(ofp, prevline);
136 	exit(0);
137 }
138 
139 /*
140  * show --
141  *	output a line depending on the flags and number of repetitions
142  *	of the line.
143  */
144 show(ofp, str)
145 	FILE *ofp;
146 	char *str;
147 {
148 	if (cflag)
149 		(void)fprintf(ofp, "%4d %s", repeats + 1, str);
150 	if (dflag && repeats || uflag && !repeats)
151 		(void)fprintf(ofp, "%s", str);
152 }
153 
154 char *
155 skip(str)
156 	register char *str;
157 {
158 	register int infield, nchars, nfields;
159 
160 	for (nfields = numfields, infield = 0; nfields && *str; ++str)
161 		if (isspace(*str)) {
162 			if (infield) {
163 				infield = 0;
164 				--nfields;
165 			}
166 		} else if (!infield)
167 			infield = 1;
168 	for (nchars = numchars; nchars-- && *str; ++str);
169 	return(str);
170 }
171 
172 FILE *
173 file(name, mode)
174 	char *name, *mode;
175 {
176 	FILE *fp;
177 
178 	if (!(fp = fopen(name, mode))) {
179 		(void)fprintf(stderr, "uniq: can't open %s.\n", name);
180 		exit(1);
181 	}
182 	return(fp);
183 }
184 
185 usage()
186 {
187 	(void)fprintf(stderr,
188 	    "usage: uniq [-c | -du] [- #fields] [+ #chars] [input [output]]\n");
189 	exit(1);
190 }
191