# 2.11BSD#431 - /usr/src/new/jove/paragraph.c

##### Functions

    BackPara          X
    DoJustify         X
    DoPara            X
    ForPara           X
    Justify           X
    RegJustify        X
    do_rfill          X
    do_space          X
    find_para         X
    get_indent        X
    i_blank           X
    i_bsblank         X
    max_line          X
    min_line          X
    tailrule          X

##### Variables

    RMargin           X
    body_indent       X
    head_indent       X

##### Macros

    I_BUFEDGE         X
    I_EMPTY           X
    I_PERIOD          X
    private           X

       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:
      10: #ifdef MAC
      11: #	undef private
      12: #	define private
      13: #endif
      14:
      15: #ifdef  LINT_ARGS
      16: private int get_indent(Line *);
      17: private Line    * tailrule(Line *);
      18: #else
      19: private int get_indent();
      20: private Line    * tailrule();
      21: #endif
      22:
      23: #ifdef MAC
      24: #	undef private
      25: #	define private static
      26: #endif
      27:
      28: /* Thanks to Brian Harvey for this paragraph boundery finding algorithm.
      29:    It's really quite hairy figuring it out.  This deals with paragraphs that
      30:    are seperated by blank lines, lines beginning with a Period (assumed to
      31:    be an nroff command), lines beginning with BackSlash (assumed to be Tex
      32:    commands).  Also handles paragraphs that are separated by lines of
      33:    different indent; and it deals with outdented paragraphs, too.  It's
      34:    really quite nice.  Here's Brian's algorithm.
      35:
      36:    Definitions:
      37:
      38:    THIS means the line containing the cursor.
      39:    PREV means the line above THIS.
      40:    NEXT means the line below THIS.
      41:
      42:    BLANK means empty, empty except for spaces and tabs, starts with a period
      43:    or a backslash, or nonexistent (because the edge of the buffer is
      44:    reached).  ((BH 12/24/85 A line starting with backslash is blank only if
      45:    the following line also starts with backslash.  This is so that \noindent
      46:    is part of a paragraph, but long strings of TeX commands don't get
      47:    rearranged.  It still isn't perfect but it's better.))
      48:
      49:    BSBLANK means BLANK or starts with a backslash.  (BH 12/24/85)
      50:
      51:    HEAD means the first (nonblank) line of the paragraph containing THIS.
      52:    BODY means all other (nonblank) lines of the paragraph.
      53:    TAIL means the last (nb) line of the paragraph.  (TAIL is part of BODY.)
      54:
      55:    HEAD INDENT means the indentation of HEAD.  M-J should preserve this.
      56:    BODY INDENT means the indentation of BODY.  Ditto.
      57:
      58:    Subprocedures:
      59:
      60:    TAILRULE(BODYLINE)
      61:    If BODYLINE is BLANK, the paragraph has only one line, and there is no
      62:    BODY and therefore no TAIL.  Return.  Otherwise, starting from BODYLINE,
      63:    move down until you find a line that either is BSBLANK or has a different
      64:    indentation from BODYLINE.  The line above that different line is TAIL.
      65:    Return.
      66:
      67:    Rules:
      68:
      69:    1.  If THIS is BLANK, which command are you doing?  If M-J or M-[, then go
      70:    up to the first non-BLANK line and start over.  (If there is no non-BLANK
      71:    line before THIS, ring the bell.)  If M-], then the first non-BLANK line
      72:    below THIS is HEAD, and the second consecutive non-BSBLANK line (if any) is
      73:    the beginning of BODY.  (If there is no non-BLANK line after THIS, ring
      74:    the bell.)  Do TAILRULE(beginning-of-BODY).  Go to rule A.
      75:
      76:    2.  If PREV is BLANK or THIS is BSBLANK, then THIS is HEAD, and NEXT (if
      77:    not BSBLANK) is in BODY.  Do TAILRULE(NEXT).  Go to rule A.
      78:
      79:    3.  If NEXT is BSBLANK, then THIS is TAIL, therefore part of BODY.  Go to
      80:    rule 5 to find HEAD.
      81:
      82:    4.  If either NEXT or PREV has the same indentation as THIS, then THIS is
      83:    part of BODY.  Do TAILRULE(THIS).  Go to rule 5 to find HEAD.  Otherwise,
      84:    go to rule 6.
      85:
      86:    5.  Go up until you find a line that is either BSBLANK or has a different
      87:    indentation from THIS.  If that line is BLANK, the line below it is HEAD.
      88:    If that line is non-BLANK, then call that new line THIS for what follows.
      89:    If (the new) PREV has the same indent as THIS, then (the new) NEXT is
      90:    HEAD.  If PREV has a different indent from THIS, then THIS is HEAD.  Go to
      91:    rule A.
      92:
      93:    6.  If you got here, then both NEXT and PREV are nonblank and are
      94:    differently indented from THIS.  This is a tricky case and there is no
      95:    guarantee that you're going to win.  The most straightforward thing to do
      96:    is assume that we are not using hanging indentation.  In that case:
      97:    whichever of PREV and THIS is indented further is HEAD.  Do
      98:    TAILRULE(HEAD+1).  Go to rule A.
      99:
     100:    6+.  A more complicated variant would be this: if THIS is indented further
     101:    than PREV, we are using regular indentation and rule 6 applies.  If PREV
     102:    is indented further than THIS, look at both NEXT and the line after NEXT.
     103:    If those two lines are indented equally, and more than THIS, then we are
     104:    using hanging indent, THIS is HEAD, and NEXT is the first line of BODY.
     105:    Do TAILRULE(NEXT).  Otherwise, rule 6 applies.
     106:
     107:    A.  You now know where HEAD and TAIL are.  The indentation of HEAD is HEAD
     108:    INDENT; the indentation of TAIL is BODY INDENT.
     109:
     110:    B.  If you are trying to M-J, you are now ready to do it.
     111:
     112:    C.  If you are trying to M-], leave point after the newline that ends
     113:    TAIL.  In other words, leave the cursor at the beginning of the line
     114:    after TAIL.  It is not possible for this to leave point where it started
     115:    unless it was already at the end of the buffer.
     116:
     117:    D.  If you are trying to M-[, if the line before HEAD is not BLANK, then
     118:    leave point just before HEAD.  That is, leave the cursor at the beginning
     119:    of HEAD.  If the line before HEAD is BLANK, then leave the cursor at the
     120:    beginning of that line.  If the cursor didn't move, go up to the first
     121:    earlier non-BLANK line and start over.
     122:
     123:
     124:    End of Algorithm.  I implemented rule 6+ because it seemed nicer.  */
     125:
     126: int RMargin = 78,
     127:     LMargin = 0;
     128: Line    *para_head,
     129:     *para_tail;
     130: int head_indent,
     131:     body_indent;
     132: static int  use_lmargin;
     133:
     134: /* some defines for paragraph boundery checking */
     135: #define I_EMPTY     -1  /* line "looks" empty (spaces and tabs) */
     136: #define I_PERIOD    -2  /* line begins with "." or "\" */
     137: #define I_BUFEDGE   -3  /* line is nonexistent (edge of buffer) */
     138:
     139: static int  bslash;     /* Nonzero if get_indent finds line starting
     140: 				   with backslash */
     141:
     142: int
     143: i_bsblank(lp)
     144: Line    *lp;
     145: {
     146:     if (i_blank(lp))
     147:         return 1;
     148:     return bslash;
     149: }
     150:
     151: int
     152: i_blank(lp)
     153: Line    *lp;
     154: {
     155:     return (get_indent(lp) < 0);
     156: }
     157:
     158: private int
     159: get_indent(lp)
     160: register Line   *lp;
     161: {
     162:     Bufpos  save;
     163:     register int    indent;
     164:
     165:     bslash = 0;
     166:     if (lp == 0)
     167:         return I_BUFEDGE;
     168:     DOTsave(&save);
     169:     SetLine(lp);
     170:     if (blnkp(linebuf))
     171:         indent = I_EMPTY;
     172:     else if (linebuf[0] == '.')
     173:         indent = I_PERIOD;
     174:     else if (linebuf[0] == '\\') {
     175:         /* BH 12/24/85.  Backslash is BLANK only if next line
     176: 		   also starts with Backslash. */
     177:         bslash += 1;
     178:         SetLine(lp->l_next);
     179:         if (linebuf[0] == '\\')
     180:             indent = I_PERIOD;
     181:         else
     182:             indent = 0;
     183:     } else {
     184:         ToIndent();
     185:         indent = calc_pos(linebuf, curchar);
     186:     }
     187:     SetDot(&save);
     188:
     189:     return indent;
     190: }
     191:
     192: private Line *
     193: tailrule(lp)
     194: register Line   *lp;
     195: {
     196:     int i;
     197:
     198:     i = get_indent(lp);
     199:     if (i < 0)
     200:         return lp;  /* one line paragraph */
     201:     do {
     202:         if ((get_indent(lp->l_next) != i) || bslash)
     203:             /* BH line with backslash is head of next para */
     204:             break;
     205:     } while ((lp = lp->l_next) != 0);
     206:     if (lp == 0)
     207:         complain((char *) 0);
     208:     return lp;
     209: }
     210:
     211: /* Finds the beginning, end and indent of the current paragraph, and sets
     212:    the above global variables.  HOW says how to behave when we're between
     213:    paragraphs.  That is, it's either FORWARD or BACKWARD depending on which
     214:    way we're favoring. */
     215:
     216: void
     217: find_para(how)
     218: {
     219:     Line    *this,
     220:         *prev,
     221:         *next,
     222:         *head = 0,
     223:         *body = 0,
     224:         *tail = 0;
     225:     int this_indent;
     226:     Bufpos  orig;       /* remember where we were when we started */
     227:
     228:     DOTsave(&orig);
     229: strt:
     230:     this = curline;
     231:     prev = curline->l_prev;
     232:     next = curline->l_next;
     233:     this_indent = get_indent(this);
     234:
     235:     if (i_blank(this)) {        /* rule 1 */
     236:         if (how == BACKWARD) {
     237:             while (i_blank(curline))
     238:                 if (firstp(curline))
     239:                     complain((char *) 0);
     240:                 else
     241:                     line_move(BACKWARD, 1, NO);
     242:             goto strt;
     243:         } else {
     244:             while (i_blank(curline))
     245:                 if (lastp(curline))
     246:                     complain((char *) 0);
     247:                 else
     248:                     line_move(FORWARD, 1, NO);
     249:             head = curline;
     250:             next = curline->l_next;
     251:             if (!i_bsblank(next))
     252:                 body = next;
     253:             else
     254:                 body = head;
     255:         }
     256:     } else if (i_bsblank(this) || i_blank(prev)) {  /* rule 2 */
     257:         head = this;
     258:         if (!i_bsblank(next))
     259:             body = next;
     260:     } else if (i_bsblank(next)) {   /* rule 3 */
     261:         tail = this;
     262:         body = this;
     263:     } else if ((get_indent(next) == this_indent) || /* rule 4 */
     264:            (get_indent(prev) == this_indent))
     265:         body = this;
     266:     else {      /* rule 6+ */
     267:         if (get_indent(prev) > this_indent) {
     268:             /* hanging indent maybe? */
     269:             if ((next != 0) &&
     270:                 (get_indent(next) == get_indent(next->l_next))) {
     271:                 head = this;
     272:                 body = next;
     273:             }
     274:         }
     275:         /* Now we handle hanging indent else and the other
     276: 		   case of this_indent > get_indent(prev).  That is,
     277: 		   if we didn't resolve HEAD in the above if, then
     278: 		   we are not a hanging indent. */
     279:         if (head == 0) {    /* still don't know */
     280:             if (this_indent > get_indent(prev))
     281:                 head = this;
     282:             else
     283:                 head = prev;
     284:             body = head->l_next;
     285:         }
     286:     }
     287:     /* rule 5 -- find the missing parts */
     288:     if (head == 0) {    /* haven't found head of paragraph so do so now */
     289:         Line    *lp;
     290:         int i;
     291:
     292:         lp = this;
     293:         do {
     294:             i = get_indent(lp->l_prev);
     295:             if (i < 0)  /* is blank */
     296:                 head = lp;
     297:             else if (i != this_indent || bslash) {
     298:                 Line    *this = lp->l_prev;
     299:
     300:                 if (get_indent(this->l_prev) == i)
     301:                     head = this->l_next;
     302:                 else
     303:                     head = this;
     304:             }
     305:         } while (head == 0 && (lp = lp->l_prev) != 0);
     306:         if (lp == 0)
     307:             complain((char *) 0);
     308:     }
     309:     if (body == 0)      /* this must be a one line paragraph */
     310:         body = head;
     311:     if (tail == 0)
     312:         tail = tailrule(body);
     313:     if (tail == 0 || head == 0 || body == 0)
     314:         complain("BUG! tail(%d),head(%d),body(%d)!", tail, head, body);
     315:     para_head = head;
     316:     para_tail = tail;
     317:     head_indent = get_indent(head);
     318:     body_indent = get_indent(body);
     319:
     320:     SetDot(&orig);
     321: }
     322:
     323: void
     324: Justify()
     325: {
     326:     use_lmargin = is_an_arg();
     327:     find_para(BACKWARD);
     328:     DoJustify(para_head, 0, para_tail, length(para_tail), NO,
     329:           use_lmargin ? LMargin : body_indent);
     330: }
     331:
     332: Line *
     333: max_line(l1, l2)
     334: Line    *l1,
     335:     *l2;
     336: {
     337:     if (inorder(l1, 0, l2, 0))
     338:         return l2;
     339:     return l1;
     340: }
     341:
     342: Line *
     343: min_line(l1, l2)
     344: Line    *l1,
     345:     *l2;
     346: {
     347:     if (inorder(l1, 0, l2, 0))
     348:         return l1;
     349:     return l2;
     350: }
     351:
     352: void
     353: RegJustify()
     354: {
     355:     Mark    *mp = CurMark(),
     356:         *tailmark;
     357:     Line    *l1 = curline,
     358:         *l2 = mp->m_line;
     359:     int c1 = curchar,
     360:         c2 = mp->m_char;
     361:     Line    *rl1,
     362:         *rl2;
     363:
     364:     use_lmargin = is_an_arg();
     365:     (void) fixorder(&l1, &c1, &l2, &c2);
     366:     do {
     367:         DotTo(l1, c1);
     368:         find_para(FORWARD);
     369:         rl1 = max_line(l1, para_head);
     370:         rl2 = min_line(l2, para_tail);
     371:         tailmark = MakeMark(para_tail, 0, M_FLOATER);
     372:         DoJustify(rl1, (rl1 == l1) ? c1 : 0, rl2,
     373:               (rl2 == l2) ? c2 : length(rl2),
     374:               NO, use_lmargin ? LMargin : body_indent);
     375:         l1 = tailmark->m_line->l_next;
     376:         DelMark(tailmark);
     377:         c1 = 0;
     378:     } while (l1 != 0 && l2 != rl2);
     379: }
     380:
     381: void
     382: do_rfill(ulm)
     383: {
     384:     Mark    *mp = CurMark();
     385:     Line    *l1 = curline,
     386:         *l2 = mp->m_line;
     387:     int c1 = curchar,
     388:         c2 = mp->m_char;
     389:
     390:     use_lmargin = ulm;
     391:     (void) fixorder(&l1, &c1, &l2, &c2);
     392:     DoJustify(l1, c1, l2, c2, NO, use_lmargin ? LMargin : 0);
     393: }
     394:
     395: void
     396: do_space()
     397: {
     398:     int c1 = curchar,
     399:         c2 = c1,
     400:         diff,
     401:         nspace;
     402:     char    ch;
     403:
     404:     while (c1 > 0 && ((ch = linebuf[c1 - 1]) == ' ' || ch == '\t'))
     405:         c1 -= 1;
     406:     while ((ch = linebuf[c2]) == ' ' || ch == '\t')
     407:         c2 += 1;
     408:     diff = (c2 - c1);
     409:     curchar = c2;
     410:
     411:     if (diff == 0)
     412:         return;
     413:     if (c1 > 0) {
     414:         int topunct = c1 - 1;
     415:
     416:         nspace = 1;
     417:         if (diff >= 2) {
     418:             while (index("\")]", linebuf[topunct])) {
     419:                 if (topunct == 0)
     420:                     break;
     421:                 topunct -= 1;
     422:             }
     423:             if (index("?!.:", linebuf[topunct]))
     424:                 nspace = 2;
     425:         }
     426:     } else
     427:         nspace = 0;
     428:
     429:     if (diff > nspace)
     430:         del_char(BACKWARD, (diff - nspace));
     431:     else if (diff < nspace)
     432:         insert_c(' ', (nspace - diff));
     433: }
     434:
     435: #ifdef MSDOS
     436: /*#pragma loop_opt(off) */
     437: #endif
     438:
     439: void
     440: DoJustify(l1, c1, l2, c2, scrunch, indent)
     441: Line    *l1,
     442:     *l2;
     443: {
     444:     int okay_char = -1;
     445:     char    *cp;
     446:     Mark    *savedot = MakeMark(curline, curchar, M_FLOATER),
     447:         *endmark;
     448:
     449:     (void) fixorder(&l1, &c1, &l2, &c2);    /* l1/c1 will be before l2/c2 */
     450:     DotTo(l1, c1);
     451:     if (get_indent(l1) >= c1) {
     452:         if (use_lmargin) {
     453:             n_indent(indent + (head_indent - body_indent));
     454:             use_lmargin = 0;    /* turn this off now */
     455:         }
     456:         ToIndent();
     457:     }
     458:     endmark = MakeMark(l2, c2, M_FLOATER);
     459:
     460:     for (;;) {
     461:         while (calc_pos(linebuf, curchar) < RMargin) {
     462:             if (curline == endmark->m_line && curchar >= endmark->m_char)
     463:                 goto outahere;
     464:             okay_char = curchar;
     465:             if (eolp()) {
     466:                 del_char(FORWARD, 1);   /* Delete line separator. */
     467:                 ins_str("  ", NO);
     468:             } else {
     469:                 cp = StrIndex(1, linebuf, curchar + 1, ' ');
     470:                 if (cp == 0)
     471:                     Eol();
     472:                 else
     473:                     curchar = (cp - linebuf);
     474:             }
     475:             do_space();
     476:         }
     477:         if (okay_char > 0)
     478:             curchar = okay_char;
     479:         if (curline == endmark->m_line && curchar >= endmark->m_char)
     480:             goto outahere;
     481:
     482:         /* Can't fit in small margin, so we do the best we can. */
     483:         if (eolp()) {
     484:             line_move(FORWARD, 1, NO);
     485:             n_indent(indent);
     486:         } else {
     487:             DelWtSpace();
     488:             LineInsert(1);
     489:             if (scrunch && TwoBlank()) {
     490:                 Eol();
     491:                 del_char(FORWARD, 1);
     492:             }
     493:             n_indent(indent);
     494:         }
     495:     }
     496: outahere:
     497:     ToMark(savedot);    /* Back to where we were */
     498:     DelMark(endmark);   /* Free up marks */
     499:     DelMark(savedot);
     500:     this_cmd = last_cmd = 0; /* So everything is under control */
     501:     f_mess("");
     502: }
     503:
     504: #ifdef MSDOS
     505: /*#pragma loop_opt() */
     506: #endif
     507:
     508: extern Line *para_head,
     509:         *para_tail;
     510:
     511: void
     512: DoPara(dir)
     513: {
     514:     register int    num = arg_value(),
     515:             first_time = TRUE;
     516:
     517:     while (--num >= 0) {
     518: tryagain:   find_para(dir);     /* find paragraph bounderies */
     519:         if ((dir == BACKWARD) &&
     520:             ((!first_time) || ((para_head == curline) && bolp()))) {
     521:                 if (bobp())
     522:                     complain((char *) 0);
     523:             b_char(1);
     524:             first_time = !first_time;
     525:             goto tryagain;
     526:         }
     527:         SetLine((dir == BACKWARD) ? para_head : para_tail);
     528:         if (dir == BACKWARD && !firstp(curline) &&
     529:             i_blank(curline->l_prev))
     530:             line_move(BACKWARD, 1, NO);
     531:         else if (dir == FORWARD) {
     532:             if (lastp(curline)) {
     533:                 Eol();
     534:                 break;
     535:             }
     536:             /* otherwise */
     537:             line_move(FORWARD, 1, NO);
     538:         }
     539:     }
     540: }
     541:
     542: void
     543: BackPara()
     544: {
     545:     DoPara(BACKWARD);
     546: }
     547:
     548: void
     549: ForPara()
     550: {
     551:     DoPara(FORWARD);
     552: }

