|
|
1.1 ! root 1: /*************************************************************************** ! 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * ! 3: * is provided to you without charge, and with no warranty. You may give * ! 4: * away copies of JOVE, including sources, provided that this notice is * ! 5: * included in all the files. * ! 6: ***************************************************************************/ ! 7: ! 8: #include "jove.h" ! 9: #include "list.h" ! 10: #include "fp.h" ! 11: #include "termcap.h" ! 12: #include "ctype.h" ! 13: #include "disp.h" ! 14: #include "scandir.h" ! 15: ! 16: ! 17: #ifdef IPROCS ! 18: # include <signal.h> ! 19: #endif ! 20: ! 21: #ifdef MAC ! 22: # include "mac.h" ! 23: #else ! 24: # include <sys/stat.h> ! 25: #endif ! 26: ! 27: #ifdef UNIX ! 28: # include <sys/file.h> ! 29: #endif ! 30: ! 31: #ifdef MSDOS ! 32: # include <fcntl.h> ! 33: # include <io.h> ! 34: # include <direct.h> ! 35: # include <dos.h> ! 36: #endif /* MSDOS */ ! 37: ! 38: #include <errno.h> ! 39: ! 40: private struct block ! 41: *b_unlink proto((struct block *)), ! 42: *lookup proto((/*int*/short)); ! 43: ! 44: private char ! 45: *dbackup proto((char *, char *, int)), ! 46: #if defined(MSDOS) ! 47: *fixpath proto((char *)), ! 48: #endif ! 49: *getblock proto((daddr, int)); ! 50: ! 51: private void ! 52: #if defined(MSDOS) ! 53: abspath proto((char *, char *)), ! 54: #endif ! 55: fake_blkio proto((struct block *, int (*)())), ! 56: DoWriteReg proto((int app)), ! 57: LRUunlink proto((struct block *)), ! 58: file_backup proto((char *fname)), ! 59: real_blkio proto((struct block *, int (*)())), ! 60: dfollow proto((char *, char *)); ! 61: ! 62: #if defined(MSDOS) ! 63: private int ! 64: Dchdir proto((char *)); ! 65: #endif ! 66: ! 67: #ifndef W_OK ! 68: # define W_OK 2 ! 69: # define F_OK 0 ! 70: #endif ! 71: ! 72: #define READ 0 ! 73: #define WRITE 1 /* block operation read or write */ ! 74: ! 75: long io_chars; /* number of chars in this open_file */ ! 76: int io_lines; /* number of lines in this open_file */ ! 77: ! 78: #if defined(VMUNIX) || defined(MSDOS) ! 79: char iobuff[LBSIZE], ! 80: genbuf[LBSIZE], ! 81: linebuf[LBSIZE]; ! 82: #else ! 83: char *iobuff, ! 84: *genbuf, ! 85: *linebuf; ! 86: #endif ! 87: ! 88: #ifdef BACKUPFILES ! 89: int BkupOnWrite = 0; ! 90: #endif ! 91: ! 92: void ! 93: close_file(fp) ! 94: File *fp; ! 95: { ! 96: if (fp) { ! 97: if (fp->f_flags & F_TELLALL) ! 98: add_mess(" %d lines, %D characters.", ! 99: io_lines, ! 100: io_chars); ! 101: f_close(fp); ! 102: } ! 103: } ! 104: ! 105: /* Write the region from line1/char1 to line2/char2 to FP. This ! 106: never CLOSES the file since we don't know if we want to. */ ! 107: ! 108: int EndWNewline = 1; ! 109: ! 110: void ! 111: putreg(fp, line1, char1, line2, char2, makesure) ! 112: register File *fp; ! 113: Line *line1, ! 114: *line2; ! 115: int char1, ! 116: char2, ! 117: makesure; ! 118: { ! 119: register int c; ! 120: register char *lp; ! 121: ! 122: if (makesure) ! 123: (void) fixorder(&line1, &char1, &line2, &char2); ! 124: while (line1 != line2->l_next) { ! 125: lp = lcontents(line1) + char1; ! 126: if (line1 == line2) { ! 127: fputnchar(lp, (char2 - char1), fp); ! 128: io_chars += (char2 - char1); ! 129: } else { ! 130: while ((c = *lp++) != '\0') { ! 131: jputc(c, fp); ! 132: io_chars += 1; ! 133: } ! 134: } ! 135: if (line1 != line2) { ! 136: io_lines += 1; ! 137: io_chars += 1; ! 138: #ifdef MSDOS ! 139: jputc('\r', fp); ! 140: #endif /* MSDOS */ ! 141: jputc('\n', fp); ! 142: } ! 143: line1 = line1->l_next; ! 144: char1 = 0; ! 145: } ! 146: flush(fp); ! 147: } ! 148: ! 149: private void ! 150: dofread(fp) ! 151: register File *fp; ! 152: { ! 153: char end[LBSIZE]; ! 154: int xeof = 0; ! 155: Line *savel = curline; ! 156: int savec = curchar; ! 157: ! 158: strcpy(end, linebuf + curchar); ! 159: xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar)); ! 160: SavLine(curline, linebuf); ! 161: if (!xeof) do { ! 162: curline = listput(curbuf, curline); ! 163: xeof = f_getputl(curline, fp); ! 164: } while (!xeof); ! 165: getDOT(); ! 166: linecopy(linebuf, (curchar = strlen(linebuf)), end); ! 167: SavLine(curline, linebuf); ! 168: IFixMarks(savel, savec, curline, curchar); ! 169: } ! 170: ! 171: void ! 172: read_file(file, is_insert) ! 173: char *file; ! 174: int is_insert; ! 175: { ! 176: Bufpos save; ! 177: File *fp; ! 178: ! 179: if (is_insert == NO) ! 180: curbuf->b_ntbf = NO; ! 181: fp = open_file(file, iobuff, F_READ, NO, NO); ! 182: if (fp == NIL) { ! 183: if (!is_insert && errno == ENOENT) ! 184: s_mess("(new file)"); ! 185: else ! 186: s_mess(IOerr("open", file)); ! 187: return; ! 188: } ! 189: if (is_insert == NO) { ! 190: set_ino(curbuf); ! 191: if (fp->f_flags & F_READONLY) { ! 192: set_arg_value(1); ! 193: } else { ! 194: set_arg_value(0); ! 195: } ! 196: TogMinor(ReadOnly); ! 197: } ! 198: ! 199: DOTsave(&save); ! 200: dofread(fp); ! 201: if (is_insert && io_chars > 0) { ! 202: modify(); ! 203: set_mark(); ! 204: } ! 205: SetDot(&save); ! 206: getDOT(); ! 207: close_file(fp); ! 208: } ! 209: ! 210: void ! 211: SaveFile() ! 212: { ! 213: if (IsModified(curbuf)) { ! 214: if (curbuf->b_fname == 0) ! 215: WriteFile(); ! 216: else { ! 217: filemunge(curbuf->b_fname); ! 218: #if !defined(MAC) && !defined(MSDOS) ! 219: chk_mtime(curbuf, curbuf->b_fname, "save"); ! 220: #endif ! 221: file_write(curbuf->b_fname, 0); ! 222: } ! 223: } else ! 224: message("No changes need to be written."); ! 225: } ! 226: ! 227: char *HomeDir; /* home directory */ ! 228: size_t HomeLen; /* length of home directory string */ ! 229: ! 230: private List *DirStack = 0; ! 231: #define dir_name(dp) ((char *) list_data(dp)) ! 232: #define PWD_PTR (list_data(DirStack)) ! 233: #define PWD ((char *) PWD_PTR) ! 234: ! 235: char * ! 236: pwd() ! 237: { ! 238: return (char *) PWD_PTR; ! 239: } ! 240: ! 241: char * ! 242: pr_name(fname, okay_home) ! 243: char *fname; ! 244: int okay_home; ! 245: { ! 246: int n; ! 247: ! 248: if (fname == 0) ! 249: return 0; ! 250: n = numcomp(fname, PWD); ! 251: ! 252: if ((PWD[n] == 0) && /* Matched to end of PWD */ ! 253: (fname[n] == '/')) ! 254: return fname + n + 1; ! 255: ! 256: if (okay_home && strcmp(HomeDir, "/") != 0 && ! 257: strncmp(fname, HomeDir, HomeLen) == 0 && ! 258: fname[HomeLen] == '/') { ! 259: static char name_buf[100]; ! 260: ! 261: swritef(name_buf, "~%s", fname + HomeLen); ! 262: return name_buf; ! 263: } ! 264: ! 265: return fname; /* return entire path name */ ! 266: } ! 267: ! 268: #ifdef MSDOS ! 269: extern unsigned int fmask; ! 270: #endif /* MSDOS */ ! 271: ! 272: void ! 273: Chdir() ! 274: { ! 275: char dirbuf[FILESIZE]; ! 276: ! 277: #ifdef MSDOS ! 278: fmask = 0x10; ! 279: #endif ! 280: (void) ask_file((char *) 0, PWD, dirbuf); ! 281: #ifdef MSDOS ! 282: fmask = 0x13; ! 283: if (Dchdir(dirbuf) == -1) ! 284: #else ! 285: if (chdir(dirbuf) == -1) ! 286: #endif ! 287: { ! 288: s_mess("cd: cannot change into %s.", dirbuf); ! 289: return; ! 290: } ! 291: UpdModLine = YES; ! 292: setCWD(dirbuf); ! 293: prCWD(); ! 294: #ifdef MAC ! 295: Bufchange++; ! 296: #endif ! 297: } ! 298: ! 299: #if defined(UNIX) ! 300: ! 301: # if !defined(BSD4_2) ! 302: char * ! 303: getwd(buffer) ! 304: char *buffer; ! 305: { ! 306: Buffer *old = curbuf; ! 307: char *ret_val; ! 308: ! 309: SetBuf(do_select((Window *) 0, "pwd-output")); ! 310: curbuf->b_type = B_PROCESS; ! 311: (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0); ! 312: ToFirst(); ! 313: strcpy(buffer, linebuf); ! 314: SetBuf(old); ! 315: return buffer; ! 316: } ! 317: # endif /* not BSD4_2 */ ! 318: ! 319: /* Check if dn is the name of the current working directory ! 320: and that it is in cannonical form */ ! 321: ! 322: int ! 323: chkCWD(dn) ! 324: char *dn; ! 325: { ! 326: char filebuf[FILESIZE]; ! 327: struct stat dnstat, ! 328: dotstat; ! 329: ! 330: if (dn[0] != '/') ! 331: return FALSE; /* need absolute pathname */ ! 332: PathParse(dn, filebuf); ! 333: return stat(filebuf, &dnstat) == 0 && ! 334: stat(".", &dotstat) == 0 && ! 335: dnstat.st_dev == dotstat.st_dev && ! 336: dnstat.st_ino == dotstat.st_ino; ! 337: } ! 338: ! 339: #endif /* UNIX */ ! 340: ! 341: void ! 342: setCWD(d) ! 343: char *d; ! 344: { ! 345: if (DirStack == NIL) ! 346: list_push(&DirStack, (Element *) 0); ! 347: if (PWD == 0) ! 348: PWD_PTR = (Element *) emalloc((size_t) (strlen(d) + 1)); ! 349: else ! 350: PWD_PTR = (Element *) ralloc(PWD, strlen(d) + 1); ! 351: strcpy(PWD, d); ! 352: } ! 353: ! 354: void ! 355: getCWD() ! 356: { ! 357: char *cwd; ! 358: char pathname[FILESIZE]; ! 359: #if defined(UNIX) && defined(JOB_CONTROL) ! 360: extern char *getwd(); ! 361: #endif ! 362: #if defined(MSDOS) ! 363: extern char *getcwd(); ! 364: #endif ! 365: ! 366: #ifndef MSDOS ! 367: cwd = getenv("CWD"); ! 368: if (cwd == 0 || !chkCWD(cwd)) { ! 369: cwd = getenv("PWD"); ! 370: if (cwd == 0 || !chkCWD(cwd)) ! 371: cwd = getwd(pathname); ! 372: } ! 373: #else /* MSDOS */ ! 374: cwd = fixpath(getcwd(pathname, FILESIZE)); ! 375: #endif /* MSDOS */ ! 376: setCWD(cwd); ! 377: } ! 378: ! 379: void ! 380: prDIRS() ! 381: { ! 382: register List *lp; ! 383: ! 384: s_mess(": %f "); ! 385: for (lp = DirStack; lp != NIL; lp = list_next(lp)) ! 386: add_mess("%s ", pr_name(dir_name(lp), YES)); ! 387: } ! 388: ! 389: void ! 390: prCWD() ! 391: { ! 392: s_mess(": %f => \"%s\"", PWD); ! 393: } ! 394: ! 395: void ! 396: Pushd() ! 397: { ! 398: char *newdir, ! 399: dirbuf[FILESIZE]; ! 400: ! 401: #ifdef MSDOS ! 402: fmask = 0x10; ! 403: #endif ! 404: newdir = ask_file((char *) 0, NullStr, dirbuf); ! 405: #ifdef MSDOS ! 406: fmask = 0x13; ! 407: #endif ! 408: UpdModLine = YES; ! 409: if (*newdir == 0) { /* Wants to swap top two entries */ ! 410: char *old_top; ! 411: ! 412: if (list_next(DirStack) == NIL) ! 413: complain("pushd: no other directory."); ! 414: old_top = PWD; ! 415: list_data(DirStack) = (Element *) dir_name(list_next(DirStack)); ! 416: list_data(list_next(DirStack)) = (Element *) old_top; ! 417: #ifdef MSDOS ! 418: (void) Dchdir(PWD); ! 419: #else ! 420: (void) chdir(PWD); ! 421: #endif ! 422: } else { ! 423: #ifdef MSDOS ! 424: if (Dchdir(dirbuf) == -1) ! 425: #else ! 426: if (chdir(dirbuf) == -1) ! 427: #endif ! 428: { ! 429: s_mess("pushd: cannot change into %s.", dirbuf); ! 430: return; ! 431: } ! 432: (void) list_push(&DirStack, (Element *) 0); ! 433: setCWD(dirbuf); ! 434: } ! 435: prDIRS(); ! 436: } ! 437: ! 438: void ! 439: Popd() ! 440: { ! 441: if (list_next(DirStack) == NIL) ! 442: complain("popd: directory stack is empty."); ! 443: UpdModLine = YES; ! 444: free((char *) list_pop(&DirStack)); ! 445: #ifdef MSDOS ! 446: (void) Dchdir(PWD); /* If this doesn't work, we's in deep shit. */ ! 447: #else ! 448: (void) chdir(PWD); /* If this doesn't work, we's in deep shit. */ ! 449: #endif ! 450: prDIRS(); ! 451: } ! 452: ! 453: private char * ! 454: dbackup(base, offset, c) ! 455: register char *base, ! 456: *offset; ! 457: register int c; ! 458: { ! 459: while (offset > base && *--offset != c) ! 460: ; ! 461: return offset; ! 462: } ! 463: ! 464: private void ! 465: dfollow(file, into) ! 466: char *file, ! 467: *into; ! 468: { ! 469: char *dp, ! 470: #ifdef MSDOS ! 471: filefix[FILESIZE], ! 472: #endif ! 473: *sp; ! 474: ! 475: #ifndef MSDOS ! 476: if (*file == '/') { /* Absolute pathname */ ! 477: strcpy(into, "/"); ! 478: file += 1; ! 479: #ifdef apollo ! 480: /* handle apollo "//..." */ ! 481: if (*file == '/') { ! 482: strcpy(into+1, "/"); ! 483: file += 1; ! 484: } ! 485: #endif ! 486: } else ! 487: strcpy(into, PWD); ! 488: #else ! 489: abspath(file, filefix); /* convert to absolute pathname */ ! 490: strcpy(into, filefix); /* and forget about drives */ ! 491: into[3] = 0; ! 492: into = &(into[2]); ! 493: file = &(filefix[3]); ! 494: #endif ! 495: dp = into + strlen(into); ! 496: ! 497: sp = file; ! 498: do { ! 499: if (*file == 0) ! 500: break; ! 501: if ((sp = strchr(file, '/')) != '\0') ! 502: *sp = 0; ! 503: if (strcmp(file, ".") == 0) ! 504: ; /* So it will get to the end of the loop */ ! 505: else if (strcmp(file, "..") == 0) { ! 506: *(dp = dbackup(into, dp, '/')) = 0; ! 507: if (dp == into) ! 508: strcpy(into, "/"), dp = into + 1; ! 509: } else { ! 510: if (into[strlen(into) - 1] != '/') ! 511: (void) strcat(into, "/"), dp += 1; ! 512: (void) strcat(into, file); ! 513: dp += strlen(file); /* stay at the end */ ! 514: } ! 515: file = sp + 1; ! 516: } while (sp != 0); ! 517: } ! 518: ! 519: #if defined(UNIX) ! 520: ! 521: # if defined(YP_PASSWD) ! 522: ! 523: #include <pwd.h> ! 524: ! 525: private void ! 526: get_hdir(user, buf) ! 527: register char *user, ! 528: *buf; ! 529: { ! 530: struct passwd *p; ! 531: ! 532: p = getpwnam(user); ! 533: endpwent(); ! 534: if (p == NULL) { ! 535: add_mess(" [unknown user: %s]", user); ! 536: SitFor(7); ! 537: complain((char *) 0); ! 538: /* NOTREACHED */ ! 539: } ! 540: strcpy(buf, p->pw_dir); ! 541: } ! 542: ! 543: #else ! 544: ! 545: private ! 546: get_hdir(user, buf) ! 547: register char *user, ! 548: *buf; ! 549: { ! 550: char fbuf[LBSIZE], ! 551: pattern[100]; ! 552: register int u_len; ! 553: File *fp; ! 554: ! 555: u_len = strlen(user); ! 556: fp = open_file("/etc/passwd", fbuf, F_READ, YES, YES); ! 557: swritef(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user); ! 558: while (f_gets(fp, genbuf, LBSIZE) != EOF) ! 559: if ((strncmp(genbuf, user, u_len) == 0) && ! 560: (LookingAt(pattern, genbuf, 0))) { ! 561: putmatch(1, buf, FILESIZE); ! 562: close_file(fp); ! 563: return; ! 564: } ! 565: close_file(fp); ! 566: add_mess(" [unknown user: %s]", user); ! 567: SitFor(7); ! 568: complain((char *) 0); ! 569: } ! 570: ! 571: #endif /* YP_PASSWD */ ! 572: #endif /* UNIX */ ! 573: ! 574: void ! 575: PathParse(name, intobuf) ! 576: char *name, ! 577: *intobuf; ! 578: { ! 579: char localbuf[FILESIZE]; ! 580: ! 581: intobuf[0] = localbuf[0] = '\0'; ! 582: if (*name == '\0') ! 583: return; ! 584: if (*name == '~') { ! 585: if (name[1] == '/' || name[1] == '\0') { ! 586: strcpy(localbuf, HomeDir); ! 587: name += 1; ! 588: } ! 589: #if !(defined(MSDOS) || defined(MAC)) /* may add for mac in future */ ! 590: else { ! 591: char *uendp = strchr(name, '/'), ! 592: unamebuf[30]; ! 593: ! 594: if (uendp == 0) ! 595: uendp = name + strlen(name); ! 596: name += 1; ! 597: null_ncpy(unamebuf, name, (size_t) (uendp - name)); ! 598: get_hdir(unamebuf, localbuf); ! 599: name = uendp; ! 600: } ! 601: #endif ! 602: } ! 603: #ifndef MSDOS ! 604: else if (*name == '\\') ! 605: name += 1; ! 606: #endif /* MSDOS */ ! 607: (void) strcat(localbuf, name); ! 608: dfollow(localbuf, intobuf); ! 609: } ! 610: ! 611: void ! 612: filemunge(newname) ! 613: char *newname; ! 614: { ! 615: struct stat stbuf; ! 616: ! 617: if (newname == 0) ! 618: return; ! 619: if (stat(newname, &stbuf)) ! 620: return; ! 621: #ifndef MSDOS ! 622: if (((stbuf.st_dev != curbuf->b_dev) || ! 623: (stbuf.st_ino != curbuf->b_ino)) && ! 624: #else /* MSDOS */ ! 625: if ( /* (stbuf.st_ino != curbuf->b_ino) && */ ! 626: #endif /* MSDOS */ ! 627: #ifndef MAC ! 628: ((stbuf.st_mode & S_IFMT) != S_IFCHR) && ! 629: #endif ! 630: (curbuf->b_fname==NIL || strcmp(newname, curbuf->b_fname) != 0)) { ! 631: rbell(); ! 632: confirm("\"%s\" already exists; overwrite it? ", newname); ! 633: } ! 634: } ! 635: ! 636: void ! 637: WrtReg() ! 638: { ! 639: DoWriteReg(NO); ! 640: } ! 641: ! 642: void ! 643: AppReg() ! 644: { ! 645: DoWriteReg(YES); ! 646: } ! 647: ! 648: int CreatMode = DFLT_MODE; ! 649: ! 650: private void ! 651: DoWriteReg(app) ! 652: int app; ! 653: { ! 654: char fnamebuf[FILESIZE], ! 655: *fname; ! 656: Mark *mp = CurMark(); ! 657: File *fp; ! 658: ! 659: /* Won't get here if there isn't a Mark */ ! 660: fname = ask_file((char *) 0, (char *) 0, fnamebuf); ! 661: ! 662: #ifdef BACKUPFILES ! 663: if (app == NO) { ! 664: filemunge(fname); ! 665: ! 666: if (BkupOnWrite) ! 667: file_backup(fname); ! 668: } ! 669: #else ! 670: if (!app) ! 671: filemunge(fname); ! 672: #endif ! 673: ! 674: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO); ! 675: putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES); ! 676: close_file(fp); ! 677: } ! 678: ! 679: int OkayBadChars = 0; ! 680: ! 681: void ! 682: WriteFile() ! 683: { ! 684: char *fname, ! 685: fnamebuf[FILESIZE]; ! 686: #ifdef MAC ! 687: if (Macmode) { ! 688: if(!(fname = pfile(fnamebuf))) return; ! 689: } ! 690: else ! 691: #endif /* MAC */ ! 692: ! 693: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); ! 694: /* Don't allow bad characters when creating new files. */ ! 695: if (!OkayBadChars ! 696: && (curbuf->b_fname==NIL || strcmp(curbuf->b_fname, fnamebuf) != 0)) ! 697: { ! 698: #ifdef UNIX ! 699: static char *badchars = "!$^&*()~`{}\"'\\|<>? "; ! 700: #endif /* UNIX */ ! 701: #ifdef MSDOS ! 702: static char *badchars = "*|<>? "; ! 703: #endif /* MSDOS */ ! 704: #ifdef MAC ! 705: static char *badchars = ":"; ! 706: #endif /* MAC */ ! 707: register char *cp = fnamebuf; ! 708: register int c; ! 709: ! 710: while ((c = *cp++ & CHARMASK) != '\0') /* avoid sign extension... */ ! 711: if (c < ' ' || c == '\177' || strchr(badchars, c)) ! 712: complain("'%p': bad character in filename.", c); ! 713: } ! 714: ! 715: #if !defined(MAC) && !defined(MSDOS) ! 716: chk_mtime(curbuf, fname, "write"); ! 717: #endif ! 718: filemunge(fname); ! 719: curbuf->b_type = B_FILE; /* in case it wasn't before */ ! 720: setfname(curbuf, fname); ! 721: file_write(fname, 0); ! 722: } ! 723: ! 724: /* Open file FNAME supplying the buffer IO routine with buffer BUF. ! 725: HOW is F_READ, F_WRITE or F_APPEND. IFBAD == COMPLAIN means that ! 726: if we fail at opening the file, call complain. LOUDNESS says ! 727: whether or not to print the "reading ..." message on the message ! 728: line. ! 729: ! 730: NOTE: This opens the pr_name(fname, NO) of fname. That is, FNAME ! 731: is usually an entire pathname, which can be slow when the ! 732: pathname is long and there are lots of symbolic links along ! 733: the way (which has become very common in my experience). So, ! 734: this speeds up opens file names in the local directory. It ! 735: will not speed up things like "../scm/foo.scm" simple because ! 736: by the time we get here that's already been expanded to an ! 737: absolute pathname. But this is a start. ! 738: */ ! 739: ! 740: File * ! 741: open_file(fname, buf, how, complainifbad, quiet) ! 742: register char *fname; ! 743: char *buf; ! 744: register int how; ! 745: int complainifbad, ! 746: quiet; ! 747: { ! 748: register File *fp; ! 749: ! 750: io_chars = 0; ! 751: io_lines = 0; ! 752: ! 753: fp = f_open(pr_name(fname, NO), how, buf, LBSIZE); ! 754: if (fp == NIL) { ! 755: message(IOerr((how == F_READ) ? "open" : "create", fname)); ! 756: if (complainifbad) ! 757: complain((char *) 0); ! 758: } else { ! 759: int rd_only = FALSE; ! 760: #ifndef MAC ! 761: if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) { ! 762: rd_only = TRUE; ! 763: fp->f_flags |= F_READONLY; ! 764: } ! 765: #endif ! 766: if (!quiet) { ! 767: fp->f_flags |= F_TELLALL; ! 768: f_mess("\"%s\"%s", pr_name(fname, YES), ! 769: rd_only ? " [Read only]" : NullStr); ! 770: } ! 771: } ! 772: return fp; ! 773: } ! 774: ! 775: #ifndef MSDOS ! 776: /* Check to see if the file has been modified since it was ! 777: last written. If so, make sure they know what they're ! 778: doing. ! 779: ! 780: I hate to use another stat(), but to use confirm we gotta ! 781: do this before we open the file. ! 782: ! 783: NOTE: This stats FNAME after converting it to a path-relative ! 784: name. I can't see why this would cause a problem ... ! 785: */ ! 786: ! 787: void ! 788: chk_mtime(thisbuf, fname, how) ! 789: Buffer *thisbuf; ! 790: char *fname, ! 791: *how; ! 792: { ! 793: struct stat stbuf; ! 794: Buffer *b; ! 795: char *mesg = "Shall I go ahead and %s anyway? "; ! 796: ! 797: if ((thisbuf->b_mtime != 0) && /* if we care ... */ ! 798: ((b = file_exists(fname)) != NIL) && /* we already have this file */ ! 799: (b == thisbuf) && /* and it's the current buffer */ ! 800: (stat(pr_name(fname, NO), &stbuf) != -1) && /* and we can stat it */ ! 801: (stbuf.st_mtime != b->b_mtime)) { /* and there's trouble. */ ! 802: rbell(); ! 803: redisplay(); /* Ring that bell! */ ! 804: TOstart("Warning", TRUE); ! 805: Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES)); ! 806: Typeout("visited or saved. Probably someone else is editing"); ! 807: Typeout("your file at the same time."); ! 808: if (how) { ! 809: Typeout(""); ! 810: Typeout("Type \"y\" if I should %s, anyway.", how); ! 811: f_mess(mesg, how); ! 812: } ! 813: TOstop(); ! 814: if (how) ! 815: confirm(mesg, how); ! 816: } ! 817: } ! 818: ! 819: #endif /* MSDOS */ ! 820: ! 821: void ! 822: file_write(fname, app) ! 823: char *fname; ! 824: int app; ! 825: { ! 826: File *fp; ! 827: ! 828: #ifdef BACKUPFILES ! 829: if (!app && BkupOnWrite) ! 830: file_backup(fname); ! 831: #endif ! 832: ! 833: fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO); ! 834: ! 835: if (EndWNewline) { /* Make sure file ends with a newLine */ ! 836: Bufpos save; ! 837: ! 838: DOTsave(&save); ! 839: ToLast(); ! 840: if (length(curline)) /* Not a blank Line */ ! 841: LineInsert(1); ! 842: SetDot(&save); ! 843: } ! 844: putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO); ! 845: close_file(fp); ! 846: set_ino(curbuf); ! 847: unmodify(); ! 848: } ! 849: ! 850: void ! 851: ReadFile() ! 852: { ! 853: Buffer *bp; ! 854: char *fname, ! 855: fnamebuf[FILESIZE]; ! 856: int lineno; ! 857: ! 858: #ifdef MAC ! 859: if(Macmode) { ! 860: if(!(fname = gfile(fnamebuf))) return; ! 861: } ! 862: else ! 863: #endif /* MAC */ ! 864: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); ! 865: #if !(defined(MSDOS) || defined(MAC)) ! 866: chk_mtime(curbuf, fname, "read"); ! 867: #endif /* MSDOS || MAC */ ! 868: ! 869: if (IsModified(curbuf)) { ! 870: char *y_or_n; ! 871: int c; ! 872: ! 873: for (;;) { ! 874: rbell(); ! 875: y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name); ! 876: c = CharUpcase(*y_or_n); ! 877: if (c == 'Y' || c == 'N') ! 878: break; ! 879: } ! 880: if (c == 'Y') ! 881: SaveFile(); ! 882: } ! 883: ! 884: if ((bp = file_exists(fnamebuf)) != NIL && ! 885: (bp == curbuf)) ! 886: lineno = pnt_line() - 1; ! 887: else ! 888: lineno = 0; ! 889: ! 890: unmodify(); ! 891: initlist(curbuf); ! 892: setfname(curbuf, fname); ! 893: read_file(fname, 0); ! 894: SetLine(next_line(curbuf->b_first, lineno)); ! 895: } ! 896: ! 897: void ! 898: InsFile() ! 899: { ! 900: char *fname, ! 901: fnamebuf[FILESIZE]; ! 902: #ifdef MAC ! 903: if(Macmode) { ! 904: if(!(fname = gfile(fnamebuf))) return; ! 905: } ! 906: else ! 907: #endif /* MAC */ ! 908: fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf); ! 909: read_file(fname, 1); ! 910: } ! 911: ! 912: #include "temp.h" ! 913: ! 914: int DOLsave = 0; /* Do Lsave flag. If lines aren't being saved ! 915: when you think they should have been, this ! 916: flag is probably not being set, or is being ! 917: cleared before lsave() was called. */ ! 918: ! 919: private int nleft, /* number of good characters left in current block */ ! 920: tmpfd = -1; ! 921: daddr DFree = 1; /* pointer to end of tmp file */ ! 922: private char *tfname; ! 923: ! 924: void ! 925: tmpinit() ! 926: { ! 927: char buf[FILESIZE]; ! 928: ! 929: #ifdef MAC ! 930: swritef(buf, "%s/%s", HomeDir, d_tempfile); ! 931: #else ! 932: swritef(buf, "%s/%s", TmpFilePath, d_tempfile); ! 933: #endif ! 934: tfname = copystr(buf); ! 935: tfname = mktemp(tfname); ! 936: (void) close(creat(tfname, 0600)); ! 937: #ifndef MSDOS ! 938: tmpfd = open(tfname, 2); ! 939: #else /* MSDOS */ ! 940: tmpfd = open(tfname, 0x8002); /* MSDOS fix */ ! 941: #endif /* MSDOS */ ! 942: if (tmpfd == -1) ! 943: complain("Warning: cannot create tmp file!"); ! 944: } ! 945: ! 946: void ! 947: tmpclose() ! 948: { ! 949: if (tmpfd == -1) ! 950: return; ! 951: (void) close(tmpfd); ! 952: tmpfd = -1; ! 953: (void) unlink(tfname); ! 954: } ! 955: ! 956: /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE ! 957: long */ ! 958: ! 959: int Jr_Len; /* length of Just Read Line */ ! 960: ! 961: #ifdef MAC /* The Lighspeed compiler can't copy with static here */ ! 962: char *getblock(); ! 963: #else ! 964: private char *getblock(); ! 965: #endif ! 966: void ! 967: getline(addr, buf) ! 968: daddr addr; ! 969: register char *buf; ! 970: { ! 971: register char *bp, ! 972: *lp; ! 973: ! 974: lp = buf; ! 975: bp = getblock(addr >> 1, READ); ! 976: do ; while ((*lp++ = *bp++) != '\0'); ! 977: Jr_Len = (lp - buf) - 1; ! 978: } ! 979: ! 980: /* Put `buf' and return the disk address */ ! 981: ! 982: daddr ! 983: putline(buf) ! 984: char *buf; ! 985: { ! 986: register char *bp, ! 987: *lp; ! 988: register int nl; ! 989: daddr free_ptr; ! 990: ! 991: lp = buf; ! 992: free_ptr = DFree; ! 993: bp = getblock(free_ptr, WRITE); ! 994: nl = nleft; ! 995: free_ptr = blk_round(free_ptr); ! 996: while ((*bp = *lp++) != '\0') { ! 997: if (*bp++ == '\n') { ! 998: *--bp = 0; ! 999: break; ! 1000: } ! 1001: if (--nl == 0) { ! 1002: free_ptr = forward_block(free_ptr); ! 1003: DFree = free_ptr; ! 1004: bp = getblock(free_ptr, WRITE); ! 1005: lp = buf; /* start over ... */ ! 1006: nl = nleft; ! 1007: } ! 1008: } ! 1009: free_ptr = DFree; ! 1010: DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE); ! 1011: /* (lp - buf) includes the null */ ! 1012: return (free_ptr << 1); ! 1013: } ! 1014: ! 1015: /* The theory is that critical section of code inside this procedure ! 1016: will never cause a problem to occur. Basically, we need to ensure ! 1017: that two blocks are in memory at the same time, but I think that ! 1018: this can never screw up. */ ! 1019: ! 1020: #define lockblock(addr) ! 1021: #define unlockblock(addr) ! 1022: ! 1023: daddr ! 1024: f_getputl(line, fp) ! 1025: Line *line; ! 1026: register File *fp; ! 1027: { ! 1028: register char *bp; ! 1029: register int c, ! 1030: nl, ! 1031: room = LBSIZE; ! 1032: daddr free_ptr; ! 1033: char *base; ! 1034: #ifdef MSDOS ! 1035: char crleft = 0; ! 1036: #endif /* MSDOS */ ! 1037: ! 1038: free_ptr = DFree; ! 1039: base = bp = getblock(free_ptr, WRITE); ! 1040: nl = nleft; ! 1041: free_ptr = blk_round(free_ptr); ! 1042: while (--room > 0) { ! 1043: #ifdef MSDOS ! 1044: if (crleft) { ! 1045: c = crleft; ! 1046: crleft = 0; ! 1047: } else ! 1048: #endif /* MSDOS */ ! 1049: c = jgetc(fp); ! 1050: if (c == EOF || c == '\n') ! 1051: break; ! 1052: #ifdef MSDOS ! 1053: if (c == '\r') ! 1054: if ((crleft = jgetc(fp)) == '\n') { ! 1055: crleft = 0; ! 1056: break; ! 1057: } ! 1058: #endif /* MSDOS */ ! 1059: if (--nl == 0) { ! 1060: char *newbp; ! 1061: size_t nbytes; ! 1062: ! 1063: lockblock(free_ptr); ! 1064: DFree = free_ptr = forward_block(free_ptr); ! 1065: nbytes = bp - base; ! 1066: newbp = getblock(free_ptr, WRITE); ! 1067: nl = nleft; ! 1068: byte_copy(base, newbp, nbytes); ! 1069: bp = newbp + nbytes; ! 1070: base = newbp; ! 1071: unlockblock(free_ptr); ! 1072: } ! 1073: *bp++ = c; ! 1074: } ! 1075: *bp++ = '\0'; ! 1076: free_ptr = DFree; ! 1077: DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE); ! 1078: line->l_dline = (free_ptr << 1); ! 1079: if (room == 0) { ! 1080: add_mess(" [Line too long]"); ! 1081: rbell(); ! 1082: return EOF; ! 1083: } ! 1084: if (c == EOF) { ! 1085: if (--bp != base) ! 1086: add_mess(" [Incomplete last line]"); ! 1087: return EOF; ! 1088: } ! 1089: io_lines += 1; ! 1090: return 0; ! 1091: } ! 1092: ! 1093: typedef struct block { ! 1094: short b_dirty, ! 1095: b_bno; ! 1096: char b_buf[JBUFSIZ]; ! 1097: struct block ! 1098: *b_LRUnext, ! 1099: *b_LRUprev, ! 1100: *b_HASHnext; ! 1101: } Block; ! 1102: ! 1103: #define HASHSIZE 7 /* Primes work best (so I'm told) */ ! 1104: #define B_HASH(bno) ((bno) % HASHSIZE) ! 1105: ! 1106: #ifdef MAC ! 1107: private Block *b_cache, ! 1108: #else ! 1109: private Block b_cache[NBUF], ! 1110: #endif ! 1111: *bht[HASHSIZE], /* Block hash table. Must be zero initially */ ! 1112: *f_block = 0, ! 1113: *l_block = 0; ! 1114: private int max_bno = -1, ! 1115: NBlocks; ! 1116: ! 1117: #ifdef MAC ! 1118: void (*blkio)(); ! 1119: #else ! 1120: private void (*blkio) proto((Block *, int (*)())); ! 1121: #endif /* MAC */ ! 1122: ! 1123: #ifdef MAC ! 1124: make_cache() /* Only 32K of static space on Mac, so... */ ! 1125: { ! 1126: return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1); ! 1127: } ! 1128: #endif /* MAC */ ! 1129: ! 1130: extern int read(), write(); ! 1131: ! 1132: private void ! 1133: real_blkio(b, iofcn) ! 1134: register Block *b; ! 1135: #if defined(MAC) || defined(IBMPC) ! 1136: register int (*iofcn)(); ! 1137: #else ! 1138: register int (*iofcn) proto((int, UnivPtr, size_t)); ! 1139: #endif /* MAC */ ! 1140: { ! 1141: (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * JBUFSIZ, 0); ! 1142: if ((*iofcn)(tmpfd, b->b_buf, (size_t)JBUFSIZ) != JBUFSIZ) ! 1143: error("[Tmp file %s error; to continue editing would be dangerous]", ! 1144: (iofcn == read) ? "READ" : "WRITE"); ! 1145: } ! 1146: ! 1147: private void ! 1148: fake_blkio(b, iofcn) ! 1149: register Block *b; ! 1150: register int (*iofcn)(); ! 1151: { ! 1152: tmpinit(); ! 1153: blkio = real_blkio; ! 1154: real_blkio(b, iofcn); ! 1155: } ! 1156: ! 1157: void ! 1158: d_cache_init() ! 1159: { ! 1160: register Block *bp, /* Block pointer */ ! 1161: **hp; /* Hash pointer */ ! 1162: register short bno; ! 1163: ! 1164: for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) { ! 1165: NBlocks += 1; ! 1166: bp->b_dirty = 0; ! 1167: bp->b_bno = bno; ! 1168: if (l_block == 0) ! 1169: l_block = bp; ! 1170: bp->b_LRUprev = 0; ! 1171: bp->b_LRUnext = f_block; ! 1172: if (f_block != 0) ! 1173: f_block->b_LRUprev = bp; ! 1174: f_block = bp; ! 1175: ! 1176: bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]); ! 1177: *hp = bp; ! 1178: } ! 1179: blkio = fake_blkio; ! 1180: } ! 1181: ! 1182: void ! 1183: SyncTmp() ! 1184: { ! 1185: register Block *b; ! 1186: #ifdef IBMPC ! 1187: register int bno = 0; ! 1188: ! 1189: /* sync the blocks in order, for file systems that don't allow ! 1190: holes (MSDOS). Perhaps this benefits floppy-based file systems. */ ! 1191: ! 1192: for (bno = 0; bno <= max_bno; ) { ! 1193: if ((b = lookup(bno++)) && b->b_dirty) { ! 1194: (*blkio)(b, write); ! 1195: b->b_dirty = 0; ! 1196: } ! 1197: } ! 1198: #else ! 1199: for (b = f_block; b != 0; b = b->b_LRUnext) ! 1200: if (b->b_dirty) { ! 1201: (*blkio)(b, write); ! 1202: b->b_dirty = 0; ! 1203: } ! 1204: #endif ! 1205: } ! 1206: ! 1207: private Block * ! 1208: lookup(bno) ! 1209: register short bno; ! 1210: { ! 1211: register Block *bp; ! 1212: ! 1213: for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext) ! 1214: if (bp->b_bno == bno) ! 1215: break; ! 1216: return bp; ! 1217: } ! 1218: ! 1219: private void ! 1220: LRUunlink(b) ! 1221: register Block *b; ! 1222: { ! 1223: if (b->b_LRUprev == 0) ! 1224: f_block = b->b_LRUnext; ! 1225: else ! 1226: b->b_LRUprev->b_LRUnext = b->b_LRUnext; ! 1227: if (b->b_LRUnext == 0) ! 1228: l_block = b->b_LRUprev; ! 1229: else ! 1230: b->b_LRUnext->b_LRUprev = b->b_LRUprev; ! 1231: } ! 1232: ! 1233: private Block * ! 1234: b_unlink(bp) ! 1235: register Block *bp; ! 1236: { ! 1237: register Block *hp, ! 1238: *prev = 0; ! 1239: ! 1240: LRUunlink(bp); ! 1241: /* Now that we have the block, we remove it from its position ! 1242: in the hash table, so we can THEN put it somewhere else with ! 1243: it's new block assignment. */ ! 1244: ! 1245: for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext) ! 1246: if (hp == bp) ! 1247: break; ! 1248: if (hp == 0) { ! 1249: writef("\rBlock %d missing!", bp->b_bno); ! 1250: finish(0); ! 1251: } ! 1252: if (prev) ! 1253: prev->b_HASHnext = hp->b_HASHnext; ! 1254: else ! 1255: bht[B_HASH(bp->b_bno)] = hp->b_HASHnext; ! 1256: ! 1257: if (bp->b_dirty) { /* do, now, the delayed write */ ! 1258: (*blkio)(bp, write); ! 1259: bp->b_dirty = 0; ! 1260: } ! 1261: ! 1262: return bp; ! 1263: } ! 1264: ! 1265: /* Get a block which contains at least part of the line with the address ! 1266: atl. Returns a pointer to the block and sets the global variable ! 1267: nleft (number of good characters left in the buffer). */ ! 1268: ! 1269: private char * ! 1270: getblock(atl, iof) ! 1271: daddr atl; ! 1272: int iof; ! 1273: { ! 1274: register int bno, ! 1275: off; ! 1276: register Block *bp; ! 1277: static Block *lastb = 0; ! 1278: ! 1279: bno = da_to_bno(atl); ! 1280: off = da_to_off(atl); ! 1281: if (da_too_huge(atl)) ! 1282: error("Tmp file too large. Get help!"); ! 1283: nleft = JBUFSIZ - off; ! 1284: if (lastb != 0 && lastb->b_bno == bno) { ! 1285: lastb->b_dirty |= iof; ! 1286: return lastb->b_buf + off; ! 1287: } ! 1288: ! 1289: /* The requested block already lives in memory, so we move ! 1290: it to the end of the LRU list (making it Most Recently Used) ! 1291: and then return a pointer to it. */ ! 1292: if ((bp = lookup(bno)) != NIL) { ! 1293: if (bp != l_block) { ! 1294: LRUunlink(bp); ! 1295: if (l_block == 0) ! 1296: f_block = l_block = bp; ! 1297: else ! 1298: l_block->b_LRUnext = bp; ! 1299: bp->b_LRUprev = l_block; ! 1300: l_block = bp; ! 1301: bp->b_LRUnext = 0; ! 1302: } ! 1303: if (bp->b_bno > max_bno) ! 1304: max_bno = bp->b_bno; ! 1305: bp->b_dirty |= iof; ! 1306: lastb = bp; ! 1307: return bp->b_buf + off; ! 1308: } ! 1309: ! 1310: /* The block we want doesn't reside in memory so we take the ! 1311: least recently used clean block (if there is one) and use ! 1312: it. */ ! 1313: bp = f_block; ! 1314: if (bp->b_dirty) /* The best block is dirty ... */ ! 1315: SyncTmp(); ! 1316: ! 1317: bp = b_unlink(bp); ! 1318: if (l_block == 0) ! 1319: l_block = f_block = bp; ! 1320: else ! 1321: l_block->b_LRUnext = bp; /* Place it at the end ... */ ! 1322: bp->b_LRUprev = l_block; ! 1323: l_block = bp; ! 1324: bp->b_LRUnext = 0; /* so it's Most Recently Used */ ! 1325: ! 1326: bp->b_dirty = iof; ! 1327: bp->b_bno = bno; ! 1328: bp->b_HASHnext = bht[B_HASH(bno)]; ! 1329: bht[B_HASH(bno)] = bp; ! 1330: ! 1331: /* Get the current contents of the block UNLESS this is a new ! 1332: block that's never been looked at before, i.e., it's past ! 1333: the end of the tmp file. */ ! 1334: ! 1335: if (bp->b_bno <= max_bno) ! 1336: (*blkio)(bp, read); ! 1337: else ! 1338: max_bno = bno; ! 1339: ! 1340: lastb = bp; ! 1341: return bp->b_buf + off; ! 1342: } ! 1343: ! 1344: char * ! 1345: lbptr(line) ! 1346: Line *line; ! 1347: { ! 1348: return getblock(line->l_dline >> 1, READ); ! 1349: } ! 1350: ! 1351: /* save the current contents of linebuf, if it has changed */ ! 1352: ! 1353: void ! 1354: lsave() ! 1355: { ! 1356: if (curbuf == 0 || !DOLsave) /* Nothing modified recently */ ! 1357: return; ! 1358: ! 1359: if (strcmp(lbptr(curline), linebuf) != 0) ! 1360: SavLine(curline, linebuf); /* Put linebuf on the disk. */ ! 1361: DOLsave = 0; ! 1362: } ! 1363: ! 1364: #ifdef BACKUPFILES ! 1365: private void ! 1366: file_backup(fname) ! 1367: char *fname; ! 1368: { ! 1369: #ifndef MSDOS ! 1370: char *s; ! 1371: register int i; ! 1372: int fd1, ! 1373: fd2; ! 1374: char tmp1[JBUFSIZ], ! 1375: tmp2[JBUFSIZ]; ! 1376: struct stat buf; ! 1377: int mode; ! 1378: ! 1379: strcpy(tmp1, fname); ! 1380: if ((s = strrchr(tmp1, '/')) == NULL) ! 1381: swritef(tmp2, "#%s~", fname); ! 1382: else { ! 1383: *s++ = '\0'; ! 1384: swritef(tmp2, "%s/#%s~", tmp1, s); ! 1385: } ! 1386: ! 1387: if ((fd1 = open(fname, 0)) < 0) ! 1388: return; ! 1389: ! 1390: /* create backup file with same mode as input file */ ! 1391: #ifndef MAC ! 1392: if (fstat(fd1, &buf) != 0) ! 1393: mode = CreatMode; ! 1394: else ! 1395: #endif ! 1396: mode = buf.st_mode; ! 1397: ! 1398: if ((fd2 = creat(tmp2, mode)) < 0) { ! 1399: (void) close(fd1); ! 1400: return; ! 1401: } ! 1402: while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0) ! 1403: write(fd2, tmp1, (size_t) i); ! 1404: #ifdef BSD4_2 ! 1405: (void) fsync(fd2); ! 1406: #endif ! 1407: (void) close(fd2); ! 1408: (void) close(fd1); ! 1409: #else /* MSDOS */ ! 1410: char *dot, ! 1411: *slash, ! 1412: tmp[FILESIZE]; ! 1413: ! 1414: strcpy(tmp, fname); ! 1415: slash = basename(tmp); ! 1416: if (dot = strrchr(slash, '.')) { ! 1417: if (!stricmp(dot,".bak")) ! 1418: return; ! 1419: else *dot = 0; ! 1420: } ! 1421: strcat(tmp, ".bak"); ! 1422: unlink(tmp); ! 1423: rename(fname, tmp); ! 1424: #endif /* MSDOS */ ! 1425: } ! 1426: #endif ! 1427: ! 1428: #if defined(MSDOS) ! 1429: ! 1430: private int /* chdir + drive */ ! 1431: Dchdir(to) ! 1432: char *to; ! 1433: { ! 1434: unsigned d, dd, n; ! 1435: ! 1436: if (to[1] == ':') { ! 1437: d = to[0]; ! 1438: if (d >= 'a') d = d - 'a' + 1; ! 1439: if (d >= 'A') d = d - 'A' + 1; ! 1440: _dos_getdrive(&dd); ! 1441: if (dd != d) ! 1442: _dos_setdrive(d, &n); ! 1443: if (to[2] == 0) ! 1444: return 0; ! 1445: } ! 1446: return chdir(to); ! 1447: } ! 1448: ! 1449: private char * ! 1450: fixpath(p) ! 1451: char *p; ! 1452: { ! 1453: char *pp = p; ! 1454: ! 1455: while (*p) { ! 1456: if (*p == '\\') ! 1457: *p = '/'; ! 1458: p++; ! 1459: } ! 1460: return(strlwr(pp)); ! 1461: } ! 1462: ! 1463: ! 1464: private void ! 1465: abspath(so, dest) ! 1466: char *so, *dest; ! 1467: { ! 1468: char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5], ! 1469: soD[3], soDIR[FILESIZE], soF[9], soEXT[5]; ! 1470: char *drive, *path; ! 1471: ! 1472: _splitpath(fixpath(so), soD, soDIR, soF, soEXT); ! 1473: getcwd(cwd, FILESIZE); ! 1474: if (*soD != 0) { ! 1475: Dchdir(soD); /* this is kinda messy */ ! 1476: getcwd(cwdDIR, FILESIZE); /* should probably just */ ! 1477: Dchdir(cwd); /* call DOS to do it */ ! 1478: strcpy(cwd, cwdDIR); ! 1479: } ! 1480: (void) fixpath(cwd); ! 1481: if (cwd[strlen(cwd)-1] != '/') ! 1482: strcat(cwd, "/x.x"); /* need dummy filename */ ! 1483: ! 1484: _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT); ! 1485: ! 1486: drive = (*soD == 0) ? cwdD : soD; ! 1487: ! 1488: if (*soDIR != '/') ! 1489: path = strcat(cwdDIR, soDIR); ! 1490: else ! 1491: path = soDIR; ! 1492: _makepath(dest, drive, path, soF, soEXT); ! 1493: fixpath(dest); /* can't do it often enough */ ! 1494: } ! 1495: ! 1496: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.