1*18fd37a7SXin LI /* #ifdef-format output routines for GNU DIFF.
2*18fd37a7SXin LI
3*18fd37a7SXin LI Copyright (C) 1989, 1991, 1992, 1993, 1994, 2001, 2002, 2004 Free
4*18fd37a7SXin LI Software Foundation, Inc.
5*18fd37a7SXin LI
6*18fd37a7SXin LI This file is part of GNU DIFF.
7*18fd37a7SXin LI
8*18fd37a7SXin LI GNU DIFF is distributed in the hope that it will be useful,
9*18fd37a7SXin LI but WITHOUT ANY WARRANTY. No author or distributor
10*18fd37a7SXin LI accepts responsibility to anyone for the consequences of using it
11*18fd37a7SXin LI or for whether it serves any particular purpose or works at all,
12*18fd37a7SXin LI unless he says so in writing. Refer to the GNU DIFF General Public
13*18fd37a7SXin LI License for full details.
14*18fd37a7SXin LI
15*18fd37a7SXin LI Everyone is granted permission to copy, modify and redistribute
16*18fd37a7SXin LI GNU DIFF, but only under the conditions described in the
17*18fd37a7SXin LI GNU DIFF General Public License. A copy of this license is
18*18fd37a7SXin LI supposed to have been given to you along with GNU DIFF so you
19*18fd37a7SXin LI can know your rights and responsibilities. It should be in a
20*18fd37a7SXin LI file named COPYING. Among other things, the copyright notice
21*18fd37a7SXin LI and this notice must be preserved on all copies. */
22*18fd37a7SXin LI
23*18fd37a7SXin LI #include "diff.h"
24*18fd37a7SXin LI
25*18fd37a7SXin LI #include <xalloc.h>
26*18fd37a7SXin LI
27*18fd37a7SXin LI struct group
28*18fd37a7SXin LI {
29*18fd37a7SXin LI struct file_data const *file;
30*18fd37a7SXin LI lin from, upto; /* start and limit lines for this group of lines */
31*18fd37a7SXin LI };
32*18fd37a7SXin LI
33*18fd37a7SXin LI static char const *format_group (FILE *, char const *, char,
34*18fd37a7SXin LI struct group const *);
35*18fd37a7SXin LI static char const *do_printf_spec (FILE *, char const *,
36*18fd37a7SXin LI struct file_data const *, lin,
37*18fd37a7SXin LI struct group const *);
38*18fd37a7SXin LI static char const *scan_char_literal (char const *, char *);
39*18fd37a7SXin LI static lin groups_letter_value (struct group const *, char);
40*18fd37a7SXin LI static void format_ifdef (char const *, lin, lin, lin, lin);
41*18fd37a7SXin LI static void print_ifdef_hunk (struct change *);
42*18fd37a7SXin LI static void print_ifdef_lines (FILE *, char const *, struct group const *);
43*18fd37a7SXin LI
44*18fd37a7SXin LI static lin next_line0;
45*18fd37a7SXin LI static lin next_line1;
46*18fd37a7SXin LI
47*18fd37a7SXin LI /* Print the edit-script SCRIPT as a merged #ifdef file. */
48*18fd37a7SXin LI
49*18fd37a7SXin LI void
print_ifdef_script(struct change * script)50*18fd37a7SXin LI print_ifdef_script (struct change *script)
51*18fd37a7SXin LI {
52*18fd37a7SXin LI next_line0 = next_line1 = - files[0].prefix_lines;
53*18fd37a7SXin LI print_script (script, find_change, print_ifdef_hunk);
54*18fd37a7SXin LI if (next_line0 < files[0].valid_lines
55*18fd37a7SXin LI || next_line1 < files[1].valid_lines)
56*18fd37a7SXin LI {
57*18fd37a7SXin LI begin_output ();
58*18fd37a7SXin LI format_ifdef (group_format[UNCHANGED],
59*18fd37a7SXin LI next_line0, files[0].valid_lines,
60*18fd37a7SXin LI next_line1, files[1].valid_lines);
61*18fd37a7SXin LI }
62*18fd37a7SXin LI }
63*18fd37a7SXin LI
64*18fd37a7SXin LI /* Print a hunk of an ifdef diff.
65*18fd37a7SXin LI This is a contiguous portion of a complete edit script,
66*18fd37a7SXin LI describing changes in consecutive lines. */
67*18fd37a7SXin LI
68*18fd37a7SXin LI static void
print_ifdef_hunk(struct change * hunk)69*18fd37a7SXin LI print_ifdef_hunk (struct change *hunk)
70*18fd37a7SXin LI {
71*18fd37a7SXin LI lin first0, last0, first1, last1;
72*18fd37a7SXin LI
73*18fd37a7SXin LI /* Determine range of line numbers involved in each file. */
74*18fd37a7SXin LI enum changes changes = analyze_hunk (hunk, &first0, &last0, &first1, &last1);
75*18fd37a7SXin LI if (!changes)
76*18fd37a7SXin LI return;
77*18fd37a7SXin LI
78*18fd37a7SXin LI begin_output ();
79*18fd37a7SXin LI
80*18fd37a7SXin LI /* Print lines up to this change. */
81*18fd37a7SXin LI if (next_line0 < first0 || next_line1 < first1)
82*18fd37a7SXin LI format_ifdef (group_format[UNCHANGED],
83*18fd37a7SXin LI next_line0, first0,
84*18fd37a7SXin LI next_line1, first1);
85*18fd37a7SXin LI
86*18fd37a7SXin LI /* Print this change. */
87*18fd37a7SXin LI next_line0 = last0 + 1;
88*18fd37a7SXin LI next_line1 = last1 + 1;
89*18fd37a7SXin LI format_ifdef (group_format[changes],
90*18fd37a7SXin LI first0, next_line0,
91*18fd37a7SXin LI first1, next_line1);
92*18fd37a7SXin LI }
93*18fd37a7SXin LI
94*18fd37a7SXin LI /* Print a set of lines according to FORMAT.
95*18fd37a7SXin LI Lines BEG0 up to END0 are from the first file;
96*18fd37a7SXin LI lines BEG1 up to END1 are from the second file. */
97*18fd37a7SXin LI
98*18fd37a7SXin LI static void
format_ifdef(char const * format,lin beg0,lin end0,lin beg1,lin end1)99*18fd37a7SXin LI format_ifdef (char const *format, lin beg0, lin end0, lin beg1, lin end1)
100*18fd37a7SXin LI {
101*18fd37a7SXin LI struct group groups[2];
102*18fd37a7SXin LI
103*18fd37a7SXin LI groups[0].file = &files[0];
104*18fd37a7SXin LI groups[0].from = beg0;
105*18fd37a7SXin LI groups[0].upto = end0;
106*18fd37a7SXin LI groups[1].file = &files[1];
107*18fd37a7SXin LI groups[1].from = beg1;
108*18fd37a7SXin LI groups[1].upto = end1;
109*18fd37a7SXin LI format_group (outfile, format, 0, groups);
110*18fd37a7SXin LI }
111*18fd37a7SXin LI
112*18fd37a7SXin LI /* Print to file OUT a set of lines according to FORMAT.
113*18fd37a7SXin LI The format ends at the first free instance of ENDCHAR.
114*18fd37a7SXin LI Yield the address of the terminating character.
115*18fd37a7SXin LI GROUPS specifies which lines to print.
116*18fd37a7SXin LI If OUT is zero, do not actually print anything; just scan the format. */
117*18fd37a7SXin LI
118*18fd37a7SXin LI static char const *
format_group(register FILE * out,char const * format,char endchar,struct group const * groups)119*18fd37a7SXin LI format_group (register FILE *out, char const *format, char endchar,
120*18fd37a7SXin LI struct group const *groups)
121*18fd37a7SXin LI {
122*18fd37a7SXin LI register char c;
123*18fd37a7SXin LI register char const *f = format;
124*18fd37a7SXin LI
125*18fd37a7SXin LI while ((c = *f) != endchar && c != 0)
126*18fd37a7SXin LI {
127*18fd37a7SXin LI char const *f1 = ++f;
128*18fd37a7SXin LI if (c == '%')
129*18fd37a7SXin LI switch ((c = *f++))
130*18fd37a7SXin LI {
131*18fd37a7SXin LI case '%':
132*18fd37a7SXin LI break;
133*18fd37a7SXin LI
134*18fd37a7SXin LI case '(':
135*18fd37a7SXin LI /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */
136*18fd37a7SXin LI {
137*18fd37a7SXin LI int i;
138*18fd37a7SXin LI uintmax_t value[2];
139*18fd37a7SXin LI FILE *thenout, *elseout;
140*18fd37a7SXin LI
141*18fd37a7SXin LI for (i = 0; i < 2; i++)
142*18fd37a7SXin LI {
143*18fd37a7SXin LI if (ISDIGIT (*f))
144*18fd37a7SXin LI {
145*18fd37a7SXin LI char *fend;
146*18fd37a7SXin LI errno = 0;
147*18fd37a7SXin LI value[i] = strtoumax (f, &fend, 10);
148*18fd37a7SXin LI if (errno)
149*18fd37a7SXin LI goto bad_format;
150*18fd37a7SXin LI f = fend;
151*18fd37a7SXin LI }
152*18fd37a7SXin LI else
153*18fd37a7SXin LI {
154*18fd37a7SXin LI value[i] = groups_letter_value (groups, *f);
155*18fd37a7SXin LI if (value[i] == -1)
156*18fd37a7SXin LI goto bad_format;
157*18fd37a7SXin LI f++;
158*18fd37a7SXin LI }
159*18fd37a7SXin LI if (*f++ != "=?"[i])
160*18fd37a7SXin LI goto bad_format;
161*18fd37a7SXin LI }
162*18fd37a7SXin LI if (value[0] == value[1])
163*18fd37a7SXin LI thenout = out, elseout = 0;
164*18fd37a7SXin LI else
165*18fd37a7SXin LI thenout = 0, elseout = out;
166*18fd37a7SXin LI f = format_group (thenout, f, ':', groups);
167*18fd37a7SXin LI if (*f)
168*18fd37a7SXin LI {
169*18fd37a7SXin LI f = format_group (elseout, f + 1, ')', groups);
170*18fd37a7SXin LI if (*f)
171*18fd37a7SXin LI f++;
172*18fd37a7SXin LI }
173*18fd37a7SXin LI }
174*18fd37a7SXin LI continue;
175*18fd37a7SXin LI
176*18fd37a7SXin LI case '<':
177*18fd37a7SXin LI /* Print lines deleted from first file. */
178*18fd37a7SXin LI print_ifdef_lines (out, line_format[OLD], &groups[0]);
179*18fd37a7SXin LI continue;
180*18fd37a7SXin LI
181*18fd37a7SXin LI case '=':
182*18fd37a7SXin LI /* Print common lines. */
183*18fd37a7SXin LI print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]);
184*18fd37a7SXin LI continue;
185*18fd37a7SXin LI
186*18fd37a7SXin LI case '>':
187*18fd37a7SXin LI /* Print lines inserted from second file. */
188*18fd37a7SXin LI print_ifdef_lines (out, line_format[NEW], &groups[1]);
189*18fd37a7SXin LI continue;
190*18fd37a7SXin LI
191*18fd37a7SXin LI default:
192*18fd37a7SXin LI f = do_printf_spec (out, f - 2, 0, 0, groups);
193*18fd37a7SXin LI if (f)
194*18fd37a7SXin LI continue;
195*18fd37a7SXin LI /* Fall through. */
196*18fd37a7SXin LI bad_format:
197*18fd37a7SXin LI c = '%';
198*18fd37a7SXin LI f = f1;
199*18fd37a7SXin LI break;
200*18fd37a7SXin LI }
201*18fd37a7SXin LI
202*18fd37a7SXin LI if (out)
203*18fd37a7SXin LI putc (c, out);
204*18fd37a7SXin LI }
205*18fd37a7SXin LI
206*18fd37a7SXin LI return f;
207*18fd37a7SXin LI }
208*18fd37a7SXin LI
209*18fd37a7SXin LI /* For the line group pair G, return the number corresponding to LETTER.
210*18fd37a7SXin LI Return -1 if LETTER is not a group format letter. */
211*18fd37a7SXin LI static lin
groups_letter_value(struct group const * g,char letter)212*18fd37a7SXin LI groups_letter_value (struct group const *g, char letter)
213*18fd37a7SXin LI {
214*18fd37a7SXin LI switch (letter)
215*18fd37a7SXin LI {
216*18fd37a7SXin LI case 'E': letter = 'e'; g++; break;
217*18fd37a7SXin LI case 'F': letter = 'f'; g++; break;
218*18fd37a7SXin LI case 'L': letter = 'l'; g++; break;
219*18fd37a7SXin LI case 'M': letter = 'm'; g++; break;
220*18fd37a7SXin LI case 'N': letter = 'n'; g++; break;
221*18fd37a7SXin LI }
222*18fd37a7SXin LI
223*18fd37a7SXin LI switch (letter)
224*18fd37a7SXin LI {
225*18fd37a7SXin LI case 'e': return translate_line_number (g->file, g->from) - 1;
226*18fd37a7SXin LI case 'f': return translate_line_number (g->file, g->from);
227*18fd37a7SXin LI case 'l': return translate_line_number (g->file, g->upto) - 1;
228*18fd37a7SXin LI case 'm': return translate_line_number (g->file, g->upto);
229*18fd37a7SXin LI case 'n': return g->upto - g->from;
230*18fd37a7SXin LI default: return -1;
231*18fd37a7SXin LI }
232*18fd37a7SXin LI }
233*18fd37a7SXin LI
234*18fd37a7SXin LI /* Print to file OUT, using FORMAT to print the line group GROUP.
235*18fd37a7SXin LI But do nothing if OUT is zero. */
236*18fd37a7SXin LI static void
print_ifdef_lines(register FILE * out,char const * format,struct group const * group)237*18fd37a7SXin LI print_ifdef_lines (register FILE *out, char const *format,
238*18fd37a7SXin LI struct group const *group)
239*18fd37a7SXin LI {
240*18fd37a7SXin LI struct file_data const *file = group->file;
241*18fd37a7SXin LI char const * const *linbuf = file->linbuf;
242*18fd37a7SXin LI lin from = group->from, upto = group->upto;
243*18fd37a7SXin LI
244*18fd37a7SXin LI if (!out)
245*18fd37a7SXin LI return;
246*18fd37a7SXin LI
247*18fd37a7SXin LI /* If possible, use a single fwrite; it's faster. */
248*18fd37a7SXin LI if (!expand_tabs && format[0] == '%')
249*18fd37a7SXin LI {
250*18fd37a7SXin LI if (format[1] == 'l' && format[2] == '\n' && !format[3] && from < upto)
251*18fd37a7SXin LI {
252*18fd37a7SXin LI fwrite (linbuf[from], sizeof (char),
253*18fd37a7SXin LI linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from],
254*18fd37a7SXin LI out);
255*18fd37a7SXin LI return;
256*18fd37a7SXin LI }
257*18fd37a7SXin LI if (format[1] == 'L' && !format[2])
258*18fd37a7SXin LI {
259*18fd37a7SXin LI fwrite (linbuf[from], sizeof (char),
260*18fd37a7SXin LI linbuf[upto] - linbuf[from], out);
261*18fd37a7SXin LI return;
262*18fd37a7SXin LI }
263*18fd37a7SXin LI }
264*18fd37a7SXin LI
265*18fd37a7SXin LI for (; from < upto; from++)
266*18fd37a7SXin LI {
267*18fd37a7SXin LI register char c;
268*18fd37a7SXin LI register char const *f = format;
269*18fd37a7SXin LI
270*18fd37a7SXin LI while ((c = *f++) != 0)
271*18fd37a7SXin LI {
272*18fd37a7SXin LI char const *f1 = f;
273*18fd37a7SXin LI if (c == '%')
274*18fd37a7SXin LI switch ((c = *f++))
275*18fd37a7SXin LI {
276*18fd37a7SXin LI case '%':
277*18fd37a7SXin LI break;
278*18fd37a7SXin LI
279*18fd37a7SXin LI case 'l':
280*18fd37a7SXin LI output_1_line (linbuf[from],
281*18fd37a7SXin LI (linbuf[from + 1]
282*18fd37a7SXin LI - (linbuf[from + 1][-1] == '\n')),
283*18fd37a7SXin LI 0, 0);
284*18fd37a7SXin LI continue;
285*18fd37a7SXin LI
286*18fd37a7SXin LI case 'L':
287*18fd37a7SXin LI output_1_line (linbuf[from], linbuf[from + 1], 0, 0);
288*18fd37a7SXin LI continue;
289*18fd37a7SXin LI
290*18fd37a7SXin LI default:
291*18fd37a7SXin LI f = do_printf_spec (out, f - 2, file, from, 0);
292*18fd37a7SXin LI if (f)
293*18fd37a7SXin LI continue;
294*18fd37a7SXin LI c = '%';
295*18fd37a7SXin LI f = f1;
296*18fd37a7SXin LI break;
297*18fd37a7SXin LI }
298*18fd37a7SXin LI
299*18fd37a7SXin LI putc (c, out);
300*18fd37a7SXin LI }
301*18fd37a7SXin LI }
302*18fd37a7SXin LI }
303*18fd37a7SXin LI
304*18fd37a7SXin LI static char const *
do_printf_spec(FILE * out,char const * spec,struct file_data const * file,lin n,struct group const * groups)305*18fd37a7SXin LI do_printf_spec (FILE *out, char const *spec,
306*18fd37a7SXin LI struct file_data const *file, lin n,
307*18fd37a7SXin LI struct group const *groups)
308*18fd37a7SXin LI {
309*18fd37a7SXin LI char const *f = spec;
310*18fd37a7SXin LI char c;
311*18fd37a7SXin LI char c1;
312*18fd37a7SXin LI
313*18fd37a7SXin LI /* Scan printf-style SPEC of the form %[-'0]*[0-9]*(.[0-9]*)?[cdoxX]. */
314*18fd37a7SXin LI /* assert (*f == '%'); */
315*18fd37a7SXin LI f++;
316*18fd37a7SXin LI while ((c = *f++) == '-' || c == '\'' || c == '0')
317*18fd37a7SXin LI continue;
318*18fd37a7SXin LI while (ISDIGIT (c))
319*18fd37a7SXin LI c = *f++;
320*18fd37a7SXin LI if (c == '.')
321*18fd37a7SXin LI while (ISDIGIT (c = *f++))
322*18fd37a7SXin LI continue;
323*18fd37a7SXin LI c1 = *f++;
324*18fd37a7SXin LI
325*18fd37a7SXin LI switch (c)
326*18fd37a7SXin LI {
327*18fd37a7SXin LI case 'c':
328*18fd37a7SXin LI if (c1 != '\'')
329*18fd37a7SXin LI return 0;
330*18fd37a7SXin LI else
331*18fd37a7SXin LI {
332*18fd37a7SXin LI char value;
333*18fd37a7SXin LI f = scan_char_literal (f, &value);
334*18fd37a7SXin LI if (!f)
335*18fd37a7SXin LI return 0;
336*18fd37a7SXin LI if (out)
337*18fd37a7SXin LI putc (value, out);
338*18fd37a7SXin LI }
339*18fd37a7SXin LI break;
340*18fd37a7SXin LI
341*18fd37a7SXin LI case 'd': case 'o': case 'x': case 'X':
342*18fd37a7SXin LI {
343*18fd37a7SXin LI lin value;
344*18fd37a7SXin LI
345*18fd37a7SXin LI if (file)
346*18fd37a7SXin LI {
347*18fd37a7SXin LI if (c1 != 'n')
348*18fd37a7SXin LI return 0;
349*18fd37a7SXin LI value = translate_line_number (file, n);
350*18fd37a7SXin LI }
351*18fd37a7SXin LI else
352*18fd37a7SXin LI {
353*18fd37a7SXin LI value = groups_letter_value (groups, c1);
354*18fd37a7SXin LI if (value < 0)
355*18fd37a7SXin LI return 0;
356*18fd37a7SXin LI }
357*18fd37a7SXin LI
358*18fd37a7SXin LI if (out)
359*18fd37a7SXin LI {
360*18fd37a7SXin LI /* For example, if the spec is "%3xn", use the printf
361*18fd37a7SXin LI format spec "%3lx". Here the spec prefix is "%3". */
362*18fd37a7SXin LI long int long_value = value;
363*18fd37a7SXin LI size_t spec_prefix_len = f - spec - 2;
364*18fd37a7SXin LI #if HAVE_C_VARARRAYS
365*18fd37a7SXin LI char format[spec_prefix_len + 3];
366*18fd37a7SXin LI #else
367*18fd37a7SXin LI char *format = xmalloc (spec_prefix_len + 3);
368*18fd37a7SXin LI #endif
369*18fd37a7SXin LI char *p = format + spec_prefix_len;
370*18fd37a7SXin LI memcpy (format, spec, spec_prefix_len);
371*18fd37a7SXin LI *p++ = 'l';
372*18fd37a7SXin LI *p++ = c;
373*18fd37a7SXin LI *p = '\0';
374*18fd37a7SXin LI fprintf (out, format, long_value);
375*18fd37a7SXin LI #if ! HAVE_C_VARARRAYS
376*18fd37a7SXin LI free (format);
377*18fd37a7SXin LI #endif
378*18fd37a7SXin LI }
379*18fd37a7SXin LI }
380*18fd37a7SXin LI break;
381*18fd37a7SXin LI
382*18fd37a7SXin LI default:
383*18fd37a7SXin LI return 0;
384*18fd37a7SXin LI }
385*18fd37a7SXin LI
386*18fd37a7SXin LI return f;
387*18fd37a7SXin LI }
388*18fd37a7SXin LI
389*18fd37a7SXin LI /* Scan the character literal represented in the string LIT; LIT points just
390*18fd37a7SXin LI after the initial apostrophe. Put the literal's value into *VALPTR.
391*18fd37a7SXin LI Yield the address of the first character after the closing apostrophe,
392*18fd37a7SXin LI or zero if the literal is ill-formed. */
393*18fd37a7SXin LI static char const *
scan_char_literal(char const * lit,char * valptr)394*18fd37a7SXin LI scan_char_literal (char const *lit, char *valptr)
395*18fd37a7SXin LI {
396*18fd37a7SXin LI register char const *p = lit;
397*18fd37a7SXin LI char value;
398*18fd37a7SXin LI ptrdiff_t digits;
399*18fd37a7SXin LI char c = *p++;
400*18fd37a7SXin LI
401*18fd37a7SXin LI switch (c)
402*18fd37a7SXin LI {
403*18fd37a7SXin LI case 0:
404*18fd37a7SXin LI case '\'':
405*18fd37a7SXin LI return 0;
406*18fd37a7SXin LI
407*18fd37a7SXin LI case '\\':
408*18fd37a7SXin LI value = 0;
409*18fd37a7SXin LI while ((c = *p++) != '\'')
410*18fd37a7SXin LI {
411*18fd37a7SXin LI unsigned int digit = c - '0';
412*18fd37a7SXin LI if (8 <= digit)
413*18fd37a7SXin LI return 0;
414*18fd37a7SXin LI value = 8 * value + digit;
415*18fd37a7SXin LI }
416*18fd37a7SXin LI digits = p - lit - 2;
417*18fd37a7SXin LI if (! (1 <= digits && digits <= 3))
418*18fd37a7SXin LI return 0;
419*18fd37a7SXin LI break;
420*18fd37a7SXin LI
421*18fd37a7SXin LI default:
422*18fd37a7SXin LI value = c;
423*18fd37a7SXin LI if (*p++ != '\'')
424*18fd37a7SXin LI return 0;
425*18fd37a7SXin LI break;
426*18fd37a7SXin LI }
427*18fd37a7SXin LI
428*18fd37a7SXin LI *valptr = value;
429*18fd37a7SXin LI return p;
430*18fd37a7SXin LI }
431