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)
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18
/* Written by Richard Stallman and David MacKenzie. */
19
/* 2000-03-22 Trimmed down to the case of "uniq -u" by Bruno Haible. */
26
/* The name this program was run with. */
27
static char *program_name;
32
fprintf (stderr, "%s: virtual memory exhausted\n", program_name);
36
/* Allocate N bytes of memory dynamically, with error checking. */
49
/* Change the size of an allocated block of memory P to N bytes,
51
If P is NULL, run xmalloc. */
54
xrealloc (void *p, size_t n)
62
/* A `struct linebuffer' holds a line of text. */
66
size_t size; /* Allocated. */
67
size_t length; /* Used. */
71
/* Initialize linebuffer LINEBUFFER for use. */
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)
90
char *buffer = linebuffer->buffer;
91
char *p = linebuffer->buffer;
92
char *end = buffer + linebuffer->size - 1; /* Sentinel. */
94
if (feof (stream) || ferror (stream))
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;
120
linebuffer->length = p - buffer;
124
/* Free linebuffer LINEBUFFER's data. */
127
freebuffer (struct linebuffer *linebuffer)
129
free (linebuffer->buffer);
132
/* Undefine, to avoid warning about redefinition on some systems. */
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. */
142
different (const char *old, const char *new, size_t oldlen, size_t newlen)
146
order = memcmp (old, new, min (oldlen, newlen));
149
return oldlen - newlen;
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. */
159
writeline (const struct linebuffer *line, FILE *stream, int linecount)
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. */
169
check_file (const char *infile, const char *outfile)
173
struct linebuffer lb1, lb2;
174
struct linebuffer *thisline, *prevline, *exch;
175
char *prevfield, *thisfield;
176
size_t prevlen, thislen;
179
if (!strcmp (infile, "-"))
182
istream = fopen (infile, "r");
185
fprintf (stderr, "%s: error opening %s\n", program_name, infile);
189
if (!strcmp (outfile, "-"))
192
ostream = fopen (outfile, "w");
195
fprintf (stderr, "%s: error opening %s\n", program_name, outfile);
202
initbuffer (thisline);
203
initbuffer (prevline);
205
if (readline (prevline, istream) == 0)
207
prevfield = prevline->buffer;
208
prevlen = prevline->length;
210
while (!feof (istream))
213
if (readline (thisline, istream) == 0)
215
thisfield = thisline->buffer;
216
thislen = thisline->length;
217
match = !different (thisfield, prevfield, thislen, prevlen);
224
writeline (prevline, ostream, match_count);
228
prevfield = thisfield;
235
writeline (prevline, ostream, match_count);
238
if (ferror (istream) || fclose (istream) == EOF)
240
fprintf (stderr, "%s: error reading %s\n", program_name, infile);
244
if (ferror (ostream) || fclose (ostream) == EOF)
246
fprintf (stderr, "%s: error writing %s\n", program_name, outfile);
255
main (int argc, char **argv)
257
const char *infile = "-";
258
const char *outfile = "-";
261
program_name = argv[0];
264
infile = argv[optind++];
267
outfile = argv[optind++];
271
fprintf (stderr, "%s: too many arguments\n", program_name);
275
check_file (infile, outfile);