+ if ('\0' == buf[offs])
+ return(1);
+
+ i = offs;
+
+ /* Accept tabs/whitespace after the initial control char. */
+
+ if (' ' == buf[i] || '\t' == buf[i]) {
+ i++;
+ while (buf[i] && (' ' == buf[i] || '\t' == buf[i]))
+ i++;
+ if ('\0' == buf[i])
+ return(1);
+ }
+
+ sv = i;
+
+ /*
+ * Copy the first word into a nil-terminated buffer.
+ * Stop copying when a tab, space, or eoln is encountered.
+ */
+
+ j = 0;
+ while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i])
+ mac[j++] = buf[i++];
+ mac[j] = '\0';
+
+ if (j == 4 || j < 2) {
+ if ( ! macrowarn(m, ln, mac, sv))
+ goto err;
+ return(1);
+ }
+
+ if (MDOC_MAX == (tok = mdoc_hash_find(mac))) {
+ if ( ! macrowarn(m, ln, mac, sv))
+ goto err;
+ return(1);
+ }
+
+ /* Disregard the first trailing tab, if applicable. */
+
+ if ('\t' == buf[i])
+ i++;
+
+ /* Jump to the next non-whitespace word. */
+
+ while (buf[i] && ' ' == buf[i])
+ i++;
+
+ /*
+ * Trailing whitespace. Note that tabs are allowed to be passed
+ * into the parser as "text", so we only warn about spaces here.
+ */
+
+ if ('\0' == buf[i] && ' ' == buf[i - 1])
+ if ( ! mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE))
+ goto err;
+
+ /*
+ * If an initial macro or a list invocation, divert directly
+ * into macro processing.
+ */
+
+ if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) {
+ if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
+ goto err;
+ return(1);
+ }
+
+ n = m->last;
+ assert(m->last);
+
+ /*
+ * If the first macro of a `Bl -column', open an `It' block
+ * context around the parsed macro.
+ */
+
+ if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
+ LIST_column == n->data.Bl->type) {
+ m->flags |= MDOC_FREECOL;
+ if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
+ goto err;
+ return(1);
+ }
+
+ /*
+ * If we're following a block-level `It' within a `Bl -column'
+ * context (perhaps opened in the above block or in ptext()),
+ * then open an `It' block context around the parsed macro.
+ */
+
+ if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
+ NULL != n->parent &&
+ MDOC_Bl == n->parent->tok &&
+ LIST_column == n->parent->data.Bl->type) {
+ m->flags |= MDOC_FREECOL;
+ if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
+ goto err;
+ return(1);
+ }
+
+ /* Normal processing of a macro. */
+
+ if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
+ goto err;
+
+ return(1);
+
+err: /* Error out. */
+
+ m->flags |= MDOC_HALT;
+ return(0);