~ubuntu-branches/debian/squeeze/ffcall/squeeze

« back to all changes in this revision

Viewing changes to avcall/uniq-u.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2010-06-26 15:29:30 UTC
  • mfrom: (5.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100626152930-c09y01gk3szcnykn
Tags: 1.10+cvs20100619-2
Ship to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 2, or (at your option)
 
7
   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, write to the Free Software Foundation,
 
16
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
17
 
 
18
/* Written by Richard Stallman and David MacKenzie. */
 
19
/* 2000-03-22  Trimmed down to the case of "uniq -u" by Bruno Haible. */
 
20
 
 
21
#include <stddef.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
 
 
26
/* The name this program was run with. */
 
27
static char *program_name;
 
28
 
 
29
static void
 
30
xalloc_fail (void)
 
31
{
 
32
  fprintf (stderr, "%s: virtual memory exhausted\n", program_name);
 
33
  exit (1);
 
34
}
 
35
 
 
36
/* Allocate N bytes of memory dynamically, with error checking.  */
 
37
 
 
38
void *
 
39
xmalloc (size_t n)
 
40
{
 
41
  void *p;
 
42
 
 
43
  p = malloc (n);
 
44
  if (p == 0)
 
45
    xalloc_fail ();
 
46
  return p;
 
47
}
 
48
 
 
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.  */
 
52
 
 
53
void *
 
54
xrealloc (void *p, size_t n)
 
55
{
 
56
  p = realloc (p, n);
 
57
  if (p == 0)
 
58
    xalloc_fail ();
 
59
  return p;
 
60
}
 
61
 
 
62
/* A `struct linebuffer' holds a line of text. */
 
63
 
 
64
struct linebuffer
 
65
{
 
66
  size_t size;                  /* Allocated. */
 
67
  size_t length;                /* Used. */
 
68
  char *buffer;
 
69
};
 
70
 
 
71
/* Initialize linebuffer LINEBUFFER for use. */
 
72
 
 
73
static void
 
74
initbuffer (struct linebuffer *linebuffer)
 
75
{
 
76
  linebuffer->length = 0;
 
77
  linebuffer->size = 200;
 
78
  linebuffer->buffer = (char *) xmalloc (linebuffer->size);
 
79
}
 
80
 
 
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.  */
 
85
 
 
86
static struct linebuffer *
 
87
readline (struct linebuffer *linebuffer, FILE *stream)
 
88
{
 
89
  int c;
 
90
  char *buffer = linebuffer->buffer;
 
91
  char *p = linebuffer->buffer;
 
92
  char *end = buffer + linebuffer->size - 1; /* Sentinel. */
 
93
 
 
94
  if (feof (stream) || ferror (stream))
 
95
    return 0;
 
96
 
 
97
  do
 
98
    {
 
99
      c = getc (stream);
 
100
      if (c == EOF)
 
101
        {
 
102
          if (p == buffer)
 
103
            return 0;
 
104
          if (p[-1] == '\n')
 
105
            break;
 
106
          c = '\n';
 
107
        }
 
108
      if (p == end)
 
109
        {
 
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;
 
115
        }
 
116
      *p++ = c;
 
117
    }
 
118
  while (c != '\n');
 
119
 
 
120
  linebuffer->length = p - buffer;
 
121
  return linebuffer;
 
122
}
 
123
 
 
124
/* Free linebuffer LINEBUFFER's data. */
 
125
 
 
126
static void
 
127
freebuffer (struct linebuffer *linebuffer)
 
128
{
 
129
  free (linebuffer->buffer);
 
130
}
 
131
 
 
132
/* Undefine, to avoid warning about redefinition on some systems.  */
 
133
#undef min
 
134
#define min(x, y) ((x) < (y) ? (x) : (y))
 
135
 
 
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. */
 
140
 
 
141
static int
 
142
different (const char *old, const char *new, size_t oldlen, size_t newlen)
 
143
{
 
144
  int order;
 
145
 
 
146
  order = memcmp (old, new, min (oldlen, newlen));
 
147
 
 
148
  if (order == 0)
 
149
    return oldlen - newlen;
 
150
  return order;
 
151
}
 
152
 
 
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. */
 
157
 
 
158
static void
 
159
writeline (const struct linebuffer *line, FILE *stream, int linecount)
 
160
{
 
161
  if (linecount == 0)
 
162
    fwrite (line->buffer, 1, line->length, stream);
 
163
}
 
164
 
 
165
/* Process input file INFILE with output to OUTFILE.
 
166
   If either is "-", use the standard I/O stream for it instead. */
 
167
 
 
168
static void
 
169
check_file (const char *infile, const char *outfile)
 
170
{
 
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;
 
178
 
 
179
  if (!strcmp (infile, "-"))
 
180
    istream = stdin;
 
181
  else
 
182
    istream = fopen (infile, "r");
 
183
  if (istream == NULL)
 
184
    {
 
185
      fprintf (stderr, "%s: error opening %s\n", program_name, infile);
 
186
      exit (1);
 
187
    }
 
188
 
 
189
  if (!strcmp (outfile, "-"))
 
190
    ostream = stdout;
 
191
  else
 
192
    ostream = fopen (outfile, "w");
 
193
  if (ostream == NULL)
 
194
    {
 
195
      fprintf (stderr, "%s: error opening %s\n", program_name, outfile);
 
196
      exit (1);
 
197
    }
 
198
 
 
199
  thisline = &lb1;
 
200
  prevline = &lb2;
 
201
 
 
202
  initbuffer (thisline);
 
203
  initbuffer (prevline);
 
204
 
 
205
  if (readline (prevline, istream) == 0)
 
206
    goto closefiles;
 
207
  prevfield = prevline->buffer;
 
208
  prevlen = prevline->length;
 
209
 
 
210
  while (!feof (istream))
 
211
    {
 
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);
 
218
 
 
219
      if (match)
 
220
        ++match_count;
 
221
 
 
222
      if (!match)
 
223
        {
 
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;
 
232
        }
 
233
    }
 
234
 
 
235
  writeline (prevline, ostream, match_count);
 
236
 
 
237
 closefiles:
 
238
  if (ferror (istream) || fclose (istream) == EOF)
 
239
    {
 
240
      fprintf (stderr, "%s: error reading %s\n", program_name, infile);
 
241
      exit (1);
 
242
    }
 
243
 
 
244
  if (ferror (ostream) || fclose (ostream) == EOF)
 
245
    {
 
246
      fprintf (stderr, "%s: error writing %s\n", program_name, outfile);
 
247
      exit (1);
 
248
    }
 
249
 
 
250
  freebuffer (&lb1);
 
251
  freebuffer (&lb2);
 
252
}
 
253
 
 
254
int
 
255
main (int argc, char **argv)
 
256
{
 
257
  const char *infile = "-";
 
258
  const char *outfile = "-";
 
259
  int optind = 1;
 
260
 
 
261
  program_name = argv[0];
 
262
 
 
263
  if (optind < argc)
 
264
    infile = argv[optind++];
 
265
 
 
266
  if (optind < argc)
 
267
    outfile = argv[optind++];
 
268
 
 
269
  if (optind < argc)
 
270
    {
 
271
      fprintf (stderr, "%s: too many arguments\n", program_name);
 
272
      exit (1);
 
273
    }
 
274
 
 
275
  check_file (infile, outfile);
 
276
 
 
277
  exit (0);
 
278
}