source: trunk/essentials/sys-apps/diffutils/src/util.c@ 3468

Last change on this file since 3468 was 3047, checked in by bird, 19 years ago

search the path on OS/2.

File size: 18.3 KB
Line 
1/* Support routines for GNU DIFF.
2
3 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002
4 Free Software Foundation, Inc.
5
6 This file is part of GNU DIFF.
7
8 GNU DIFF is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU DIFF is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23#include "diff.h"
24#include <dirname.h>
25#include <error.h>
26#include <quotesys.h>
27#include <regex.h>
28#include <xalloc.h>
29
30char const pr_program[] = PR_PROGRAM;
31
32/* Queue up one-line messages to be printed at the end,
33 when -l is specified. Each message is recorded with a `struct msg'. */
34
35struct msg
36{
37 struct msg *next;
38 char args[1]; /* Format + 4 args, each '\0' terminated, concatenated. */
39};
40
41/* Head of the chain of queues messages. */
42
43static struct msg *msg_chain;
44
45/* Tail of the chain of queues messages. */
46
47static struct msg **msg_chain_end = &msg_chain;
48
49
50/* Use when a system call returns non-zero status.
51 NAME should normally be the file name. */
52
53void
54perror_with_name (char const *name)
55{
56 error (0, errno, "%s", name);
57}
58
59/* Use when a system call returns non-zero status and that is fatal. */
60
61void
62pfatal_with_name (char const *name)
63{
64 int e = errno;
65 print_message_queue ();
66 error (EXIT_TROUBLE, e, "%s", name);
67 abort ();
68}
69
70/* Print an error message containing MSGID, then exit. */
71
72void
73fatal (char const *msgid)
74{
75 print_message_queue ();
76 error (EXIT_TROUBLE, 0, "%s", _(msgid));
77 abort ();
78}
79
80
81/* Like printf, except if -l in effect then save the message and print later.
82 This is used for things like "Only in ...". */
83
84void
85message (char const *format_msgid, char const *arg1, char const *arg2)
86{
87 message5 (format_msgid, arg1, arg2, 0, 0);
88}
89
90void
91message5 (char const *format_msgid, char const *arg1, char const *arg2,
92 char const *arg3, char const *arg4)
93{
94 if (paginate)
95 {
96 char *p;
97 char const *arg[5];
98 int i;
99 size_t size[5];
100 size_t total_size = offsetof (struct msg, args);
101 struct msg *new;
102
103 arg[0] = format_msgid;
104 arg[1] = arg1;
105 arg[2] = arg2;
106 arg[3] = arg3 ? arg3 : "";
107 arg[4] = arg4 ? arg4 : "";
108
109 for (i = 0; i < 5; i++)
110 total_size += size[i] = strlen (arg[i]) + 1;
111
112 new = xmalloc (total_size);
113
114 for (i = 0, p = new->args; i < 5; p += size[i++])
115 memcpy (p, arg[i], size[i]);
116
117 *msg_chain_end = new;
118 new->next = 0;
119 msg_chain_end = &new->next;
120 }
121 else
122 {
123 if (sdiff_merge_assist)
124 putchar (' ');
125 printf (_(format_msgid), arg1, arg2, arg3, arg4);
126 }
127}
128
129/* Output all the messages that were saved up by calls to `message'. */
130
131void
132print_message_queue (void)
133{
134 char const *arg[5];
135 int i;
136 struct msg *m = msg_chain;
137
138 while (m)
139 {
140 struct msg *next = m->next;
141 arg[0] = m->args;
142 for (i = 0; i < 4; i++)
143 arg[i + 1] = arg[i] + strlen (arg[i]) + 1;
144 printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]);
145 free (m);
146 m = next;
147 }
148}
149
150
151/* Call before outputting the results of comparing files NAME0 and NAME1
152 to set up OUTFILE, the stdio stream for the output to go to.
153
154 Usually, OUTFILE is just stdout. But when -l was specified
155 we fork off a `pr' and make OUTFILE a pipe to it.
156 `pr' then outputs to our stdout. */
157
158static char const *current_name0;
159static char const *current_name1;
160static bool currently_recursive;
161
162void
163setup_output (char const *name0, char const *name1, bool recursive)
164{
165 current_name0 = name0;
166 current_name1 = name1;
167 currently_recursive = recursive;
168 outfile = 0;
169}
170
171#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
172static pid_t pr_pid;
173#endif
174
175void
176begin_output (void)
177{
178 char *name;
179
180 if (outfile != 0)
181 return;
182
183 /* Construct the header of this piece of diff. */
184 name = xmalloc (strlen (current_name0) + strlen (current_name1)
185 + strlen (switch_string) + 7);
186
187 /* POSIX 1003.1-2001 specifies this format. But there are some bugs in
188 the standard: it says that we must print only the last component
189 of the pathnames, and it requires two spaces after "diff" if
190 there are no options. These requirements are silly and do not
191 match historical practice. */
192 sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
193
194 if (paginate)
195 {
196 if (fflush (stdout) != 0)
197 pfatal_with_name (_("write failed"));
198
199 /* Make OUTFILE a pipe to a subsidiary `pr'. */
200 {
201#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
202 int pipes[2];
203
204 if (pipe (pipes) != 0)
205 pfatal_with_name ("pipe");
206
207 pr_pid = vfork ();