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