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