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: /* Contains commands that deal with creating, selecting, killing and 9: listing buffers, and buffer modes, and find-file, etc. */ 10: 11: #include "jove.h" 12: 13: #ifdef MAC 14: # include "mac.h" 15: #else 16: # include <sys/stat.h> 17: #endif 18: 19: #ifdef MAC 20: # undef private 21: # define private 22: #endif 23: 24: #ifdef LINT_ARGS 25: private Buffer 26: * buf_alloc(void), 27: * mak_buf(void); 28: 29: private char * line_cnt(Buffer *, char *); 30: 31: private void 32: BufNSelect(int), 33: defb_wind(Buffer *), 34: kill_buf(Buffer *), 35: mkbuflist(char **); 36: #else 37: private Buffer 38: * buf_alloc(), 39: * mak_buf(); 40: 41: private char * line_cnt(); 42: 43: private void 44: BufNSelect(), 45: defb_wind(), 46: kill_buf(), 47: mkbuflist(); 48: #endif /* LINT_ARGS */ 49: 50: #ifdef MAC 51: # undef private 52: # define private static 53: #endif 54: 55: char *Mainbuf = "Main", 56: *NoName = "Sans un nom!"; 57: 58: Buffer *world = 0, /* First in the list */ 59: *curbuf = 0, 60: *lastbuf = 0; /* Last buffer we were in so we have a default 61: buffer during a select buffer. */ 62: 63: /* Toggle BIT in the current buffer's minor mode flags. If argument is 64: supplied, a positive one always turns on the mode and zero argument 65: always turns it off. */ 66: 67: void 68: TogMinor(bit) 69: { 70: if (is_an_arg()) { 71: if (arg_value() == 0) 72: curbuf->b_minor &= ~bit; 73: else 74: curbuf->b_minor |= bit; 75: } else 76: curbuf->b_minor ^= bit; 77: UpdModLine = YES; 78: } 79: 80: /* Creates a new buffer, links it at the end of the buffer chain, and 81: returns it. */ 82: 83: static Buffer * 84: buf_alloc() 85: { 86: register Buffer *b, 87: *lastbp; 88: 89: lastbp = 0; 90: for (b = world; b != 0; lastbp = b, b = b->b_next) 91: ; 92: 93: b = (Buffer *) emalloc(sizeof (Buffer)); 94: if (lastbp) 95: lastbp->b_next = b; 96: else 97: world = b; 98: b->b_first = 0; 99: b->b_next = 0; 100: #ifdef MAC 101: b->Type = BUFFER; /* kludge, but simplifies menu handlers */ 102: b->Name = 0; 103: #endif 104: return b; 105: } 106: 107: /* Makes a buffer and initializes it. Obsolete. Used to take two 108: arguments, a buffer name and a file name. */ 109: 110: static Buffer * 111: mak_buf() 112: { 113: register Buffer *newb; 114: register int i; 115: 116: newb = buf_alloc(); 117: newb->b_fname = 0; 118: newb->b_name = NoName; 119: set_ino(newb); 120: newb->b_marks = 0; 121: newb->b_themark = 0; /* Index into markring */ 122: /* No marks yet */ 123: for (i = 0; i < NMARKS; i++) 124: newb->b_markring[i] = 0; 125: newb->b_modified = 0; 126: newb->b_type = B_FILE; /* File until proven SCRATCH */ 127: newb->b_ntbf = 0; 128: newb->b_minor = 0; 129: newb->b_major = TEXT; 130: newb->b_first = 0; 131: newb->b_keybinds = 0; 132: #ifdef IPROCS 133: newb->b_process = 0; 134: #endif 135: initlist(newb); 136: #ifdef MAC 137: Bufchange = 1; 138: #endif 139: return newb; 140: } 141: 142: void 143: ReNamBuf() 144: { 145: register char *new = 0, 146: *prompt = ProcFmt, 147: *second = "%s already exists; new name? "; 148: 149: for (;;) { 150: new = ask((char *) 0, prompt, new); 151: if (!buf_exists(new)) 152: break; 153: prompt = second; 154: } 155: setbname(curbuf, new); 156: } 157: 158: void 159: FindFile() 160: { 161: register char *name; 162: char fnamebuf[FILESIZE]; 163: 164: name = ask_file((char *) 0, curbuf->b_fname, fnamebuf); 165: SetABuf(curbuf); 166: SetBuf(do_find(curwind, name, 0)); 167: } 168: 169: private void 170: mkbuflist(bnamp) 171: register char **bnamp; 172: { 173: register Buffer *b; 174: 175: for (b = world; b != 0; b = b->b_next) 176: if (b->b_name != 0) 177: *bnamp++ = b->b_name; 178: *bnamp = 0; 179: } 180: 181: char * 182: ask_buf(def) 183: Buffer *def; 184: { 185: char *bnames[100]; 186: register char *bname; 187: register int offset; 188: char prompt[100]; 189: 190: if (def != 0 && def->b_name != 0) 191: sprintf(prompt, ": %f (default %s) ", def->b_name); 192: else 193: sprintf(prompt, ProcFmt); 194: mkbuflist(bnames); 195: offset = complete(bnames, prompt, RET_STATE); 196: if (offset == EOF) 197: complain((char *) 0); 198: if (offset == ORIGINAL || offset == AMBIGUOUS) 199: bname = Minibuf; 200: else if (offset == NULLSTRING) { 201: if (def) 202: bname = def->b_name; 203: else 204: complain((char *) 0); 205: } else if (offset < 0) 206: complain((char *) 0); 207: else 208: bname = bnames[offset]; 209: 210: return bname; 211: } 212: 213: void 214: BufSelect() 215: { 216: register char *bname; 217: 218: bname = ask_buf(lastbuf); 219: SetABuf(curbuf); 220: SetBuf(do_select(curwind, bname)); 221: } 222: 223: #ifdef MSDOS 224: 225: private void 226: BufNSelect(n) 227: { 228: char *bnames[100]; 229: char *bname; 230: int i; 231: 232: mkbuflist(bnames); 233: for (i=0; i<n; i++) 234: if (bnames[i] == 0) 235: complain("[No such buffer]"); 236: bname = bnames[n-1]; 237: SetABuf(curbuf); 238: SetBuf(do_select(curwind, bname)); 239: } 240: 241: void Buf1Select() { BufNSelect(1); } 242: void Buf2Select() { BufNSelect(2); } 243: void Buf3Select() { BufNSelect(3); } 244: void Buf4Select() { BufNSelect(4); } 245: void Buf5Select() { BufNSelect(5); } 246: void Buf6Select() { BufNSelect(6); } 247: void Buf7Select() { BufNSelect(7); } 248: void Buf8Select() { BufNSelect(8); } 249: void Buf9Select() { BufNSelect(9); } 250: void Buf10Select() { BufNSelect(10); } 251: 252: #endif /* MSDOS */ 253: 254: private void 255: defb_wind(b) 256: register Buffer *b; 257: { 258: register Window *w = fwind; 259: char *alt; 260: 261: if (lastbuf == b || lastbuf == 0) { 262: lastbuf = 0; 263: alt = (b->b_next != 0) ? b->b_next->b_name : Mainbuf; 264: } else 265: alt = lastbuf->b_name; 266: 267: do { 268: if (w->w_bufp == b) { 269: if (one_windp() || alt != Mainbuf) 270: (void) do_select(w, alt); 271: else { 272: Window *save = w->w_next; 273: del_wind(w); 274: w = save->w_prev; 275: } 276: } 277: w = w->w_next; 278: } while (w != fwind || w->w_bufp == b); 279: } 280: 281: Buffer * 282: getNMbuf() 283: { 284: register Buffer *delbuf; 285: register char *bname; 286: 287: bname = ask_buf(curbuf); 288: if ((delbuf = buf_exists(bname)) == 0) 289: complain("[No such buffer]"); 290: if (delbuf->b_modified) 291: confirm("%s modified, are you sure? ", bname); 292: return delbuf; 293: } 294: 295: void 296: BufErase() 297: { 298: register Buffer *delbuf; 299: 300: if (delbuf = getNMbuf()) { 301: initlist(delbuf); 302: delbuf->b_modified = 0; 303: } 304: } 305: 306: private void 307: kill_buf(delbuf) 308: register Buffer *delbuf; 309: { 310: register Buffer *b, 311: *lastb = 0; 312: #ifndef MAC 313: extern Buffer *perr_buf; 314: #endif 315: 316: #ifdef IPROCS 317: pbuftiedp(delbuf); /* check for lingering processes */ 318: #endif 319: for (b = world; b != 0; lastb = b, b = b->b_next) 320: if (b == delbuf) 321: break; 322: if (lastb) 323: lastb->b_next = delbuf->b_next; 324: else 325: world = delbuf->b_next; 326: 327: #define okay_free(ptr) if (ptr) free(ptr) 328: 329: lfreelist(delbuf->b_first); 330: okay_free(delbuf->b_name); 331: okay_free(delbuf->b_fname); 332: flush_marks(delbuf); 333: free((char *) delbuf); 334: 335: if (delbuf == lastbuf) 336: SetABuf(curbuf); 337: #ifndef MAC 338: if (perr_buf == delbuf) { 339: ErrFree(); 340: perr_buf = 0; 341: } 342: #endif 343: defb_wind(delbuf); 344: if (curbuf == delbuf) 345: SetBuf(curwind->w_bufp); 346: #ifdef MAC 347: Bufchange = 1; 348: #endif 349: } 350: 351: /* offer to kill some buffers */ 352: 353: void 354: KillSome() 355: { 356: register Buffer *b, 357: *next; 358: Buffer *oldb; 359: register char *y_or_n; 360: 361: for (b = world; b != 0; b = next) { 362: next = b->b_next; 363: if (yes_or_no_p("Kill %s? ", b->b_name) == NO) 364: continue; 365: if (IsModified(b)) { 366: y_or_n = ask("No", "%s modified; should I save it? ", b->b_name); 367: if (CharUpcase(*y_or_n) == 'Y') { 368: oldb = curbuf; 369: SetBuf(b); 370: SaveFile(); 371: SetBuf(oldb); 372: } 373: } 374: kill_buf(b); 375: } 376: } 377: 378: void 379: BufKill() 380: { 381: Buffer *b; 382: 383: if ((b = getNMbuf()) == 0) 384: return; 385: kill_buf(b); 386: } 387: 388: private char * 389: line_cnt(b, buf) 390: register Buffer *b; 391: char *buf; 392: { 393: register int nlines = 0; 394: register Line *lp; 395: 396: for (lp = b->b_first; lp != 0; lp = lp->l_next, nlines++) 397: ; 398: sprintf(buf, "%d", nlines); 399: return buf; 400: } 401: 402: private char *TypeNames[] = { 403: 0, 404: "Scratch", 405: "File", 406: "Process", 407: }; 408: 409: void 410: BufList() 411: { 412: register char *format = "%-2s %-5s %-11s %-1s %-*s %-s"; 413: register Buffer *b; 414: int bcount = 1, /* To give each buffer a number */ 415: buf_width = 11; 416: char nbuf[10]; 417: 418: for (b = world; b != 0; b = b->b_next) 419: buf_width = max(buf_width, strlen(b->b_name)); 420: 421: TOstart("Buffer list", TRUE); /* true means auto-newline */ 422: 423: Typeout("(* means buffer needs saving)"); 424: Typeout("(+ means file hasn't been read yet)"); 425: Typeout(NullStr); 426: Typeout(format, "NO", "Lines", "Type", NullStr, buf_width, "Name", "File"); 427: Typeout(format, "--", "-----", "----", NullStr, buf_width, "----", "----"); 428: for (b = world; b != 0; b = b->b_next) { 429: Typeout(format, itoa(bcount++), 430: line_cnt(b, nbuf), 431: TypeNames[b->b_type], 432: IsModified(b) ? "*" : 433: b->b_ntbf ? "+" : NullStr, 434: buf_width, 435: /* For the * (variable length field) */ 436: b->b_name, 437: filename(b)); 438: 439: if (TOabort) 440: break; 441: } 442: TOstop(); 443: } 444: 445: void 446: bufname(b) 447: register Buffer *b; 448: { 449: char tmp[100], 450: *cp; 451: int try = 1; 452: 453: if (b->b_fname == 0) 454: complain("[No file name]"); 455: cp = basename(b->b_fname); 456: strcpy(tmp, cp); 457: while (buf_exists(tmp)) { 458: sprintf(tmp, "%s.%d", cp, try); 459: try += 1; 460: } 461: setbname(b, tmp); 462: } 463: 464: void 465: initlist(b) 466: register Buffer *b; 467: { 468: lfreelist(b->b_first); 469: b->b_first = b->b_dot = b->b_last = 0; 470: (void) listput(b, b->b_first); 471: 472: SavLine(b->b_dot, NullStr); 473: b->b_char = 0; 474: AllMarkSet(b, b->b_dot, 0); 475: if (b == curbuf) 476: getDOT(); 477: } 478: 479: /* Returns pointer to buffer with name NAME, or if NAME is a string of digits 480: returns the buffer whose number equals those digits. Otherwise, returns 481: 0. */ 482: 483: Buffer * 484: buf_exists(name) 485: register char *name; 486: { 487: register Buffer *bp; 488: int n; 489: 490: if (name == 0) 491: return 0; 492: 493: for (bp = world; bp != 0; bp = bp->b_next) 494: if (strcmp(bp->b_name, name) == 0) 495: return bp; 496: 497: /* Doesn't match any names. Try for a buffer number... */ 498: 499: if (chr_to_int(name, 10, YES, &n) != INT_BAD) { 500: for (bp = world; n > 1; bp = bp->b_next) { 501: if (bp == 0) 502: break; 503: n -= 1; 504: } 505: return bp; 506: } 507: 508: return 0; 509: } 510: 511: /* Returns buffer pointer with a file name NAME, if one exists. Stat's the 512: file and compares inodes, in case NAME is a link, as well as the actual 513: characters that make up the file name. */ 514: 515: Buffer * 516: file_exists(name) 517: register char *name; 518: { 519: struct stat stbuf; 520: register struct stat *s = &stbuf; 521: register Buffer *b = 0; 522: char fnamebuf[FILESIZE]; 523: 524: #ifdef MSDOS 525: strlwr(name); 526: #endif /* MSDOS */ 527: if (name) { 528: PathParse(name, fnamebuf); 529: if (stat(fnamebuf, s) == -1) 530: s->st_ino = 0; 531: for (b = world; b != 0; b = b->b_next) { 532: if ( 533: #ifndef MSDOS 534: (b->b_ino != 0 && b->b_ino == s->st_ino && 535: b->b_dev != 0 && b->b_dev == s->st_dev) || 536: #endif /* MSDOS */ 537: (strcmp(b->b_fname, fnamebuf) == 0)) 538: break; 539: } 540: } 541: return b; 542: } 543: 544: char * 545: ralloc(obj, size) 546: register char *obj; 547: { 548: register char *new; 549: 550: if (obj) 551: new = realloc(obj, (unsigned) size); 552: if (new == 0 || !obj) 553: new = emalloc(size); 554: return new; 555: } 556: 557: void 558: setbname(b, name) 559: register Buffer *b; 560: register char *name; 561: { 562: UpdModLine = YES; /* Kludge ... but speeds things up considerably */ 563: if (name) { 564: if (b->b_name == NoName) 565: b->b_name = 0; 566: b->b_name = ralloc(b->b_name, strlen(name) + 1); 567: strcpy(b->b_name, name); 568: } else 569: b->b_name = 0; 570: #ifdef MAC 571: Bufchange = 1; 572: #endif 573: } 574: 575: void 576: setfname(b, name) 577: register Buffer *b; 578: register char *name; 579: { 580: char wholename[FILESIZE], 581: oldname[FILESIZE], 582: *oldptr = oldname; 583: Buffer *save = curbuf; 584: 585: SetBuf(b); 586: UpdModLine = YES; /* Kludge ... but speeds things up considerably */ 587: if (b->b_fname == 0) 588: oldptr = 0; 589: else 590: strcpy(oldname, b->b_fname); 591: if (name) { 592: #ifdef MSDOS 593: strlwr(name); 594: #endif /* MSDOS */ 595: PathParse(name, wholename); 596: curbuf->b_fname = ralloc(curbuf->b_fname, strlen(wholename) + 1); 597: strcpy(curbuf->b_fname, wholename); 598: } else 599: b->b_fname = 0; 600: DoAutoExec(curbuf->b_fname, oldptr); 601: curbuf->b_mtime = curbuf->b_dev = curbuf->b_ino = 0; /* until they're known. */ 602: SetBuf(save); 603: #ifdef MAC 604: Bufchange = 1; 605: #endif 606: } 607: 608: void 609: set_ino(b) 610: register Buffer *b; 611: { 612: struct stat stbuf; 613: 614: if (b->b_fname == 0 || stat(pr_name(b->b_fname, NO), &stbuf) == -1) { 615: b->b_dev = 0; 616: b->b_ino = 0; 617: b->b_mtime = 0; 618: } else { 619: b->b_dev = stbuf.st_dev; 620: b->b_ino = stbuf.st_ino; 621: b->b_mtime = stbuf.st_mtime; 622: } 623: } 624: 625: /* Find the file `fname' into buf and put in in window `w' */ 626: 627: Buffer * 628: do_find(w, fname, force) 629: register Window *w; 630: register char *fname; 631: { 632: register Buffer *b; 633: 634: b = file_exists(fname); 635: if (b == 0) { 636: b = mak_buf(); 637: setfname(b, fname); 638: bufname(b); 639: set_ino(b); 640: b->b_ntbf = 1; 641: } 642: if (force) { 643: Buffer *oldb = curbuf; 644: 645: SetBuf(b); /* this'll read the file */ 646: SetBuf(oldb); 647: } 648: if (w) 649: tiewind(w, b); 650: return b; 651: } 652: 653: /* set alternate buffer */ 654: 655: void 656: SetABuf(b) 657: Buffer *b; 658: { 659: if (b != 0) 660: lastbuf = b; 661: } 662: 663: 664: /* check to see if BP is a valid buffer pointer */ 665: int 666: valid_bp(bp) 667: register Buffer *bp; 668: { 669: register Buffer *b; 670: 671: for (b = world; b != 0; b = b->b_next) 672: if (b == bp) 673: break; 674: return b != 0; 675: } 676: 677: void 678: SetBuf(newbuf) 679: register Buffer *newbuf; 680: { 681: register Buffer *oldb = curbuf, 682: *b; 683: 684: if (newbuf == curbuf || newbuf == 0) 685: return; 686: 687: if (!valid_bp(newbuf)) 688: complain("Internal error: (0x%x) is not a valid buffer pointer!", newbuf); 689: lsave(); 690: curbuf = newbuf; 691: curline = newbuf->b_dot; 692: curchar = newbuf->b_char; 693: getDOT(); 694: /* do the read now ... */ 695: if (curbuf->b_ntbf) 696: read_file(curbuf->b_fname, 0); 697: #ifdef MAC 698: Modechange = 1; 699: #endif 700: 701: #ifdef IPROCS 702: if (oldb != 0 && ((oldb->b_process == 0) != (curbuf->b_process == 0))) { 703: if (curbuf->b_process) 704: PushPBs(); /* Push process bindings */ 705: else if (oldb->b_process) 706: PopPBs(); 707: } 708: #endif 709: } 710: 711: Buffer * 712: do_select(w, name) 713: register Window *w; 714: register char *name; 715: { 716: register Buffer *new; 717: 718: if ((new = buf_exists(name)) == 0) { 719: new = mak_buf(); 720: setfname(new, (char *) 0); 721: setbname(new, name); 722: } 723: if (w) 724: tiewind(w, new); 725: return new; 726: }