Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
/* Support routines for GNU DIFF.
2
   Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
3
 
4
This file is part of GNU DIFF.
5
 
6
GNU DIFF is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU DIFF is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU DIFF; see the file COPYING.  If not, write to
18
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
 
20
/* $FreeBSD: src/contrib/diff/util.c,v 1.2.6.2 2000/09/20 02:24:32 jkh Exp $ */
21
 
22
#include "diff.h"
23
 
24
#ifndef PR_PROGRAM
25
#define PR_PROGRAM "/bin/pr"
26
#endif
27
 
28
/* Queue up one-line messages to be printed at the end,
29
   when -l is specified.  Each message is recorded with a `struct msg'.  */
30
 
31
struct msg
32
{
33
  struct msg *next;
34
  char const *format;
35
  char const *arg1;
36
  char const *arg2;
37
  char const *arg3;
38
  char const *arg4;
39
};
40
 
41
/* Head of the chain of queues messages.  */
42
 
43
static struct msg *msg_chain;
44
 
45
/* Tail of the chain of queues messages.  */
46
 
47
static struct msg **msg_chain_end = &msg_chain;
48
 
49
/* Use when a system call returns non-zero status.
50
   TEXT should normally be the file name.  */
51
 
52
void
53
perror_with_name (text)
54
     char const *text;
55
{
56
  int e = errno;
57
  fprintf (stderr, "%s: ", program_name);
58
  errno = e;
59
  perror (text);
60
}
61
 
62
/* Use when a system call returns non-zero status and that is fatal.  */
63
 
64
void
65
pfatal_with_name (text)
66
     char const *text;
67
{
68
  int e = errno;
69
  print_message_queue ();
70
  fprintf (stderr, "%s: ", program_name);
71
  errno = e;
72
  perror (text);
73
  exit (2);
74
}
75
 
76
/* Print an error message from the format-string FORMAT
77
   with args ARG1 and ARG2.  */
78
 
79
void
80
error (format, arg, arg1)
81
     char const *format, *arg, *arg1;
82
{
83
  fprintf (stderr, "%s: ", program_name);
84
  fprintf (stderr, format, arg, arg1);
85
  fprintf (stderr, "\n");
86
}
87
 
88
/* Print an error message containing the string TEXT, then exit.  */
89
 
90
void
91
fatal (m)
92
     char const *m;
93
{
94
  print_message_queue ();
95
  error ("%s", m, 0);
96
  exit (2);
97
}
98
 
99
/* Like printf, except if -l in effect then save the message and print later.
100
   This is used for things like "binary files differ" and "Only in ...".  */
101
 
102
void
103
message (format, arg1, arg2)
104
     char const *format, *arg1, *arg2;
105
{
106
  message5 (format, arg1, arg2, 0, 0);
107
}
108
 
109
void
110
message5 (format, arg1, arg2, arg3, arg4)
111
     char const *format, *arg1, *arg2, *arg3, *arg4;
112
{
113
  if (paginate_flag)
114
    {
115
      struct msg *new = (struct msg *) xmalloc (sizeof (struct msg));
116
      new->format = format;
117
      new->arg1 = concat (arg1, "", "");
118
      new->arg2 = concat (arg2, "", "");
119
      new->arg3 = arg3 ? concat (arg3, "", "") : 0;
120
      new->arg4 = arg4 ? concat (arg4, "", "") : 0;
121
      new->next = 0;
122
      *msg_chain_end = new;
123
      msg_chain_end = &new->next;
124
    }
125
  else
126
    {
127
      if (sdiff_help_sdiff)
128
	putchar (' ');
129
      printf (format, arg1, arg2, arg3, arg4);
130
    }
131
}
132
 
133
/* Output all the messages that were saved up by calls to `message'.  */
134
 
135
void
136
print_message_queue ()
137
{
138
  struct msg *m;
139
 
140
  for (m = msg_chain; m; m = m->next)
141
    printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4);
142
}
143
 
144
/* Call before outputting the results of comparing files NAME0 and NAME1
145
   to set up OUTFILE, the stdio stream for the output to go to.
146
 
147
   Usually, OUTFILE is just stdout.  But when -l was specified
148
   we fork off a `pr' and make OUTFILE a pipe to it.
149
   `pr' then outputs to our stdout.  */
150
 
151
static char const *current_name0;
152
static char const *current_name1;
153
static int current_depth;
154
 
155
void
156
setup_output (name0, name1, depth)
157
     char const *name0, *name1;
158
     int depth;
159
{
160
  current_name0 = name0;
161
  current_name1 = name1;
162
  current_depth = depth;
163
  outfile = 0;
164
}
165
 
