• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/libiconv-1.14/tests/
1/* uniq -- remove duplicate lines from a sorted file
2   Copyright (C) 86, 91, 1995-1998, 1999 Free Software Foundation, Inc.
3
4   This program is free software: you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17/* Written by Richard Stallman and David MacKenzie. */
18/* 2000-03-22  Trimmed down to the case of "uniq -u" by Bruno Haible. */
19
20#include <stddef.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25/* The name this program was run with. */
26static char *program_name;
27
28static void
29xalloc_fail (void)
30{
31  fprintf (stderr, "%s: virtual memory exhausted\n", program_name);
32  exit (1);
33}
34
35/* Allocate N bytes of memory dynamically, with error checking.  */
36
37void *
38xmalloc (size_t n)
39{
40  void *p;
41
42  p = malloc (n);
43  if (p == 0)
44    xalloc_fail ();
45  return p;
46}
47
48/* Change the size of an allocated block of memory P to N bytes,
49   with error checking.
50   If P is NULL, run xmalloc.  */
51
52void *
53xrealloc (void *p, size_t n)
54{
55  p = realloc (p, n);
56  if (p == 0)
57    xalloc_fail ();
58  return p;
59}
60
61/* A `struct linebuffer' holds a line of text. */
62
63struct linebuffer
64{
65  size_t size;                  /* Allocated. */
66  size_t length;                /* Used. */
67  char *buffer;
68};
69
70/* Initialize linebuffer LINEBUFFER for use. */
71
72static void
73initbuffer (struct linebuffer *linebuffer)
74{
75  linebuffer->length = 0;
76  linebuffer->size = 200;
77  linebuffer->buffer = (char *) xmalloc (linebuffer->size);
78}
79
80/* Read an arbitrarily long line of text from STREAM into LINEBUFFER.
81   Keep the newline; append a newline if it's the last line of a file
82   that ends in a non-newline character.  Do not null terminate.
83   Return LINEBUFFER, except at end of file return 0.  */
84
85static struct linebuffer *
86readline (struct linebuffer *linebuffer, FILE *stream)
87{
88  int c;
89  char *buffer = linebuffer->buffer;
90  char *p = linebuffer->buffer;
91  char *end = buffer + linebuffer->size - 1; /* Sentinel. */
92
93  if (feof (stream) || ferror (stream))
94    return 0;
95
96  do
97    {
98      c = getc (stream);
99      if (c == EOF)
100        {
101          if (p == buffer)
102            return 0;
103          if (p[-1] == '\n')
104            break;
105          c = '\n';
106        }
107      if (p == end)
108        {
109          linebuffer->size *= 2;
110          buffer = (char *) xrealloc (buffer, linebuffer->size);
111          p = p - linebuffer->buffer + buffer;
112          linebuffer->buffer = buffer;
113          end = buffer + linebuffer->size - 1;
114        }
115      *p++ = c;
116    }
117  while (c != '\n');
118
119  linebuffer->length = p - buffer;
120  return linebuffer;
121}
122
123/* Free linebuffer LINEBUFFER's data. */
124
125static void
126freebuffer (struct linebuffer *linebuffer)
127{
128  free (linebuffer->buffer);
129}
130
131/* Undefine, to avoid warning about redefinition on some systems.  */
132#undef min
133#define min(x, y) ((x) < (y) ? (x) : (y))
134
135/* Return zero if two strings OLD and NEW match, nonzero if not.
136   OLD and NEW point not to the beginnings of the lines
137   but rather to the beginnings of the fields to compare.
138   OLDLEN and NEWLEN are their lengths. */
139
140static int
141different (const char *old, const char *new, size_t oldlen, size_t newlen)
142{
143  int order;
144
145  order = memcmp (old, new, min (oldlen, newlen));
146
147  if (order == 0)
148    return oldlen - newlen;
149  return order;
150}
151
152/* Output the line in linebuffer LINE to stream STREAM
153   provided that the switches say it should be output.
154   If requested, print the number of times it occurred, as well;
155   LINECOUNT + 1 is the number of times that the line occurred. */
156
157static void
158writeline (const struct linebuffer *line, FILE *stream, int linecount)
159{
160  if (linecount == 0)
161    fwrite (line->buffer, 1, line->length, stream);
162}
163
164/* Process input file INFILE with output to OUTFILE.
165   If either is "-", use the standard I/O stream for it instead. */
166
167static void
168check_file (const char *infile, const char *outfile)
169{
170  FILE *istream;
171  FILE *ostream;
172  struct linebuffer lb1, lb2;
173  struct linebuffer *thisline, *prevline, *exch;
174  char *prevfield, *thisfield;
175  size_t prevlen, thislen;
176  int match_count = 0;
177
178  if (!strcmp (infile, "-"))
179    istream = stdin;
180  else
181    istream = fopen (infile, "r");
182  if (istream == NULL)
183    {
184      fprintf (stderr, "%s: error opening %s\n", program_name, infile);
185      exit (1);
186    }
187
188  if (!strcmp (outfile, "-"))
189    ostream = stdout;
190  else
191    ostream = fopen (outfile, "w");
192  if (ostream == NULL)
193    {
194      fprintf (stderr, "%s: error opening %s\n", program_name, outfile);
195      exit (1);
196    }
197
198  thisline = &lb1;
199  prevline = &lb2;
200
201  initbuffer (thisline);
202  initbuffer (prevline);
203
204  if (readline (prevline, istream) == 0)
205    goto closefiles;
206  prevfield = prevline->buffer;
207  prevlen = prevline->length;
208
209  while (!feof (istream))
210    {
211      int match;
212      if (readline (thisline, istream) == 0)
213        break;
214      thisfield = thisline->buffer;
215      thislen = thisline->length;
216      match = !different (thisfield, prevfield, thislen, prevlen);
217
218      if (match)
219        ++match_count;
220
221      if (!match)
222        {
223          writeline (prevline, ostream, match_count);
224          exch = prevline;
225          prevline = thisline;
226          thisline = exch;
227          prevfield = thisfield;
228          prevlen = thislen;
229          if (!match)
230            match_count = 0;
231        }
232    }
233
234  writeline (prevline, ostream, match_count);
235
236 closefiles:
237  if (ferror (istream) || fclose (istream) == EOF)
238    {
239      fprintf (stderr, "%s: error reading %s\n", program_name, infile);
240      exit (1);
241    }
242
243  if (ferror (ostream) || fclose (ostream) == EOF)
244    {
245      fprintf (stderr, "%s: error writing %s\n", program_name, outfile);
246      exit (1);
247    }
248
249  freebuffer (&lb1);
250  freebuffer (&lb2);
251}
252
253int
254main (int argc, char **argv)
255{
256  const char *infile = "-";
257  const char *outfile = "-";
258  int optind = 1;
259
260  program_name = argv[0];
261
262  if (optind < argc)
263    infile = argv[optind++];
264
265  if (optind < argc)
266    outfile = argv[optind++];
267
268  if (optind < argc)
269    {
270      fprintf (stderr, "%s: too many arguments\n", program_name);
271      exit (1);
272    }
273
274  check_file (infile, outfile);
275
276  exit (0);
277}
278