+
+static struct termp *
+term_alloc(enum termenc enc)
+{
+ struct termp *p;
+
+ if (NULL == (p = malloc(sizeof(struct termp))))
+ err(1, "malloc");
+ bzero(p, sizeof(struct termp));
+ p->maxrmargin = 78;
+ p->enc = enc;
+ return(p);
+}
+
+
+static int
+term_isclosedelim(const char *p, int len)
+{
+
+ if (1 != len)
+ return(0);
+
+ switch (*p) {
+ case('.'):
+ /* FALLTHROUGH */
+ case(','):
+ /* FALLTHROUGH */
+ case(';'):
+ /* FALLTHROUGH */
+ case(':'):
+ /* FALLTHROUGH */
+ case('?'):
+ /* FALLTHROUGH */
+ case('!'):
+ /* FALLTHROUGH */
+ case(')'):
+ /* FALLTHROUGH */
+ case(']'):
+ /* FALLTHROUGH */
+ case('}'):
+ return(1);
+ default:
+ break;
+ }
+
+ return(0);
+}
+
+
+static int
+term_isopendelim(const char *p, int len)
+{
+
+ if (1 != len)
+ return(0);
+
+ switch (*p) {
+ case('('):
+ /* FALLTHROUGH */
+ case('['):
+ /* FALLTHROUGH */
+ case('{'):
+ return(1);
+ default:
+ break;
+ }
+
+ return(0);
+}
+
+
+/*
+ * Flush a line of text. A "line" is loosely defined as being something
+ * that should be followed by a newline, regardless of whether it's
+ * broken apart by newlines getting there. A line can also be a
+ * fragment of a columnar list.
+ *
+ * Specifically, a line is whatever's in p->buf of length p->col, which
+ * is zeroed after this function returns.
+ *
+ * The usage of termp:flags is as follows:
+ *
+ * - TERMP_NOLPAD: when beginning to write the line, don't left-pad the
+ * offset value. This is useful when doing columnar lists where the
+ * prior column has right-padded.
+ *
+ * - TERMP_NOBREAK: this is the most important and is used when making
+ * columns. In short: don't print a newline and instead pad to the
+ * right margin. Used in conjunction with TERMP_NOLPAD.
+ *
+ * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
+ * the line is overrun, and don't pad-right if it's underrun.
+ *
+ * - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
+ * overruning, instead save the position and continue at that point
+ * when the next invocation.
+ *
+ * In-line line breaking:
+ *
+ * If TERMP_NOBREAK is specified and the line overruns the right
+ * margin, it will break and pad-right to the right margin after
+ * writing. If maxrmargin is violated, it will break and continue
+ * writing from the right-margin, which will lead to the above
+ * scenario upon exit.
+ *
+ * Otherwise, the line will break at the right margin. Extremely long
+ * lines will cause the system to emit a warning (TODO: hyphenate, if
+ * possible).
+ *
+ * FIXME: newline breaks occur (in groff) also occur when a single
+ * space follows a NOBREAK!
+ */