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) 05/25/87"; 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 } 260