Annotation of embedaddon/libiconv/tests/uniq-u.c, revision 1.1.1.1

1.1       misho       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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>