blob: 034ea316e2b6a02647c7b6db5c1d4c198f51466e [file] [log] [blame]
John Beppuabb47722000-01-06 00:48:21 +00001/*
Erik Andersen0b874ed2000-01-06 01:14:56 +00002 * Mini uniq implementation for busybox
John Beppuabb47722000-01-06 00:48:21 +00003 *
4 *
5 * Copyright (C) 1999 by Lineo, inc.
6 * Written by John Beppu <beppu@lineo.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "internal.h"
25#include <stdio.h>
John Beppu96f1f332000-01-06 23:49:21 +000026#include <string.h>
27#include <errno.h>
John Beppuabb47722000-01-06 00:48:21 +000028
29static const char uniq_usage[] =
John Beppu9d831652000-01-07 01:57:32 +000030"Usage: uniq [OPTION]... [INPUT [OUTPUT]]\n"
31"Discard all but one of successive identical lines from INPUT (or\n"
32"standard input), writing to OUTPUT (or standard output).\n"
33"\n"
34"\t-h\tdisplay this help and exit\n"
35"\n"
36"A field is a run of whitespace, then non-whitespace characters.\n"
37"Fields are skipped before chars.\n"
John Beppuabb47722000-01-06 00:48:21 +000038;
39
40/* max chars in line */
41#define UNIQ_MAX 4096
42
43typedef void (Print)(FILE *, const char *);
44
45typedef int (Decide)(const char *, const char *);
46
47/* container for two lines to be compared */
48typedef struct {
49 char *a;
50 char *b;
51 int recurrence;
52 FILE *in;
53 FILE *out;
54 void *func;
55} Subject;
56
57/* set up all the variables of a uniq operation */
58static Subject *
59subject_init(Subject *self, FILE *in, FILE *out, void *func)
60{
61 self->a = NULL;
62 self->b = NULL;
63 self->in = in;
64 self->out = out;
65 self->func = func;
66 self->recurrence = 0;
67 return self;
68}
69
70/* point a and b to the appropriate lines;
71 * count the recurrences (if any) of a string;
72 */
73static Subject *
74subject_next(Subject *self)
75{
76 /* tmp line holders */
77 static char line[2][UNIQ_MAX];
78 static int alternator = 0;
79
80 if (fgets(line[alternator], UNIQ_MAX, self->in)) {
81 self->a = self->b;
82 self->b = line[alternator];
83 alternator ^= 1;
84 return self;
85 }
86
87 return NULL;
88}
89
90static Subject *
91subject_last(Subject *self)
92{
93 self->a = self->b;
94 self->b = NULL;
95 return self;
96}
97
98static Subject *
99subject_study(Subject *self)
100{
101 if (self->a == NULL) {
102 return self;
103 }
104 if (self->b == NULL) {
105 fprintf(self->out, "%s", self->a);
106 return self;
107 }
108 if (strcmp(self->a, self->b) == 0) {
109 self->recurrence++;
110 } else {
111 fprintf(self->out, "%s", self->a);
112 self->recurrence = 0;
113 }
114 return self;
115}
116
John Beppu96f1f332000-01-06 23:49:21 +0000117static int
118set_file_pointers(int schema, FILE **in, FILE **out, char **argv)
119{
120 switch (schema) {
121 case 0:
122 *in = stdin;
123 *out = stdout;
124 break;
125 case 1:
126 *in = fopen(argv[0], "r");
127 *out = stdout;
128 break;
129 case 2:
130 *in = fopen(argv[0], "r");
131 *out = fopen(argv[1], "w");
132 break;
133 }
134 if (*in == NULL) {
135 fprintf(stderr, "uniq: %s: %s\n", argv[0], strerror(errno));
136 return errno;
137 }
138 if (*out == NULL) {
139 fprintf(stderr, "uniq: %s: %s\n", argv[1], strerror(errno));
140 return errno;
141 }
142 return 0;
143}
144
145
John Beppuabb47722000-01-06 00:48:21 +0000146/* one variable is the decision algo */
147/* another variable is the printing algo */
148
149/* I don't think I have to have more than a 1 line memory
150 this is the one constant */
151
152/* it seems like GNU/uniq only takes one or two files as an option */
153
154/* ________________________________________________________________________ */
155int
156uniq_main(int argc, char **argv)
157{
158 int i;
159 char opt;
160 FILE *in, *out;
161 Subject s;
162
John Beppuabb47722000-01-06 00:48:21 +0000163 /* parse argv[] */
164 for (i = 1; i < argc; i++) {
165 if (argv[i][0] == '-') {
166 opt = argv[i][1];
167 switch (opt) {
Erik Andersen0b874ed2000-01-06 01:14:56 +0000168 case '-':
John Beppuabb47722000-01-06 00:48:21 +0000169 case 'h':
170 usage(uniq_usage);
171 default:
172 usage(uniq_usage);
173 }
174 } else {
175 break;
176 }
177 }
178
John Beppu96f1f332000-01-06 23:49:21 +0000179 /* 0 src: stdin; dst: stdout */
180 /* 1 src: file; dst: stdout */
181 /* 2 src: file; dst: file */
182 if (set_file_pointers((argc - 1), &in, &out, &argv[i])) {
183 exit(1);
184 }
185
186 subject_init(&s, in, out, NULL);
187 while (subject_next(&s)) {
188 subject_study(&s);
189 }
190 subject_last(&s);
191 subject_study(&s);
192
John Beppuabb47722000-01-06 00:48:21 +0000193 exit(0);
194}
195
John Beppu9d831652000-01-07 01:57:32 +0000196/* $Id: uniq.c,v 1.4 2000/01/07 01:57:32 beppu Exp $ */