Commit | Line | Data |
---|---|---|
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 | |
8 | static 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 | ||
92 | char (*action)[]; | |
93 | FILE *file1, *file2; | |
94 | char linebuf[1024]; | |
95 | char nextch; | |
96 | int num1, num2, t, line; | |
97 | char lineact; | |
98 | ||
99 | #ifndef lint | |
100 | char copyright[] = | |
101 | "@(#) Copyright (c) 1986 Regents of the University of California.\n\ | |
102 | All rights reserved.\n"; | |
103 | #endif not lint | |
104 | ||
105 | main(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 | ||
191 | usage() | |
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 | ||
215 | readnum() | |
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 | ||
229 | readline() | |
230 | { | |
231 | ||
232 | dbg(readline); | |
233 | num1 = readnum(); | |
234 | if (nextch == ',') | |
235 | num2 = readnum(); | |
236 | else | |
237 | num2 = num1; | |
238 | lineact = nextch; | |
239 | } | |
240 | ||
241 | skiptilleol() | |
242 | { | |
243 | ||
244 | dbg(skiptilleol); | |
245 | while (nextch != '\n') | |
246 | nextch = getc(file1); | |
247 | } | |
248 | ||
249 | skiptilldot() | |
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 | } |