did tedious stuff
[oweals/busybox.git] / uniq.c
1 /*
2  * Mini uniq implementation for busybox
3  *
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>
26 #include <string.h>
27 #include <errno.h>
28
29 static const char uniq_usage[] =
30 "haha\n"
31 ;
32
33 /* max chars in line */
34 #define UNIQ_MAX 4096
35
36 typedef void (Print)(FILE *, const char *);
37
38 typedef int (Decide)(const char *, const char *);
39
40 /* container for two lines to be compared */
41 typedef struct {
42     char    *a;
43     char    *b;
44     int     recurrence;
45     FILE    *in;
46     FILE    *out;
47     void    *func;
48 } Subject;
49
50 /* set up all the variables of a uniq operation */
51 static Subject *
52 subject_init(Subject *self, FILE *in, FILE *out, void *func)
53 {
54     self->a    = NULL;
55     self->b    = NULL;
56     self->in   = in;
57     self->out  = out;
58     self->func = func;
59     self->recurrence = 0;
60     return self;
61 }
62
63 /* point a and b to the appropriate lines;
64  * count the recurrences (if any) of a string;
65  */
66 static Subject *
67 subject_next(Subject *self)
68 {
69     /* tmp line holders */
70     static char line[2][UNIQ_MAX];
71     static int  alternator = 0;
72
73     if (fgets(line[alternator], UNIQ_MAX, self->in)) {
74         self->a = self->b;
75         self->b = line[alternator];
76         alternator ^= 1;
77         return self;
78     }
79
80     return NULL;
81 }
82
83 static Subject *
84 subject_last(Subject *self)
85 {
86     self->a = self->b;
87     self->b = NULL;
88     return self;
89 }
90
91 static Subject *
92 subject_study(Subject *self)
93 {
94     if (self->a == NULL) {
95         return self;
96     }
97     if (self->b == NULL) {
98         fprintf(self->out, "%s", self->a);
99         return self;
100     }
101     if (strcmp(self->a, self->b) == 0) {
102         self->recurrence++;
103     } else {
104         fprintf(self->out, "%s", self->a);
105         self->recurrence = 0;
106     }
107     return self;
108 }
109
110 static int
111 set_file_pointers(int schema, FILE **in, FILE **out, char **argv)
112 {
113     switch (schema) {
114         case 0:
115             *in = stdin;
116             *out = stdout;
117             break;
118         case 1:
119             *in = fopen(argv[0], "r");
120             *out = stdout;
121             break;
122         case 2:
123             *in = fopen(argv[0], "r");
124             *out = fopen(argv[1], "w");
125             break;
126     }
127     if (*in == NULL) {
128         fprintf(stderr, "uniq: %s: %s\n", argv[0], strerror(errno));
129         return errno;
130     }
131     if (*out == NULL) {
132         fprintf(stderr, "uniq: %s: %s\n", argv[1], strerror(errno));
133         return errno;
134     }
135     return 0;
136 }
137
138
139 /* one variable is the decision algo */
140 /* another variable is the printing algo */
141
142 /* I don't think I have to have more than a 1 line memory 
143    this is the one constant */
144
145 /* it seems like GNU/uniq only takes one or two files as an option */
146
147 /* ________________________________________________________________________ */
148 int
149 uniq_main(int argc, char **argv)
150 {
151     int     i;
152     char    opt;
153     FILE    *in, *out;
154     Subject s;
155
156     /* parse argv[] */
157     for (i = 1; i < argc; i++) {
158         if (argv[i][0] == '-') {
159             opt = argv[i][1];
160             switch (opt) {
161                 case '-':
162                 case 'h':
163                     usage(uniq_usage);
164                 default:
165                     usage(uniq_usage);
166             }
167         } else {
168             break;
169         }
170     }
171
172     /* 0 src: stdin; dst: stdout */
173     /* 1 src: file;  dst: stdout */
174     /* 2 src: file;  dst: file   */
175     if (set_file_pointers((argc - 1), &in, &out, &argv[i])) {
176         exit(1);
177     }
178
179     subject_init(&s, in, out, NULL);
180     while (subject_next(&s)) { 
181         subject_study(&s);
182     }
183     subject_last(&s);
184     subject_study(&s);
185
186     exit(0);
187 }
188
189 /* $Id: uniq.c,v 1.3 2000/01/06 23:49:21 beppu Exp $ */