|
|
1.1 ! root 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: #include "jove.h" ! 11: ! 12: #include "ctype.h" ! 13: ! 14: /* Make a newline after AFTER in buffer BUF, UNLESS after is 0, ! 15: in which case we insert the newline before after. */ ! 16: ! 17: Line * ! 18: listput(buf, after) ! 19: register Buffer *buf; ! 20: register Line *after; ! 21: { ! 22: register Line *newline = nbufline(); ! 23: ! 24: if (after == 0) { /* Before the first line */ ! 25: newline->l_next = buf->b_first; ! 26: newline->l_prev = 0; ! 27: buf->b_first = newline; ! 28: } else { ! 29: newline->l_prev = after; ! 30: newline->l_next = after->l_next; ! 31: after->l_next = newline; ! 32: } ! 33: if (newline->l_next) ! 34: newline->l_next->l_prev = newline; ! 35: else ! 36: if (buf) ! 37: buf->b_last = newline; ! 38: if (buf && buf->b_dot == 0) ! 39: buf->b_dot = newline; ! 40: return newline; ! 41: } ! 42: ! 43: /* Divide the current line and move the current line to the next one */ ! 44: ! 45: LineInsert() ! 46: { ! 47: register int num = exp; ! 48: char newline[LBSIZE]; ! 49: register Line *newdot, ! 50: *olddot; ! 51: int oldchar; ! 52: ! 53: exp = 1; ! 54: olddot = curline; ! 55: oldchar = curchar; ! 56: ! 57: newdot = curline; ! 58: while (--num >= 0) { ! 59: newdot = listput(curbuf, newdot); ! 60: SavLine(newdot, NullStr); ! 61: } ! 62: ! 63: modify(); ! 64: if (curchar != 0) { ! 65: strcpy(newline, &linebuf[curchar]); ! 66: linebuf[curchar] = '\0'; /* Shorten this line */ ! 67: SavLine(curline, linebuf); ! 68: strcpy(linebuf, newline); ! 69: } else { /* Redisplay optimization */ ! 70: newdot->l_dline = curline->l_dline; ! 71: SavLine(curline, NullStr); ! 72: } ! 73: ! 74: makedirty(curline); ! 75: curline = newdot; ! 76: curchar = 0; ! 77: makedirty(curline); ! 78: IFixMarks(olddot, oldchar, curline, curchar); ! 79: } ! 80: ! 81: n_indent(goal) ! 82: register int goal; ! 83: { ! 84: if (goal < 0) ! 85: return; ! 86: DoTimes(Insert('\t'), (goal / tabstop)); ! 87: if (goal % tabstop) ! 88: DoTimes(Insert(' '), (goal % tabstop)); ! 89: exp_p = 0; ! 90: exp = 1; ! 91: } ! 92: ! 93: SelfInsert() ! 94: { ! 95: #ifdef ABBREV ! 96: if (MinorMode(Abbrev) && !ismword(LastKeyStruck) && ! 97: !bolp() && ismword(linebuf[curchar - 1])) ! 98: AbbrevExpand(); ! 99: #endif ! 100: if (MinorMode(OverWrite)) { ! 101: register int num, ! 102: i; ! 103: ! 104: for (i = 0, num = exp, exp = 1; i < num; i++) { ! 105: int pos = calc_pos(linebuf, curchar); ! 106: ! 107: if (!eolp()) { ! 108: if (linebuf[curchar] == '\t') { ! 109: if ((pos + 1) == ((pos + tabstop) - (pos % tabstop))) ! 110: DelNChar(); ! 111: } else ! 112: DelNChar(); ! 113: } ! 114: Insert(LastKeyStruck); ! 115: } ! 116: } else ! 117: Insert(LastKeyStruck); ! 118: ! 119: if (MinorMode(Fill) && (curchar >= RMargin || ! 120: (calc_pos(linebuf, curchar) >= RMargin))) ! 121: DoJustify(curline, 0, curline, ! 122: curchar + strlen(&linebuf[curchar]), 1, LMargin); ! 123: } ! 124: ! 125: Insert(c) ! 126: { ! 127: if (exp <= 0) ! 128: return; ! 129: modify(); ! 130: makedirty(curline); ! 131: ins_c(c, linebuf, curchar, exp, LBSIZE); ! 132: IFixMarks(curline, curchar, curline, curchar + exp); ! 133: curchar += exp; ! 134: } ! 135: ! 136: /* Tab in to the right place for C mode */ ! 137: ! 138: Tab() ! 139: { ! 140: #ifdef LISP ! 141: if (MajorMode(LISPMODE)) { ! 142: Mark *m = bolp() ? 0 : MakeMark(curline, curchar, FLOATER); ! 143: ! 144: Bol(); ! 145: DelWtSpace(); ! 146: (void) lisp_indent(); ! 147: if (m) { ! 148: ToMark(m); ! 149: DelMark(m); ! 150: } ! 151: if (bolp()) ! 152: ToIndent(); ! 153: return; ! 154: } ! 155: #endif ! 156: if (MajorMode(CMODE) && strlen(linebuf) == 0) ! 157: (void) c_indent(CIndIncrmt); ! 158: else ! 159: SelfInsert(); ! 160: } ! 161: ! 162: QuotChar() ! 163: { ! 164: int c; ! 165: extern int alarmed; /* If waitfor had to wait. */ ! 166: ! 167: c = waitchar(); ! 168: if (alarmed) ! 169: message(key_strokes); ! 170: if (c == CTL(J)) ! 171: LineInsert(); ! 172: else if (c != CTL(@)) ! 173: Insert(c); ! 174: } ! 175: ! 176: /* Insert the paren. If in C mode and c is a '}' then insert the ! 177: '}' in the "right" place for C indentation; that is indented ! 178: the same amount as the matching '{' is indented. */ ! 179: ! 180: int PDelay = 5, /* 1/2 a second */ ! 181: CIndIncrmt = 8; ! 182: ! 183: DoParen() ! 184: { ! 185: Bufpos *bp = (Bufpos *) -1; ! 186: int nx, ! 187: c = LastKeyStruck; ! 188: ! 189: if (!isclosep(c)) { ! 190: SelfInsert(); ! 191: return; ! 192: } ! 193: ! 194: if (MajorMode(CMODE) && c == '}' && blnkp(linebuf)) { ! 195: DelWtSpace(); ! 196: bp = c_indent(0); ! 197: } ! 198: #ifdef LISP ! 199: if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf)) { ! 200: DelWtSpace(); ! 201: bp = lisp_indent(); ! 202: } ! 203: #endif ! 204: SelfInsert(); ! 205: if (MinorMode(ShowMatch) && !charp() && !in_macro()) { ! 206: BackChar(); /* Back onto the ')' */ ! 207: if ((int) bp == -1) ! 208: bp = m_paren(c, BACKWARD, NO, YES); ! 209: ForChar(); ! 210: if (bp != 0) { ! 211: nx = in_window(curwind, bp->p_line); ! 212: if (nx != -1) { /* is visible */ ! 213: Bufpos b; ! 214: ! 215: DOTsave(&b); ! 216: SetDot(bp); ! 217: (void) SitFor(PDelay); ! 218: SetDot(&b); ! 219: } else ! 220: s_mess("%s", lcontents(bp->p_line)); ! 221: } ! 222: mp_error(); /* display error message */ ! 223: } ! 224: } ! 225: ! 226: LineAI() ! 227: { ! 228: DoNewline(TRUE); ! 229: } ! 230: ! 231: Newline() ! 232: { ! 233: DoNewline(MinorMode(Indent)); ! 234: } ! 235: ! 236: DoNewline(indentp) ! 237: { ! 238: Bufpos save; ! 239: int indent; ! 240: ! 241: /* first we calculate the indent of the current line */ ! 242: DOTsave(&save); ! 243: ToIndent(); ! 244: indent = calc_pos(linebuf, curchar); ! 245: SetDot(&save); ! 246: ! 247: /* If there is more than 2 blank lines in a row then don't make ! 248: a newline, just move down one. */ ! 249: ! 250: #ifdef ABBREV ! 251: if (MinorMode(Abbrev) && !ismword(LastKeyStruck) && ! 252: !bolp() && ismword(linebuf[curchar - 1])) ! 253: AbbrevExpand(); ! 254: #endif ! 255: #ifdef LISP ! 256: if (MajorMode(LISPMODE)) ! 257: DelWtSpace(); ! 258: #endif ! 259: else if (blnkp(linebuf)) ! 260: DelWtSpace(); ! 261: ! 262: if (exp == 1 && eolp() && TwoBlank()) ! 263: SetLine(curline->l_next); ! 264: else ! 265: LineInsert(); ! 266: ! 267: if (indentp) ! 268: #ifdef LISP ! 269: if (MajorMode(LISPMODE)) ! 270: (void) lisp_indent(); ! 271: else ! 272: #endif ! 273: n_indent((LMargin == 0) ? indent : LMargin); ! 274: } ! 275: ! 276: ins_str(str, ok_nl) ! 277: register char *str; ! 278: { ! 279: register char c; ! 280: Bufpos save; ! 281: int llen; ! 282: ! 283: DOTsave(&save); ! 284: llen = strlen(linebuf); ! 285: while (c = *str++) { ! 286: if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) { ! 287: IFixMarks(save.p_line, save.p_char, curline, curchar); ! 288: modify(); ! 289: makedirty(curline); ! 290: LineInsert(); ! 291: DOTsave(&save); ! 292: llen = strlen(linebuf); ! 293: } ! 294: if (c != '\n') { ! 295: ins_c(c, linebuf, curchar++, 1, LBSIZE); ! 296: llen++; ! 297: } ! 298: } ! 299: IFixMarks(save.p_line, save.p_char, curline, curchar); ! 300: modify(); ! 301: makedirty(curline); ! 302: } ! 303: ! 304: OpenLine() ! 305: { ! 306: Bufpos dot; ! 307: ! 308: DOTsave(&dot); ! 309: LineInsert(); /* Open the lines... */ ! 310: SetDot(&dot); ! 311: } ! 312: ! 313: /* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at ! 314: ATLINE/ATCHAR in WHATBUF. */ ! 315: ! 316: Bufpos * ! 317: DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf) ! 318: Line *fline, ! 319: *tline, ! 320: *atline; ! 321: Buffer *whatbuf; ! 322: { ! 323: register Line *newline; ! 324: static Bufpos bp; ! 325: char save[LBSIZE], ! 326: buf[LBSIZE]; ! 327: Line *startline = atline; ! 328: int startchar = atchar; ! 329: ! 330: lsave(); ! 331: if (whatbuf) ! 332: modify(); ! 333: (void) ltobuf(atline, genbuf); ! 334: strcpy(save, &genbuf[atchar]); ! 335: ! 336: (void) ltobuf(fline, buf); ! 337: if (fline == tline) ! 338: buf[tchar] = '\0'; ! 339: ! 340: linecopy(genbuf, atchar, &buf[fchar]); ! 341: atline->l_dline = putline(genbuf); ! 342: makedirty(atline); ! 343: ! 344: fline = fline->l_next; ! 345: while (fline != tline->l_next) { ! 346: newline = listput(whatbuf, atline); ! 347: newline->l_dline = fline->l_dline; ! 348: makedirty(newline); ! 349: fline = fline->l_next; ! 350: atline = newline; ! 351: atchar = 0; ! 352: } ! 353: ! 354: (void) getline(atline->l_dline, genbuf); ! 355: atchar += tchar; ! 356: linecopy(genbuf, atchar, save); ! 357: atline->l_dline = putline(genbuf); ! 358: makedirty(atline); ! 359: IFixMarks(startline, startchar, atline, atchar); ! 360: bp.p_line = atline; ! 361: bp.p_char = atchar; ! 362: this_cmd = YANKCMD; ! 363: getDOT(); /* Whatever used to be in linebuf */ ! 364: return &bp; ! 365: } ! 366: ! 367: YankPop() ! 368: { ! 369: Line *line, ! 370: *last; ! 371: Mark *mp = CurMark(); ! 372: Bufpos *dot; ! 373: int dir = -1; /* Direction to rotate the ring */ ! 374: ! 375: if (last_cmd != YANKCMD) ! 376: complain("Yank something first!"); ! 377: ! 378: lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar)); ! 379: ! 380: /* Now must find a recently killed region. */ ! 381: ! 382: if (exp < 0) ! 383: dir = 1; ! 384: ! 385: killptr += dir; ! 386: for (;;) { ! 387: if (killptr < 0) ! 388: killptr = NUMKILLS - 1; ! 389: else if (killptr >= NUMKILLS) ! 390: killptr = 0; ! 391: if (killbuf[killptr]) ! 392: break; ! 393: killptr += dir; ! 394: } ! 395: ! 396: this_cmd = YANKCMD; ! 397: ! 398: line = killbuf[killptr]; ! 399: last = lastline(line); ! 400: dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf); ! 401: MarkSet(CurMark(), curline, curchar); ! 402: SetDot(dot); ! 403: } ! 404: ! 405: /* This is an attempt to reduce the amount of memory taken up by each line. ! 406: Without this each malloc of a line uses sizeof (line) + sizeof(HEADER) ! 407: where line is 3 words and HEADER is 1 word. ! 408: This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line) ! 409: and divide each chuck into lineS. A line is free in a chunk when its ! 410: line->l_dline == 0, so freeline sets dline to 0. */ ! 411: ! 412: #define CHUNKSIZE 300 ! 413: ! 414: struct chunk { ! 415: int c_nlines; /* Number of lines in this chunk (so they ! 416: don't all have to be CHUNKSIZE long). */ ! 417: Line *c_block; /* Chunk of memory */ ! 418: struct chunk *c_nextfree; /* Next chunk of lines */ ! 419: }; ! 420: ! 421: static struct chunk *fchunk = 0; ! 422: static Line *ffline = 0; /* First free line */ ! 423: ! 424: freeline(line) ! 425: register Line *line; ! 426: { ! 427: line->l_dline = 0; ! 428: line->l_next = ffline; ! 429: if (ffline) ! 430: ffline->l_prev = line; ! 431: line->l_prev = 0; ! 432: ffline = line; ! 433: } ! 434: ! 435: lfreelist(first) ! 436: register Line *first; ! 437: { ! 438: if (first) ! 439: lfreereg(first, lastline(first)); ! 440: } ! 441: ! 442: /* Append region from line1 to line2 onto the free list of lines */ ! 443: ! 444: lfreereg(line1, line2) ! 445: register Line *line1, ! 446: *line2; ! 447: { ! 448: register Line *next, ! 449: *last = line2->l_next; ! 450: ! 451: while (line1 != last) { ! 452: next = line1->l_next; ! 453: freeline(line1); ! 454: line1 = next; ! 455: } ! 456: } ! 457: ! 458: static ! 459: newchunk() ! 460: { ! 461: register Line *newline; ! 462: register int i; ! 463: struct chunk *f; ! 464: int nlines = CHUNKSIZE; ! 465: ! 466: f = (struct chunk *) emalloc(sizeof (struct chunk)); ! 467: if (f == 0) ! 468: return 0; ! 469: ! 470: if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) { ! 471: while (nlines > 0) { ! 472: f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines)); ! 473: if (f->c_block != 0) ! 474: break; ! 475: nlines /= 2; ! 476: } ! 477: } ! 478: ! 479: if (nlines <= 0) ! 480: return 0; ! 481: ! 482: f->c_nlines = nlines; ! 483: for (i = 0, newline = f->c_block; i < nlines; newline++, i++) ! 484: freeline(newline); ! 485: f->c_nextfree = fchunk; ! 486: fchunk = f; ! 487: return 1; ! 488: } ! 489: ! 490: /* New BUFfer LINE */ ! 491: ! 492: Line * ! 493: nbufline() ! 494: { ! 495: register Line *newline; ! 496: ! 497: if (ffline == 0) /* No free list */ ! 498: if (newchunk() == 0) ! 499: complain("[Out of lines] "); ! 500: newline = ffline; ! 501: ffline = ffline->l_next; ! 502: if (ffline) ! 503: ffline->l_prev = 0; ! 504: return newline; ! 505: } ! 506: ! 507: /* Remove the free lines, in chunk c, from the free list because they are ! 508: no longer free. */ ! 509: ! 510: static ! 511: remfreelines(c) ! 512: register struct chunk *c; ! 513: { ! 514: register Line *lp; ! 515: register int i; ! 516: ! 517: for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) { ! 518: if (lp->l_prev) ! 519: lp->l_prev->l_next = lp->l_next; ! 520: else ! 521: ffline = lp->l_next; ! 522: if (lp->l_next) ! 523: lp->l_next->l_prev = lp->l_prev; ! 524: } ! 525: } ! 526: ! 527: /* This is used to garbage collect the chunks of lines when malloc fails ! 528: and we are NOT looking for a new buffer line. This goes through each ! 529: chunk, and if every line in a given chunk is not allocated, the entire ! 530: chunk is `free'd by "free()". */ ! 531: ! 532: GCchunks() ! 533: { ! 534: register struct chunk *cp; ! 535: struct chunk *prev = 0, ! 536: *next = 0; ! 537: register int i; ! 538: register Line *newline; ! 539: ! 540: for (cp = fchunk; cp != 0; cp = next) { ! 541: for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++) ! 542: if (newline->l_dline != 0) ! 543: break; ! 544: ! 545: next = cp->c_nextfree; ! 546: ! 547: if (i == cp->c_nlines) { /* Unlink it!!! */ ! 548: if (prev) ! 549: prev->c_nextfree = cp->c_nextfree; ! 550: else ! 551: fchunk = cp->c_nextfree; ! 552: remfreelines(cp); ! 553: free((char *) cp->c_block); ! 554: free((char *) cp); ! 555: } else ! 556: prev = cp; ! 557: } ! 558: } ! 559: ! 560: #ifdef LISP ! 561: ! 562: /* Grind S-Expr */ ! 563: ! 564: GSexpr() ! 565: { ! 566: Bufpos dot, ! 567: end; ! 568: ! 569: if (linebuf[curchar] != '(') ! 570: complain((char *) 0); ! 571: DOTsave(&dot); ! 572: FSexpr(); ! 573: DOTsave(&end); ! 574: exp = 1; ! 575: SetDot(&dot); ! 576: for (;;) { ! 577: if (curline == end.p_line) ! 578: break; ! 579: line_move(FORWARD, NO); ! 580: if (!blnkp(linebuf)) { ! 581: DelWtSpace(); ! 582: (void) lisp_indent(); ! 583: } ! 584: } ! 585: SetDot(&dot); ! 586: } ! 587: ! 588: /* lisp_indent() indents a new line in Lisp Mode, according to where ! 589: the matching close-paren would go if we typed that (sort of). */ ! 590: ! 591: Bufpos * ! 592: lisp_indent() ! 593: { ! 594: Bufpos *bp, ! 595: savedot; ! 596: int goal; ! 597: ! 598: bp = m_paren(')', BACKWARD, NO, YES); ! 599: ! 600: if (bp == 0) ! 601: return 0; ! 602: ! 603: /* ! 604: * Otherwise, we indent to the first argument of ! 605: * the current s-expression. This is done by ! 606: * starting at the matching paren, skipping ! 607: * to a word (atom), skipping over it, and ! 608: * skipping to the next one. ! 609: * ! 610: * We want to end up ! 611: * ! 612: * (atom atom atom ... ! 613: * ^ here. ! 614: */ ! 615: ! 616: DOTsave(&savedot); ! 617: SetDot(bp); ! 618: DoTimes(ForChar(), 1); ! 619: if (linebuf[curchar] != '(') { ! 620: static char *specials[] = { ! 621: "def", ! 622: "let", ! 623: "lambda", ! 624: "fluid-let", ! 625: "macro", ! 626: "lexpr", ! 627: "nlambda", ! 628: "dolist", ! 629: "caseq", ! 630: "selectq", ! 631: "while", ! 632: "prog", ! 633: 0 ! 634: }; ! 635: int i = 0; ! 636: ! 637: while (specials[i]) { ! 638: char *cp1 = specials[i], ! 639: *cp2 = &linebuf[curchar]; ! 640: int n = strlen(cp1); ! 641: ! 642: while (--n >= 0) ! 643: if (Upper(*cp1++) != Upper(*cp2++)) ! 644: break; ! 645: if (n < 0) ! 646: break; /* Matched. */ ! 647: i++; ! 648: } ! 649: if (specials[i] == 0) { ! 650: if (index(&linebuf[curchar], ' ') != 0) { ! 651: WITH_TABLE(curbuf->b_major) ! 652: ForWord(); ! 653: END_TABLE(); ! 654: while (linebuf[curchar] == ' ') ! 655: curchar++; ! 656: } ! 657: } else ! 658: curchar++; ! 659: } ! 660: goal = calc_pos(linebuf, curchar); ! 661: SetDot(&savedot); ! 662: n_indent(goal); ! 663: ! 664: return bp; ! 665: } ! 666: #endif LISP
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.