home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / jove / part03 / insert.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-02-02  |  13.3 KB  |  688 lines

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