blob: 1e41eaacdf9418574b99d621c7a466f05eecb227 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
John Beppuabb47722000-01-06 00:48:21 +00002/*
Erik Andersen0b874ed2000-01-06 01:14:56 +00003 * Mini uniq implementation for busybox
John Beppuabb47722000-01-06 00:48:21 +00004 *
5 *
6 * Copyright (C) 1999 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>
John Beppu96f1f332000-01-06 23:49:21 +000027#include <string.h>
28#include <errno.h>
John Beppuabb47722000-01-06 00:48:21 +000029
30static const char uniq_usage[] =
Erik Andersene49d5ec2000-02-08 19:58:47 +000031 "uniq [OPTION]... [INPUT [OUTPUT]]\n"
32 "Discard all but one of successive identical lines from INPUT (or\n"
33 "standard input), writing to OUTPUT (or standard output).\n"
34 "\n"
35 "\t-h\tdisplay this help and exit\n"
36
37 "\n"
38 "A field is a run of whitespace, then non-whitespace characters.\n"
39 "Fields are skipped before chars.\n";
John Beppuabb47722000-01-06 00:48:21 +000040
41/* max chars in line */
42#define UNIQ_MAX 4096
43
Erik Andersene49d5ec2000-02-08 19:58:47 +000044typedef void (Print) (FILE *, const char *);
John Beppuabb47722000-01-06 00:48:21 +000045
Erik Andersene49d5ec2000-02-08 19:58:47 +000046typedef int (Decide) (const char *, const char *);
John Beppuabb47722000-01-06 00:48:21 +000047
48/* container for two lines to be compared */
49typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000050 char *a;
51 char *b;
52 int recurrence;
53 FILE *in;
54 FILE *out;
55 void *func;
John Beppuabb47722000-01-06 00:48:21 +000056} Subject;
57
58/* set up all the variables of a uniq operation */
Erik Andersene49d5ec2000-02-08 19:58:47 +000059static Subject *subject_init(Subject * self, FILE * in, FILE * out,
60 void *func)
John Beppuabb47722000-01-06 00:48:21 +000061{
Erik Andersene49d5ec2000-02-08 19:58:47 +000062 self->a = NULL;
63 self->b = NULL;
64 self->in = in;
65 self->out = out;
66 self->func = func;
67 self->recurrence = 0;
68 return self;
John Beppuabb47722000-01-06 00:48:21 +000069}
70
71/* point a and b to the appropriate lines;
72 * count the recurrences (if any) of a string;
73 */
Erik Andersene49d5ec2000-02-08 19:58:47 +000074static Subject *subject_next(Subject * self)
John Beppuabb47722000-01-06 00:48:21 +000075{
Erik Andersene49d5ec2000-02-08 19:58:47 +000076 /* tmp line holders */
77 static char line[2][UNIQ_MAX];
78 static int alternator = 0;
John Beppuabb47722000-01-06 00:48:21 +000079
Erik Andersene49d5ec2000-02-08 19:58:47 +000080 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 *subject_last(Subject * self)
91{
John Beppuabb47722000-01-06 00:48:21 +000092 self->a = self->b;
Erik Andersene49d5ec2000-02-08 19:58:47 +000093 self->b = NULL;
John Beppuabb47722000-01-06 00:48:21 +000094 return self;
John Beppuabb47722000-01-06 00:48:21 +000095}
96
Erik Andersene49d5ec2000-02-08 19:58:47 +000097static Subject *subject_study(Subject * self)
John Beppuabb47722000-01-06 00:48:21 +000098{
Erik Andersene49d5ec2000-02-08 19:58:47 +000099 if (self->a == NULL) {
100 return self;
101 }
102 if (self->b == NULL) {
103 fprintf(self->out, "%s", self->a);
104 return self;
105 }
106 if (strcmp(self->a, self->b) == 0) {
107 self->recurrence++;
108 } else {
109 fprintf(self->out, "%s", self->a);
110 self->recurrence = 0;
111 }
John Beppuabb47722000-01-06 00:48:21 +0000112 return self;
John Beppuabb47722000-01-06 00:48:21 +0000113}
114
John Beppu96f1f332000-01-06 23:49:21 +0000115static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000116set_file_pointers(int schema, FILE ** in, FILE ** out, char **argv)
John Beppu96f1f332000-01-06 23:49:21 +0000117{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 switch (schema) {
John Beppu96f1f332000-01-06 23:49:21 +0000119 case 0:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000120 *in = stdin;
121 *out = stdout;
122 break;
John Beppu96f1f332000-01-06 23:49:21 +0000123 case 1:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000124 *in = fopen(argv[0], "r");
125 *out = stdout;
126 break;
John Beppu96f1f332000-01-06 23:49:21 +0000127 case 2:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128 *in = fopen(argv[0], "r");
129 *out = fopen(argv[1], "w");
130 break;
131 }
132 if (*in == NULL) {
133 fprintf(stderr, "uniq: %s: %s\n", argv[0], strerror(errno));
134 return errno;
135 }
136 if (*out == NULL) {
137 fprintf(stderr, "uniq: %s: %s\n", argv[1], strerror(errno));
138 return errno;
139 }
140 return 0;
John Beppu96f1f332000-01-06 23:49:21 +0000141}
142
143
John Beppuabb47722000-01-06 00:48:21 +0000144/* one variable is the decision algo */
145/* another variable is the printing algo */
146
147/* I don't think I have to have more than a 1 line memory
148 this is the one constant */
149
150/* it seems like GNU/uniq only takes one or two files as an option */
151
152/* ________________________________________________________________________ */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000153int uniq_main(int argc, char **argv)
John Beppuabb47722000-01-06 00:48:21 +0000154{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000155 int i;
156 char opt;
157 FILE *in, *out;
158 Subject s;
John Beppuabb47722000-01-06 00:48:21 +0000159
Erik Andersene49d5ec2000-02-08 19:58:47 +0000160 /* parse argv[] */
161 for (i = 1; i < argc; i++) {
162 if (argv[i][0] == '-') {
163 opt = argv[i][1];
164 switch (opt) {
165 case '-':
166 case 'h':
167 usage(uniq_usage);
168 default:
169 usage(uniq_usage);
170 }
171 } else {
172 break;
173 }
John Beppuabb47722000-01-06 00:48:21 +0000174 }
John Beppuabb47722000-01-06 00:48:21 +0000175
Erik Andersene49d5ec2000-02-08 19:58:47 +0000176 /* 0 src: stdin; dst: stdout */
177 /* 1 src: file; dst: stdout */
178 /* 2 src: file; dst: file */
179 if (set_file_pointers((argc - 1), &in, &out, &argv[i])) {
180 exit(1);
181 }
John Beppu96f1f332000-01-06 23:49:21 +0000182
Erik Andersene49d5ec2000-02-08 19:58:47 +0000183 subject_init(&s, in, out, NULL);
184 while (subject_next(&s)) {
185 subject_study(&s);
186 }
187 subject_last(&s);
John Beppu96f1f332000-01-06 23:49:21 +0000188 subject_study(&s);
John Beppu96f1f332000-01-06 23:49:21 +0000189
Erik Andersene49d5ec2000-02-08 19:58:47 +0000190 exit(0);
John Beppuabb47722000-01-06 00:48:21 +0000191}
192
Erik Andersene49d5ec2000-02-08 19:58:47 +0000193/* $Id: uniq.c,v 1.7 2000/02/08 19:58:47 erik Exp $ */