Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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