166
#if HAVE_FORK
167
static pid_t pr_pid;
168
#endif
169
 
170
void
171
begin_output ()
172
{
173
  char *name;
174
 
175
  if (outfile != 0)
176
    return;
177
 
178
  /* Construct the header of this piece of diff.  */
179
  name = xmalloc (strlen (current_name0) + strlen (current_name1)
180
		  + strlen (switch_string) + 7);
181
  /* Posix.2 section 4.17.6.1.1 specifies this format.  But there is a
182
     bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304):
183
     it says that we must print only the last component of the pathnames.
184
     This requirement is silly and does not match historical practice.  */
185
  sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
186
 
187
  if (paginate_flag)
188
    {
189
      /* Make OUTFILE a pipe to a subsidiary `pr'.  */
190
 
191
#if HAVE_FORK
192
      int pipes[2];
193
 
194
      if (pipe (pipes) != 0)
195
	pfatal_with_name ("pipe");
196
 
197
      fflush (stdout);
198
 
199
      pr_pid = fork ();
200
      if (pr_pid < 0)
201
	pfatal_with_name ("vfork");
202
 
203
      if (pr_pid == 0)
204
	{
205
	  close (pipes[1]);
206
	  if (pipes[0] != STDIN_FILENO)
207
	    {
208
	      if (dup2 (pipes[0], STDIN_FILENO) < 0)
209
		pfatal_with_name ("dup2");
210
	      close (pipes[0]);
211
	    }
212
#ifdef __FreeBSD__
213
	  execl (PR_PROGRAM, PR_PROGRAM, "-F", "-h", name, 0);
214
#else
215
	  execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, 0);
216
#endif
217
	  pfatal_with_name (PR_PROGRAM);
218
	}
219
      else
220
	{
221
	  close (pipes[0]);
222
	  outfile = fdopen (pipes[1], "w");
223
	  if (!outfile)
224
	    pfatal_with_name ("fdopen");
225
	}
226
#else /* ! HAVE_FORK */
227
      char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10);
228
      char *p;
229
      char const *a = name;
230
      sprintf (command, "%s -f -h ", PR_PROGRAM);
231
      p = command + strlen (command);
232
      SYSTEM_QUOTE_ARG (p, a);
233
      *p = 0;
234
      outfile = popen (command, "w");
235
      if (!outfile)
236
	pfatal_with_name (command);
237
      free (command);
238
#endif /* ! HAVE_FORK */
239
    }
240
  else
241
    {
242
 
243
      /* If -l was not specified, output the diff straight to `stdout'.  */
244
 
245
      outfile = stdout;
246
 
247
      /* If handling multiple files (because scanning a directory),
248
	 print which files the following output is about.  */
249
      if (current_depth > 0)
250
	printf ("%s\n", name);
251
    }
252
 
253
  free (name);
254
 
255
  /* A special header is needed at the beginning of context output.  */
256
  switch (output_style)
257
    {
258
    case OUTPUT_CONTEXT:
259
      print_context_header (files, 0);
260
      break;
261
 
262
    case OUTPUT_UNIFIED:
263
      print_context_header (files, 1);
264
      break;
265
 
266
    default:
267
      break;
268
    }
269
}
270
 
271
/* Call after the end of output of diffs for one file.
272
   Close OUTFILE and get rid of the `pr' subfork.  */
273
 
274
void
275
finish_output ()
276
{
277
  if (outfile != 0 && outfile != stdout)
278
    {
279
      int wstatus;
280
      if (ferror (outfile))
281
	fatal ("write error");
282
#if ! HAVE_FORK
283
      wstatus = pclose (outfile);
284
#else /* HAVE_FORK */
285
      if (fclose (outfile) != 0)
286
	pfatal_with_name ("write error");
287
      if (waitpid (pr_pid, &wstatus, 0) < 0)
288
	pfatal_with_name ("waitpid");
289
#endif /* HAVE_FORK */
290
      if (wstatus != 0)
291
	fatal ("subsidiary pr failed");
292
    }
293
 
294
  outfile = 0;
295
}
296
 
297
/* Compare two lines (typically one from each input file)
298
   according to the command line options.
299
   For efficiency, this is invoked only when the lines do not match exactly
300
   but an option like -i might cause us to ignore the difference.
301
   Return nonzero if the lines differ.  */
302
 
303
int
304
line_cmp (s1, s2)
305
     char const *s1, *s2;
