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

Defined functions

DoNewline defined in line 236; used 2 times
DoParen defined in line 183; used 2 times
DoYank defined in line 316; used 7 times
GCchunks defined in line 532; used 1 times
GSexpr defined in line 564; used 2 times
LineAI defined in line 226; used 2 times
Newline defined in line 231; used 2 times
OpenLine defined in line 304; used 3 times
QuotChar defined in line 162; used 2 times
SelfInsert defined in line 93; used 6 times
Tab defined in line 138; used 2 times
YankPop defined in line 367; used 2 times
freeline defined in line 424; used 2 times
lfreelist defined in line 435; used 5 times
lfreereg defined in line 444; used 2 times
lisp_indent defined in line 591; used 5 times
listput defined in line 17; used 5 times
n_indent defined in line 81; used 9 times
nbufline defined in line 492; used 4 times
newchunk defined in line 458; used 1 times
remfreelines defined in line 510; used 1 times

Defined variables

PDelay defined in line 180; used 2 times
fchunk defined in line 421; used 4 times
ffline defined in line 422; used 11 times

Defined struct's

chunk defined in line 414; used 16 times

Defined macros

CHUNKSIZE defined in line 412; used 1 times
Last modified: 1986-04-02
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2348
Valid CSS Valid XHTML 1.0 Strict