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