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