source@mandoc.bsd.lv
 help / color / mirror / Atom feed
From: schwarze@mandoc.bsd.lv
To: source@mandoc.bsd.lv
Subject: mandoc: Even though roff(7) numerical expressions use integer arithmetic
Date: Mon, 6 Jan 2025 18:50:21 +0000 (UTC)	[thread overview]
Message-ID: <9500a3aca8c768a9@mandoc.bsd.lv> (raw)

Log Message:
-----------
Even though roff(7) numerical expressions use integer arithmetic throughout
and all numbers are rounded down before any arithmetic operation is attempted,  
let the number parser support decimal fractions in front of scaling units,
which is useful for all scaling units except basic units ('u').

For example, this allows 0.25i = 2.5n = 60u.
On the other hand, even though 3p = 10u, we get 1p+1p+1p = 1p*3 = 9u
because arithmetic operations do not support floating point,
so the intermediate result gets rounded down as 1p = 3.33u = 3u.

Modified Files:
--------------
    mandoc:
        roff.c
    mandoc/regress/roff/nr:
        scale.in
        scale.out_ascii

Revision Data
-------------
Index: roff.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/roff.c,v
diff -Lroff.c -Lroff.c -u -p -r1.403 -r1.404
--- roff.c
+++ roff.c
@@ -2422,7 +2422,7 @@ roff_cond_text(ROFF_ARGS)
 /* --- handling of numeric and conditional expressions -------------------- */
 
 /*
- * Parse a single signed integer number.  Stop at the first non-digit.
+ * Parse a single signed decimal number.  Stop at the first non-digit.
  * If there is at least one digit, return success and advance the
  * parse point, else return failure and let the parse point unchanged.
  * Ignore overflows, treat them just like the C language.
@@ -2430,10 +2430,8 @@ roff_cond_text(ROFF_ARGS)
 static int
 roff_getnum(const char *v, int *pos, int *res, char unit, int skipspace)
 {
-	int	 myres, n, p;
-
-	if (NULL == res)
-		res = &myres;
+	double	 frac, myres;
+	int	 n, p;
 
 	p = *pos;
 	n = v[p] == '-';
@@ -2444,13 +2442,17 @@ roff_getnum(const char *v, int *pos, int
 		while (isspace((unsigned char)v[p]))
 			p++;
 
-	for (*res = 0; isdigit((unsigned char)v[p]); p++)
-		*res = 10 * *res + v[p] - '0';
+	for (myres = 0.0; isdigit((unsigned char)v[p]); p++)
+		myres = myres * 10.0 + (v[p] - '0');
+	if (v[p] == '.')
+		for (frac = 0.1; isdigit((unsigned char)v[++p]); frac *= 0.1)
+			myres += frac * (v[p] - '0');
+
 	if (p == *pos + n)
 		return 0;
 
 	if (n)
-		*res = -*res;
+		myres *= -1.0;
 
 	/* Each number may be followed by one optional scaling unit. */
 
@@ -2462,36 +2464,35 @@ roff_getnum(const char *v, int *pos, int
 
 	switch (unit) {
 	case 'f':
-		*res *= 65536;
+		myres *= 65536.0;
 		break;
 	case 'i':
-		*res *= 240;
+		myres *= 240.0;
 		break;
 	case 'c':
-		*res *= 24000;
-		*res /= 254;
+		myres *= 240.0 / 2.54;
 		break;
 	case 'v':
 	case 'P':
-		*res *= 40;
+		myres *= 40.0;
 		break;
 	case 'm':
 	case 'n':
-		*res *= 24;
+		myres *= 24.0;
 		break;
 	case 'p':
-		*res *= 10;
-		*res /= 3;
+		myres *= 40.0 / 12.0;
 		break;
 	case 'u':
 		break;
 	case 'M':
-		*res *= 6;
-		*res /= 25;
+		myres *= 24.0 / 100.0;
 		break;
 	default:
 		break;
 	}
+	if (res != NULL)
+		*res = myres;
 	*pos = p;
 	return 1;
 }
Index: scale.out_ascii
===================================================================
RCS file: /home/cvs/mandoc/mandoc/regress/roff/nr/scale.out_ascii,v
diff -Lregress/roff/nr/scale.out_ascii -Lregress/roff/nr/scale.out_ascii -u -p -r1.3 -r1.4
--- regress/roff/nr/scale.out_ascii
+++ regress/roff/nr/scale.out_ascii
@@ -6,4 +6,8 @@ N\bNA\bAM\bME\bE
 D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
      65537 241 945 41 41 25 25 34 2 25 1
 
-OpenBSD                        January 23, 2015                      NR-INT(1)
+     0.001f = 65u; 0.1i = 24u; 0.1c = 9u; 0.25P = 10u; 0.6p = 2u
+
+     3p = 10u; 1p+1p+1p = 9u; 1p*3 = 9u
+
+OpenBSD                         January 6, 2025                      NR-INT(1)
Index: scale.in
===================================================================
RCS file: /home/cvs/mandoc/mandoc/regress/roff/nr/scale.in,v
diff -Lregress/roff/nr/scale.in -Lregress/roff/nr/scale.in -u -p -r1.2 -r1.3
--- regress/roff/nr/scale.in
+++ regress/roff/nr/scale.in
@@ -1,5 +1,5 @@
-.\" $OpenBSD: scale.in,v 1.2 2017/07/04 14:53:27 schwarze Exp $
-.TH NR-INT 1 "January 23, 2015"
+.\" $OpenBSD: scale.in,v 1.3 2025/01/06 18:48:13 schwarze Exp $
+.TH NR-INT 1 "January 6, 2025"
 .SH NAME
 nr-scale \- scaling units in numeric expressions
 .SH DESCRIPTION
@@ -25,3 +25,21 @@ nr-scale \- scaling units in numeric exp
 \nY
 .nr Y 1X+2
 \nY
+.PP
+.nr Y 0.001f
+0.001f = \nYu;
+.nr Y 0.1i
+0.1i = \nYu;
+.nr Y 0.1c
+0.1c = \nYu;
+.nr Y 0.25P
+0.25P = \nYu;
+.nr Y 0.6p
+0.6p = \nYu
+.PP
+.nr Y 3p
+3p = \nYu;
+.nr Y 1p+1p+1p
+1p+1p+1p = \nYu;
+.nr Y 1p*3
+1p*3 = \nYu
--
 To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv


                 reply	other threads:[~2025-01-06 18:50 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9500a3aca8c768a9@mandoc.bsd.lv \
    --to=schwarze@mandoc.bsd.lv \
    --cc=source@mandoc.bsd.lv \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).