nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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. */ |
||
26 | static char *program_name; |
||
27 | |||
28 | static void |
||
29 | xalloc_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 | |||
37 | void * |
||
38 | xmalloc (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 | |||
52 | void * |
||
53 | xrealloc (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 | |||
63 | struct linebuffer |
||
64 | { |
||
65 | size_t size; /* Allocated. */ |
||
66 | size_t length; /* Used. */ |
||
67 | char *buffer; |
||
68 | }; |
||
69 | |||
70 | /* Initialize linebuffer LINEBUFFER for use. */ |
||
71 | |||
72 | static void |
||
73 | initbuffer (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 | |||
85 | static struct linebuffer * |
||
86 | readline (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 | |||
125 | static void |
||
126 | freebuffer (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 | |||
140 | static int |
||
141 | different (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 | |||
157 | static void |
||
158 | writeline (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 | |||
167 | static void |
||
168 | check_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 | |||
253 | int |
||
254 | main (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 | } |