+ size_t sz, rsz, i;
+ int ssz, c;
+ const char *seq, *rhs;
+ enum mandoc_esc esc;
+ static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
+
+ /*
+ * Account for escaped sequences within string length
+ * calculations. This follows the logic in term_word() as we
+ * must calculate the width of produced strings.
+ */
+
+ sz = 0;
+ while ('\0' != *cp) {
+ rsz = strcspn(cp, rej);
+ for (i = 0; i < rsz; i++)
+ sz += (*p->width)(p, *cp++);
+
+ c = 0;
+ switch (*cp) {
+ case ('\\'):
+ cp++;
+ esc = mandoc_escape(&cp, &seq, &ssz);
+ if (ESCAPE_ERROR == esc)
+ return(sz);
+
+ if (TERMENC_ASCII != p->enc)
+ switch (esc) {
+ case (ESCAPE_UNICODE):
+ c = mchars_num2uc
+ (seq + 1, ssz - 1);
+ if ('\0' == c)
+ break;
+ sz += (*p->width)(p, c);
+ continue;
+ case (ESCAPE_SPECIAL):
+ c = mchars_spec2cp
+ (p->symtab, seq, ssz);
+ if (c <= 0)
+ break;
+ sz += (*p->width)(p, c);
+ continue;
+ default:
+ break;
+ }
+
+ rhs = NULL;
+
+ switch (esc) {
+ case (ESCAPE_UNICODE):
+ sz += (*p->width)(p, '?');
+ break;
+ case (ESCAPE_NUMBERED):
+ c = mchars_num2char(seq, ssz);
+ if ('\0' != c)
+ sz += (*p->width)(p, c);
+ break;
+ case (ESCAPE_SPECIAL):
+ rhs = mchars_spec2str
+ (p->symtab, seq, ssz, &rsz);
+
+ if (ssz != 1 || rhs)
+ break;
+
+ rhs = seq;
+ rsz = ssz;
+ break;
+ default:
+ break;
+ }
+
+ if (NULL == rhs)
+ break;
+
+ for (i = 0; i < rsz; i++)
+ sz += (*p->width)(p, *rhs++);
+ break;
+ case (ASCII_NBRSP):
+ sz += (*p->width)(p, ' ');
+ cp++;
+ break;
+ case (ASCII_HYPH):
+ sz += (*p->width)(p, '-');
+ cp++;
+ break;
+ default:
+ break;