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