xref: /csrg-svn/local/local.cmd/chgbars.c (revision 31207)
1*31207Smckusick /*
2*31207Smckusick  * Copyright (c) 1987 Regents of the University of California.
3*31207Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*31207Smckusick  * specifies the terms and conditions for redistribution.
5*31207Smckusick  */
6*31207Smckusick 
7*31207Smckusick #ifndef lint
8*31207Smckusick static char sccsid[] = "@(#)chgbars.c	5.1 (Berkeley) 05/25/87";
9*31207Smckusick #endif not lint
10*31207Smckusick 
11*31207Smckusick /*
12*31207Smckusick  * Derived from original program by A. Dain Samples.
13*31207Smckusick  *
14*31207Smckusick  * The program chgbars will accept the output from a diff comparison of
15*31207Smckusick  * two versions of a file.  It will then read the new version of the file
16*31207Smckusick  * and insert the appropriate troff commands to put change bars in the
17*31207Smckusick  * right margin. Typing 'chgbars' without any arguments will give you
18*31207Smckusick  * some documentation and an example.
19*31207Smckusick  *
20*31207Smckusick  * Caveat: If you make a change inside an equation or table, the
21*31207Smckusick  * preprocessors eqn and tbl may not like what chgbars does to the file.
22*31207Smckusick  * You may have to go into the output from chgbars to remove or rearrange
23*31207Smckusick  * some of the lines of the form '.mc |  \"open' or '.mc  \"close' in
24*31207Smckusick  * order to get through tbl or eqn.
25*31207Smckusick  *
26*31207Smckusick  * Unfortunately, users of RCS will be disappointed: one cannot use rcsdiff.
27*31207Smckusick  * Rcsdiff compares the files in the wrong order.
28*31207Smckusick  *
29*31207Smckusick  * There is a relatively easy way to do the job with the tools sed and awk.
30*31207Smckusick  * However, sed does not allow enough commands to process large documents.
31*31207Smckusick  * In the true spirit of a filter/tool, chgbars is limited only by the
32*31207Smckusick  * amount of memory on the machine, and is fast and useful.
33*31207Smckusick  *
34*31207Smckusick  * The modifications necessary are outlined:
35*31207Smckusick  *
36*31207Smckusick  * FORM OF DIFF OUTPUT	COMMENT			NEW SED COMMANDS
37*31207Smckusick  * ================================================================
38*31207Smckusick  * 100a			means those lines	100a\\
39*31207Smckusick  * L1			were deleted from	.mc |\\
40*31207Smckusick  * L2			oldfile			.mc
41*31207Smckusick  * :
42*31207Smckusick  * Ln
43*31207Smckusick  * .
44*31207Smckusick  * ----------------------------------------------------------------
45*31207Smckusick  * 100c
46*31207Smckusick  * L1
47*31207Smckusick  * L2
48*31207Smckusick  * :
49*31207Smckusick  * Ln
50*31207Smckusick  * .
51*31207Smckusick  *	means that line 100 in newfile replaced all those lines in oldfile.
52*31207Smckusick  *		100a
53*31207Smckusick  *		.mc
54*31207Smckusick  *		99 a
55*31207Smckusick  *		.mc |
56*31207Smckusick  * ----------------------------------------------------------------
57*31207Smckusick  * 100d			that line was added	100a\\
58*31207Smckusick  *			to oldfile		.mc
59*31207Smckusick  *						99a\\
60*31207Smckusick  *						.mc |
61*31207Smckusick  * ----------------------------------------------------------------
62*31207Smckusick  * 100,200d		those lines were	200a\\
63*31207Smckusick  *			added to oldfile		.mc
64*31207Smckusick  *						99a\\
65*31207Smckusick  *						.mc |
66*31207Smckusick  * ----------------------------------------------------------------
67*31207Smckusick  * 100,200c
68*31207Smckusick  * L1
69*31207Smckusick  * L2
70*31207Smckusick  * :
71*31207Smckusick  * Ln
72*31207Smckusick  * .
73*31207Smckusick  *	means lines 100 to 200 of newfile replaced all the following lines
74*31207Smckusick  *	in oldfile.
75*31207Smckusick  *		200a
76*31207Smckusick  *		.mc
77*31207Smckusick  *		99a
78*31207Smckusick  *		.mc |
79*31207Smckusick  * ----------------------------------------------------------------
80*31207Smckusick  */
81*31207Smckusick 
82*31207Smckusick #include <stdio.h>
83*31207Smckusick #include <strings.h>
84*31207Smckusick #include <ctype.h>
85*31207Smckusick 
86*31207Smckusick #define dbg(s)  /* fprintf(stderr,"s\n") */
87*31207Smckusick #define none 0
88*31207Smckusick #define open 1
89*31207Smckusick #define close 2
90*31207Smckusick #define both 3
91*31207Smckusick 
92*31207Smckusick char (*action)[];
93*31207Smckusick FILE *file1, *file2;
94*31207Smckusick char linebuf[1024];
95*31207Smckusick char nextch;
96*31207Smckusick int num1, num2, t, line;
97*31207Smckusick char lineact;
98*31207Smckusick 
99*31207Smckusick #ifndef lint
100*31207Smckusick char copyright[] =
101*31207Smckusick "@(#) Copyright (c) 1986 Regents of the University of California.\n\
102*31207Smckusick  All rights reserved.\n";
103*31207Smckusick #endif not lint
104*31207Smckusick 
main(argc,argv)105*31207Smckusick main(argc, argv)
106*31207Smckusick 	int argc;
107*31207Smckusick 	char *argv[];
108*31207Smckusick {
109*31207Smckusick 	register char  *p;
110*31207Smckusick 	register int    i;
111*31207Smckusick 
112*31207Smckusick 	if (argc < 2)
113*31207Smckusick 		usage();
114*31207Smckusick 	/* open $1 */
115*31207Smckusick 	if (strcmp(argv[1], "-") == 0) {
116*31207Smckusick 		file1 = stdin;
117*31207Smckusick 		if (argc <= 2)
118*31207Smckusick 			usage();
119*31207Smckusick 	} else if ((file1 = fopen(argv[1], "r")) == NULL) {
120*31207Smckusick 		fprintf(stderr, "error: can't open %s\n", argv[1]);
121*31207Smckusick 		exit(1);
122*31207Smckusick 	}
123*31207Smckusick 	/*
124*31207Smckusick 	 * read each entry setting the appropriate entry in action[]
125*31207Smckusick 	 *
126*31207Smckusick 	 * get the first line number: since diff -e puts the numbers out
127*31207Smckusick 	 * in reverse order, this tells us how big to make the file
128*31207Smckusick 	 */
129*31207Smckusick 	readline();
130*31207Smckusick 	if (lineact == 'a')
131*31207Smckusick 		t = num1;
132*31207Smckusick 	else
133*31207Smckusick 		t = num2;
134*31207Smckusick 	action = (char (*)[]) malloc(t + 1);
135*31207Smckusick 	for (p = (char *) action, i = 0; i < t; i++)
136*31207Smckusick 		*p++ = (char) none;
137*31207Smckusick 	while (!feof(file1)) {
138*31207Smckusick 		if (lineact == 'a') {
139*31207Smckusick 			(*action)[num1] = both;
140*31207Smckusick 			skiptilldot();
141*31207Smckusick 		} else {
142*31207Smckusick 			(*action)[num1 - 1] = open;
143*31207Smckusick 			(*action)[num2] = close;
144*31207Smckusick 			if (lineact == 'c')
145*31207Smckusick 				skiptilldot();
146*31207Smckusick 			else
147*31207Smckusick 				skiptilleol();
148*31207Smckusick 		}
149*31207Smckusick 		readline();
150*31207Smckusick 	}
151*31207Smckusick 	fclose(file1);
152*31207Smckusick 	/* open $2 */
153*31207Smckusick 	if (argc == 2)
154*31207Smckusick 		file2 = stdin;
155*31207Smckusick 	else
156*31207Smckusick 		file2 = fopen(argv[2], "r");
157*31207Smckusick 	if (file2 == NULL) {
158*31207Smckusick 		fprintf(stderr, "can't open %2\n", argv[2]);
159*31207Smckusick 		exit(1);
160*31207Smckusick 	}
161*31207Smckusick 	line = 0;
162*31207Smckusick 	while (!feof(file2)) {
163*31207Smckusick 		if (line != 0)
164*31207Smckusick 			fputs(linebuf, stdout);
165*31207Smckusick 		if (line <= t) {
166*31207Smckusick 			switch ((*action)[line]) {
167*31207Smckusick 			case open:
168*31207Smckusick 				printf(".mc |   \\\"open\n");
169*31207Smckusick 				break;
170*31207Smckusick 			case close:
171*31207Smckusick 				printf(".mc     \\\"close\n");
172*31207Smckusick 				break;
173*31207Smckusick 			case both:
174*31207Smckusick 				printf(".mc |   \\\"both\n");
175*31207Smckusick 				printf(".mc\n");
176*31207Smckusick 				break;
177*31207Smckusick 			default:;
178*31207Smckusick 			}
179*31207Smckusick 		}
180*31207Smckusick 		fgets(linebuf, sizeof(linebuf), file2);
181*31207Smckusick 		line++;
182*31207Smckusick 	}
183*31207Smckusick 	if (line <= t) {
184*31207Smckusick 		fprintf(stderr, "oops: number of lines read does not match\n");
185*31207Smckusick 		fprintf(stderr, "number of lines expected\n");
186*31207Smckusick 		exit(1);
187*31207Smckusick 	}
188*31207Smckusick 	exit(0);
189*31207Smckusick }
190*31207Smckusick 
usage()191*31207Smckusick usage()
192*31207Smckusick {
193*31207Smckusick 
194*31207Smckusick 	fprintf(stderr, "Usage:\n");
195*31207Smckusick 	fprintf(stderr, "\tchgbars diff.out\n");
196*31207Smckusick 	fprintf(stderr, "\t\t\treads the output from diff, and expects the\n");
197*31207Smckusick 	fprintf(stderr, "\t\t\tfile to be modified on stdin\n");
198*31207Smckusick 	fprintf(stderr, "\tchgbars diff.out file.tbm\n");
199*31207Smckusick 	fprintf(stderr, "\t\t\tboth the output from diff and the file to be\n");
200*31207Smckusick 	fprintf(stderr, "\t\t\tmodified are stated explicitly\n");
201*31207Smckusick 	fprintf(stderr, "\tchgbars - file.tbm\n");
202*31207Smckusick 	fprintf(stderr, "\t\t\treads the output from diff on stdin\n");
203*31207Smckusick 	fprintf(stderr, "\nE.g.\n");
204*31207Smckusick 	fprintf(stderr, "diff -b -e newfile oldfile | chgbars - newfile | vtroff -ms\n");
205*31207Smckusick 	fprintf(stderr, "\t(note the order of the files in the diff command!)\n");
206*31207Smckusick 	fprintf(stderr, "\n\nBe forewarned: chgbars does not know about tables or equations.\n");
207*31207Smckusick 	fprintf(stderr, "If any part of a table or equation is changed, chgbars will insert the\n");
208*31207Smckusick 	fprintf(stderr, ".mc commands, whether tbl or eqn likes it or not.\n");
209*31207Smckusick 	fprintf(stderr, "This means that you may have to do some hand editing of the output of\n");
210*31207Smckusick 	fprintf(stderr, "chgbars to make it acceptable to one or both of these preprocessors.\n");
211*31207Smckusick 
212*31207Smckusick 	exit(1);
213*31207Smckusick }
214*31207Smckusick 
readnum()215*31207Smckusick readnum()
216*31207Smckusick {
217*31207Smckusick 	int num;
218*31207Smckusick 
219*31207Smckusick 	dbg(readnum);
220*31207Smckusick 	num = 0;
221*31207Smckusick 	nextch = getc(file1);
222*31207Smckusick 	while (isdigit(nextch)) {
223*31207Smckusick 		num = num * 10 + nextch - '0';
224*31207Smckusick 		nextch = getc(file1);
225*31207Smckusick 	}
226*31207Smckusick 	return num;
227*31207Smckusick }
228*31207Smckusick 
readline()229*31207Smckusick readline()
230*31207Smckusick {
231*31207Smckusick 
232*31207Smckusick 	dbg(readline);
233*31207Smckusick 	num1 = readnum();
234*31207Smckusick 	if (nextch == ',')
235*31207Smckusick 		num2 = readnum();
236*31207Smckusick 	else
237*31207Smckusick 		num2 = num1;
238*31207Smckusick 	lineact = nextch;
239*31207Smckusick }
240*31207Smckusick 
skiptilleol()241*31207Smckusick skiptilleol()
242*31207Smckusick {
243*31207Smckusick 
244*31207Smckusick 	dbg(skiptilleol);
245*31207Smckusick 	while (nextch != '\n')
246*31207Smckusick 		nextch = getc(file1);
247*31207Smckusick }
248*31207Smckusick 
skiptilldot()249*31207Smckusick skiptilldot()
250*31207Smckusick {
251*31207Smckusick 
252*31207Smckusick 	dbg(skiptilldot);
253*31207Smckusick 	do {
254*31207Smckusick 		if (fgets(linebuf, sizeof(linebuf), file1) == NULL) {
255*31207Smckusick 			fprintf(stderr, "error reading file1\n");
256*31207Smckusick 			exit(1);
257*31207Smckusick 		}
258*31207Smckusick 	} while (strcmp(linebuf, ".\n") != 0);
259*31207Smckusick }
260