+}
+
+
+size_t
+term_len(const struct termp *p, size_t sz)
+{
+
+ return((*p->width)(p, ' ') * sz);
+}
+
+
+size_t
+term_strlen(const struct termp *p, const char *cp)
+{
+ size_t sz, ssz, rsz, i;
+ enum roffdeco d;
+ const char *seq, *rhs;
+
+ for (sz = 0; '\0' != *cp; )
+ /*
+ * Account for escaped sequences within string length
+ * calculations. This follows the logic in term_word()
+ * as we must calculate the width of produced strings.
+ */
+ if ('\\' == *cp) {
+ seq = ++cp;
+ cp += a2roffdeco(&d, &seq, &ssz);
+
+ switch (d) {
+ case (DECO_RESERVED):
+ rhs = chars_res2str
+ (p->symtab, seq, ssz, &rsz);
+ break;
+ case (DECO_SPECIAL):
+ /* FALLTHROUGH */
+ case (DECO_SSPECIAL):
+ rhs = chars_spec2str
+ (p->symtab, seq, ssz, &rsz);
+
+ /* Allow for one-char escapes. */
+ if (DECO_SSPECIAL != d || rhs)
+ break;
+
+ rhs = seq;
+ rsz = ssz;
+ break;
+ default:
+ rhs = NULL;
+ break;
+ }
+
+ if (rhs)
+ for (i = 0; i < rsz; i++)
+ sz += (*p->width)(p, *rhs++);
+ } else
+ sz += (*p->width)(p, *cp++);
+
+ return(sz);
+}
+
+
+/* ARGSUSED */
+size_t
+term_vspan(const struct termp *p, const struct roffsu *su)
+{
+ double r;
+
+ switch (su->unit) {
+ case (SCALE_CM):
+ r = su->scale * 2;
+ break;
+ case (SCALE_IN):
+ r = su->scale * 6;
+ break;
+ case (SCALE_PC):
+ r = su->scale;
+ break;
+ case (SCALE_PT):
+ r = su->scale / 8;
+ break;
+ case (SCALE_MM):
+ r = su->scale / 1000;
+ break;
+ case (SCALE_VS):
+ r = su->scale;
+ break;
+ default:
+ r = su->scale - 1;
+ break;
+ }
+
+ if (r < 0.0)
+ r = 0.0;
+ return(/* LINTED */(size_t)
+ r);
+}
+
+
+size_t
+term_hspan(const struct termp *p, const struct roffsu *su)
+{
+ double v;
+
+ v = ((*p->hspan)(p, su));
+ if (v < 0.0)
+ v = 0.0;
+ return((size_t) /* LINTED */
+ v);