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., 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. */
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
);