static int pre_ft(DECL_ARGS) { const char *cp; if (NULL == n->child) { term_fontlast(p); return 0; } cp = n->child->string; switch (*cp) { case '4': case '3': case 'B': term_fontrepl(p, TERMFONT_BOLD); break; case '2': case 'I': term_fontrepl(p, TERMFONT_UNDER); break; case 'P': term_fontlast(p); break; case '1': case 'C': case 'R': term_fontrepl(p, TERMFONT_NONE); break; default: break; } return 0; }
static void roff_term_pre_ft(ROFF_TERM_ARGS) { const char *cp; cp = n->child->string; switch (mandoc_font(cp, (int)strlen(cp))) { case ESCAPE_FONTBOLD: term_fontrepl(p, TERMFONT_BOLD); break; case ESCAPE_FONTITALIC: term_fontrepl(p, TERMFONT_UNDER); break; case ESCAPE_FONTBI: term_fontrepl(p, TERMFONT_BI); break; case ESCAPE_FONTPREV: term_fontlast(p); break; case ESCAPE_FONTROMAN: case ESCAPE_FONTCW: term_fontrepl(p, TERMFONT_NONE); break; default: break; } }
/* ARGSUSED */ static int pre_SS(DECL_ARGS) { switch (n->type) { case (MAN_BLOCK): mt->lmargin = term_len(p, INDENT); mt->offset = term_len(p, INDENT); /* If following a prior empty `SS', no vspace. */ if (n->prev && MAN_SS == n->prev->tok) if (NULL == n->prev->body->child) break; if (NULL == n->prev) break; term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); p->offset = term_len(p, HALFINDENT); break; case (MAN_BODY): p->offset = mt->offset; break; default: break; } return(1); }
static int pre_SS(DECL_ARGS) { int i; switch (n->type) { case MAN_BLOCK: mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* If following a prior empty `SS', no vspace. */ if (n->prev && MAN_SS == n->prev->tok) if (NULL == n->prev->body->child) break; if (NULL == n->prev) break; for (i = 0; i < mt->pardist; i++) term_vspace(p); break; case MAN_HEAD: term_fontrepl(p, TERMFONT_BOLD); p->offset = term_len(p, 3); break; case MAN_BODY: p->offset = mt->offset; break; default: break; } return(1); }
/* ARGSUSED */ static int pre_SH(DECL_ARGS) { switch (n->type) { case (MAN_BLOCK): mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* If following a prior empty `SH', no vspace. */ if (n->prev && MAN_SH == n->prev->tok) if (NULL == n->prev->body->child) break; /* If the first macro, no vspae. */ if (NULL == n->prev) break; term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); p->offset = 0; break; case (MAN_BODY): p->offset = mt->offset; break; default: break; } return(1); }
/* ARGSUSED */ static int pre_B(DECL_ARGS) { term_fontrepl(p, TERMFONT_BOLD); return(1); }
static void print_man_foot(struct termp *p, const void *arg) { const struct man_meta *meta; meta = (const struct man_meta *)arg; term_fontrepl(p, TERMFONT_NONE); term_vspace(p); term_vspace(p); term_vspace(p); p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; p->rmargin = p->maxrmargin - term_strlen(p, meta->date); p->offset = 0; /* term_strlen() can return zero. */ if (p->rmargin == p->maxrmargin) p->rmargin--; if (meta->source) term_word(p, meta->source); if (meta->source) term_word(p, ""); term_flushln(p); p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; p->offset = p->rmargin; p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; term_word(p, meta->date); term_flushln(p); }
/* ARGSUSED */ static int pre_I(DECL_ARGS) { term_fontrepl(p, TERMFONT_UNDER); return(1); }
/* ARGSUSED */ static int pre_OP(DECL_ARGS) { term_word(p, "["); p->flags |= TERMP_NOSPACE; if (NULL != (n = n->child)) { term_fontrepl(p, TERMFONT_BOLD); term_word(p, n->string); } if (NULL != n && NULL != n->next) { term_fontrepl(p, TERMFONT_UNDER); term_word(p, n->next->string); } term_fontrepl(p, TERMFONT_NONE); p->flags |= TERMP_NOSPACE; term_word(p, "]"); return(0); }
static int pre_alternate(DECL_ARGS) { enum termfont font[2]; struct roff_node *nn; int savelit, i; switch (n->tok) { case MAN_RB: font[0] = TERMFONT_NONE; font[1] = TERMFONT_BOLD; break; case MAN_RI: font[0] = TERMFONT_NONE; font[1] = TERMFONT_UNDER; break; case MAN_BR: font[0] = TERMFONT_BOLD; font[1] = TERMFONT_NONE; break; case MAN_BI: font[0] = TERMFONT_BOLD; font[1] = TERMFONT_UNDER; break; case MAN_IR: font[0] = TERMFONT_UNDER; font[1] = TERMFONT_NONE; break; case MAN_IB: font[0] = TERMFONT_UNDER; font[1] = TERMFONT_BOLD; break; default: abort(); } savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { term_fontrepl(p, font[i]); if (savelit && NULL == nn->next) mt->fl |= MANT_LITERAL; assert(nn->type == ROFFT_TEXT); term_word(p, nn->string); if (nn->flags & MAN_EOS) p->flags |= TERMP_SENTENCE; if (nn->next) p->flags |= TERMP_NOSPACE; } return 0; }
/* ARGSUSED */ static int pre_ft(DECL_ARGS) { const char *cp; if (NULL == n->child) { term_fontlast(p); return(0); } cp = n->child->string; switch (*cp) { case ('4'): /* FALLTHROUGH */ case ('3'): /* FALLTHROUGH */ case ('B'): term_fontrepl(p, TERMFONT_BOLD); break; case ('2'): /* FALLTHROUGH */ case ('I'): term_fontrepl(p, TERMFONT_UNDER); break; case ('P'): term_fontlast(p); break; case ('1'): /* FALLTHROUGH */ case ('C'): /* FALLTHROUGH */ case ('R'): term_fontrepl(p, TERMFONT_NONE); break; default: break; } return(0); }
static void print_mdoc_foot(struct termp *p, const void *arg) { const struct mdoc_meta *meta; size_t sz; meta = (const struct mdoc_meta *)arg; term_fontrepl(p, TERMFONT_NONE); /* * Output the footer in new-groff style, that is, three columns * with the middle being the manual date and flanking columns * being the operating system: * * SYSTEM DATE SYSTEM */ term_vspace(p); p->offset = 0; sz = term_strlen(p, meta->date); p->rmargin = p->maxrmargin > sz ? (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0; p->trailspace = 1; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; term_word(p, meta->os); term_flushln(p); p->offset = p->rmargin; sz = term_strlen(p, meta->os); p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0; p->flags |= TERMP_NOSPACE; term_word(p, meta->date); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin; p->trailspace = 0; p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; term_word(p, meta->os); term_flushln(p); p->offset = 0; p->rmargin = p->maxrmargin; p->flags = 0; }
/* ARGSUSED */ static int pre_alternate(DECL_ARGS) { enum termfont font[2]; const struct man_node *nn; int savelit, i; switch (n->tok) { case (MAN_RB): font[0] = TERMFONT_NONE; font[1] = TERMFONT_BOLD; break; case (MAN_RI): font[0] = TERMFONT_NONE; font[1] = TERMFONT_UNDER; break; case (MAN_BR): font[0] = TERMFONT_BOLD; font[1] = TERMFONT_NONE; break; case (MAN_BI): font[0] = TERMFONT_BOLD; font[1] = TERMFONT_UNDER; break; case (MAN_IR): font[0] = TERMFONT_UNDER; font[1] = TERMFONT_NONE; break; case (MAN_IB): font[0] = TERMFONT_UNDER; font[1] = TERMFONT_BOLD; break; default: abort(); } savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { term_fontrepl(p, font[i]); if (savelit && NULL == nn->next) mt->fl |= MANT_LITERAL; print_man_node(p, mt, nn, m); if (nn->next) p->flags |= TERMP_NOSPACE; } return(0); }
static void print_mdoc_foot(struct termp *p, const void *arg) { char buf[DATESIZ], os[BUFSIZ]; const struct mdoc_meta *m; m = (const struct mdoc_meta *)arg; term_fontrepl(p, TERMFONT_NONE); /* * Output the footer in new-groff style, that is, three columns * with the middle being the manual date and flanking columns * being the operating system: * * SYSTEM DATE SYSTEM */ time2a(m->date, buf, DATESIZ); strlcpy(os, m->os, BUFSIZ); term_vspace(p); p->offset = 0; p->rmargin = (p->maxrmargin - term_strlen(p, buf) + term_len(p, 1)) / 2; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; term_word(p, os); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin - term_strlen(p, os); p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; term_word(p, buf); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; term_word(p, os); term_flushln(p); p->offset = 0; p->rmargin = p->maxrmargin; p->flags = 0; }
static int pre_SS(DECL_ARGS) { int i; switch (n->type) { case ROFFT_BLOCK: mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* * No vertical space before the first subsection * and after an empty subsection. */ do { n = n->prev; } while (n != NULL && n->tok != TOKEN_NONE && termacts[n->tok].flags & MAN_NOTEXT); if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL)) break; for (i = 0; i < mt->pardist; i++) term_vspace(p); break; case ROFFT_HEAD: term_fontrepl(p, TERMFONT_BOLD); p->offset = term_len(p, 3); p->rmargin = mt->offset; p->trailspace = mt->offset; p->flags |= TERMP_NOBREAK | TERMP_BRIND; break; case ROFFT_BODY: p->offset = mt->offset; p->rmargin = p->maxrmargin; p->trailspace = 0; p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); break; default: break; } return 1; }
static int pre_SH(DECL_ARGS) { int i; switch (n->type) { case MAN_BLOCK: mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* * No vertical space before the first section * and after an empty section. */ do { n = n->prev; } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT); if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) break; for (i = 0; i < mt->pardist; i++) term_vspace(p); break; case MAN_HEAD: term_fontrepl(p, TERMFONT_BOLD); p->offset = 0; break; case MAN_BODY: p->offset = mt->offset; break; default: break; } return(1); }
/* * Handle pwords, partial words, which may be either a single word or a * phrase that cannot be broken down (such as a literal string). This * handles word styling. */ void term_word(struct termp *p, const char *word) { const char nbrsp[2] = { ASCII_NBRSP, 0 }; const char *seq, *cp; int sz, uc; size_t ssz; enum mandoc_esc esc; if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { bufferc(p, ' '); if (TERMP_SENTENCE & p->flags) bufferc(p, ' '); } else bufferc(p, ASCII_NBRSP); } if (TERMP_PREKEEP & p->flags) p->flags |= TERMP_KEEP; if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; else p->flags |= TERMP_NOSPACE; p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE); p->skipvsp = 0; while ('\0' != *word) { if ('\\' != *word) { if (TERMP_SKIPCHAR & p->flags) { p->flags &= ~TERMP_SKIPCHAR; word++; continue; } if (TERMP_NBRWORD & p->flags) { if (' ' == *word) { encode(p, nbrsp, 1); word++; continue; } ssz = strcspn(word, "\\ "); } else ssz = strcspn(word, "\\"); encode(p, word, ssz); word += (int)ssz; continue; } word++; esc = mandoc_escape(&word, &seq, &sz); if (ESCAPE_ERROR == esc) continue; switch (esc) { case ESCAPE_UNICODE: uc = mchars_num2uc(seq + 1, sz - 1); break; case ESCAPE_NUMBERED: uc = mchars_num2char(seq, sz); if (uc < 0) continue; break; case ESCAPE_SPECIAL: if (p->enc == TERMENC_ASCII) { cp = mchars_spec2str(p->symtab, seq, sz, &ssz); if (cp != NULL) encode(p, cp, ssz); } else { uc = mchars_spec2cp(p->symtab, seq, sz); if (uc > 0) encode1(p, uc); } continue; case ESCAPE_FONTBOLD: term_fontrepl(p, TERMFONT_BOLD); continue; case ESCAPE_FONTITALIC: term_fontrepl(p, TERMFONT_UNDER); continue; case ESCAPE_FONTBI: term_fontrepl(p, TERMFONT_BI); continue; case ESCAPE_FONT: /* FALLTHROUGH */ case ESCAPE_FONTROMAN: term_fontrepl(p, TERMFONT_NONE); continue; case ESCAPE_FONTPREV: term_fontlast(p); continue; case ESCAPE_NOSPACE: if (TERMP_SKIPCHAR & p->flags) p->flags &= ~TERMP_SKIPCHAR; else if ('\0' == *word) p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE); continue; case ESCAPE_SKIPCHAR: p->flags |= TERMP_SKIPCHAR; continue; case ESCAPE_OVERSTRIKE: cp = seq + sz; while (seq < cp) { if (*seq == '\\') { mandoc_escape(&seq, NULL, NULL); continue; } encode1(p, *seq++); if (seq < cp) encode(p, "\b", 1); } default: continue; } /* * Common handling for Unicode and numbered * character escape sequences. */ if (p->enc == TERMENC_ASCII) { cp = ascii_uc2str(uc); encode(p, cp, strlen(cp)); } else { if ((uc < 0x20 && uc != 0x09) || (uc > 0x7E && uc < 0xA0)) uc = 0xFFFD; encode1(p, uc); } } p->flags &= ~TERMP_NBRWORD; }
static void print_man_foot(struct termp *p, const void *arg) { char title[BUFSIZ]; size_t datelen; const struct man_meta *meta; meta = (const struct man_meta *)arg; assert(meta->title); assert(meta->msec); assert(meta->date); term_fontrepl(p, TERMFONT_NONE); term_vspace(p); /* * Temporary, undocumented option to imitate mdoc(7) output. * In the bottom right corner, use the source instead of * the title. */ if ( ! p->mdocstyle) { term_vspace(p); term_vspace(p); snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); } else if (meta->source) { strlcpy(title, meta->source, BUFSIZ); } else { title[0] = '\0'; } datelen = term_strlen(p, meta->date); /* Bottom left corner: manual source. */ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; p->offset = 0; p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2; if (meta->source) term_word(p, meta->source); term_flushln(p); /* At the bottom in the middle: manual date. */ p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; p->rmargin = p->maxrmargin - term_strlen(p, title); if (p->offset + datelen >= p->rmargin) p->rmargin = p->offset + datelen; term_word(p, meta->date); term_flushln(p); /* Bottom right corner: manual title and section. */ p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; p->rmargin = p->maxrmargin; term_word(p, title); term_flushln(p); }
static void print_man_node(DECL_ARGS) { size_t rm, rmax; int c; switch (n->type) { case(MAN_TEXT): /* * If we have a blank line, output a vertical space. * If we have a space as the first character, break * before printing the line's data. */ if ('\0' == *n->string) { term_vspace(p); return; } else if (' ' == *n->string && MAN_LINE & n->flags) term_newln(p); term_word(p, n->string); /* * If we're in a literal context, make sure that words * togehter on the same line stay together. This is a * POST-printing call, so we check the NEXT word. Since * -man doesn't have nested macros, we don't need to be * more specific than this. */ if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) && (NULL == n->next || n->next->line > n->line)) { rm = p->rmargin; rmax = p->maxrmargin; p->rmargin = p->maxrmargin = TERM_MAXMARGIN; p->flags |= TERMP_NOSPACE; term_flushln(p); p->rmargin = rm; p->maxrmargin = rmax; } if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; return; case (MAN_EQN): term_eqn(p, n->eqn); return; case (MAN_TBL): /* * Tables are preceded by a newline. Then process a * table line, which will cause line termination, */ if (TBL_SPAN_FIRST & n->span->flags) term_newln(p); term_tbl(p, n->span); return; default: break; } if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); c = 1; if (termacts[n->tok].pre) c = (*termacts[n->tok].pre)(p, mt, n, m); if (c && n->child) print_man_nodelist(p, mt, n->child, m); if (termacts[n->tok].post) (*termacts[n->tok].post)(p, mt, n, m); if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; }
static void print_man_node(DECL_ARGS) { size_t rm, rmax; int c; switch (n->type) { case ROFFT_TEXT: /* * If we have a blank line, output a vertical space. * If we have a space as the first character, break * before printing the line's data. */ if ('\0' == *n->string) { term_vspace(p); return; } else if (' ' == *n->string && MAN_LINE & n->flags) term_newln(p); term_word(p, n->string); goto out; case ROFFT_EQN: if ( ! (n->flags & MAN_LINE)) p->flags |= TERMP_NOSPACE; term_eqn(p, n->eqn); if (n->next != NULL && ! (n->next->flags & MAN_LINE)) p->flags |= TERMP_NOSPACE; return; case ROFFT_TBL: if (p->tbl.cols == NULL) term_vspace(p); term_tbl(p, n->span); return; default: break; } if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); c = 1; if (termacts[n->tok].pre) c = (*termacts[n->tok].pre)(p, mt, n, meta); if (c && n->child) print_man_nodelist(p, mt, n->child, meta); if (termacts[n->tok].post) (*termacts[n->tok].post)(p, mt, n, meta); if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); out: /* * If we're in a literal context, make sure that words * together on the same line stay together. This is a * POST-printing call, so we check the NEXT word. Since * -man doesn't have nested macros, we don't need to be * more specific than this. */ if (mt->fl & MANT_LITERAL && ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && (n->next == NULL || n->next->flags & MAN_LINE)) { rm = p->rmargin; rmax = p->maxrmargin; p->rmargin = p->maxrmargin = TERM_MAXMARGIN; p->flags |= TERMP_NOSPACE; if (n->string != NULL && *n->string != '\0') term_flushln(p); else term_newln(p); if (rm < rmax && n->parent->tok == MAN_HP) { p->offset = rm; p->rmargin = rmax; } else p->rmargin = rm; p->maxrmargin = rmax; } if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; }
/* * Handle pwords, partial words, which may be either a single word or a * phrase that cannot be broken down (such as a literal string). This * handles word styling. */ void term_word(struct termp *p, const char *word) { const char *seq, *cp; char c; int sz, uc; size_t ssz; enum mandoc_esc esc; if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { if (TERMP_PREKEEP & p->flags) p->flags |= TERMP_KEEP; bufferc(p, ' '); if (TERMP_SENTENCE & p->flags) bufferc(p, ' '); } else bufferc(p, ASCII_NBRSP); } if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; else p->flags |= TERMP_NOSPACE; p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM); while ('\0' != *word) { if ((ssz = strcspn(word, "\\")) > 0) encode(p, word, ssz); word += (int)ssz; if ('\\' != *word) continue; word++; esc = mandoc_escape(&word, &seq, &sz); if (ESCAPE_ERROR == esc) break; if (TERMENC_ASCII != p->enc) switch (esc) { case (ESCAPE_UNICODE): uc = mchars_num2uc(seq + 1, sz - 1); if ('\0' == uc) break; encode1(p, uc); continue; case (ESCAPE_SPECIAL): uc = mchars_spec2cp(p->symtab, seq, sz); if (uc <= 0) break; encode1(p, uc); continue; default: break; } switch (esc) { case (ESCAPE_UNICODE): encode1(p, '?'); break; case (ESCAPE_NUMBERED): c = mchars_num2char(seq, sz); if ('\0' != c) encode(p, &c, 1); break; case (ESCAPE_SPECIAL): cp = mchars_spec2str(p->symtab, seq, sz, &ssz); if (NULL != cp) encode(p, cp, ssz); else if (1 == ssz) encode(p, seq, sz); break; case (ESCAPE_FONTBOLD): term_fontrepl(p, TERMFONT_BOLD); break; case (ESCAPE_FONTITALIC): term_fontrepl(p, TERMFONT_UNDER); break; case (ESCAPE_FONT): /* FALLTHROUGH */ case (ESCAPE_FONTROMAN): term_fontrepl(p, TERMFONT_NONE); break; case (ESCAPE_FONTPREV): term_fontlast(p); break; case (ESCAPE_NOSPACE): if ('\0' == *word) p->flags |= TERMP_NOSPACE; break; default: break; } } }
static void print_man_foot(struct termp *p, const struct roff_meta *meta) { char *title; size_t datelen, titlen; assert(meta->title); assert(meta->msec); assert(meta->date); term_fontrepl(p, TERMFONT_NONE); if (meta->hasbody) term_vspace(p); /* * Temporary, undocumented option to imitate mdoc(7) output. * In the bottom right corner, use the operating system * instead of the title. */ if ( ! p->mdocstyle) { if (meta->hasbody) { term_vspace(p); term_vspace(p); } mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec); } else if (meta->os) { title = mandoc_strdup(meta->os); } else { title = mandoc_strdup(""); } datelen = term_strlen(p, meta->date); /* Bottom left corner: operating system. */ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; p->trailspace = 1; p->offset = 0; p->rmargin = p->maxrmargin > datelen ? (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; if (meta->os) term_word(p, meta->os); term_flushln(p); /* At the bottom in the middle: manual date. */ p->offset = p->rmargin; titlen = term_strlen(p, title); p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0; p->flags |= TERMP_NOSPACE; term_word(p, meta->date); term_flushln(p); /* Bottom right corner: manual title and section. */ p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; p->trailspace = 0; p->offset = p->rmargin; p->rmargin = p->maxrmargin; term_word(p, title); term_flushln(p); free(title); }