blob: 0324856fd97ac360404a5b00591480a816ae7451 [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 *
Erik Andersen61677fe2000-04-13 01:18:56 +00006 * Copyright (C) 1999,2000 by Lineo, inc.
John Beppuabb47722000-01-06 00:48:21 +00007 * 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 Andersene5b6c7d2000-04-17 16:16:10 +000031 "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";
John Beppuabb47722000-01-06 00:48:21 +000034
35/* max chars in line */
36#define UNIQ_MAX 4096
37
Erik Andersene49d5ec2000-02-08 19:58:47 +000038typedef void (Print) (FILE *, const char *);
John Beppuabb47722000-01-06 00:48:21 +000039
Erik Andersene49d5ec2000-02-08 19:58:47 +000040typedef int (Decide) (const char *, const char *);
John Beppuabb47722000-01-06 00:48:21 +000041
42/* container for two lines to be compared */
43typedef struct {
Erik Andersene49d5ec2000-02-08 19:58:47 +000044 char *a;
45 char *b;
46 int recurrence;
47 FILE *in;
48 FILE *out;
49 void *func;
John Beppuabb47722000-01-06 00:48:21 +000050} Subject;
51
52/* set up all the variables of a uniq operation */
Erik Andersene49d5ec2000-02-08 19:58:47 +000053static Subject *subject_init(Subject * self, FILE * in, FILE * out,
54 void *func)
John Beppuabb47722000-01-06 00:48:21 +000055{
Erik Andersene49d5ec2000-02-08 19:58:47 +000056 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;
John Beppuabb47722000-01-06 00:48:21 +000063}
64
65/* point a and b to the appropriate lines;
66 * count the recurrences (if any) of a string;
67 */
Erik Andersene49d5ec2000-02-08 19:58:47 +000068static Subject *subject_next(Subject * self)
John Beppuabb47722000-01-06 00:48:21 +000069{
Erik Andersene49d5ec2000-02-08 19:58:47 +000070 /* tmp line holders */
71 static char line[2][UNIQ_MAX];
72 static int alternator = 0;
John Beppuabb47722000-01-06 00:48:21 +000073
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 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
84static Subject *subject_last(Subject * self)
85{
John Beppuabb47722000-01-06 00:48:21 +000086 self->a = self->b;
Erik Andersene49d5ec2000-02-08 19:58:47 +000087 self->b = NULL;
John Beppuabb47722000-01-06 00:48:21 +000088 return self;
John Beppuabb47722000-01-06 00:48:21 +000089}
90
Erik Andersene49d5ec2000-02-08 19:58:47 +000091static Subject *subject_study(Subject * self)
John Beppuabb47722000-01-06 00:48:21 +000092{
Erik Andersene49d5ec2000-02-08 19:58:47 +000093 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 }
John Beppuabb47722000-01-06 00:48:21 +0000106 return self;
John Beppuabb47722000-01-06 00:48:21 +0000107}
108
John Beppu96f1f332000-01-06 23:49:21 +0000109static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000110set_file_pointers(int schema, FILE ** in, FILE ** out, char **argv)
John Beppu96f1f332000-01-06 23:49:21 +0000111{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000112 switch (schema) {
John Beppu96f1f332000-01-06 23:49:21 +0000113 case 0:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000114 *in = stdin;
115 *out = stdout;
116 break;
John Beppu96f1f332000-01-06 23:49:21 +0000117 case 1:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 *in = fopen(argv[0], "r");
119 *out = stdout;
120 break;
John Beppu96f1f332000-01-06 23:49:21 +0000121 case 2:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122 *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;
John Beppu96f1f332000-01-06 23:49:21 +0000135}
136
137
John Beppuabb47722000-01-06 00:48:21 +0000138/* 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/* ________________________________________________________________________ */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000147int uniq_main(int argc, char **argv)
John Beppuabb47722000-01-06 00:48:21 +0000148{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149 int i;
150 char opt;
151 FILE *in, *out;
152 Subject s;
John Beppuabb47722000-01-06 00:48:21 +0000153
Erik Andersene49d5ec2000-02-08 19:58:47 +0000154 /* 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 }
John Beppuabb47722000-01-06 00:48:21 +0000168 }
John Beppuabb47722000-01-06 00:48:21 +0000169
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170 /* 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 }
John Beppu96f1f332000-01-06 23:49:21 +0000176
Erik Andersene49d5ec2000-02-08 19:58:47 +0000177 subject_init(&s, in, out, NULL);
178 while (subject_next(&s)) {
179 subject_study(&s);
180 }
181 subject_last(&s);
John Beppu96f1f332000-01-06 23:49:21 +0000182 subject_study(&s);
John Beppu96f1f332000-01-06 23:49:21 +0000183
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 exit(0);
John Beppuabb47722000-01-06 00:48:21 +0000185}
186
Erik Andersene5b6c7d2000-04-17 16:16:10 +0000187/* $Id: uniq.c,v 1.9 2000/04/17 16:16:10 erik Exp $ */