+static void
+post_tg(POST_ARGS)
+{
+ struct roff_node *n; /* The .Tg node. */
+ struct roff_node *nch; /* The first child of the .Tg node. */
+ struct roff_node *nn; /* The next node after the .Tg node. */
+ struct roff_node *np; /* The parent of the next node. */
+ struct roff_node *nt; /* The TEXT node containing the tag. */
+ size_t len; /* The number of bytes in the tag. */
+
+ /* Find the next node. */
+ n = mdoc->last;
+ for (nn = n; nn != NULL; nn = nn->parent) {
+ if (nn->next != NULL) {
+ nn = nn->next;
+ break;
+ }
+ }
+
+ /* Find the tag. */
+ nt = nch = n->child;
+ if (nch == NULL && nn != NULL && nn->child != NULL &&
+ nn->child->type == ROFFT_TEXT)
+ nt = nn->child;
+
+ /* Validate the tag. */
+ if (nt == NULL || *nt->string == '\0')
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg");
+ if (nt == NULL) {
+ roff_node_delete(mdoc, n);
+ return;
+ }
+ len = strcspn(nt->string, " \t\\");
+ if (nt->string[len] != '\0')
+ mandoc_msg(MANDOCERR_TG_SPC, nt->line,
+ nt->pos + len, "Tg %s", nt->string);
+
+ /* Keep only the first argument. */
+ if (nch != NULL && nch->next != NULL) {
+ mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line,
+ nch->next->pos, "Tg ... %s", nch->next->string);
+ while (nch->next != NULL)
+ roff_node_delete(mdoc, nch->next);
+ }
+
+ /* Drop the macro if the first argument is invalid. */
+ if (len == 0 || nt->string[len] != '\0') {
+ roff_node_delete(mdoc, n);
+ return;
+ }
+
+ /* By default, tag the .Tg node itself. */
+ if (nn == NULL || nn->flags & NODE_ID)
+ nn = n;
+
+ /* Explicit tagging of specific macros. */
+ switch (nn->tok) {
+ case MDOC_Sh:
+ case MDOC_Ss:
+ case MDOC_Fo:
+ nn = nn->head->child == NULL ? n : nn->head;
+ break;
+ case MDOC_It:
+ np = nn->parent;
+ while (np->tok != MDOC_Bl)
+ np = np->parent;
+ switch (np->norm->Bl.type) {
+ case LIST_column:
+ break;
+ case LIST_diag:
+ case LIST_hang:
+ case LIST_inset:
+ case LIST_ohang:
+ case LIST_tag:
+ nn = nn->head;
+ break;
+ case LIST_bullet:
+ case LIST_dash:
+ case LIST_enum:
+ case LIST_hyphen:
+ case LIST_item:
+ nn = nn->body->child == NULL ? n : nn->body;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MDOC_Bd:
+ case MDOC_Bl:
+ case MDOC_D1:
+ case MDOC_Dl:
+ nn = nn->body->child == NULL ? n : nn->body;
+ break;
+ case MDOC_Pp:
+ break;
+ case MDOC_Cm:
+ case MDOC_Dv:
+ case MDOC_Em:
+ case MDOC_Er:
+ case MDOC_Ev:
+ case MDOC_Fl:
+ case MDOC_Fn:
+ case MDOC_Ic:
+ case MDOC_Li:
+ case MDOC_Ms:
+ case MDOC_No:
+ case MDOC_Sy:
+ if (nn->child == NULL)
+ nn = n;
+ break;
+ default:
+ nn = n;
+ break;
+ }
+ tag_put(nt->string, TAG_MANUAL, nn);
+ if (nn != n)
+ n->flags |= NODE_NOPRT;
+}
+