File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / tests / uniq-u.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:57:49 2012 UTC (12 years, 4 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_13_1, HEAD
libiconv

    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>