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