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