gbranden pushed a commit to branch master
in repository groff.
commit 5e98483fa1e8612774f845f45357aadba4537a1c
Author: G. Branden Robinson <[email protected]>
AuthorDate: Fri Dec 19 12:56:39 2025 -0600
src/roff/troff/number.cpp: Fix code style nits.
* src/roff/troff/number.cpp: Replace preprocessor macro `SCALING_UNITS`
with `static const char` array `valid_scaling_units`.
(is_valid_term): Use the array instead of the string literal macro as
the haystack in strchr(3) call; explicitly construct a `char`-typed
needle from an `int`-typed argument.
(is_valid_term, scale): Parenthesize formally complex expressions.
(scale): Split one `&&`-using assert(3)ion into two. Construct
temporary `unsigned int` objects using the syntax C++ seems to support
for this. Return object of type `units` rather than `int`. (They're
type-aliased with `typedef`, but scrupulous type correctness is more
conceptually coherent and forecloses an avenue of future error.)
---
ChangeLog | 24 +++++++
src/roff/troff/number.cpp | 157 +++++++++++++++++++++++-----------------------
2 files changed, 104 insertions(+), 77 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ee1d4136a..efff63002 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2025-12-19 G. Branden Robinson <[email protected]>
+
+ * src/roff/troff/number.cpp: Fix code style nits. Replace
+ preprocessor macro `SCALING_UNITS` with `static const char`
+ array `valid_scaling_units`.
+ (is_valid_term): Use the array instead of the string literal
+ macro as the haystack in strchr(3) call; explicitly construct a
+ `char`-typed needle from an `int`-typed argument.
+ (is_valid_term, scale): Parenthesize formally complex
+ expressions.
+ (scale): Split one `&&`-using assert(3)ion into two. Construct
+ temporary `unsigned int` objects using the syntax C++ seems to
+ support for this. Return object of type `units` rather than
+ `int`. (They're type-aliased with `typedef`, but scrupulous
+ type correctness is more conceptually coherent and forecloses an
+ avenue of future error.)
+ (is_valid_expression, is_valid_term): Prepare (I think) all
+ comparisons of C++ character literals to the input read by our
+ numeric expression parser for groff's planned wider fundamental
+ character type. Construct `int`s from character literals, and
+ annotate their need to be constructed as that future type.
+
+ Continues the long process of fixing Savannah #67735.
+
2025-12-19 G. Branden Robinson <[email protected]>
[troff]: Trivially refactor.
diff --git a/src/roff/troff/number.cpp b/src/roff/troff/number.cpp
index 7b6db19ce..b271b2e9e 100644
--- a/src/roff/troff/number.cpp
+++ b/src/roff/troff/number.cpp
@@ -251,7 +251,7 @@ static bool is_valid_expression_start()
enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
-#define SCALING_UNITS "icfPmnpuvMsz"
+static const char valid_scaling_units[] = "icfPmnpuvMsz";
static bool is_valid_term(units *u, int scaling_unit,
bool is_parenthesized, bool is_mandatory);
@@ -267,16 +267,16 @@ static bool is_valid_expression(units *u, int
scaling_unit,
tok.skip_spaces();
int op = tok.ch();// safely compares to char literals; TODO: grochar
switch (op) {
- case '+':
- case '-':
- case '/':
- case '*':
- case '%':
- case ':':
- case '&':
+ case int('+'): // TODO: grochar
+ case int('-'): // TODO: grochar
+ case int('/'): // TODO: grochar
+ case int('*'): // TODO: grochar
+ case int('%'): // TODO: grochar
+ case int(':'): // TODO: grochar
+ case int('&'): // TODO: grochar
tok.next();
break;
- case '>':
+ case int('>'): // TODO: grochar
tok.next();
if (tok.ch() == int('=')) { // TODO: grochar
tok.next();
@@ -287,7 +287,7 @@ static bool is_valid_expression(units *u, int scaling_unit,
op = OP_MAX;
}
break;
- case '<':
+ case int('<'): // TODO: grochar
tok.next();
if (tok.ch() == int('=')) { // TODO: grochar
tok.next();
@@ -298,7 +298,7 @@ static bool is_valid_expression(units *u, int scaling_unit,
op = OP_MIN;
}
break;
- case '=':
+ case int('='): // TODO: grochar
tok.next();
if (tok.ch() == int('=')) // TODO: grochar
tok.next();
@@ -311,10 +311,10 @@ static bool is_valid_expression(units *u, int
scaling_unit,
is_mandatory))
return false;
switch (op) {
- case '<':
+ case int('<'): // TODO: grochar
*u = *u < u2;
break;
- case '>':
+ case int('>'): // TODO: grochar
*u = *u > u2;
break;
case OP_LEQ:
@@ -331,41 +331,41 @@ static bool is_valid_expression(units *u, int
scaling_unit,
if (*u < u2)
*u = u2;
break;
- case '=':
+ case int('='): // TODO: grochar
*u = (*u == u2);
break;
- case '&':
+ case int('&'): // TODO: grochar
*u = (*u > 0) && (u2 > 0);
break;
- case ':':
+ case int(':'): // TODO: grochar
*u = (*u > 0) || (u2 > 0);
break;
- case '+':
+ case int('+'): // TODO: grochar
if (ckd_add(u, *u, u2)) {
warning(WARN_RANGE, "integer addition saturated");
return false;
}
break;
- case '-':
+ case int('-'): // TODO: grochar
if (ckd_sub(u, *u, u2)) {
warning(WARN_RANGE, "integer subtraction saturated");
return false;
}
break;
- case '*':
+ case int('*'): // TODO: grochar
if (ckd_mul(u, *u, u2)) {
warning(WARN_RANGE, "integer multiplication saturated");
return false;
}
break;
- case '/':
+ case int('/'): // TODO: grochar
if (0 == u2) {
error("division by zero");
return false;
}
*u /= u2;
break;
- case '%':
+ case int('%'): // TODO: grochar
if (0 == u2) {
error("modulus by zero");
return false;
@@ -398,7 +398,7 @@ static bool is_valid_term(units *u, int scaling_unit,
break;
int c = tok.ch(); // safely compares to char literals; TODO: grochar
switch (c) {
- case '|':
+ case int('|'): // TODO: grochar
// | is not restricted to the outermost level
// tbl uses this
tok.next();
@@ -416,10 +416,10 @@ static bool is_valid_term(units *u, int scaling_unit,
if (is_negative)
*u = -*u;
return true;
- case '(':
+ case int('('): // TODO: grochar
tok.next();
c = tok.ch();
- if (')' == c) { // TODO: grochar
+ if (int(')') == c) { // TODO: grochar
if (is_mandatory)
return false;
warning(WARN_SYNTAX, "empty parentheses");
@@ -427,9 +427,9 @@ static bool is_valid_term(units *u, int scaling_unit,
*u = 0;
return true;
}
- else if (c != 0 && strchr(SCALING_UNITS, c) != 0) {
+ else if ((c != 0) && (strchr(valid_scaling_units, char(c)) != 0)) {
tok.next();
- if (tok.ch() == ';') { // TODO: grochar
+ if (tok.ch() == int(';')) { // TODO: grochar
tok.next();
scaling_unit = c;
}
@@ -447,7 +447,7 @@ static bool is_valid_term(units *u, int scaling_unit,
true /* is_parenthesized */, is_mandatory))
return false;
tok.skip_spaces();
- if (tok.ch() != ')') { // TODO: grochar
+ if (tok.ch() != int(')')) { // TODO: grochar
if (is_mandatory)
return false;
warning(WARN_SYNTAX, "expected ')', got %1", tok.description());
@@ -460,19 +460,19 @@ static bool is_valid_term(units *u, int scaling_unit,
warning(WARN_RANGE, "integer multiplication saturated");
}
return true;
- case '.':
+ case int('.'): // TODO: grochar
*u = 0;
break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
+ case int('0'): // TODO: grochar
+ case int('1'): // TODO: grochar
+ case int('2'): // TODO: grochar
+ case int('3'): // TODO: grochar
+ case int('4'): // TODO: grochar
+ case int('5'): // TODO: grochar
+ case int('6'): // TODO: grochar
+ case int('7'): // TODO: grochar
+ case int('8'): // TODO: grochar
+ case int('9'): // TODO: grochar
*u = 0;
do {
if (!is_overflowing) {
@@ -491,14 +491,14 @@ static bool is_valid_term(units *u, int scaling_unit,
if (is_overflowing)
warning(WARN_RANGE, "integer value saturated");
break;
- case '/':
- case '*':
- case '%':
- case ':':
- case '&':
- case '>':
- case '<':
- case '=':
+ case int('/'): // TODO: grochar
+ case int('*'): // TODO: grochar
+ case int('%'): // TODO: grochar
+ case int(':'): // TODO: grochar
+ case int('&'): // TODO: grochar
+ case int('>'): // TODO: grochar
+ case int('<'): // TODO: grochar
+ case int('='): // TODO: grochar
warning(WARN_SYNTAX, "empty left operand to '%1' operator",
char(c));
*u = 0;
@@ -516,7 +516,8 @@ static bool is_valid_term(units *u, int scaling_unit,
if (!csdigit(c))
break;
// we may multiply the divisor by 254 later on
- if (divisor <= INT_MAX / 2540 && *u <= (INT_MAX - 9) / 10) {
+ if ((divisor <= (INT_MAX / 2540)) && (*u <= ((INT_MAX - 9) / 10)))
+ {
*u *= 10;
*u += c - '0';
divisor *= 10;
@@ -527,35 +528,38 @@ static bool is_valid_term(units *u, int scaling_unit,
int si = scaling_unit;
bool do_next = false;
if (((c = tok.ch()) != 0)
- && (strchr(SCALING_UNITS, c) != 0 /* nullptr */)) {
+ && (strchr(valid_scaling_units, c) != 0 /* nullptr */)) {
switch (scaling_unit) {
- case 0:
+ case int(0): // TODO: grochar; null character, not digit zero
// We know it's a recognized scaling unit because it matched the
// `strchr()` above, so we don't use `tok.description()`.
warning(WARN_SCALE, "a scaling unit is not valid in this context"
" (got '%1')", char(c));
break;
- case 'f':
- if (c != 'f' && c != 'u') {
+ case int('f'): // TODO: grochar
+ if (c != int('f') && c != int('u')) { // TODO: grochar
warning(WARN_SCALE, "'%1' scaling unit invalid in this context;"
" use 'f' or 'u'", char(c));
break;
}
si = c;
break;
- case 'z':
- if (c != 'u' && c != 'z' && c != 'p' && c != 's') {
+ case int('z'): // TODO: grochar
+ if (c != int('u')
+ && c != int('z')
+ && c != int('p')
+ && c != int('s')) { // TODO: grochar
warning(WARN_SCALE, "'%1' scaling unit invalid in this context;"
" use 'z', 'p', 's', or 'u'", char(c));
break;
}
si = c;
break;
- case 'u':
+ case int('u'): // TODO: grochar
si = c;
break;
default:
- if ('z' == c) {
+ if (int('z') == c) { // TODO: grochar
warning(WARN_SCALE, "'z' scaling unit invalid in this context");
break;
}
@@ -567,27 +571,27 @@ static bool is_valid_term(units *u, int scaling_unit,
do_next = true;
}
switch (si) {
- case 'i':
+ case int('i'): // TODO: grochar
*u = scale(*u, units_per_inch, divisor);
break;
- case 'c':
- *u = scale(*u, units_per_inch * 100, divisor * 254);
+ case int('c'): // TODO: grochar
+ *u = scale(*u, (units_per_inch * 100), (divisor * 254));
break;
- case 0:
- case 'u':
+ case int(0): // TODO: grochar; null character, not digit zero
+ case int('u'): // TODO: grochar
if (divisor != 1)
*u /= divisor;
break;
- case 'f':
+ case int('f'): // TODO: grochar
*u = scale(*u, 65536, divisor);
break;
- case 'p':
+ case int('p'): // TODO: grochar
*u = scale(*u, units_per_inch, divisor * 72);
break;
- case 'P':
+ case int('P'): // TODO: grochar
*u = scale(*u, units_per_inch, divisor * 6);
break;
- case 'm':
+ case int('m'): // TODO: grochar
{
// Convert to hunits so that with -Tascii 'm' behaves as in nroff.
hunits em = curenv->get_size();
@@ -595,14 +599,14 @@ static bool is_valid_term(units *u, int scaling_unit,
divisor);
}
break;
- case 'M':
+ case int('M'): // TODO: grochar
{
hunits em = curenv->get_size();
*u = scale(*u, em.is_zero() ? hresolution : em.to_units(),
(divisor * 100));
}
break;
- case 'n':
+ case int('n'): // TODO: grochar
{
// Convert to hunits so that with -Tascii 'n' behaves as in nroff.
hunits en = curenv->get_size() / 2;
@@ -610,17 +614,17 @@ static bool is_valid_term(units *u, int scaling_unit,
divisor);
}
break;
- case 'v':
+ case int('v'): // TODO: grochar
*u = scale(*u, curenv->get_vertical_spacing().to_units(), divisor);
break;
- case 's':
+ case int('s'): // TODO: grochar
while (divisor > INT_MAX / (sizescale * 72)) {
divisor /= 10;
*u /= 10;
}
*u = scale(*u, units_per_inch, divisor * sizescale * 72);
break;
- case 'z':
+ case int('z'): // TODO: grochar
*u = scale(*u, sizescale, divisor);
break;
default:
@@ -637,18 +641,17 @@ static bool is_valid_term(units *u, int scaling_unit,
units scale(units n, units x, units y)
{
- assert(x >= 0 && y > 0);
+ assert(x >= 0);
+ assert(y > 0);
if (0 == x)
return 0;
if (n >= 0) {
- if (n <= INT_MAX / x)
- return (n * x) / y;
+ if (n <= (INT_MAX / x))
+ return ((n * x) / y);
}
else {
- // I'd prefer to say "(unsigned int(n))", but C++ doesn't seem to
- // permit function-style construction with a type qualifier. --GBR
- if (-(unsigned(n)) <= -(unsigned(INT_MIN)) / x)
- return (n * x) / y;
+ if ((-(unsigned int)(n)) <= ((-(unsigned int)(INT_MIN)) / x))
+ return ((n * x) / y);
}
double res = n * double(x) / double(y);
if (res > INT_MAX) {
@@ -659,7 +662,7 @@ units scale(units n, units x, units y)
warning(WARN_RANGE, "integer value saturated");
return INT_MIN;
}
- return int(res);
+ return units(res);
}
vunits::vunits(units x)
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit