]> pd.if.org Git - pd_readline/blobdiff - mg/paragraph.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / paragraph.c
diff --git a/mg/paragraph.c b/mg/paragraph.c
new file mode 100644 (file)
index 0000000..57ce412
--- /dev/null
@@ -0,0 +1,362 @@
+/*     $OpenBSD: paragraph.c,v 1.22 2011/11/29 05:59:54 lum Exp $      */
+
+/* This file is in the public domain. */
+
+/*
+ * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
+ * and GNU-ified by mwm@ucbvax.         Several bug fixes by blarson@usc-oberon.
+ */
+
+#include "def.h"
+
+static int     fillcol = 70;
+
+#define MAXWORD 256
+
+/*
+ * Move to start of paragraph.  Go back to the beginning of the current
+ * paragraph here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
+ * combination to delimit the beginning of a paragraph.
+ */
+/* ARGSUSED */
+int
+gotobop(int f, int n)
+{
+       /* the other way... */
+       if (n < 0)
+               return (gotoeop(f, -n));
+
+       while (n-- > 0) {
+               /* first scan back until we are in a word */
+               while (backchar(FFRAND, 1) && inword() == 0);
+
+               /* and go to the B-O-Line */
+               curwp->w_doto = 0;
+
+               /*
+                * and scan back until we hit a <NL><SP> <NL><TAB> or
+                * <NL><NL>
+                */
+               while (lback(curwp->w_dotp) != curbp->b_headp)
+                       if (llength(lback(curwp->w_dotp)) &&
+                           lgetc(curwp->w_dotp, 0) != ' ' &&
+                           lgetc(curwp->w_dotp, 0) != '.' &&
+                           lgetc(curwp->w_dotp, 0) != '\t')
+                               curwp->w_dotp = lback(curwp->w_dotp);
+                       else {
+                               if (llength(lback(curwp->w_dotp)) &&
+                                   lgetc(curwp->w_dotp, 0) == '.') {
+                                       curwp->w_dotp = lforw(curwp->w_dotp);
+                                       if (curwp->w_dotp == curbp->b_headp) {
+                                               /*
+                                                * beyond end of buffer,
+                                                * cleanup time
+                                                */
+                                               curwp->w_dotp =
+                                                   lback(curwp->w_dotp);
+                                               curwp->w_doto =
+                                                   llength(curwp->w_dotp);
+                                       }
+                               }
+                               break;
+                       }
+       }
+       /* force screen update */
+       curwp->w_rflag |= WFMOVE;
+       return (TRUE);
+}
+
+/*
+ * Move to end of paragraph.  Go forward to the end of the current paragraph
+ * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE> combination to
+ * delimit the beginning of a paragraph.
+ */
+/* ARGSUSED */
+int
+gotoeop(int f, int n)
+{
+       /* the other way... */
+       if (n < 0)
+               return (gotobop(f, -n));
+
+       /* for each one asked for */
+       while (n-- > 0) {
+               /* Find the first word on/after the current line */
+               curwp->w_doto = 0;
+               while (forwchar(FFRAND, 1) && inword() == 0);
+
+               curwp->w_doto = 0;
+               curwp->w_dotp = lforw(curwp->w_dotp);
+
+               /* and scan forword until we hit a <NL><SP> or ... */
+               while (curwp->w_dotp != curbp->b_headp) {
+                       if (llength(curwp->w_dotp) &&
+                           lgetc(curwp->w_dotp, 0) != ' ' &&
+                           lgetc(curwp->w_dotp, 0) != '.' &&
+                           lgetc(curwp->w_dotp, 0) != '\t')
+                               curwp->w_dotp = lforw(curwp->w_dotp);
+                       else
+                               break;
+               }
+               if (curwp->w_dotp == curbp->b_headp) {
+                       /* beyond end of buffer, cleanup time */
+                       curwp->w_dotp = lback(curwp->w_dotp);
+                       curwp->w_doto = llength(curwp->w_dotp);
+                       break;
+               }
+       }
+       /* force screen update */
+       curwp->w_rflag |= WFMOVE;
+       return (TRUE);
+}
+
+/*
+ * Justify a paragraph.  Fill the current paragraph according to the current
+ * fill column.
+ */
+/* ARGSUSED */
+int
+fillpara(int f, int n)
+{
+       int      c;             /* current char during scan             */
+       int      wordlen;       /* length of current word               */
+       int      clength;       /* position on line during fill         */
+       int      i;             /* index during word copy               */
+       int      eopflag;       /* Are we at the End-Of-Paragraph?      */
+       int      firstflag;     /* first word? (needs no space)         */
+       int      newlength;     /* tentative new line length            */
+       int      eolflag;       /* was at end of line                   */
+       int      retval;        /* return value                         */
+       struct line     *eopline;       /* pointer to line just past EOP        */
+       char     wbuf[MAXWORD]; /* buffer for current word              */
+
+       undo_boundary_enable(FFRAND, 0);
+
+       /* record the pointer to the line just past the EOP */
+       (void)gotoeop(FFRAND, 1);
+       if (curwp->w_doto != 0) {
+               /* paragraph ends at end of buffer */
+               (void)lnewline();
+               eopline = lforw(curwp->w_dotp);
+       } else
+               eopline = curwp->w_dotp;
+
+       /* and back top the begining of the paragraph */
+       (void)gotobop(FFRAND, 1);
+
+       /* initialize various info */
+       while (inword() == 0 && forwchar(FFRAND, 1));
+
+       clength = curwp->w_doto;
+       wordlen = 0;
+
+       /* scan through lines, filling words */
+       firstflag = TRUE;
+       eopflag = FALSE;
+       while (!eopflag) {
+
+               /* get the next character in the paragraph */
+               if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) {
+                       c = ' ';
+                       if (lforw(curwp->w_dotp) == eopline)
+                               eopflag = TRUE;
+               } else
+                       c = lgetc(curwp->w_dotp, curwp->w_doto);
+
+               /* and then delete it */
+               if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) {
+                       retval = FALSE;
+                       goto cleanup;
+               }
+
+               /* if not a separator, just add it in */
+               if (c != ' ' && c != '\t') {
+                       if (wordlen < MAXWORD - 1)
+                               wbuf[wordlen++] = c;
+                       else {
+                               /*
+                                * You lose chars beyond MAXWORD if the word
+                                * is too long. I'm too lazy to fix it now; it
+                                * just silently truncated the word before,
+                                * so I get to feel smug.
+                                */
+                               ewprintf("Word too long!");
+                       }
+               } else if (wordlen) {
+
+                       /* calculate tentative new length with word added */
+                       newlength = clength + 1 + wordlen;
+
+                       /*
+                        * if at end of line or at doublespace and previous
+                        * character was one of '.','?','!' doublespace here.
+                        * behave the same way if a ')' is preceded by a
+                        * [.?!] and followed by a doublespace.
+                        */
+                       if ((eolflag ||
+                           curwp->w_doto == llength(curwp->w_dotp) ||
+                           (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' '
+                           || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) ||
+                           (wbuf[wordlen - 1] == ')' && wordlen >= 2 &&
+                           ISEOSP(wbuf[wordlen - 2]))) &&
+                           wordlen < MAXWORD - 1)
+                               wbuf[wordlen++] = ' ';
+
+                       /* at a word break with a word waiting */
+                       if (newlength <= fillcol) {
+                               /* add word to current line */
+                               if (!firstflag) {
+                                       (void)linsert(1, ' ');
+                                       ++clength;
+                               }
+                               firstflag = FALSE;
+                       } else {
+                               if (curwp->w_doto > 0 &&
+                                   lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') {
+                                       curwp->w_doto -= 1;
+                                       (void)ldelete((RSIZE) 1, KNONE);
+                               }
+                               /* start a new line */
+                               (void)lnewline();
+                               clength = 0;
+                       }
+
+                       /* and add the word in in either case */
+                       for (i = 0; i < wordlen; i++) {
+                               (void)linsert(1, wbuf[i]);
+                               ++clength;
+                       }
+                       wordlen = 0;
+               }
+       }
+       /* and add a last newline for the end of our new paragraph */
+       (void)lnewline();
+
+       /*
+        * We really should wind up where we started, (which is hard to keep
+        * track of) but I think the end of the last line is better than the
+        * beginning of the blank line.
+        */
+       (void)backchar(FFRAND, 1);
+       retval = TRUE;
+cleanup:
+       undo_boundary_enable(FFRAND, 1);
+       return (retval);
+}
+
+/*
+ * Delete a paragraph.  Delete n paragraphs starting with the current one.
+ */
+/* ARGSUSED */
+int
+killpara(int f, int n)
+{
+       int     status;         /* returned status of functions */
+
+       /* for each paragraph to delete */
+       while (n--) {
+
+               /* mark out the end and beginning of the para to delete */
+               (void)gotoeop(FFRAND, 1);
+
+               /* set the mark here */
+               curwp->w_markp = curwp->w_dotp;
+               curwp->w_marko = curwp->w_doto;
+
+               /* go to the beginning of the paragraph */
+               (void)gotobop(FFRAND, 1);
+
+               /* force us to the beginning of line */
+               curwp->w_doto = 0;
+
+               /* and delete it */
+               if ((status = killregion(FFRAND, 1)) != TRUE)
+                       return (status);
+
+               /* and clean up the 2 extra lines */
+               (void)ldelete((RSIZE) 1, KFORW);
+       }
+       return (TRUE);
+}
+
+/*
+ * Insert char with work wrap.  Check to see if we're past fillcol, and if so,
+ * justify this line.  As a last step, justify the line.
+ */
+/* ARGSUSED */
+int
+fillword(int f, int n)
+{
+       char    c;
+       int     col, i, nce;
+
+       for (i = col = 0; col <= fillcol; ++i, ++col) {
+               if (i == curwp->w_doto)
+                       return selfinsert(f, n);
+               c = lgetc(curwp->w_dotp, i);
+               if (c == '\t'
+#ifdef NOTAB
+                   && !(curbp->b_flag & BFNOTAB)
+#endif
+                       )
+                       col |= 0x07;
+               else if (ISCTRL(c) != FALSE)
+                       ++col;
+       }
+       if (curwp->w_doto != llength(curwp->w_dotp)) {
+               (void)selfinsert(f, n);
+               nce = llength(curwp->w_dotp) - curwp->w_doto;
+       } else
+               nce = 0;
+       curwp->w_doto = i;
+
+       if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
+               do {
+                       (void)backchar(FFRAND, 1);
+               } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
+                   c != '\t' && curwp->w_doto > 0);
+
+       if (curwp->w_doto == 0)
+               do {
+                       (void)forwchar(FFRAND, 1);
+               } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' &&
+                   c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
+
+       (void)delwhite(FFRAND, 1);
+       (void)lnewline();
+       i = llength(curwp->w_dotp) - nce;
+       curwp->w_doto = i > 0 ? i : 0;
+       curwp->w_rflag |= WFMOVE;
+       if (nce == 0 && curwp->w_doto != 0)
+               return (fillword(f, n));
+       return (TRUE);
+}
+
+/*
+ * Set fill column to n for justify.
+ */
+int
+setfillcol(int f, int n)
+{
+       char buf[32], *rep;
+       const char *es;
+       int nfill;
+
+       if ((f & FFARG) != 0) {
+               fillcol = n;
+       } else {
+               if ((rep = eread("Set fill-column: ", buf, sizeof(buf),
+                   EFNEW | EFCR)) == NULL)
+                       return (ABORT);
+               else if (rep[0] == '\0')
+                       return (FALSE);
+               nfill = strtonum(rep, 0, INT_MAX, &es);
+               if (es != NULL) {
+                       ewprintf("Invalid fill column: %s", rep);
+                       return (FALSE);
+               }
+               fillcol = nfill;
+               ewprintf("Fill column set to %d", fillcol);
+       }
+       return (TRUE);
+}