home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / Editors / mjovesrc.zoo / insert.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  16KB  |  824 lines

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