[9] | 1 | /* tmp.c */
|
---|
| 2 |
|
---|
| 3 | /* Author:
|
---|
| 4 | * Steve Kirkendall
|
---|
| 5 | * 14407 SW Teal Blvd. #C
|
---|
| 6 | * Beaverton, OR 97005
|
---|
| 7 | * kirkenda@cs.pdx.edu
|
---|
| 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
|
---|
| 149 | #if AMIGA || MSDOS || (TOS && defined(__GNUC__))
|
---|
| 150 | if (*o_readonly || !(statb.st_mode & S_IWRITE))
|
---|
| 151 | #endif
|
---|
| 152 | #if TOS && !defined(__GNUC__)
|
---|
| 153 | if (*o_readonly || (statb.st_mode & S_IJRON))
|
---|
| 154 | #endif
|
---|
| 155 | #if ANY_UNIX
|
---|
| 156 | if (*o_readonly || !(statb.st_mode &
|
---|
| 157 | ((geteuid() == 0) ? 0222 :
|
---|
| 158 | ((statb.st_uid != geteuid() ? 0022 : 0200)))))
|
---|
| 159 | #endif
|
---|
| 160 | #if VMS
|
---|
| 161 | if (*o_readonly)
|
---|
| 162 | #endif
|
---|
| 163 | {
|
---|
| 164 | setflag(file, READONLY);
|
---|
| 165 | }
|
---|
| 166 | }
|
---|
| 167 | else
|
---|
| 168 | {
|
---|
| 169 | origtime = 0L;
|
---|
| 170 | }
|
---|
| 171 | }
|
---|
| 172 | else
|
---|
| 173 | {
|
---|
| 174 | setflag(file, NOFILE);
|
---|
| 175 | origfd = -1;
|
---|
| 176 | origtime = 0L;
|
---|
| 177 | stat(".", &statb);
|
---|
| 178 | }
|
---|
| 179 |
|
---|
| 180 | /* make a name for the tmp file */
|
---|
| 181 | tmpnum++;
|
---|
| 182 | #if MSDOS || TOS
|
---|
| 183 | /* MS-Dos doesn't allow multiple slashes, but supports drives
|
---|
| 184 | * with current directories.
|
---|
| 185 | * This relies on TMPNAME beginning with "%s\\"!!!!
|
---|
| 186 | */
|
---|
| 187 | strcpy(tmpname, o_directory);
|
---|
| 188 | if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
|
---|
| 189 | tmpname[i++]=SLASH;
|
---|
| 190 | sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
|
---|
| 191 | #else
|
---|
| 192 | sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
|
---|
| 193 | #endif
|
---|
| 194 |
|
---|
| 195 | /* make sure nobody else is editing the same file */
|
---|
| 196 | if (access(tmpname, 0) == 0)
|
---|
| 197 | {
|
---|
| 198 | FAIL("Temp file \"%s\" already exists?", tmpname);
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | /* create the temp file */
|
---|
| 202 | #if ANY_UNIX
|
---|
| 203 | close(creat(tmpname, 0600)); /* only we can read it */
|
---|
| 204 | #else
|
---|
| 205 | close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */
|
---|
| 206 | #endif
|
---|
| 207 | tmpfd = open(tmpname, O_RDWR | O_BINARY);
|
---|
| 208 | if (tmpfd < 0)
|
---|
| 209 | {
|
---|
| 210 | FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
|
---|
| 211 | return 1;
|
---|
| 212 | }
|
---|
| 213 |
|
---|
| 214 | /* allocate space for the header in the file */
|
---|
| 215 | write(tmpfd, hdr.c, (unsigned)BLKSIZE);
|
---|
| 216 | write(tmpfd, tmpblk.c, (unsigned)BLKSIZE);
|
---|
| 217 |
|
---|
| 218 | #ifndef NO_RECYCLE
|
---|
| 219 | /* initialize the block allocator */
|
---|
| 220 | /* This must already be done here, before the first attempt
|
---|
| 221 | * to write to the new file! GB */
|
---|
| 222 | garbage();
|
---|
| 223 | #endif
|
---|
| 224 |
|
---|
| 225 | /* initialize lnum[] */
|
---|
| 226 | for (i = 1; i < MAXBLKS; i++)
|
---|
| 227 | {
|
---|
| 228 | lnum[i] = INFINITY;
|
---|
| 229 | }
|
---|
| 230 | lnum[0] = 0;
|
---|
| 231 |
|
---|
| 232 | /* if there is no original file, then create a 1-line file */
|
---|
| 233 | if (origfd < 0)
|
---|
| 234 | {
|
---|
| 235 | hdr.n[0] = 0; /* invalid inode# denotes new file */
|
---|
| 236 |
|
---|
| 237 | this = blkget(1); /* get the new text block */
|
---|
| 238 | strcpy(this->c, "\n"); /* put a line in it */
|
---|
| 239 |
|
---|
| 240 | lnum[1] = 1L; /* block 1 ends with line 1 */
|
---|
| 241 | nlines = 1L; /* there is 1 line in the file */
|
---|
| 242 | nbytes = 1L;
|
---|
| 243 |
|
---|
| 244 | if (*origname)
|
---|
| 245 | {
|
---|
| 246 | msg("\"%s\" [NEW FILE] 1 line, 1 char", origname);
|
---|
| 247 | }
|
---|
| 248 | else
|
---|
| 249 | {
|
---|
| 250 | msg("\"[NO FILE]\" 1 line, 1 char");
|
---|
| 251 | }
|
---|
| 252 | }
|
---|
| 253 | else /* there is an original file -- read it in */
|
---|
| 254 | {
|
---|
| 255 | nbytes = nlines = 0;
|
---|
| 256 |
|
---|
| 257 | /* preallocate 1 "next" buffer */
|
---|
| 258 | i = 1;
|
---|
| 259 | next = blkget(i);
|
---|
| 260 | inbuf = 0;
|
---|
| 261 |
|
---|
| 262 | /* loop, moving blocks from orig to tmp */
|
---|
| 263 | for (;;)
|
---|
| 264 | {
|
---|
| 265 | /* "next" buffer becomes "this" buffer */
|
---|
| 266 | this = next;
|
---|
| 267 |
|
---|
| 268 | /* read [more] text into this block */
|
---|
| 269 | nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
|
---|
| 270 | if (nread < 0)
|
---|
| 271 | {
|
---|
| 272 | close(origfd);
|
---|
| 273 | close(tmpfd);
|
---|
| 274 | tmpfd = -1;
|
---|
| 275 | unlink(tmpname);
|
---|
| 276 | FAIL("Error reading \"%s\"", origname);
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | /* convert NUL characters to something else */
|
---|
| 280 | for (j = k = inbuf; k < inbuf + nread; k++)
|
---|
| 281 | {
|
---|
| 282 | if (!this->c[k])
|
---|
| 283 | {
|
---|
| 284 | setflag(file, HADNUL);
|
---|
| 285 | this->c[j++] = 0x80;
|
---|
| 286 | }
|
---|
| 287 | #ifndef CRUNCH
|
---|
| 288 | else if (*o_beautify && this->c[k] < ' ' && this->c[k] > 0)
|
---|
| 289 | {
|
---|
| 290 | if (this->c[k] == '\t'
|
---|
| 291 | || this->c[k] == '\n'
|
---|
| 292 | || this->c[k] == '\f')
|
---|
| 293 | {
|
---|
| 294 | this->c[j++] = this->c[k];
|
---|
| 295 | }
|
---|
| 296 | else if (this->c[k] == '\b')
|
---|
| 297 | {
|
---|
| 298 | /* delete '\b', but complain */
|
---|
| 299 | setflag(file, HADBS);
|
---|
| 300 | }
|
---|
| 301 | /* else silently delete control char */
|
---|
| 302 | }
|
---|
| 303 | #endif
|
---|
| 304 | else
|
---|
| 305 | {
|
---|
| 306 | this->c[j++] = this->c[k];
|
---|
| 307 | }
|
---|
| 308 | }
|
---|
| 309 | inbuf = j;
|
---|
| 310 |
|
---|
| 311 | /* if the buffer is empty, quit */
|
---|
| 312 | if (inbuf == 0)
|
---|
| 313 | {
|
---|
| 314 | goto FoundEOF;
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | #if MSDOS || TOS
|
---|
| 318 | /* BAH! MS text mode read fills inbuf, then compresses eliminating \r
|
---|
| 319 | but leaving garbage at end of buf. The same is true for TURBOC. GB. */
|
---|
| 320 |
|
---|
| 321 | memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
|
---|
| 322 | #endif
|
---|
| 323 |
|
---|
| 324 | /* search backward for last newline */
|
---|
| 325 | for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
|
---|
| 326 | {
|
---|
| 327 | }
|
---|
| 328 | if (k++ < 0)
|
---|
| 329 | {
|
---|
| 330 | if (inbuf >= BLKSIZE - 1)
|
---|
| 331 | {
|
---|
| 332 | k = 80;
|
---|
| 333 | }
|
---|
| 334 | else
|
---|
| 335 | {
|
---|
| 336 | k = inbuf;
|
---|
| 337 | }
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | /* allocate next buffer */
|
---|
| 341 | next = blkget(++i);
|
---|
| 342 |
|
---|
| 343 | /* move fragmentary last line to next buffer */
|
---|
| 344 | inbuf -= k;
|
---|
| 345 | for (j = 0; k < BLKSIZE; j++, k++)
|
---|
| 346 | {
|
---|
| 347 | next->c[j] = this->c[k];
|
---|
| 348 | this->c[k] = 0;
|
---|
| 349 | }
|
---|
| 350 |
|
---|
| 351 | /* if necessary, add a newline to this buf */
|
---|
| 352 | for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
|
---|
| 353 | {
|
---|
| 354 | }
|
---|
| 355 | if (this->c[k] != '\n')
|
---|
| 356 | {
|
---|
| 357 | setflag(file, ADDEDNL);
|
---|
| 358 | this->c[k + 1] = '\n';
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 | /* count the lines in this block */
|
---|
| 362 | for (k = 0; k < BLKSIZE && this->c[k]; k++)
|
---|
| 363 | {
|
---|
| 364 | if (this->c[k] == '\n')
|
---|
| 365 | {
|
---|
| 366 | nlines++;
|
---|
| 367 | }
|
---|
| 368 | nbytes++;
|
---|
| 369 | }
|
---|
| 370 | lnum[i - 1] = nlines;
|
---|
| 371 | }
|
---|
| 372 | FoundEOF:
|
---|
| 373 |
|
---|
| 374 | /* if this is a zero-length file, add 1 line */
|
---|
| 375 | if (nlines == 0)
|
---|
| 376 | {
|
---|
| 377 | this = blkget(1); /* get the new text block */
|
---|
| 378 | strcpy(this->c, "\n"); /* put a line in it */
|
---|
| 379 |
|
---|
| 380 | lnum[1] = 1; /* block 1 ends with line 1 */
|
---|
| 381 | nlines = 1; /* there is 1 line in the file */
|
---|
| 382 | nbytes = 1;
|
---|
| 383 | }
|
---|
| 384 |
|
---|
| 385 | #if MSDOS || TOS
|
---|
| 386 | /* each line has an extra CR that we didn't count yet */
|
---|
| 387 | nbytes += nlines;
|
---|
| 388 | #endif
|
---|
| 389 |
|
---|
| 390 | /* report the number of lines in the file */
|
---|
| 391 | msg("\"%s\" %s %ld line%s, %ld char%s",
|
---|
| 392 | origname,
|
---|
| 393 | (tstflag(file, READONLY) ? "[READONLY]" : ""),
|
---|
| 394 | nlines,
|
---|
| 395 | nlines == 1 ? "" : "s",
|
---|
| 396 | nbytes,
|
---|
| 397 | nbytes == 1 ? "" : "s");
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | /* initialize the cursor to start of line 1 */
|
---|
| 401 | cursor = MARK_FIRST;
|
---|
| 402 |
|
---|
| 403 | /* close the original file */
|
---|
| 404 | close(origfd);
|
---|
| 405 |
|
---|
| 406 | /* any other messages? */
|
---|
| 407 | if (tstflag(file, HADNUL))
|
---|
| 408 | {
|
---|
| 409 | msg("This file contained NULs. They've been changed to \\x80 chars");
|
---|
| 410 | }
|
---|
| 411 | if (tstflag(file, ADDEDNL))
|
---|
| 412 | {
|
---|
| 413 | msg("Newline characters have been inserted to break up long lines");
|
---|
| 414 | }
|
---|
| 415 | #ifndef CRUNCH
|
---|
| 416 | if (tstflag(file, HADBS))
|
---|
| 417 | {
|
---|
| 418 | msg("Backspace characters deleted due to ':set beautify'");
|
---|
| 419 | }
|
---|
| 420 | #endif
|
---|
| 421 |
|
---|
| 422 | storename(origname);
|
---|
| 423 |
|
---|
| 424 | #ifndef NO_MODELINES
|
---|
| 425 | if (nlines > 10)
|
---|
| 426 | {
|
---|
| 427 | do_modelines(1L, 5L);
|
---|
| 428 | do_modelines(nlines - 4L, nlines);
|
---|
| 429 | }
|
---|
| 430 | else
|
---|
| 431 | {
|
---|
| 432 | do_modelines(1L, nlines);
|
---|
| 433 | }
|
---|
| 434 | #endif
|
---|
| 435 |
|
---|
| 436 | /* force all blocks out onto the disk, to support file recovery */
|
---|
| 437 | blksync();
|
---|
| 438 |
|
---|
| 439 | return 0;
|
---|
| 440 | }
|
---|
| 441 |
|
---|
| 442 |
|
---|
| 443 |
|
---|
| 444 | /* This function copies the temp file back onto an original file.
|
---|
| 445 | * Returns TRUE if successful, or FALSE if the file could NOT be saved.
|
---|
| 446 | */
|
---|
| 447 | int tmpsave(filename, bang)
|
---|
| 448 | char *filename; /* the name to save it to */
|
---|
| 449 | int bang; /* forced write? */
|
---|
| 450 | {
|
---|
| 451 | int fd; /* fd of the file we're writing to */
|
---|
| 452 | REG int len; /* length of a text block */
|
---|
| 453 | REG BLK *this; /* a text block */
|
---|
| 454 | long bytes; /* byte counter */
|
---|
| 455 | REG int i;
|
---|
| 456 |
|
---|
| 457 | /* if no filename is given, assume the original file name */
|
---|
| 458 | if (!filename || !*filename)
|
---|
| 459 | {
|
---|
| 460 | filename = origname;
|
---|
| 461 | }
|
---|
| 462 |
|
---|
| 463 | /* if still no file name, then fail */
|
---|
| 464 | if (!*filename)
|
---|
| 465 | {
|
---|
| 466 | msg("Don't know a name for this file -- NOT WRITTEN");
|
---|
| 467 | return FALSE;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
| 470 | /* can't rewrite a READONLY file */
|
---|
| 471 | #if AMIGA
|
---|
| 472 | if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang)
|
---|
| 473 | #else
|
---|
| 474 | if (!strcmp(filename, origname) && *o_readonly && !bang)
|
---|
| 475 | #endif
|
---|
| 476 | {
|
---|
| 477 | msg("\"%s\" [READONLY] -- NOT WRITTEN", filename);
|
---|
| 478 | return FALSE;
|
---|
| 479 | }
|
---|
| 480 |
|
---|
| 481 | /* open the file */
|
---|
| 482 | if (*filename == '>' && filename[1] == '>')
|
---|
| 483 | {
|
---|
| 484 | filename += 2;
|
---|
| 485 | while (*filename == ' ' || *filename == '\t')
|
---|
| 486 | {
|
---|
| 487 | filename++;
|
---|
| 488 | }
|
---|
| 489 | #ifdef O_APPEND
|
---|
| 490 | fd = open(filename, O_WRONLY|O_APPEND);
|
---|
| 491 | #else
|
---|
| 492 | fd = open(filename, O_WRONLY);
|
---|
| 493 | lseek(fd, 0L, 2);
|
---|
| 494 | #endif
|
---|
| 495 | }
|
---|
| 496 | else
|
---|
| 497 | {
|
---|
| 498 | /* either the file must not exist, or it must be the original
|
---|
| 499 | * file, or we must have a bang, or "writeany" must be set.
|
---|
| 500 | */
|
---|
| 501 | if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang
|
---|
| 502 | #ifndef CRUNCH
|
---|
| 503 | && !*o_writeany
|
---|
| 504 | #endif
|
---|
| 505 | )
|
---|
| 506 | {
|
---|
| 507 | msg("File already exists - Use :w! to overwrite");
|
---|
| 508 | return FALSE;
|
---|
| 509 | }
|
---|
| 510 | #if VMS
|
---|
| 511 | /* Create a new VMS version of this file. */
|
---|
| 512 | {
|
---|
| 513 | char *strrchr(), *ptr = strrchr(filename,';');
|
---|
| 514 | if (ptr) *ptr = '\0'; /* Snip off any ;number in the name */
|
---|
| 515 | }
|
---|
| 516 | #endif
|
---|
| 517 | fd = creat(filename, FILEPERMS);
|
---|
| 518 | }
|
---|
| 519 | if (fd < 0)
|
---|
| 520 | {
|
---|
| 521 | msg("Can't write to \"%s\" -- NOT WRITTEN", filename);
|
---|
| 522 | return FALSE;
|
---|
| 523 | }
|
---|
| 524 |
|
---|
| 525 | /* write each text block to the file */
|
---|
| 526 | bytes = 0L;
|
---|
| 527 | for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++)
|
---|
| 528 | {
|
---|
| 529 | for (len = 0; len < BLKSIZE && this->c[len]; len++)
|
---|
| 530 | {
|
---|
| 531 | }
|
---|
| 532 | if (twrite(fd, this->c, len) < len)
|
---|
| 533 | {
|
---|
| 534 | msg("Trouble writing to \"%s\"", filename);
|
---|
| 535 | if (!strcmp(filename, origname))
|
---|
| 536 | {
|
---|
| 537 | setflag(file, MODIFIED);
|
---|
| 538 | }
|
---|
| 539 | close(fd);
|
---|
| 540 | return FALSE;
|
---|
| 541 | }
|
---|
| 542 | bytes += len;
|
---|
| 543 | }
|
---|
| 544 |
|
---|
| 545 | /* reset the "modified" flag, but not the "undoable" flag */
|
---|
| 546 | clrflag(file, MODIFIED);
|
---|
| 547 | significant = FALSE;
|
---|
| 548 |
|
---|
| 549 | /* report lines & characters */
|
---|
| 550 | #if MSDOS || TOS
|
---|
| 551 | bytes += nlines; /* for the inserted carriage returns */
|
---|
| 552 | #endif
|
---|
| 553 | msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes);
|
---|
| 554 |
|
---|
| 555 | /* close the file */
|
---|
| 556 | close(fd);
|
---|
| 557 |
|
---|
| 558 | return TRUE;
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 |
|
---|
| 562 | /* This function deletes the temporary file. If the file has been modified
|
---|
| 563 | * and "bang" is FALSE, then it returns FALSE without doing anything; else
|
---|
| 564 | * it returns TRUE.
|
---|
| 565 | *
|
---|
| 566 | * If the "autowrite" option is set, then instead of returning FALSE when
|
---|
| 567 | * the file has been modified and "bang" is false, it will call tmpend().
|
---|
| 568 | */
|
---|
| 569 | int tmpabort(bang)
|
---|
| 570 | int bang;
|
---|
| 571 | {
|
---|
| 572 | /* if there is no file, return successfully */
|
---|
| 573 | if (tmpfd < 0)
|
---|
| 574 | {
|
---|
| 575 | return TRUE;
|
---|
| 576 | }
|
---|
| 577 |
|
---|
| 578 | /* see if we must return FALSE -- can't quit */
|
---|
| 579 | if (!bang && tstflag(file, MODIFIED))
|
---|
| 580 | {
|
---|
| 581 | /* if "autowrite" is set, then act like tmpend() */
|
---|
| 582 | if (*o_autowrite)
|
---|
| 583 | return tmpend(bang);
|
---|
| 584 | else
|
---|
| 585 | return FALSE;
|
---|
| 586 | }
|
---|
| 587 |
|
---|
| 588 | /* delete the tmp file */
|
---|
| 589 | cutswitch();
|
---|
| 590 | strcpy(prevorig, origname);
|
---|
| 591 | prevline = markline(cursor);
|
---|
| 592 | *origname = '\0';
|
---|
| 593 | origtime = 0L;
|
---|
| 594 | blkinit();
|
---|
| 595 | nlines = 0;
|
---|
| 596 | initflags();
|
---|
| 597 | return TRUE;
|
---|
| 598 | }
|
---|
| 599 |
|
---|
| 600 | /* This function saves the file if it has been modified, and then deletes
|
---|
| 601 | * the temporary file. Returns TRUE if successful, or FALSE if the file
|
---|
| 602 | * needs to be saved but can't be. When it returns FALSE, it will not have
|
---|
| 603 | * deleted the tmp file, either.
|
---|
| 604 | */
|
---|
| 605 | int tmpend(bang)
|
---|
| 606 | int bang;
|
---|
| 607 | {
|
---|
| 608 | /* save the file if it has been modified */
|
---|
| 609 | if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang)
|
---|
| 610 | {
|
---|
| 611 | return FALSE;
|
---|
| 612 | }
|
---|
| 613 |
|
---|
| 614 | /* delete the tmp file */
|
---|
| 615 | tmpabort(TRUE);
|
---|
| 616 |
|
---|
| 617 | return TRUE;
|
---|
| 618 | }
|
---|
| 619 |
|
---|
| 620 |
|
---|
| 621 | /* If the tmp file has been changed, then this function will force those
|
---|
| 622 | * changes to be written to the disk, so that the tmp file will survive a
|
---|
| 623 | * system crash or power failure.
|
---|
| 624 | */
|
---|
| 625 | #if AMIGA || MSDOS || TOS
|
---|
| 626 | sync()
|
---|
| 627 | {
|
---|
| 628 | /* MS-DOS and TOS don't flush their buffers until the file is closed,
|
---|
| 629 | * so here we close the tmp file and then immediately reopen it.
|
---|
| 630 | */
|
---|
| 631 | close(tmpfd);
|
---|
| 632 | tmpfd = open(tmpname, O_RDWR | O_BINARY);
|
---|
| 633 | return 0;
|
---|
| 634 | }
|
---|
| 635 | #endif
|
---|
| 636 |
|
---|
| 637 |
|
---|
| 638 | /* This function stores the file's name in the second block of the temp file.
|
---|
| 639 | * SLEAZE ALERT! SLEAZE ALERT! The "tmpblk" buffer is probably being used
|
---|
| 640 | * to store the arguments to a command, so we can't use it here. Instead,
|
---|
| 641 | * we'll borrow the buffer that is used for "shift-U".
|
---|
| 642 | */
|
---|
| 643 | storename(name)
|
---|
| 644 | char *name; /* the name of the file - normally origname */
|
---|
| 645 | {
|
---|
| 646 | #ifndef CRUNCH
|
---|
| 647 | int len;
|
---|
| 648 | char *ptr;
|
---|
| 649 | #endif
|
---|
| 650 |
|
---|
| 651 | /* we're going to clobber the U_text buffer, so reset U_line */
|
---|
| 652 | U_line = 0L;
|
---|
| 653 |
|
---|
| 654 | if (!name)
|
---|
| 655 | {
|
---|
| 656 | strncpy(U_text, "", BLKSIZE);
|
---|
| 657 | U_text[1] = 127;
|
---|
| 658 | }
|
---|
| 659 | #ifndef CRUNCH
|
---|
| 660 | else if (*name != SLASH)
|
---|
| 661 | {
|
---|
| 662 | /* get the directory name */
|
---|
| 663 | ptr = getcwd(U_text, BLKSIZE);
|
---|
| 664 | if (ptr != U_text)
|
---|
| 665 | {
|
---|
| 666 | strcpy(U_text, ptr);
|
---|
| 667 | }
|
---|
| 668 |
|
---|
| 669 | /* append a slash to the directory name */
|
---|
| 670 | len = strlen(U_text);
|
---|
| 671 | U_text[len++] = SLASH;
|
---|
| 672 |
|
---|
| 673 | /* append the filename, padded with heaps o' NULs */
|
---|
| 674 | strncpy(U_text + len, *name ? name : "foo", BLKSIZE - len);
|
---|
| 675 | }
|
---|
| 676 | #endif
|
---|
| 677 | else
|
---|
| 678 | {
|
---|
| 679 | /* copy the filename into U_text */
|
---|
| 680 | strncpy(U_text, *name ? name : "foo", BLKSIZE);
|
---|
| 681 | }
|
---|
| 682 |
|
---|
| 683 | if (tmpfd >= 0)
|
---|
| 684 | {
|
---|
| 685 | /* write the name out to second block of the temp file */
|
---|
| 686 | lseek(tmpfd, (long)BLKSIZE, 0);
|
---|
| 687 | write(tmpfd, U_text, (unsigned)BLKSIZE);
|
---|
| 688 | }
|
---|
| 689 | return 0;
|
---|
| 690 | }
|
---|
| 691 |
|
---|
| 692 |
|
---|
| 693 |
|
---|
| 694 | /* This function handles deadly signals. It restores sanity to the terminal
|
---|
| 695 | * preserves the current temp file, and deletes any old temp files.
|
---|
| 696 | */
|
---|
| 697 | int deathtrap(sig)
|
---|
| 698 | int sig; /* the deadly signal that we caught */
|
---|
| 699 | {
|
---|
| 700 | char *why;
|
---|
| 701 |
|
---|
| 702 | /* restore the terminal's sanity */
|
---|
| 703 | endwin();
|
---|
| 704 |
|
---|
| 705 | #ifdef CRUNCH
|
---|
| 706 | why = "-Elvis died";
|
---|
| 707 | #else
|
---|
| 708 | /* give a more specific description of how Elvis died */
|
---|
| 709 | switch (sig)
|
---|
| 710 | {
|
---|
| 711 | # ifdef SIGHUP
|
---|
| 712 | case SIGHUP: why = "-the modem lost its carrier"; break;
|
---|
| 713 | # endif
|
---|
| 714 | # ifndef DEBUG
|
---|
| 715 | # ifdef SIGILL
|
---|
| 716 | case SIGILL: why = "-Elvis hit an illegal instruction"; break;
|
---|
| 717 | # endif
|
---|
| 718 | # ifdef SIGBUS
|
---|
| 719 | case SIGBUS: why = "-Elvis had a bus error"; break;
|
---|
| 720 | # endif
|
---|
| 721 | # if defined(SIGSEGV) && !defined(TOS)
|
---|
| 722 | case SIGSEGV: why = "-Elvis had a segmentation violation"; break;
|
---|
| 723 | # endif
|
---|
| 724 | # ifdef SIGSYS
|
---|
| 725 | case SIGSYS: why = "-Elvis munged a system call"; break;
|
---|
| 726 | # endif
|
---|
| 727 | # endif /* !DEBUG */
|
---|
| 728 | # ifdef SIGPIPE
|
---|
| 729 | case SIGPIPE: why = "-the pipe reader died"; break;
|
---|
| 730 | # endif
|
---|
| 731 | # ifdef SIGTERM
|
---|
| 732 | case SIGTERM: why = "-Elvis was terminated"; break;
|
---|
| 733 | # endif
|
---|
| 734 | # if !MINIX
|
---|
| 735 | # ifdef SIGUSR1
|
---|
| 736 | case SIGUSR1: why = "-Elvis was killed via SIGUSR1"; break;
|
---|
| 737 | # endif
|
---|
| 738 | # ifdef SIGUSR2
|
---|
| 739 | case SIGUSR2: why = "-Elvis was killed via SIGUSR2"; break;
|
---|
| 740 | # endif
|
---|
| 741 | # endif
|
---|
| 742 | default: why = "-Elvis died"; break;
|
---|
| 743 | }
|
---|
| 744 | #endif
|
---|
| 745 |
|
---|
| 746 | /* if we had a temp file going, then preserve it */
|
---|
| 747 | if (tmpnum > 0 && tmpfd >= 0)
|
---|
| 748 | {
|
---|
| 749 | close(tmpfd);
|
---|
| 750 | sprintf(tmpblk.c, "%s \"%s\" %s", PRESERVE, why, tmpname);
|
---|
| 751 | system(tmpblk.c);
|
---|
| 752 | }
|
---|
| 753 |
|
---|
| 754 | /* delete any old temp files */
|
---|
| 755 | cutend();
|
---|
| 756 |
|
---|
| 757 | /* exit with the proper exit status */
|
---|
| 758 | exit(sig);
|
---|
| 759 | }
|
---|