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