Fix the way 'factor' behaves when using OpenSSL to match the description

of how it works when not compiled with OpenSSL.

Also, allow users to specify a hexadecimal number by using a prefix of
'0x'.  Before this, users could only specify a hexadecimal value if that
value included a hex digit ('a'-'f') in the value.

PR:		243136
Submitted by:	Steve Kargl
Reviewed by:	gad
MFC after:	3 weeks
This commit is contained in:
Garance A Drosehn 2020-01-12 20:25:11 +00:00
parent fe1274ee39
commit 526473251e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356666
3 changed files with 69 additions and 21 deletions

View File

@ -36,7 +36,7 @@
.\"
.\" chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
.\"
.Dd October 10, 2002
.Dd January 12, 2020
.Dt FACTOR 6
.Os
.Sh NAME
@ -67,11 +67,22 @@ When
.Nm
is invoked with no arguments,
.Nm
reads numbers, one per line, from standard input, until end of file or error.
reads numbers, one per line, from standard input until end of file or 0
is entered or an error occurs.
Leading white-space and empty lines are ignored.
.Pp
Numbers may be preceded by a single
.Ql + .
Numbers can be either decimal or hexadecimal strings where the longest
leading substring is used.
Numbers are terminated by a non-digit character (such as a newline).
If the string contains only decimal digits, it is treated as a
decimal representation for a number.
A hexadecimal string can contain an optional
.Em 0x
or
.Em 0X
prefix.
After a number is read, it is factored.
.Pp
The
@ -89,7 +100,7 @@ The
value must not be greater than the maximum.
The default and maximum value of
.Ar stop
is 3825123056546413050.
is 18446744073709551615.
.Pp
When the
.Nm primes

View File

@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -97,15 +98,16 @@ typedef u_long BN_ULONG;
#define BN_is_one(v) (*(v) == 1)
#define BN_mod_word(a, b) (*(a) % (b))
static int BN_dec2bn(BIGNUM **a, const char *str);
static int BN_hex2bn(BIGNUM **a, const char *str);
static int BN_dec2bn(BIGNUM **, const char *);
static int BN_hex2bn(BIGNUM **, const char *);
static BN_ULONG BN_div_word(BIGNUM *, BN_ULONG);
static void BN_print_fp(FILE *, const BIGNUM *);
#endif
static void BN_print_dec_fp(FILE *, const BIGNUM *);
static void convert_str2bn(BIGNUM **, char *);
static bool is_hex_str(char *);
static void pr_fact(BIGNUM *); /* print factors of a value */
static void pr_print(BIGNUM *); /* print a prime */
static void usage(void);
@ -148,21 +150,13 @@ main(int argc, char *argv[])
for (p = buf; isblank(*p); ++p);
if (*p == '\n' || *p == '\0')
continue;
if (*p == '-')
errx(1, "negative numbers aren't permitted.");
if (BN_dec2bn(&val, buf) == 0 &&
BN_hex2bn(&val, buf) == 0)
errx(1, "%s: illegal numeric format.", buf);
convert_str2bn(&val, p);
pr_fact(val);
}
/* Factor the arguments. */
else
for (; *argv != NULL; ++argv) {
if (argv[0][0] == '-')
errx(1, "negative numbers aren't permitted.");
if (BN_dec2bn(&val, argv[0]) == 0 &&
BN_hex2bn(&val, argv[0]) == 0)
errx(1, "%s: illegal numeric format.", argv[0]);
for (p = *argv; p != NULL; p = *++argv) {
convert_str2bn(&val, p);
pr_fact(val);
}
exit(0);
@ -346,7 +340,7 @@ BN_dec2bn(BIGNUM **a, const char *str)
errno = 0;
**a = strtoul(str, &p, 10);
return (errno == 0 && (*p == '\n' || *p == '\0'));
return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */
}
static int
@ -356,7 +350,7 @@ BN_hex2bn(BIGNUM **a, const char *str)
errno = 0;
**a = strtoul(str, &p, 16);
return (errno == 0 && (*p == '\n' || *p == '\0'));
return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */
}
static BN_ULONG
@ -370,3 +364,46 @@ BN_div_word(BIGNUM *a, BN_ULONG b)
}
#endif
/*
* Scan the string from left-to-right to see if the longest substring
* is a valid hexadecimal number.
*/
static bool
is_hex_str(char *str)
{
char c, *p;
bool saw_hex = false;
for (p = str; *p; p++) {
if (isdigit(*p))
continue;
c = tolower(*p);
if (c >= 'a' && c <= 'f') {
saw_hex = true;
continue;
}
break; /* Not a hexadecimal digit. */
}
return saw_hex;
}
/* Convert string pointed to by *str to a bignum. */
static void
convert_str2bn(BIGNUM **val, char *p)
{
int n = 0;
if (*p == '+') p++;
if (*p == '-')
errx(1, "negative numbers aren't permitted.");
if (*p == '0') {
p++;
if (*p == 'x' || *p == 'X')
n = BN_hex2bn(val, ++p);
} else {
n = is_hex_str(p) ? BN_hex2bn(val, p) : BN_dec2bn(val, p);
}
if (n == 0)
errx(1, "%s: illegal numeric format.", p);
}

View File

@ -55,8 +55,8 @@ static const char rcsid[] =
* primes [-h] [start [stop]]
*
* Print primes >= start and < stop. If stop is omitted,
* the value 4294967295 (2^32-1) is assumed. If start is
* omitted, start is read from standard input.
* the value 18446744073709551615 (2^64-1) is assumed. If
* start is omitted, start is read from standard input.
*
* validation check: there are 664579 primes between 0 and 10^7
*/