1 /* #ifdef-format output routines for GNU DIFF.
2 Copyright (C) 1989, 1991, 1992, 1993, 1994, 1998 Free Software Foundation, Inc.
4 This file is part of GNU DIFF.
6 GNU DIFF is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY. No author or distributor
8 accepts responsibility to anyone for the consequences of using it
9 or for whether it serves any particular purpose or works at all,
10 unless he says so in writing. Refer to the GNU DIFF General Public
11 License for full details.
13 Everyone is granted permission to copy, modify and redistribute
14 GNU DIFF, but only under the conditions described in the
15 GNU DIFF General Public License. A copy of this license is
16 supposed to have been given to you along with GNU DIFF so you
17 can know your rights and responsibilities. It should be in a
18 file named COPYING. Among other things, the copyright notice
19 and this notice must be preserved on all copies. */
26 struct file_data const *file;
27 int from, upto; /* start and limit lines for this group of lines */
30 static char *format_group PARAMS((int, char *, int, struct group const *));
31 static char *scan_char_literal PARAMS((char *, int *));
32 static char *scan_printf_spec PARAMS((char *));
33 static int groups_letter_value PARAMS((struct group const *, int));
34 static void format_ifdef PARAMS((char *, int, int, int, int));
35 static void print_ifdef_hunk PARAMS((struct change *));
36 static void print_ifdef_lines PARAMS((int, char *, struct group const *));
40 /* Print the edit-script SCRIPT as a merged #ifdef file. */
43 print_ifdef_script (script)
44 struct change *script;
46 next_line = - files[0].prefix_lines;
47 print_script (script, find_change, print_ifdef_hunk);
48 if (next_line < files[0].valid_lines)
51 format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines,
52 next_line - files[0].valid_lines + files[1].valid_lines,
53 files[1].valid_lines);
57 /* Print a hunk of an ifdef diff.
58 This is a contiguous portion of a complete edit script,
59 describing changes in consecutive lines. */
62 print_ifdef_hunk (hunk)
65 int first0, last0, first1, last1, deletes, inserts;
68 /* Determine range of line numbers involved in each file. */
69 analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts);
71 format = deletes ? group_format[CHANGED] : group_format[NEW];
73 format = group_format[OLD];
79 /* Print lines up to this change. */
80 if (next_line < first0)
81 format_ifdef (group_format[UNCHANGED], next_line, first0,
82 next_line - first0 + first1, first1);
84 /* Print this change. */
85 next_line = last0 + 1;
86 format_ifdef (format, first0, next_line, first1, last1 + 1);
89 /* Print a set of lines according to FORMAT.
90 Lines BEG0 up to END0 are from the first file;
91 lines BEG1 up to END1 are from the second file. */
94 format_ifdef (format, beg0, end0, beg1, end1)
96 int beg0, end0, beg1, end1;
98 struct group groups[2];
100 groups[0].file = &files[0];
101 groups[0].from = beg0;
102 groups[0].upto = end0;
103 groups[1].file = &files[1];
104 groups[1].from = beg1;
105 groups[1].upto = end1;
106 format_group (1, format, '\0', groups);
109 /* If DOIT is non-zero, output a set of lines according to FORMAT.
110 The format ends at the first free instance of ENDCHAR.
111 Yield the address of the terminating character.
112 GROUPS specifies which lines to print.
113 If OUT is zero, do not actually print anything; just scan the format. */
116 format_group (doit, format, endchar, groups)
120 struct group const *groups;
123 register char *f = format;
125 while ((c = *f) != endchar && c != 0)
137 /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
140 int thendoit, elsedoit;
142 for (i = 0; i < 2; i++)
144 unsigned char f0 = f[0];
148 while (ISDIGIT ((unsigned char) *++f))
153 value[i] = groups_letter_value (groups, f0);
161 if (value[0] == value[1])
162 thendoit = doit, elsedoit = 0;
164 thendoit = 0, elsedoit = doit;
165 f = format_group (thendoit, f, ':', groups);
168 f = format_group (elsedoit, f + 1, ')', groups);
176 /* Print lines deleted from first file. */
177 print_ifdef_lines (doit, line_format[OLD], &groups[0]);
181 /* Print common lines. */
182 print_ifdef_lines (doit, line_format[UNCHANGED], &groups[0]);
186 /* Print lines inserted from second file. */
187 print_ifdef_lines (doit, line_format[NEW], &groups[1]);
195 f = scan_printf_spec (spec);
203 f = scan_char_literal (f, &value);
209 value = groups_letter_value (groups, c);
216 /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
218 printf_output (spec - 1, value);
219 /* Undo the temporary replacement. */
233 /* Don't take the address of a register variable. */
235 write_output (&cc, 1);
241 /* For the line group pair G, return the number corresponding to LETTER.
242 Return -1 if LETTER is not a group format letter. */
244 groups_letter_value (g, letter)
245 struct group const *g;
248 if (ISUPPER (letter))
251 letter = tolower (letter);
255 case 'e': return translate_line_number (g->file, g->from) - 1;
256 case 'f': return translate_line_number (g->file, g->from);
257 case 'l': return translate_line_number (g->file, g->upto) - 1;
258 case 'm': return translate_line_number (g->file, g->upto);
259 case 'n': return g->upto - g->from;
264 /* Output using FORMAT to print the line group GROUP.
265 But do nothing if DOIT is zero. */
267 print_ifdef_lines (doit, format, group)
270 struct group const *group;
272 struct file_data const *file = group->file;
273 char const * const *linbuf = file->linbuf;
274 int from = group->from, upto = group->upto;
279 /* If possible, use a single fwrite; it's faster. */
280 if (!tab_expand_flag && format[0] == '%')
282 if (format[1] == 'l' && format[2] == '\n' && !format[3])
284 write_output (linbuf[from],
285 (linbuf[upto] + (linbuf[upto][-1] != '\n')
289 if (format[1] == 'L' && !format[2])
291 write_output (linbuf[from],
292 linbuf[upto] - linbuf[from]);
297 for (; from < upto; from++)
300 register char *f = format;
303 while ((c = *f++) != 0)
314 output_1_line (linbuf[from],
316 - (linbuf[from + 1][-1] == '\n'), 0, 0);
320 output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
328 f = scan_printf_spec (spec);
336 f = scan_char_literal (f, &value);
342 value = translate_line_number (file, from);
348 /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
350 printf_output (spec - 1, value);
351 /* Undo the temporary replacement. */
363 /* Don't take the address of a register variable. */
365 write_output (&cc, 1);
370 /* Scan the character literal represented in the string LIT; LIT points just
371 after the initial apostrophe. Put the literal's value into *INTPTR.
372 Yield the address of the first character after the closing apostrophe,
373 or zero if the literal is ill-formed. */
375 scan_char_literal (lit, intptr)
379 register char *p = lit;
391 while ((c = *p++) != '\'')
393 unsigned digit = c - '0';
396 value = 8 * value + digit;
398 digits = p - lit - 2;
399 if (! (1 <= digits && digits <= 3))
413 /* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
414 Return the address of the character following SPEC, or zero if failure. */
416 scan_printf_spec (spec)
419 register unsigned char c;
421 while ((c = *spec++) == '-')
426 while (ISDIGIT (c = *spec++))
430 case 'c': case 'd': case 'o': case 'x': case 'X':