ISO-8859-16 has changed.
[libiconv.git] / tests / uniq-u.c
blob31b850ff5bdcc4db89b70296e6f429558dbc2e7e
1 /* uniq -- remove duplicate lines from a sorted file
2 Copyright (C) 86, 91, 1995-1998, 1999 Free Software Foundation, Inc.
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 2, or (at your option)
7 any later version.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Richard Stallman and David MacKenzie. */
19 /* 2000-03-22 Trimmed down to the case of "uniq -u" by Bruno Haible. */
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
26 /* The name this program was run with. */
27 static char *program_name;
29 static void
30 xalloc_fail (void)
32 fprintf (stderr, "%s: virtual memory exhausted\n", program_name);
33 exit (1);
36 /* Allocate N bytes of memory dynamically, with error checking. */
38 void *
39 xmalloc (size_t n)
41 void *p;
43 p = malloc (n);
44 if (p == 0)
45 xalloc_fail ();
46 return p;
49 /* Change the size of an allocated block of memory P to N bytes,
50 with error checking.
51 If P is NULL, run xmalloc. */
53 void *
54 xrealloc (void *p, size_t n)
56 p = realloc (p, n);
57 if (p == 0)
58 xalloc_fail ();
59 return p;
62 /* A `struct linebuffer' holds a line of text. */
64 struct linebuffer
66 size_t size; /* Allocated. */
67 size_t length; /* Used. */
68 char *buffer;
71 /* Initialize linebuffer LINEBUFFER for use. */
73 static void
74 initbuffer (struct linebuffer *linebuffer)
76 linebuffer->length = 0;
77 linebuffer->size = 200;
78 linebuffer->buffer = (char *) xmalloc (linebuffer->size);
81 /* Read an arbitrarily long line of text from STREAM into LINEBUFFER.
82 Keep the newline; append a newline if it's the last line of a file
83 that ends in a non-newline character. Do not null terminate.
84 Return LINEBUFFER, except at end of file return 0. */
86 static struct linebuffer *
87 readline (struct linebuffer *linebuffer, FILE *stream)
89 int c;
90 char *buffer = linebuffer->buffer;
91 char *p = linebuffer->buffer;
92 char *end = buffer + linebuffer->size - 1; /* Sentinel. */
94 if (feof (stream) || ferror (stream))
95 return 0;
99 c = getc (stream);
100 if (c == EOF)
102 if (p == buffer)
103 return 0;
104 if (p[-1] == '\n')
105 break;
106 c = '\n';
108 if (p == end)
110 linebuffer->size *= 2;
111 buffer = (char *) xrealloc (buffer, linebuffer->size);
112 p = p - linebuffer->buffer + buffer;
113 linebuffer->buffer = buffer;
114 end = buffer + linebuffer->size - 1;
116 *p++ = c;
118 while (c != '\n');
120 linebuffer->length = p - buffer;
121 return linebuffer;
124 /* Free linebuffer LINEBUFFER's data. */
126 static void
127 freebuffer (struct linebuffer *linebuffer)
129 free (linebuffer->buffer);
132 /* Undefine, to avoid warning about redefinition on some systems. */
133 #undef min
134 #define min(x, y) ((x) < (y) ? (x) : (y))
136 /* Return zero if two strings OLD and NEW match, nonzero if not.
137 OLD and NEW point not to the beginnings of the lines
138 but rather to the beginnings of the fields to compare.
139 OLDLEN and NEWLEN are their lengths. */
141 static int
142 different (const char *old, const char *new, size_t oldlen, size_t newlen)
144 int order;
146 order = memcmp (old, new, min (oldlen, newlen));
148 if (order == 0)
149 return oldlen - newlen;
150 return order;
153 /* Output the line in linebuffer LINE to stream STREAM
154 provided that the switches say it should be output.
155 If requested, print the number of times it occurred, as well;
156 LINECOUNT + 1 is the number of times that the line occurred. */
158 static void
159 writeline (const struct linebuffer *line, FILE *stream, int linecount)
161 if (linecount == 0)
162 fwrite (line->buffer, 1, line->length, stream);
165 /* Process input file INFILE with output to OUTFILE.
166 If either is "-", use the standard I/O stream for it instead. */
168 static void
169 check_file (const char *infile, const char *outfile)
171 FILE *istream;
172 FILE *ostream;
173 struct linebuffer lb1, lb2;
174 struct linebuffer *thisline, *prevline, *exch;
175 char *prevfield, *thisfield;
176 size_t prevlen, thislen;
177 int match_count = 0;
179 if (!strcmp (infile, "-"))
180 istream = stdin;
181 else
182 istream = fopen (infile, "r");
183 if (istream == NULL)
185 fprintf (stderr, "%s: error opening %s\n", program_name, infile);
186 exit (1);
189 if (!strcmp (outfile, "-"))
190 ostream = stdout;
191 else
192 ostream = fopen (outfile, "w");
193 if (ostream == NULL)
195 fprintf (stderr, "%s: error opening %s\n", program_name, outfile);
196 exit (1);
199 thisline = &lb1;
200 prevline = &lb2;
202 initbuffer (thisline);
203 initbuffer (prevline);
205 if (readline (prevline, istream) == 0)
206 goto closefiles;
207 prevfield = prevline->buffer;
208 prevlen = prevline->length;
210 while (!feof (istream))
212 int match;
213 if (readline (thisline, istream) == 0)
214 break;
215 thisfield = thisline->buffer;
216 thislen = thisline->length;
217 match = !different (thisfield, prevfield, thislen, prevlen);
219 if (match)
220 ++match_count;
222 if (!match)
224 writeline (prevline, ostream, match_count);
225 exch = prevline;
226 prevline = thisline;
227 thisline = exch;
228 prevfield = thisfield;
229 prevlen = thislen;
230 if (!match)
231 match_count = 0;
235 writeline (prevline, ostream, match_count);
237 closefiles:
238 if (ferror (istream) || fclose (istream) == EOF)
240 fprintf (stderr, "%s: error reading %s\n", program_name, infile);
241 exit (1);
244 if (ferror (ostream) || fclose (ostream) == EOF)
246 fprintf (stderr, "%s: error writing %s\n", program_name, outfile);
247 exit (1);
250 freebuffer (&lb1);
251 freebuffer (&lb2);
255 main (int argc, char **argv)
257 const char *infile = "-";
258 const char *outfile = "-";
259 int optind = 1;
261 program_name = argv[0];
263 if (optind < argc)
264 infile = argv[optind++];
266 if (optind < argc)
267 outfile = argv[optind++];
269 if (optind < argc)
271 fprintf (stderr, "%s: too many arguments\n", program_name);
272 exit (1);
275 check_file (infile, outfile);
277 exit (0);