306
{
307
  register unsigned char const *t1 = (unsigned char const *) s1;
308
  register unsigned char const *t2 = (unsigned char const *) s2;
309
 
310
  while (1)
311
    {
312
      register unsigned char c1 = *t1++;
313
      register unsigned char c2 = *t2++;
314
 
315
      /* Test for exact char equality first, since it's a common case.  */
316
      if (c1 != c2)
317
	{
318
	  /* Ignore horizontal white space if -b or -w is specified.  */
319
 
320
	  if (ignore_all_space_flag)
321
	    {
322
	      /* For -w, just skip past any white space.  */
323
	      while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
324
	      while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
325
	    }
326
	  else if (ignore_space_change_flag)
327
	    {
328
	      /* For -b, advance past any sequence of white space in line 1
329
		 and consider it just one Space, or nothing at all
330
		 if it is at the end of the line.  */
331
	      if (ISSPACE (c1))
332
		{
333
		  while (c1 != '\n')
334
		    {
335
		      c1 = *t1++;
336
		      if (! ISSPACE (c1))
337
			{
338
			  --t1;
339
			  c1 = ' ';
340
			  break;
341
			}
342
		    }
343
		}
344
 
345
	      /* Likewise for line 2.  */
346
	      if (ISSPACE (c2))
347
		{
348
		  while (c2 != '\n')
349
		    {
350
		      c2 = *t2++;
351
		      if (! ISSPACE (c2))
352
			{
353
			  --t2;
354
			  c2 = ' ';
355
			  break;
356
			}
357
		    }
358
		}
359
 
360
	      if (c1 != c2)
361
		{
362
		  /* If we went too far when doing the simple test
363
		     for equality, go back to the first non-white-space
364
		     character in both sides and try again.  */
365
		  if (c2 == ' ' && c1 != '\n'
366
		      && (unsigned char const *) s1 + 1 < t1
367
		      && ISSPACE(t1[-2]))
368
		    {
369
		      --t1;
370
		      continue;
371
		    }
372
		  if (c1 == ' ' && c2 != '\n'
373
		      && (unsigned char const *) s2 + 1 < t2
374
		      && ISSPACE(t2[-2]))
375
		    {
376
		      --t2;
377
		      continue;
378
		    }
379
		}
380
	    }
381
 
382
	  /* Lowercase all letters if -i is specified.  */
383
 
384
	  if (ignore_case_flag)
385
	    {
386
	      if (ISUPPER (c1))
387
		c1 = tolower (c1);
388
	      if (ISUPPER (c2))
389
		c2 = tolower (c2);
390
	    }
391
 
392
	  if (c1 != c2)
393
	    break;
394
	}
395
      if (c1 == '\n')
396
	return 0;
397
    }
398
 
399
  return (1);
400
}
401
 
402
/* Find the consecutive changes at the start of the script START.
403
   Return the last link before the first gap.  */
404
 
405
struct change *
406
find_change (start)
407
     struct change *start;
408
{
409
  return start;
410
}
411
 
412
struct change *
413
find_reverse_change (start)
414
     struct change *start;
415
{
416
  return start;
417
}
418
 
419
/* Divide SCRIPT into pieces by calling HUNKFUN and
420
   print each piece with PRINTFUN.
421
   Both functions take one arg, an edit script.
422
 
423
   HUNKFUN is called with the tail of the script
424
   and returns the last link that belongs together with the start
425
   of the tail.
426
 
427
   PRINTFUN takes a subscript which belongs together (with a null
428
   link at the end) and prints it.  */
429
 
430
void
431
print_script (script, hunkfun, printfun)
432
     struct change *script;
433
     struct change * (*hunkfun) PARAMS((struct change *));
434
     void (*printfun) PARAMS((struct change *));
435
{
436
  struct change *next = script;
437
 
438
  while (next)
439
    {
440
      struct change *this, *end;
441
 
442
      /* Find a set of changes that belong together.  */
443
      this = next;
444
      end = (*hunkfun) (next);
445
 
446
      /* Disconnect them from the rest of the changes,
447
	 making them a hunk, and remember the rest for next iteration.  */
448
      next = end->link;
449
      end->link = 0;
450
#ifdef DEBUG
451
      debug_script (this);
452
#endif
453
 
454
      /* Print this hunk.  */
455
      (*printfun) (this);
456
 
457
      /* Reconnect the script so it will all be freed properly.  */
458
      end->link = next;
459
    }
460
}
461
 
462
/* Print the text of a single line LINE,
463
   flagging it with the characters in LINE_FLAG (which say whether
464
   the line is inserted, deleted, changed, etc.).  */
465
 
466
void
467
print_1_line (line_flag, line)
468
     char const *line_flag;
469
     char const * const *line;
