Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* tmp.c */ |
2 | ||
3 | /* Author: | |
4 | * Steve Kirkendall | |
5 | * 14407 SW Teal Blvd. #C | |
6 | * Beaverton, OR 97005 | |
7 | * kirkenda@cs.pdx.edu | |
15637ed4 RG |
8 | */ |
9 | ||
10 | ||
11 | /* This file contains functions which create & readback a TMPFILE */ | |
12 | ||
13 | ||
14 | #include "config.h" | |
15 | #include "vi.h" | |
16 | #if TOS | |
17 | # include <stat.h> | |
18 | #else | |
19 | # if OSK | |
20 | # include "osk.h" | |
21 | # else | |
22 | # if AMIGA | |
23 | # include "amistat.h" | |
24 | # else | |
25 | # include <sys/stat.h> | |
26 | # endif | |
27 | # endif | |
28 | #endif | |
29 | #if TURBOC | |
30 | # include <process.h> | |
31 | #endif | |
32 | ||
33 | #ifndef NO_MODELINES | |
34 | static void do_modelines(l, stop) | |
35 | long l; /* line number to start at */ | |
36 | long stop; /* line number to stop at */ | |
37 | { | |
38 | char *str; /* used to scan through the line */ | |
39 | char *start; /* points to the start of the line */ | |
40 | char buf[80]; | |
41 | ||
42 | /* if modelines are disabled, then do nothing */ | |
43 | if (!*o_modelines) | |
44 | { | |
45 | return; | |
46 | } | |
47 | ||
48 | /* for each line... */ | |
49 | for (; l <= stop; l++) | |
50 | { | |
51 | /* for each position in the line.. */ | |
52 | for (str = fetchline(l); *str; str++) | |
53 | { | |
54 | /* if it is the start of a modeline command... */ | |
55 | if ((str[0] == 'e' && str[1] == 'x' | |
56 | || str[0] == 'v' && str[1] == 'i') | |
57 | && str[2] == ':') | |
58 | { | |
59 | start = str += 3; | |
60 | ||
61 | /* find the end */ | |
62 | for (str = start + strlen(start); *--str != ':'; ) | |
63 | { | |
64 | } | |
65 | ||
66 | /* if it is a well-formed modeline, execute it */ | |
67 | if (str > start && str - start < sizeof buf) | |
68 | { | |
69 | strncpy(buf, start, (int)(str - start)); | |
70 | exstring(buf, str - start, '\\'); | |
71 | break; | |
72 | } | |
73 | } | |
74 | } | |
75 | } | |
76 | } | |
77 | #endif | |
78 | ||
79 | ||
80 | /* The FAIL() macro prints an error message and then exits. */ | |
81 | #define FAIL(why,arg) mode = MODE_EX; msg(why, arg); endwin(); exit(9) | |
82 | ||
83 | /* This is the name of the temp file */ | |
84 | static char tmpname[80]; | |
85 | ||
86 | /* This function creates the temp file and copies the original file into it. | |
87 | * Returns if successful, or stops execution if it fails. | |
88 | */ | |
89 | int tmpstart(filename) | |
90 | char *filename; /* name of the original file */ | |
91 | { | |
92 | int origfd; /* fd used for reading the original file */ | |
93 | struct stat statb; /* stat buffer, used to examine inode */ | |
94 | REG BLK *this; /* pointer to the current block buffer */ | |
95 | REG BLK *next; /* pointer to the next block buffer */ | |
96 | int inbuf; /* number of characters in a buffer */ | |
97 | int nread; /* number of bytes read */ | |
98 | REG int j, k; | |
99 | int i; | |
100 | long nbytes; | |
101 | ||
102 | /* switching to a different file certainly counts as a change */ | |
103 | changes++; | |
104 | redraw(MARK_UNSET, FALSE); | |
105 | ||
106 | /* open the original file for reading */ | |
107 | *origname = '\0'; | |
108 | if (filename && *filename) | |
109 | { | |
110 | strcpy(origname, filename); | |
111 | origfd = open(origname, O_RDONLY); | |
112 | if (origfd < 0 && errno != ENOENT) | |
113 | { | |
114 | msg("Can't open \"%s\"", origname); | |
115 | return tmpstart(""); | |
116 | } | |
117 | if (origfd >= 0) | |
118 | { | |
119 | if (stat(origname, &statb) < 0) | |
120 | { | |
121 | FAIL("Can't stat \"%s\"", origname); | |
122 | } | |
123 | #if TOS | |
124 | if (origfd >= 0 && (statb.st_mode & S_IJDIR)) | |
125 | #else | |
126 | # if OSK | |
127 | if (origfd >= 0 && (statb.st_mode & S_IFDIR)) | |
128 | # else | |
129 | if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG) | |
130 | # endif | |
131 | #endif | |
132 | { | |
133 | msg("\"%s\" is not a regular file", origname); | |
134 | return tmpstart(""); | |
135 | } | |
136 | } | |
137 | else | |
138 | { | |
139 | stat(".", &statb); | |
140 | } | |
141 | if (origfd >= 0) | |
142 | { | |
143 | origtime = statb.st_mtime; | |
144 | #if OSK | |
145 | if (*o_readonly || !(statb.st_mode & | |
146 | ((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE : | |
147 | ((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE))))) | |
148 | #endif | |
08746e8b | 149 | #if AMIGA || MSDOS |
15637ed4 RG |
150 | if (*o_readonly || !(statb.st_mode & S_IWRITE)) |
151 | #endif | |
08746e8b AM |
152 | #if TOS |
153 | # ifdef __GNUC__ | |
154 | if (*o_readonly || !(statb.st_mode & S_IWRITE)) | |
155 | # else | |
15637ed4 | 156 | if (*o_readonly || (statb.st_mode & S_IJRON)) |
08746e8b | 157 | # endif |
15637ed4 RG |
158 | #endif |
159 | #if ANY_UNIX | |
160 | if (*o_readonly || !(statb.st_mode & | |
161 | ((geteuid() == 0) ? 0222 : | |
162 | ((statb.st_uid != geteuid() ? 0022 : 0200))))) | |
163 | #endif | |
164 | #if VMS | |
165 | if (*o_readonly) | |
166 | #endif | |
167 | { | |
168 | setflag(file, READONLY); | |
169 | } | |
170 | } | |
171 | else | |
172 | { | |
173 | origtime = 0L; | |
174 | } | |
175 | } | |
176 | else | |
177 | { | |
178 | setflag(file, NOFILE); | |
179 | origfd = -1; | |
180 | origtime = 0L; | |
181 | stat(".", &statb); | |
182 | } | |
183 | ||
184 | /* make a name for the tmp file */ | |
08746e8b AM |
185 | do |
186 | { | |
187 | tmpnum++; | |
15637ed4 | 188 | #if MSDOS || TOS |
08746e8b AM |
189 | /* MS-Dos doesn't allow multiple slashes, but supports drives |
190 | * with current directories. | |
191 | * This relies on TMPNAME beginning with "%s\\"!!!! | |
192 | */ | |
193 | strcpy(tmpname, o_directory); | |
194 | if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1])) | |
195 | tmpname[i++]=SLASH; | |
196 | sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum); | |
15637ed4 | 197 | #else |
08746e8b | 198 | sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum); |
15637ed4 | 199 | #endif |
08746e8b AM |
200 | } while (access(tmpname, 0) == 0); |
201 | ||
202 | /* !!! RACE CONDITION HERE - some other process with the same PID could | |
203 | * create the temp file between the access() call and the creat() call. | |
204 | * This could happen in a couple of ways: | |
205 | * - different workstation may share the same temp dir via NFS. Each | |
206 | * workstation could have a process with the same number. | |
207 | * - The DOS version may be running multiple times on the same physical | |
208 | * machine in different virtual machines. The DOS pid number will | |
209 | * be the same on all virtual machines. | |
210 | * | |
211 | * This race condition could be fixed by replacing access(tmpname, 0) | |
212 | * with open(tmpname, O_CREAT|O_EXCL, 0600), if we could only be sure | |
213 | * that open() *always* used modern UNIX semantics. | |
214 | */ | |
15637ed4 RG |
215 | |
216 | /* create the temp file */ | |
217 | #if ANY_UNIX | |
218 | close(creat(tmpname, 0600)); /* only we can read it */ | |
219 | #else | |
220 | close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */ | |
221 | #endif | |
222 | tmpfd = open(tmpname, O_RDWR | O_BINARY); | |
223 | if (tmpfd < 0) | |
224 | { | |
225 | FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory); | |
226 | return 1; | |
227 | } | |
228 | ||
229 | /* allocate space for the header in the file */ | |
08746e8b AM |
230 | if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) < BLKSIZE |
231 | || write(tmpfd, tmpblk.c, (unsigned)BLKSIZE) < BLKSIZE) | |
232 | { | |
233 | FAIL("Error writing headers to \"%s\"", tmpname); | |
234 | } | |
15637ed4 RG |
235 | |
236 | #ifndef NO_RECYCLE | |
237 | /* initialize the block allocator */ | |
238 | /* This must already be done here, before the first attempt | |
239 | * to write to the new file! GB */ | |
240 | garbage(); | |
241 | #endif | |
242 | ||
243 | /* initialize lnum[] */ | |
244 | for (i = 1; i < MAXBLKS; i++) | |
245 | { | |
246 | lnum[i] = INFINITY; | |
247 | } | |
248 | lnum[0] = 0; | |
249 | ||
250 | /* if there is no original file, then create a 1-line file */ | |
251 | if (origfd < 0) | |
252 | { | |
253 | hdr.n[0] = 0; /* invalid inode# denotes new file */ | |
254 | ||
255 | this = blkget(1); /* get the new text block */ | |
256 | strcpy(this->c, "\n"); /* put a line in it */ | |
257 | ||
258 | lnum[1] = 1L; /* block 1 ends with line 1 */ | |
259 | nlines = 1L; /* there is 1 line in the file */ | |
260 | nbytes = 1L; | |
261 | ||
262 | if (*origname) | |
263 | { | |
264 | msg("\"%s\" [NEW FILE] 1 line, 1 char", origname); | |
265 | } | |
266 | else | |
267 | { | |
268 | msg("\"[NO FILE]\" 1 line, 1 char"); | |
269 | } | |
270 | } | |
271 | else /* there is an original file -- read it in */ | |
272 | { | |
273 | nbytes = nlines = 0; | |
274 | ||
275 | /* preallocate 1 "next" buffer */ | |
276 | i = 1; | |
277 | next = blkget(i); | |
278 | inbuf = 0; | |
279 | ||
280 | /* loop, moving blocks from orig to tmp */ | |
281 | for (;;) | |
282 | { | |
283 | /* "next" buffer becomes "this" buffer */ | |
284 | this = next; | |
285 | ||
286 | /* read [more] text into this block */ | |
287 | nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf); | |
288 | if (nread < 0) | |
289 | { | |
290 | close(origfd); | |
291 | close(tmpfd); | |
292 | tmpfd = -1; | |
293 | unlink(tmpname); | |
294 | FAIL("Error reading \"%s\"", origname); | |
295 | } | |
296 | ||
297 | /* convert NUL characters to something else */ | |
298 | for (j = k = inbuf; k < inbuf + nread; k++) | |
299 | { | |
300 | if (!this->c[k]) | |
301 | { | |
302 | setflag(file, HADNUL); | |
303 | this->c[j++] = 0x80; | |
304 | } | |
305 | #ifndef CRUNCH | |
08746e8b | 306 | else if (*o_beautify && this->c[k] < ' ' && this->c[k] >= 1) |
15637ed4 RG |
307 | { |
308 | if (this->c[k] == '\t' | |
309 | || this->c[k] == '\n' | |
310 | || this->c[k] == '\f') | |
311 | { | |
312 | this->c[j++] = this->c[k]; | |
313 | } | |
314 | else if (this->c[k] == '\b') | |
315 | { | |
316 | /* delete '\b', but complain */ | |
317 | setflag(file, HADBS); | |
318 | } | |
319 | /* else silently delete control char */ | |
320 | } | |
321 | #endif | |
322 | else | |
323 | { | |
324 | this->c[j++] = this->c[k]; | |
325 | } | |
326 | } | |
327 | inbuf = j; | |
328 | ||
329 | /* if the buffer is empty, quit */ | |
330 | if (inbuf == 0) | |
331 | { | |
332 | goto FoundEOF; | |
333 | } | |
334 | ||
335 | #if MSDOS || TOS | |
336 | /* BAH! MS text mode read fills inbuf, then compresses eliminating \r | |
337 | but leaving garbage at end of buf. The same is true for TURBOC. GB. */ | |
338 | ||
339 | memset(this->c + inbuf, '\0', BLKSIZE - inbuf); | |
340 | #endif | |
341 | ||
342 | /* search backward for last newline */ | |
343 | for (k = inbuf; --k >= 0 && this->c[k] != '\n';) | |
344 | { | |
345 | } | |
346 | if (k++ < 0) | |
347 | { | |
348 | if (inbuf >= BLKSIZE - 1) | |
349 | { | |
350 | k = 80; | |
351 | } | |
352 | else | |
353 | { | |
354 | k = inbuf; | |
355 | } | |
356 | } | |
357 | ||
358 | /* allocate next buffer */ | |
08746e8b AM |
359 | if (i >= MAXBLKS - 2) |
360 | { | |
361 | FAIL("File too big. Limit is approx %ld kbytes.", MAXBLKS * BLKSIZE / 1024L); | |
362 | } | |
15637ed4 RG |
363 | next = blkget(++i); |
364 | ||
365 | /* move fragmentary last line to next buffer */ | |
366 | inbuf -= k; | |
367 | for (j = 0; k < BLKSIZE; j++, k++) | |
368 | { | |
369 | next->c[j] = this->c[k]; | |
370 | this->c[k] = 0; | |
371 | } | |
372 | ||
373 | /* if necessary, add a newline to this buf */ | |
374 | for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; ) | |
375 | { | |
376 | } | |
377 | if (this->c[k] != '\n') | |
378 | { | |
379 | setflag(file, ADDEDNL); | |
380 | this->c[k + 1] = '\n'; | |
381 | } | |
382 | ||
383 | /* count the lines in this block */ | |
384 | for (k = 0; k < BLKSIZE && this->c[k]; k++) | |
385 | { | |
386 | if (this->c[k] == '\n') | |
387 | { | |
388 | nlines++; | |
389 | } | |
390 | nbytes++; | |
391 | } | |
392 | lnum[i - 1] = nlines; | |
393 | } | |
394 | FoundEOF: | |
395 | ||
396 | /* if this is a zero-length file, add 1 line */ | |
397 | if (nlines == 0) | |
398 | { | |
399 | this = blkget(1); /* get the new text block */ | |
400 | strcpy(this->c, "\n"); /* put a line in it */ | |
401 | ||
402 | lnum[1] = 1; /* block 1 ends with line 1 */ | |
403 | nlines = 1; /* there is 1 line in the file */ | |
404 | nbytes = 1; | |
405 | } | |
406 | ||
407 | #if MSDOS || TOS | |
408 | /* each line has an extra CR that we didn't count yet */ | |
409 | nbytes += nlines; | |
410 | #endif | |
411 | ||
412 | /* report the number of lines in the file */ | |
413 | msg("\"%s\" %s %ld line%s, %ld char%s", | |
414 | origname, | |
415 | (tstflag(file, READONLY) ? "[READONLY]" : ""), | |
416 | nlines, | |
417 | nlines == 1 ? "" : "s", | |
418 | nbytes, | |
419 | nbytes == 1 ? "" : "s"); | |
420 | } | |
421 | ||
422 | /* initialize the cursor to start of line 1 */ | |
423 | cursor = MARK_FIRST; | |
424 | ||
425 | /* close the original file */ | |
426 | close(origfd); | |
427 | ||
428 | /* any other messages? */ | |
429 | if (tstflag(file, HADNUL)) | |
430 | { | |
431 | msg("This file contained NULs. They've been changed to \\x80 chars"); | |
432 | } | |
433 | if (tstflag(file, ADDEDNL)) | |
434 | { | |
435 | msg("Newline characters have been inserted to break up long lines"); | |
436 | } | |
437 | #ifndef CRUNCH | |
438 | if (tstflag(file, HADBS)) | |
439 | { | |
440 | msg("Backspace characters deleted due to ':set beautify'"); | |
441 | } | |
442 | #endif | |
443 | ||
444 | storename(origname); | |
445 | ||
446 | #ifndef NO_MODELINES | |
447 | if (nlines > 10) | |
448 | { | |
449 | do_modelines(1L, 5L); | |
450 | do_modelines(nlines - 4L, nlines); | |
451 | } | |
452 | else | |
453 | { | |
454 | do_modelines(1L, nlines); | |
455 | } | |
456 | #endif | |
457 | ||
458 | /* force all blocks out onto the disk, to support file recovery */ | |
459 | blksync(); | |
460 | ||
461 | return 0; | |
462 | } | |
463 | ||
464 | ||
465 | ||
466 | /* This function copies the temp file back onto an original file. | |
467 | * Returns TRUE if successful, or FALSE if the file could NOT be saved. | |
468 | */ | |
469 | int tmpsave(filename, bang) | |
470 | char *filename; /* the name to save it to */ | |
471 | int bang; /* forced write? */ | |
472 | { | |
473 | int fd; /* fd of the file we're writing to */ | |
474 | REG int len; /* length of a text block */ | |
475 | REG BLK *this; /* a text block */ | |
476 | long bytes; /* byte counter */ | |
477 | REG int i; | |
478 | ||
479 | /* if no filename is given, assume the original file name */ | |
480 | if (!filename || !*filename) | |
481 | { | |
482 | filename = origname; | |
483 | } | |
484 | ||
485 | /* if still no file name, then fail */ | |
486 | if (!*filename) | |
487 | { | |
488 | msg("Don't know a name for this file -- NOT WRITTEN"); | |
489 | return FALSE; | |
490 | } | |
491 | ||
492 | /* can't rewrite a READONLY file */ | |
15637ed4 | 493 | if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang) |
15637ed4 RG |
494 | { |
495 | msg("\"%s\" [READONLY] -- NOT WRITTEN", filename); | |
496 | return FALSE; | |
497 | } | |
498 | ||
499 | /* open the file */ | |
500 | if (*filename == '>' && filename[1] == '>') | |
501 | { | |
502 | filename += 2; | |
503 | while (*filename == ' ' || *filename == '\t') | |
504 | { | |
505 | filename++; | |
506 | } | |
507 | #ifdef O_APPEND | |
508 | fd = open(filename, O_WRONLY|O_APPEND); | |
509 | #else | |
510 | fd = open(filename, O_WRONLY); | |
511 | lseek(fd, 0L, 2); | |
512 | #endif | |
513 | } | |
514 | else | |
515 | { | |
516 | /* either the file must not exist, or it must be the original | |
517 | * file, or we must have a bang, or "writeany" must be set. | |
518 | */ | |
519 | if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang | |
520 | #ifndef CRUNCH | |
521 | && !*o_writeany | |
522 | #endif | |
523 | ) | |
524 | { | |
525 | msg("File already exists - Use :w! to overwrite"); | |
526 | return FALSE; | |
527 | } | |
528 | #if VMS | |
529 | /* Create a new VMS version of this file. */ | |
530 | { | |
531 | char *strrchr(), *ptr = strrchr(filename,';'); | |
532 | if (ptr) *ptr = '\0'; /* Snip off any ;number in the name */ | |
533 | } | |
534 | #endif | |
535 | fd = creat(filename, FILEPERMS); | |
536 | } | |
537 | if (fd < 0) | |
538 | { | |
539 | msg("Can't write to \"%s\" -- NOT WRITTEN", filename); | |
540 | return FALSE; | |
541 | } | |
542 | ||
543 | /* write each text block to the file */ | |
544 | bytes = 0L; | |
545 | for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++) | |
546 | { | |
547 | for (len = 0; len < BLKSIZE && this->c[len]; len++) | |
548 | { | |
549 | } | |
550 | if (twrite(fd, this->c, len) < len) | |
551 | { | |
552 | msg("Trouble writing to \"%s\"", filename); | |
553 | if (!strcmp(filename, origname)) | |
554 | { | |
555 | setflag(file, MODIFIED); | |
556 | } | |
557 | close(fd); | |
558 | return FALSE; | |
559 | } | |
560 | bytes += len; | |
561 | } | |
562 | ||
563 | /* reset the "modified" flag, but not the "undoable" flag */ | |
564 | clrflag(file, MODIFIED); | |
565 | significant = FALSE; | |
08746e8b AM |
566 | if (!strcmp(origname, filename)) |
567 | { | |
568 | exitcode &= ~1; | |
569 | } | |
15637ed4 RG |
570 | |
571 | /* report lines & characters */ | |
572 | #if MSDOS || TOS | |
573 | bytes += nlines; /* for the inserted carriage returns */ | |
574 | #endif | |
575 | msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes); | |
576 | ||
577 | /* close the file */ | |
578 | close(fd); | |
579 | ||
580 | return TRUE; | |
581 | } | |
582 | ||
583 | ||
584 | /* This function deletes the temporary file. If the file has been modified | |
585 | * and "bang" is FALSE, then it returns FALSE without doing anything; else | |
586 | * it returns TRUE. | |
587 | * | |
588 | * If the "autowrite" option is set, then instead of returning FALSE when | |
589 | * the file has been modified and "bang" is false, it will call tmpend(). | |
590 | */ | |
591 | int tmpabort(bang) | |
592 | int bang; | |
593 | { | |
594 | /* if there is no file, return successfully */ | |
595 | if (tmpfd < 0) | |
596 | { | |
597 | return TRUE; | |
598 | } | |
599 | ||
600 | /* see if we must return FALSE -- can't quit */ | |
601 | if (!bang && tstflag(file, MODIFIED)) | |
602 | { | |
603 | /* if "autowrite" is set, then act like tmpend() */ | |
604 | if (*o_autowrite) | |
605 | return tmpend(bang); | |
606 | else | |
607 | return FALSE; | |
608 | } | |
609 | ||
610 | /* delete the tmp file */ | |
611 | cutswitch(); | |
612 | strcpy(prevorig, origname); | |
613 | prevline = markline(cursor); | |
614 | *origname = '\0'; | |
615 | origtime = 0L; | |
616 | blkinit(); | |
617 | nlines = 0; | |
618 | initflags(); | |
15637ed4 RG |
619 | return TRUE; |
620 | } | |
621 | ||
622 | /* This function saves the file if it has been modified, and then deletes | |
623 | * the temporary file. Returns TRUE if successful, or FALSE if the file | |
624 | * needs to be saved but can't be. When it returns FALSE, it will not have | |
625 | * deleted the tmp file, either. | |
626 | */ | |
627 | int tmpend(bang) | |
628 | int bang; | |
629 | { | |
630 | /* save the file if it has been modified */ | |
631 | if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang) | |
632 | { | |
633 | return FALSE; | |
634 | } | |
635 | ||
636 | /* delete the tmp file */ | |
637 | tmpabort(TRUE); | |
638 | ||
639 | return TRUE; | |
640 | } | |
641 | ||
642 | ||
643 | /* If the tmp file has been changed, then this function will force those | |
644 | * changes to be written to the disk, so that the tmp file will survive a | |
645 | * system crash or power failure. | |
646 | */ | |
647 | #if AMIGA || MSDOS || TOS | |
648 | sync() | |
649 | { | |
650 | /* MS-DOS and TOS don't flush their buffers until the file is closed, | |
651 | * so here we close the tmp file and then immediately reopen it. | |
652 | */ | |
653 | close(tmpfd); | |
654 | tmpfd = open(tmpname, O_RDWR | O_BINARY); | |
655 | return 0; | |
656 | } | |
657 | #endif | |
658 | ||
659 | ||
660 | /* This function stores the file's name in the second block of the temp file. | |
661 | * SLEAZE ALERT! SLEAZE ALERT! The "tmpblk" buffer is probably being used | |
662 | * to store the arguments to a command, so we can't use it here. Instead, | |
663 | * we'll borrow the buffer that is used for "shift-U". | |
664 | */ | |
08746e8b | 665 | int |
15637ed4 RG |
666 | storename(name) |
667 | char *name; /* the name of the file - normally origname */ | |
668 | { | |
669 | #ifndef CRUNCH | |
670 | int len; | |
671 | char *ptr; | |
672 | #endif | |
673 | ||
674 | /* we're going to clobber the U_text buffer, so reset U_line */ | |
675 | U_line = 0L; | |
676 | ||
677 | if (!name) | |
678 | { | |
679 | strncpy(U_text, "", BLKSIZE); | |
680 | U_text[1] = 127; | |
681 | } | |
682 | #ifndef CRUNCH | |
08746e8b AM |
683 | # if TOS || MINT || MSDOS || AMIGA |
684 | else if (*name != '/' && *name != '\\' && !(*name && name[1] == ':')) | |
685 | # else | |
15637ed4 | 686 | else if (*name != SLASH) |
08746e8b | 687 | # endif |
15637ed4 RG |
688 | { |
689 | /* get the directory name */ | |
690 | ptr = getcwd(U_text, BLKSIZE); | |
691 | if (ptr != U_text) | |
692 | { | |
693 | strcpy(U_text, ptr); | |
694 | } | |
695 | ||
696 | /* append a slash to the directory name */ | |
697 | len = strlen(U_text); | |
698 | U_text[len++] = SLASH; | |
699 | ||
700 | /* append the filename, padded with heaps o' NULs */ | |
701 | strncpy(U_text + len, *name ? name : "foo", BLKSIZE - len); | |
702 | } | |
703 | #endif | |
704 | else | |
705 | { | |
706 | /* copy the filename into U_text */ | |
707 | strncpy(U_text, *name ? name : "foo", BLKSIZE); | |
708 | } | |
709 | ||
710 | if (tmpfd >= 0) | |
711 | { | |
712 | /* write the name out to second block of the temp file */ | |
713 | lseek(tmpfd, (long)BLKSIZE, 0); | |
08746e8b AM |
714 | if (write(tmpfd, U_text, (unsigned)BLKSIZE) < BLKSIZE) |
715 | { | |
716 | FAIL("Error stuffing name \"%s\" into temp file", U_text); | |
717 | } | |
15637ed4 RG |
718 | } |
719 | return 0; | |
720 | } | |
721 | ||
722 | ||
723 | ||
724 | /* This function handles deadly signals. It restores sanity to the terminal | |
725 | * preserves the current temp file, and deletes any old temp files. | |
726 | */ | |
08746e8b | 727 | SIGTYPE deathtrap(sig) |
15637ed4 RG |
728 | int sig; /* the deadly signal that we caught */ |
729 | { | |
730 | char *why; | |
731 | ||
732 | /* restore the terminal's sanity */ | |
733 | endwin(); | |
734 | ||
735 | #ifdef CRUNCH | |
736 | why = "-Elvis died"; | |
737 | #else | |
738 | /* give a more specific description of how Elvis died */ | |
739 | switch (sig) | |
740 | { | |
741 | # ifdef SIGHUP | |
742 | case SIGHUP: why = "-the modem lost its carrier"; break; | |
743 | # endif | |
744 | # ifndef DEBUG | |
745 | # ifdef SIGILL | |
746 | case SIGILL: why = "-Elvis hit an illegal instruction"; break; | |
747 | # endif | |
748 | # ifdef SIGBUS | |
749 | case SIGBUS: why = "-Elvis had a bus error"; break; | |
750 | # endif | |
08746e8b AM |
751 | # ifdef SIGSEGV |
752 | # if !TOS | |
15637ed4 | 753 | case SIGSEGV: why = "-Elvis had a segmentation violation"; break; |
08746e8b | 754 | # endif |
15637ed4 RG |
755 | # endif |
756 | # ifdef SIGSYS | |
757 | case SIGSYS: why = "-Elvis munged a system call"; break; | |
758 | # endif | |
759 | # endif /* !DEBUG */ | |
760 | # ifdef SIGPIPE | |
761 | case SIGPIPE: why = "-the pipe reader died"; break; | |
762 | # endif | |
763 | # ifdef SIGTERM | |
764 | case SIGTERM: why = "-Elvis was terminated"; break; | |
765 | # endif | |
766 | # if !MINIX | |
767 | # ifdef SIGUSR1 | |
768 | case SIGUSR1: why = "-Elvis was killed via SIGUSR1"; break; | |
769 | # endif | |
770 | # ifdef SIGUSR2 | |
771 | case SIGUSR2: why = "-Elvis was killed via SIGUSR2"; break; | |
772 | # endif | |
773 | # endif | |
774 | default: why = "-Elvis died"; break; | |
775 | } | |
776 | #endif | |
777 | ||
778 | /* if we had a temp file going, then preserve it */ | |
779 | if (tmpnum > 0 && tmpfd >= 0) | |
780 | { | |
781 | close(tmpfd); | |
782 | sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname); | |
783 | system(tmpblk.c); | |
784 | } | |
785 | ||
786 | /* delete any old temp files */ | |
787 | cutend(); | |
788 | ||
789 | /* exit with the proper exit status */ | |
790 | exit(sig); | |
791 | } |