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