470
{
471
  char const *text = line[0], *limit = line[1]; /* Help the compiler.  */
472
  FILE *out = outfile; /* Help the compiler some more.  */
473
  char const *flag_format = 0;
474
 
475
  /* If -T was specified, use a Tab between the line-flag and the text.
476
     Otherwise use a Space (as Unix diff does).
477
     Print neither space nor tab if line-flags are empty.  */
478
 
479
  if (line_flag && *line_flag)
480
    {
481
      flag_format = tab_align_flag ? "%s\t" : "%s ";
482
      fprintf (out, flag_format, line_flag);
483
    }
484
 
485
  output_1_line (text, limit, flag_format, line_flag);
486
 
487
  if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
488
    fputc ('\n', out);
489
}
490
 
491
/* Output a line from TEXT up to LIMIT.  Without -t, output verbatim.
492
   With -t, expand white space characters to spaces, and if FLAG_FORMAT
493
   is nonzero, output it with argument LINE_FLAG after every
494
   internal carriage return, so that tab stops continue to line up.  */
495
 
496
void
497
output_1_line (text, limit, flag_format, line_flag)
498
     char const *text, *limit, *flag_format, *line_flag;
499
{
500
  if (!tab_expand_flag)
501
    fwrite (text, sizeof (char), limit - text, outfile);
502
  else
503
    {
504
      register FILE *out = outfile;
505
      register unsigned char c;
506
      register char const *t = text;
507
      register unsigned column = 0;
508
 
509
      while (t < limit)
510
	switch ((c = *t++))
511
	  {
512
	  case '\t':
513
	    {
514
	      unsigned spaces = TAB_WIDTH - column % TAB_WIDTH;
515
	      column += spaces;
516
	      do
517
		putc (' ', out);
518
	      while (--spaces);
519
	    }
520
	    break;
521
 
522
	  case '\r':
523
	    putc (c, out);
524
	    if (flag_format && t < limit && *t != '\n')
525
	      fprintf (out, flag_format, line_flag);
526
	    column = 0;
527
	    break;
528
 
529
	  case '\b':
530
	    if (column == 0)
531
	      continue;
532
	    column--;
533
	    putc (c, out);
534
	    break;
535
 
536
	  default:
537
	    if (ISPRINT (c))
538
	      column++;
539
	    putc (c, out);
540
	    break;
541
	  }
542
    }
543
}
544
 
545
int
546
change_letter (inserts, deletes)
547
     int inserts, deletes;
548
{
549
  if (!inserts)
550
    return 'd';
551
  else if (!deletes)
552
    return 'a';
553
  else
554
    return 'c';
555
}
556
 
557
/* Translate an internal line number (an index into diff's table of lines)
558
   into an actual line number in the input file.
559
   The internal line number is LNUM.  FILE points to the data on the file.
560
 
561
   Internal line numbers count from 0 starting after the prefix.
562
   Actual line numbers count from 1 within the entire file.  */
563
 
564
int
565
translate_line_number (file, lnum)
566
     struct file_data const *file;
567
     int lnum;
568
{
569
  return lnum + file->prefix_lines + 1;
570
}
571
 
572
void
573
translate_range (file, a, b, aptr, bptr)
574
     struct file_data const *file;
575
     int a, b;
576
     int *aptr, *bptr;
577
{
578
  *aptr = translate_line_number (file, a - 1) + 1;
579
  *bptr = translate_line_number (file, b + 1) - 1;
580
}
581
 
582
/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
583
   If the two numbers are identical, print just one number.
584
 
585
   Args A and B are internal line numbers.
586
   We print the translated (real) line numbers.  */
587
 
588
void
589
print_number_range (sepchar, file, a, b)
590
     int sepchar;
591
     struct file_data *file;
592
     int a, b;
593
{
594
  int trans_a, trans_b;
595
  translate_range (file, a, b, &trans_a, &trans_b);
596
 
597
  /* Note: we can have B < A in the case of a range of no lines.
598
     In this case, we should print the line number before the range,
599
     which is B.  */
600
  if (trans_b > trans_a)
601
    fprintf (outfile, "%d%c%d", trans_a, sepchar, trans_b);
602
  else
603
    fprintf (outfile, "%d", trans_b);
604
}
605
 
606
/* Look at a hunk of edit script and report the range of lines in each file
607
   that it applies to.  HUNK is the start of the hunk, which is a chain
608
   of `struct change'.  The first and last line numbers of file 0 are stored in
609
   *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
610
   Note that these are internal line numbers that count from 0.
611
 
612
   If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
613
 
614
   Also set *DELETES nonzero if any lines of file 0 are deleted
615
   and set *INSERTS nonzero if any lines of file 1 are inserted.
616
   If only ignorable lines are inserted or deleted, both are
617
   set to 0.  */
