1 /* #ifdef-format output routines for GNU DIFF.
2 Copyright (C) 1989, 1991, 1992, 1993, 1994 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((FILE *, 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((FILE *, 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 (outfile, format, '\0', groups);
109 /* Print to file OUT 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 (out, 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 FILE *thenout, *elseout;
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 thenout = out, elseout = 0;
164 thenout = 0, elseout = out;
165 f = format_group (thenout, f, ':', groups);
168 f = format_group (elseout, f + 1, ')', groups);
176 /* Print lines deleted from first file. */
177 print_ifdef_lines (out, line_format[OLD], &groups[0]);
181 /* Print common lines. */
182 print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
186 /* Print lines inserted from second file. */
187 print_ifdef_lines (out, 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 fprintf (out, spec - 1, value);
219 /* Undo the temporary replacement. */
237 /* For the line group pair G, return the number corresponding to LETTER.
238 Return -1 if LETTER is not a group format letter. */
240 groups_letter_value (g, letter)
241 struct group const *g;
244 if (ISUPPER (letter))
247 letter = tolower (letter);
251 case 'e': return translate_line_number (g->file, g->from) - 1;
252 case 'f': return translate_line_number (g->file, g->from);
253 case 'l': return translate_line_number (g->file, g->upto) - 1;
254 case 'm': return translate_line_number (g->file, g->upto);
255 case 'n': return g->upto - g->from;
260 /* Print to file OUT, using FORMAT to print the line group GROUP.
261 But do nothing if OUT is zero. */
263 print_ifdef_lines (out, format, group)
266 struct group const *group;
268 struct file_data const *file = group->file;
269 char const * const *linbuf = file->linbuf;
270 int from = group->from, upto = group->upto;
275 /* If possible, use a single fwrite; it's faster. */
276 if (!tab_expand_flag && format[0] == '%')
278 if (format[1] == 'l' && format[2] == '\n' && !format[3])
280 fwrite (linbuf[from], sizeof (char),
281 linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
285 if (format[1] == 'L' && !format[2])
287 fwrite (linbuf[from], sizeof (char),
288 linbuf[upto] - linbuf[from], out);
293 for (; from < upto; from++)
296 register char *f = format;
298 while ((c = *f++) != 0)
309 output_1_line (linbuf[from],
311 - (linbuf[from + 1][-1] == '\n'), 0, 0);
315 output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
323 f = scan_printf_spec (spec);
331 f = scan_char_literal (f, &value);
337 value = translate_line_number (file, from);
343 /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */
345 fprintf (out, spec - 1, value);
346 /* Undo the temporary replacement. */
362 /* Scan the character literal represented in the string LIT; LIT points just
363 after the initial apostrophe. Put the literal's value into *INTPTR.
364 Yield the address of the first character after the closing apostrophe,
365 or zero if the literal is ill-formed. */
367 scan_char_literal (lit, intptr)
371 register char *p = lit;
383 while ((c = *p++) != '\'')
385 unsigned digit = c - '0';
388 value = 8 * value + digit;
390 digits = p - lit - 2;
391 if (! (1 <= digits && digits <= 3))
405 /* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'.
406 Return the address of the character following SPEC, or zero if failure. */
408 scan_printf_spec (spec)
411 register unsigned char c;
413 while ((c = *spec++) == '-')
418 while (ISDIGIT (c = *spec++))
422 case 'c': case 'd': case 'o': case 'x': case 'X':