util.c revision 1.1.1.1 1 #include "EXTERN.h"
2 #include "common.h"
3 #include "INTERN.h"
4 #include "util.h"
5
6 /* Rename a file, copying it if necessary. */
7
8 int
9 move_file(from,to)
10 char *from, *to;
11 {
12 char bakname[512];
13 Reg1 char *s;
14 Reg2 int i;
15 Reg3 int fromfd;
16
17 /* to stdout? */
18
19 if (strEQ(to, "-")) {
20 #ifdef DEBUGGING
21 if (debug & 4)
22 say2("Moving %s to stdout.\n", from);
23 #endif
24 fromfd = open(from, 0);
25 if (fromfd < 0)
26 fatal2("patch: internal error, can't reopen %s\n", from);
27 while ((i=read(fromfd, buf, sizeof buf)) > 0)
28 if (write(1, buf, i) != 1)
29 fatal1("patch: write failed\n");
30 Close(fromfd);
31 return 0;
32 }
33
34 Strcpy(bakname, to);
35 Strcat(bakname, origext?origext:ORIGEXT);
36 if (stat(to, &filestat) >= 0) { /* output file exists */
37 dev_t to_device = filestat.st_dev;
38 ino_t to_inode = filestat.st_ino;
39 char *simplename = bakname;
40
41 for (s=bakname; *s; s++) {
42 if (*s == '/')
43 simplename = s+1;
44 }
45 /* find a backup name that is not the same file */
46 while (stat(bakname, &filestat) >= 0 &&
47 to_device == filestat.st_dev && to_inode == filestat.st_ino) {
48 for (s=simplename; *s && !islower(*s); s++) ;
49 if (*s)
50 *s = toupper(*s);
51 else
52 Strcpy(simplename, simplename+1);
53 }
54 while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
55 #ifdef DEBUGGING
56 if (debug & 4)
57 say3("Moving %s to %s.\n", to, bakname);
58 #endif
59 if (link(to, bakname) < 0) {
60 say3("patch: can't backup %s, output is in %s\n",
61 to, from);
62 return -1;
63 }
64 while (unlink(to) >= 0) ;
65 }
66 #ifdef DEBUGGING
67 if (debug & 4)
68 say3("Moving %s to %s.\n", from, to);
69 #endif
70 if (link(from, to) < 0) { /* different file system? */
71 Reg4 int tofd;
72
73 tofd = creat(to, 0666);
74 if (tofd < 0) {
75 say3("patch: can't create %s, output is in %s.\n",
76 to, from);
77 return -1;
78 }
79 fromfd = open(from, 0);
80 if (fromfd < 0)
81 fatal2("patch: internal error, can't reopen %s\n", from);
82 while ((i=read(fromfd, buf, sizeof buf)) > 0)
83 if (write(tofd, buf, i) != i)
84 fatal1("patch: write failed\n");
85 Close(fromfd);
86 Close(tofd);
87 }
88 Unlink(from);
89 return 0;
90 }
91
92 /* Copy a file. */
93
94 void
95 copy_file(from,to)
96 char *from, *to;
97 {
98 Reg3 int tofd;
99 Reg2 int fromfd;
100 Reg1 int i;
101
102 tofd = creat(to, 0666);
103 if (tofd < 0)
104 fatal2("patch: can't create %s.\n", to);
105 fromfd = open(from, 0);
106 if (fromfd < 0)
107 fatal2("patch: internal error, can't reopen %s\n", from);
108 while ((i=read(fromfd, buf, sizeof buf)) > 0)
109 if (write(tofd, buf, i) != i)
110 fatal2("patch: write (%s) failed\n", to);
111 Close(fromfd);
112 Close(tofd);
113 }
114
115 /* Allocate a unique area for a string. */
116
117 char *
118 savestr(s)
119 Reg1 char *s;
120 {
121 Reg3 char *rv;
122 Reg2 char *t;
123
124 if (!s)
125 s = "Oops";
126 t = s;
127 while (*t++);
128 rv = malloc((MEM) (t - s));
129 if (rv == Nullch) {
130 if (using_plan_a)
131 out_of_mem = TRUE;
132 else
133 fatal1("patch: out of memory (savestr)\n");
134 }
135 else {
136 t = rv;
137 while (*t++ = *s++);
138 }
139 return rv;
140 }
141
142 #if defined(lint) && defined(CANVARARG)
143
144 /*VARARGS ARGSUSED*/
145 say(pat) char *pat; { ; }
146 /*VARARGS ARGSUSED*/
147 fatal(pat) char *pat; { ; }
148 /*VARARGS ARGSUSED*/
149 ask(pat) char *pat; { ; }
150
151 #else
152
153 /* Vanilla terminal output (buffered). */
154
155 void
156 say(pat,arg1,arg2,arg3)
157 char *pat;
158 int arg1,arg2,arg3;
159 {
160 fprintf(stderr, pat, arg1, arg2, arg3);
161 Fflush(stderr);
162 }
163
164 /* Terminal output, pun intended. */
165
166 void /* very void */
167 fatal(pat,arg1,arg2,arg3)
168 char *pat;
169 int arg1,arg2,arg3;
170 {
171 void my_exit();
172
173 say(pat, arg1, arg2, arg3);
174 my_exit(1);
175 }
176
177 /* Get a response from the user, somehow or other. */
178
179 void
180 ask(pat,arg1,arg2,arg3)
181 char *pat;
182 int arg1,arg2,arg3;
183 {
184 int ttyfd;
185 int r;
186 bool tty2 = isatty(2);
187
188 Sprintf(buf, pat, arg1, arg2, arg3);
189 Fflush(stderr);
190 write(2, buf, strlen(buf));
191 if (tty2) { /* might be redirected to a file */
192 r = read(2, buf, sizeof buf);
193 }
194 else if (isatty(1)) { /* this may be new file output */
195 Fflush(stdout);
196 write(1, buf, strlen(buf));
197 r = read(1, buf, sizeof buf);
198 }
199 else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
200 /* might be deleted or unwriteable */
201 write(ttyfd, buf, strlen(buf));
202 r = read(ttyfd, buf, sizeof buf);
203 Close(ttyfd);
204 }
205 else if (isatty(0)) { /* this is probably patch input */
206 Fflush(stdin);
207 write(0, buf, strlen(buf));
208 r = read(0, buf, sizeof buf);
209 }
210 else { /* no terminal at all--default it */
211 buf[0] = '\n';
212 r = 1;
213 }
214 if (r <= 0)
215 buf[0] = 0;
216 else
217 buf[r] = '\0';
218 if (!tty2)
219 say1(buf);
220 }
221 #endif lint
222
223 /* How to handle certain events when not in a critical region. */
224
225 void
226 set_signals()
227 {
228 void my_exit();
229
230 #ifndef lint
231 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
232 Signal(SIGHUP, my_exit);
233 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
234 Signal(SIGINT, my_exit);
235 #endif
236 }
237
238 /* How to handle certain events when in a critical region. */
239
240 void
241 ignore_signals()
242 {
243 #ifndef lint
244 Signal(SIGHUP, SIG_IGN);
245 Signal(SIGINT, SIG_IGN);
246 #endif
247 }
248
249 /* Make sure we'll have the directories to create a file. */
250
251 void
252 makedirs(filename,striplast)
253 Reg1 char *filename;
254 bool striplast;
255 {
256 char tmpbuf[256];
257 Reg2 char *s = tmpbuf;
258 char *dirv[20];
259 Reg3 int i;
260 Reg4 int dirvp = 0;
261
262 while (*filename) {
263 if (*filename == '/') {
264 filename++;
265 dirv[dirvp++] = s;
266 *s++ = '\0';
267 }
268 else {
269 *s++ = *filename++;
270 }
271 }
272 *s = '\0';
273 dirv[dirvp] = s;
274 if (striplast)
275 dirvp--;
276 if (dirvp < 0)
277 return;
278 strcpy(buf, "mkdir");
279 s = buf;
280 for (i=0; i<=dirvp; i++) {
281 while (*s) s++;
282 *s++ = ' ';
283 strcpy(s, tmpbuf);
284 *dirv[i] = '/';
285 }
286 system(buf);
287 }
288
289 /* Make filenames more reasonable. */
290
291 char *
292 fetchname(at,strip_leading,assume_exists)
293 char *at;
294 int strip_leading;
295 int assume_exists;
296 {
297 char *s;
298 char *name;
299 Reg1 char *t;
300 char tmpbuf[200];
301
302 if (!at)
303 return Nullch;
304 s = savestr(at);
305 for (t=s; isspace(*t); t++) ;
306 name = t;
307 #ifdef DEBUGGING
308 if (debug & 128)
309 say4("fetchname %s %d %d\n",name,strip_leading,assume_exists);
310 #endif
311 if (strnEQ(name, "/dev/null", 9)) /* so files can be created by diffing */
312 return Nullch; /* against /dev/null. */
313 for (; *t && !isspace(*t); t++)
314 if (*t == '/')
315 if (--strip_leading >= 0)
316 name = t+1;
317 *t = '\0';
318 if (name != s && *s != '/') {
319 name[-1] = '\0';
320 if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) {
321 name[-1] = '/';
322 name=s;
323 }
324 }
325 name = savestr(name);
326 Sprintf(tmpbuf, "RCS/%s", name);
327 free(s);
328 if (stat(name, &filestat) < 0 && !assume_exists) {
329 Strcat(tmpbuf, RCSSUFFIX);
330 if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) {
331 Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name);
332 if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) {
333 free(name);
334 name = Nullch;
335 }
336 }
337 }
338 return name;
339 }
340