Annotation of embedaddon/libiconv/tests/uniq-u.c, revision 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>