xref: /freebsd-src/contrib/diff/src/ifdef.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
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