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