#### Defined functions

BackPara defined in line 542; used 4 times

- in /usr/src/new/jove/externs.h line 192, 800
- in /usr/src/new/jove/funcdefs.c line 100, 288

DoJustify defined in line 439; used 6 times

- in line 328, 372, 392
- in /usr/src/new/jove/externs.h line 264, 872
- in /usr/src/new/jove/insert.c line 179

DoPara defined in line 511; used 4 times

- in line 545, 551
- in /usr/src/new/jove/externs.h line 267, 875

ForPara defined in line 548; used 4 times

- in /usr/src/new/jove/externs.h line 294, 902
- in /usr/src/new/jove/funcdefs.c line 99, 401

Justify defined in line 323; used 4 times

- in /usr/src/new/jove/externs.h line 310, 918
- in /usr/src/new/jove/funcdefs.c line 121, 390

RegJustify defined in line 352; used 4 times

- in /usr/src/new/jove/externs.h line 359, 967
- in /usr/src/new/jove/funcdefs.c line 122, 391

do_rfill defined in line 381; used 3 times

- in /usr/src/new/jove/c.c line 606
- in /usr/src/new/jove/externs.h line 442, 1050

do_space defined in line 395; used 3 times

- in line 475
- in /usr/src/new/jove/externs.h line 445, 1053

