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>