123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /* `comm' compare two sorted files line by line.
- Copyright (C) 1986 Richard M. Stallman
- NO WARRANTY
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- CORRECTION.
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
- GENERAL PUBLIC LICENSE TO COPY
- 1. You may copy and distribute verbatim copies of this source file
- as you receive it, in any medium, provided that you conspicuously
- and appropriately publish on each copy a valid copyright notice
- "Copyright (C) 1986 Richard M. Stallman"; and include following the
- copyright notice a verbatim copy of the above disclaimer of warranty
- and of this License.
- 2. You may modify your copy or copies of this source file or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be freely distributed
- and licensed to all third parties on terms identical to those
- contained in this License Agreement (except that you may choose
- to grant more extensive warranty protection to third parties,
- at your option).
- 3. You may copy and distribute this program or any portion of it in
- compiled, executable or object code form under the terms of Paragraphs
- 1 and 2 above provided that you do the following:
- a) cause each such copy to be accompanied by the
- corresponding machine-readable source code, which must
- be distributed under the terms of Paragraphs 1 and 2 above; or,
- b) cause each such copy to be accompanied by a
- written offer, with no time limit, to give any third party
- free (except for a nominal shipping charge) a machine readable
- copy of the corresponding source code, to be distributed
- under the terms of Paragraphs 1 and 2 above; or,
- c) in the case of a recipient of this program in compiled, executable
- or object code form (without the corresponding source code) you
- shall cause copies you distribute to be accompanied by a copy
- of the written offer of source code which you received along
- with the copy you received.
- 4. You may not copy, sublicense, distribute or transfer this program
- except as expressly provided under this License Agreement. Any attempt
- otherwise to copy, sublicense, distribute or transfer this program is void and
- your rights to use the program under this License agreement shall be
- automatically terminated. However, parties who have received computer
- software programs from you with this License Agreement will not have
- their licenses terminated so long as such parties remain in full compliance.
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
- #include <stdio.h>
- /* A `struct linebuffer' is a structure which holds a line of text.
- `readline' reads a line from a stream into a linebuffer
- and works regardless of the length of the line. */
- struct linebuffer
- {
- long size;
- char *buffer;
- };
- /* Buffers for next available line of file1, file2 */
- struct linebuffer lb1, lb2;
- /* If nonzero, print lines that are found only in file 1 */
- int only_file_1;
- /* If nonzero, print lines that are found only in file 2 */
- int only_file_2;
- /* If nonzero, print lines that are found in both files */
- int both;
- void initbuffer ();
- struct linebuffer *readline ();
- void writeline ();
- char *concat ();
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i;
- char *file1, *file2;
- only_file_1 = 1;
- only_file_2 = 1;
- both = 1;
- for (i = 1; i < argc; i++)
- {
- if (argv[i][0] == '-')
- {
- char *p = argv[i] + 1;
- char c;
- while (c = *p++)
- switch (c)
- {
- case '1':
- only_file_1 = 0;
- break;
- case '2':
- only_file_2 = 0;
- break;
-
- case '3':
- both = 0;
- break;
- default:
- error ("unrecognized switch %s", argv[i]);
- goto argdone;
- }
- argdone: ;
- }
- else if (!file1)
- file1 = argv[i];
- else if (!file2)
- file2 = argv[i];
- else
- {
- error ("too many arguments", 0);
- break;
- }
- }
- if (!file2)
- fatal ("no files specified", 0);
- compare_files (file1, file2);
- }
- /* Initialize a linebuffer for use */
- void
- initbuffer (linebuffer)
- struct linebuffer *linebuffer;
- {
- linebuffer->size = 200;
- linebuffer->buffer = (char *) xmalloc (200);
- }
- /* Read a line of text from `stream' into `linebuffer'.
- Return `linebuffer', except if there is no line to be read
- because we are at end of file, return 0. */
- struct linebuffer *
- readline (linebuffer, stream)
- struct linebuffer *linebuffer;
- FILE *stream;
- {
- char *buffer = linebuffer->buffer;
- char *p = linebuffer->buffer;
- char *end = p + linebuffer->size;
- if (feof (stream)) return 0;
- while (1)
- {
- int c = getc (stream);
- if (p == end)
- {
- buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
- p += buffer - linebuffer->buffer;
- end += buffer - linebuffer->buffer;
- linebuffer->buffer = buffer;
- }
- if (c < 0 || c == '\n')
- {
- *p = 0;
- break;
- }
- *p++ = c;
- }
- if (feof (stream) && p == buffer) return 0;
- return linebuffer;
- }
- /* Output the line in the specified linebuffer
- provided the switches say it should be output.
- `class' is 1 for a line found only in file 1,
- 2 for a line only in file 2, 3 for a line in both. */
- void
- writeline (line, stream, class)
- struct linebuffer *line;
- FILE *stream;
- int class;
- {
- switch (class)
- {
- case 1:
- if (!only_file_1) return;
- break;
- case 2:
- if (!only_file_2) return;
- /* Skip the tab stop for case 1, if we are printing case 1. */
- if (only_file_1)
- putc ('\t', stream);
- break;
- case 3:
- if (!both) return;
- /* Skip the tab stop for case 1, if we are printing case 1. */
- if (only_file_1)
- putc ('\t', stream);
- /* Skip the tab stop for case 2, if we are printing case 2. */
- if (only_file_2)
- putc ('\t', stream);
- break;
- }
- fputs (line->buffer, stream);
- putc ('\n', stream);
- }
- /* Assume that each input file is sorted;
- merge them and output the result. */
- int
- compare_files (file1, file2)
- char *file1, *file2;
- {
- struct linebuffer lb1[2];
- struct linebuffer *thisline[2];
- FILE *streams[2];
- char **infiles = &file1;
- int i;
- /* For each file, we have one linebuffer in lb1. */
- /* thisline[i] points to the linebuffer holding the next available line in file i,
- or is zero if there are no lines left in that file. */
- /* streams[i] holds the input stream for file i. */
- /* infiles[i] is the name of file i. */
- /* Initialize all that storage */
- for (i = 0; i < 2; i++)
- {
- initbuffer (&lb1[i]);
- thisline[i] = &lb1[i];
- streams[i] = infiles[i] ? fopen (infiles[i], "r") : stdin;
- if (!streams[i])
- pfatal_with_name (infiles[i]);
- thisline[i] = readline (thisline[i], streams[i]);
- }
- while (thisline[0] || thisline[1])
- {
- int order;
- /* Compare the next avail lines of the two files. */
- if (!thisline[0])
- order = 1;
- else if (!thisline[1])
- order = -1;
- else
- order = strcmp (thisline[0]->buffer, thisline[1]->buffer);
- /* Output the line that is lesser */
- if (order == 0)
- writeline (thisline[1], stdout, 3);
- else if (order > 0)
- writeline (thisline[1], stdout, 2);
- else
- writeline (thisline[0], stdout, 1);
- /* Step the file the line came from. If the files match, step both files. */
- if (order >= 0)
- thisline[1] = readline (thisline[1], streams[1]);
- if (order <= 0)
- thisline[0] = readline (thisline[0], streams[0]);
- }
- /* Free all storage and close all input streams */
- for (i = 0; i < 2; i++)
- {
- if (infiles[i])
- fclose (streams[i]);
- free (lb1[i].buffer);
- }
- }
- /* Print error message and exit. */
- fatal (s1, s2)
- char *s1, *s2;
- {
- error (s1, s2);
- exit (1);
- }
- /* Print error message. `s1' is printf control string, `s2' is arg for it. */
- error (s1, s2)
- char *s1, *s2;
- {
- printf ("comm: ");
- printf (s1, s2);
- printf ("\n");
- }
- pfatal_with_name (name)
- char *name;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- char *s;
- if (errno < sys_nerr)
- s = concat ("", sys_errlist[errno], " for %s");
- else
- s = "cannot open %s";
- fatal (s, name);
- }
- /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
- char *
- concat (s1, s2, s3)
- char *s1, *s2, *s3;
- {
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
- return result;
- }
- /* Like malloc but get fatal error if memory is exhausted. */
- int
- xmalloc (size)
- int size;
- {
- int result = malloc (size);
- if (!result)
- fatal ("virtual memory exhausted", 0);
- return result;
- }
- int
- xrealloc (ptr, size)
- char *ptr;
- int size;
- {
- int result = realloc (ptr, size);
- if (!result)
- fatal ("virtual memory exhausted");
- return result;
- }
|