find_para defined in line 216; used 5 times

- in line 327, 368, 518
- in /usr/src/new/jove/externs.h line 460, 1068

get_indent defined in line 158; used 17 times

- in line 16-19(2), 155, 198-202(2), 233, 263-270(5), 280, 294, 300, 317-318(2), 451

i_blank defined in line 151; used 8 times

- in line 146, 235-237(2), 244, 256, 529
- in /usr/src/new/jove/externs.h line 89, 696

i_bsblank defined in line 142; used 6 times

- in line 251-260(4)
- in /usr/src/new/jove/externs.h line 90, 697

max_line defined in line 332; used 3 times

- in line 369
- in /usr/src/new/jove/externs.h line 145, 753

min_line defined in line 342; used 3 times

- in line 370
- in /usr/src/new/jove/externs.h line 146, 754

tailrule defined in line 192; used 3 times

- in line 17-20(2), 312

#### Defined variables

RMargin defined in line 126; used 4 times

- in line 461
- in /usr/src/new/jove/misc.c line 523
- in /usr/src/new/jove/paragraph.c line 461
- in /usr/src/new/jove/vars.c line 77

body_indent defined in line 131; used 4 times

- in line 318, 329, 374, 453

bslash defined in line 139; used 5 times

- in line 148, 165, 177, 202, 297

head_indent defined in line 130; used 2 times

- in line 317, 453

para_head declared in line 508; defined in line 128; used 5 times

- in line 315, 328, 369, 520, 527

para_tail declared in line 509; defined in line 129; used 6 times

- in line 316, 328(2), 370-371(2), 527

use_lmargin defined in line 132; used 8 times

- in line 326-329(2), 364, 374, 390-392(2), 452-454(2)

#### Defined macros

I_BUFEDGE defined in line 137; used 1 times

- in line 167

I_EMPTY defined in line 135; used 1 times

- in line 171

I_PERIOD defined in line 136; used 2 times

- in line 173, 180

private defined in line 25; used 8 times

- in line 11-24(6), 158, 192

Last modified: 1988-03-15 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1343 |