618
 
619
void
620
analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts)
621
     struct change *hunk;
622
     int *first0, *last0, *first1, *last1;
623
     int *deletes, *inserts;
624
{
625
  int l0, l1, show_from, show_to;
626
  int i;
627
  int trivial = ignore_blank_lines_flag || ignore_regexp_list;
628
  struct change *next;
629
 
630
  show_from = show_to = 0;
631
 
632
  *first0 = hunk->line0;
633
  *first1 = hunk->line1;
634
 
635
  next = hunk;
636
  do
637
    {
638
      l0 = next->line0 + next->deleted - 1;
639
      l1 = next->line1 + next->inserted - 1;
640
      show_from += next->deleted;
641
      show_to += next->inserted;
642
 
643
      for (i = next->line0; i <= l0 && trivial; i++)
644
	if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n')
645
	  {
646
	    struct regexp_list *r;
647
	    char const *line = files[0].linbuf[i];
648
	    int len = files[0].linbuf[i + 1] - line;
649
 
650
	    for (r = ignore_regexp_list; r; r = r->next)
651
	      if (0 <= re_search (&r->buf, line, len, 0, len, 0))
652
		break;	/* Found a match.  Ignore this line.  */
653
	    /* If we got all the way through the regexp list without
654
	       finding a match, then it's nontrivial.  */
655
	    if (!r)
656
	      trivial = 0;
657
	  }
658
 
659
      for (i = next->line1; i <= l1 && trivial; i++)
660
	if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n')
661
	  {
662
	    struct regexp_list *r;
663
	    char const *line = files[1].linbuf[i];
664
	    int len = files[1].linbuf[i + 1] - line;
665
 
666
	    for (r = ignore_regexp_list; r; r = r->next)
667
	      if (0 <= re_search (&r->buf, line, len, 0, len, 0))
668
		break;	/* Found a match.  Ignore this line.  */
669
	    /* If we got all the way through the regexp list without
670
	       finding a match, then it's nontrivial.  */
671
	    if (!r)
672
	      trivial = 0;
673
	  }
674
    }
675
  while ((next = next->link) != 0);
676
 
677
  *last0 = l0;
678
  *last1 = l1;
679
 
680
  /* If all inserted or deleted lines are ignorable,
681
     tell the caller to ignore this hunk.  */
682
 
683
  if (trivial)
684
    show_from = show_to = 0;
685
 
686
  *deletes = show_from;
687
  *inserts = show_to;
688
}
689
 
690
/* malloc a block of memory, with fatal error message if we can't do it. */
691
 
692
VOID *
693
xmalloc (size)
694
     size_t size;
695
{
696
  register VOID *value;
697
 
698
  if (size == 0)
699
    size = 1;
700
 
701
  value = (VOID *) malloc (size);
702
 
703
  if (!value)
704
    fatal ("memory exhausted");
705
  return value;
706
}
707
 
708
/* realloc a block of memory, with fatal error message if we can't do it. */
709
 
710
VOID *
711
xrealloc (old, size)
712
     VOID *old;
713
     size_t size;
714
{
715
  register VOID *value;
716
 
717
  if (size == 0)
718
    size = 1;
719
 
720
  value = (VOID *) realloc (old, size);
721
 
722
  if (!value)
723
    fatal ("memory exhausted");
724
  return value;
725
}
726
 
727
/* Concatenate three strings, returning a newly malloc'd string.  */
728
 
729
char *
730
concat (s1, s2, s3)
731
     char const *s1, *s2, *s3;
732
{
733
  size_t len = strlen (s1) + strlen (s2) + strlen (s3);
734
  char *new = xmalloc (len + 1);
735
  sprintf (new, "%s%s%s", s1, s2, s3);
736
  return new;
737
}
738
 
739
/* Yield the newly malloc'd pathname
740
   of the file in DIR whose filename is FILE.  */
741
 
742
char *
743
dir_file_pathname (dir, file)
744
     char const *dir, *file;
745
{
746
  char const *p = filename_lastdirchar (dir);
747
  return concat (dir, "/" + (p && !p[1]), file);
748
}
749
 
750
void
751
debug_script (sp)
752
     struct change *sp;
753
{
754
  fflush (stdout);
755
  for (; sp; sp = sp->link)
756
    fprintf (stderr, "%3d %3d delete %d insert %d\n",
757
	     sp->line0, sp->line1, sp->deleted, sp->inserted);
758
  fflush (stderr);
759
}