X-Git-Url: https://git.cameronkatri.com/bsdgames-darwin.git/blobdiff_plain/be1c32e4fa4b1b23ec06fbba9266e0f67f20913f..1c75ca2e2dc72d118edbb854455e602d70d80a52:/factor/factor.c diff --git a/factor/factor.c b/factor/factor.c index 670e8968..6329ec79 100644 --- a/factor/factor.c +++ b/factor/factor.c @@ -1,5 +1,4 @@ -/* $NetBSD: factor.c,v 1.20 2010/04/22 14:28:48 drochner Exp $ */ - +/* $NetBSD: factor.c,v 1.38 2020/10/12 13:54:51 christos Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -32,17 +31,20 @@ * SUCH DAMAGE. */ -#include #ifndef lint +#include +#ifdef __COPYRIGHT __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)factor.c 8.4 (Berkeley) 5/4/95"; -#else -__RCSID("$NetBSD: factor.c,v 1.20 2010/04/22 14:28:48 drochner Exp $"); + The Regents of the University of California. All rights reserved."); +#endif +#ifdef __SCCSID +__SCCSID("@(#)factor.c 8.4 (Berkeley) 5/4/95"); +#endif +#ifdef __RCSID +__RCSID("$NetBSD: factor.c,v 1.38 2020/10/12 13:54:51 christos Exp $"); +#endif +#ifdef __FBSDID +__FBSDID("$FreeBSD: head/usr.bin/factor/factor.c 356666 2020-01-12 20:25:11Z gad $"); #endif #endif /* not lint */ @@ -54,7 +56,7 @@ __RCSID("$NetBSD: factor.c,v 1.20 2010/04/22 14:28:48 drochner Exp $"); * chongo /\oo/\ * * usage: - * factor [number] ... + * factor [-hx] [number] ... * * The form of the output is: * @@ -62,90 +64,88 @@ __RCSID("$NetBSD: factor.c,v 1.20 2010/04/22 14:28:48 drochner Exp $"); * * where factor1 <= factor2 <= factor3 <= ... * - * If no args are given, the list of numbers are read from stdin. + * If the -h flag is specified, the output is in "human-readable" format. + * Duplicate factors are printed in the form of x^n. + * + * If the -x flag is specified numbers are printed in hex. + * + * If no number args are given, the list of numbers are read from stdin. */ #include #include #include +#include #include +#include #include #include #include +#include "primes.h" + #ifdef HAVE_OPENSSL + #include + +#define PRIME_CHECKS 5 + +/* print factors for big numbers */ +static void pollard_pminus1(BIGNUM *, int, int); + #else + typedef long BIGNUM; typedef u_long BN_ULONG; -static int BN_dec2bn(BIGNUM **a, const char *str); -#define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1)) -#define BN_is_zero(v) (*(v) == 0) -#define BN_is_one(v) (*(v) == 1) -#define BN_new() ((BIGNUM *)calloc(sizeof(BIGNUM), 1)) + +#define BN_CTX int +#define BN_CTX_new() NULL +#define BN_new() calloc(sizeof(BIGNUM), 1) +#define BN_free(a) free(a) + +#define BN_copy(a, b) *(a) = *(b) +#define BN_cmp(a, b) (*(a) - *(b)) #define BN_is_zero(v) (*(v) == 0) #define BN_is_one(v) (*(v) == 1) #define BN_mod_word(a, b) (*(a) % (b)) -#endif - -#include "primes.h" - -/* - * prime[i] is the (i-1)th prime. - * - * We are able to sieve 2^32-1 because this byte table yields all primes - * up to 65537 and 65537^2 > 2^32-1. - */ -extern const ubig prime[]; -extern const ubig *pr_limit; /* largest prime in the prime array */ - -#define PRIME_CHECKS 5 - -#ifdef HAVE_OPENSSL -static BN_CTX *ctx; /* just use a global context */ -#endif -static void pr_fact(BIGNUM *); /* print factors of a value */ -static void BN_print_dec_fp(FILE *, const BIGNUM *); -static void usage(void) __dead; -#ifdef HAVE_OPENSSL -static void pollard_pminus1(BIGNUM *); /* print factors for big numbers */ -#else -static char *BN_bn2dec(const BIGNUM *); +static BIGNUM *BN_dup(const BIGNUM *); +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 void pr_fact(BIGNUM *, int, int); /* print factors of a value */ +static void pr_print(BIGNUM *, int, int); /* print a prime */ +static void usage(void) __dead; -#ifndef HAVE_OPENSSL -static int -BN_dec2bn(BIGNUM **a, const char *str) -{ - char *p; - - errno = 0; - **a = strtoul(str, &p, 10); - if (errno) - err(1, "%s", str); - return (*p == '\n' || *p == '\0'); -} -#endif +static BN_CTX *ctx; /* just use a global context */ int main(int argc, char *argv[]) { BIGNUM *val; - int ch; + int ch, hflag, xflag; char *p, buf[LINE_MAX]; /* > max number of digits. */ -#ifdef HAVE_OPENSSL + hflag = xflag = 0; ctx = BN_CTX_new(); -#endif val = BN_new(); if (val == NULL) errx(1, "can't initialise bignum"); - while ((ch = getopt(argc, argv, "")) != -1) + while ((ch = getopt(argc, argv, "hx")) != -1) switch (ch) { + case 'h': + hflag++; + break; + case 'x': + xflag++; + break; case '?': default: usage(); @@ -161,44 +161,52 @@ main(int argc, char *argv[]) err(1, "stdin"); exit (0); } - for (p = buf; isblank(*p); ++p); + for (p = buf; isblank((unsigned char)*p); ++p); if (*p == '\n' || *p == '\0') continue; - if (*p == '-') - errx(1, "negative numbers aren't permitted."); - if (BN_dec2bn(&val, buf) == 0) - errx(1, "%s: illegal numeric format.", argv[0]); - pr_fact(val); + convert_str2bn(&val, p); + pr_fact(val, hflag, xflag); } /* 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) - errx(1, "%s: illegal numeric format.", argv[0]); - pr_fact(val); + for (p = *argv; p != NULL; p = *++argv) { + convert_str2bn(&val, p); + pr_fact(val, hflag, xflag); } exit(0); } +static void +pr_exp(int i, int xflag) +{ + printf(xflag && i > 9 ? "^0x%x" : "^%d", i); +} + +static void +pr_uint64(uint64_t i, int xflag) +{ + printf(xflag ? " 0x%" PRIx64 : " %" PRIu64, i); +} + /* * pr_fact - print the factors of a number * - * If the number is 0 or 1, then print the number and return. - * If the number is < 0, print -1, negate the number and continue - * processing. - * * Print the factors of the number, from the lowest to the highest. - * A factor will be printed numtiple times if it divides the value + * A factor will be printed multiple times if it divides the value * multiple times. * + * If hflag is specified, duplicate factors are printed in "human- + * readable" form of x^n. + * + * If the xflag is specified, numbers will be printed in hex. + * * Factors are printed with leading tabs. */ static void -pr_fact(BIGNUM *val) +pr_fact(BIGNUM *val, int hflag, int xflag) { - const ubig *fact; /* The factor found. */ + int i; + const uint64_t *fact; /* The factor found. */ /* Firewall - catch 0 and 1. */ if (BN_is_zero(val)) /* Historical practice; 0 just exits. */ @@ -210,15 +218,19 @@ pr_fact(BIGNUM *val) /* Factor value. */ - BN_print_dec_fp(stdout, val); + if (xflag) { + fputs("0x", stdout); + BN_print_fp(stdout, val); + } else + BN_print_dec_fp(stdout, val); putchar(':'); + fflush(stdout); for (fact = &prime[0]; !BN_is_one(val); ++fact) { /* Look for the smallest factor. */ - while (fact <= pr_limit) { + do { if (BN_mod_word(val, (BN_ULONG)*fact) == 0) break; - fact++; - } + } while (++fact <= pr_limit); /* Watch for primes larger than the table. */ if (fact > pr_limit) { @@ -227,62 +239,99 @@ pr_fact(BIGNUM *val) bnfact = BN_new(); BN_set_word(bnfact, *(fact - 1)); - BN_sqr(bnfact, bnfact, ctx); - if (BN_cmp(bnfact, val) > 0 - || BN_is_prime(val, PRIME_CHECKS, NULL, NULL, - NULL) == 1) { - putchar(' '); - BN_print_dec_fp(stdout, val); - } else - pollard_pminus1(val); + if (!BN_sqr(bnfact, bnfact, ctx)) + errx(1, "error in BN_sqr()"); + if (BN_cmp(bnfact, val) > 0 || + BN_is_prime_ex(val, PRIME_CHECKS, NULL, NULL) == 1) + pr_print(val, hflag, xflag); + else + pollard_pminus1(val, hflag, xflag); #else - printf(" %s", BN_bn2dec(val)); + pr_print(val, hflag, xflag); #endif + pr_print(NULL, hflag, xflag); break; } /* Divide factor out until none are left. */ + i = 0; do { - printf(" %lu", *fact); + i++; + if (!hflag) + pr_uint64(*fact, xflag); BN_div_word(val, (BN_ULONG)*fact); } while (BN_mod_word(val, (BN_ULONG)*fact) == 0); + if (hflag) { + pr_uint64(*fact, xflag); + if (i > 1) + pr_exp(i, xflag); + } + /* Let the user know we're doing something. */ fflush(stdout); } putchar('\n'); } -/* - * Sigh.. No _decimal_ output to file functions in BN. - */ static void -BN_print_dec_fp(FILE *fp, const BIGNUM *num) +pr_print(BIGNUM *val, int hflag, int xflag) { - char *buf; - - buf = BN_bn2dec(num); - if (buf == NULL) - return; /* XXX do anything here? */ - fprintf(fp, buf); - free(buf); + static BIGNUM *sval; + static int ex = 1; + BIGNUM *pval; + + if (hflag) { + if (sval == NULL) { + sval = BN_dup(val); + return; + } + + if (val != NULL && BN_cmp(val, sval) == 0) { + ex++; + return; + } + pval = sval; + } else if (val == NULL) { + return; + } else { + pval = val; + } + + if (xflag) { + fputs(" 0x", stdout); + BN_print_fp(stdout, pval); + } else { + putchar(' '); + BN_print_dec_fp(stdout, pval); + } + + if (hflag) { + if (ex > 1) + pr_exp(ex, xflag); + + if (val != NULL) { + BN_copy(sval, val); + } else { + BN_free(sval); + sval = NULL; + } + ex = 1; + } } -void +static void usage(void) { - fprintf(stderr, "usage: factor [value ...]\n"); - exit (0); + fprintf(stderr, "Usage: %s [-hx] [value ...]\n", getprogname()); + exit(1); } - - - #ifdef HAVE_OPENSSL -/* pollard p-1, algorithm from Jim Gillogly, May 2000 */ +/* pollard p-1, algorithm from Jim Gillogly, May 2000 */ static void -pollard_pminus1(BIGNUM *val) +pollard_pminus1(BIGNUM *val, int hflag, int xflag) { BIGNUM *base, *rbase, *num, *i, *x; @@ -293,8 +342,9 @@ pollard_pminus1(BIGNUM *val) x = BN_new(); BN_set_word(rbase, 1); - newbase: - BN_add_word(rbase, 1); +newbase: + if (!BN_add_word(rbase, 1)) + errx(1, "error in BN_add_word()"); BN_set_word(i, 2); BN_copy(base, rbase); @@ -305,43 +355,79 @@ pollard_pminus1(BIGNUM *val) BN_copy(x, base); BN_sub_word(x, 1); - BN_gcd(x, x, val, ctx); + if (!BN_gcd(x, x, val, ctx)) + errx(1, "error in BN_gcd()"); if (!BN_is_one(x)) { - if (BN_is_prime(x, PRIME_CHECKS, NULL, NULL, - NULL) == 1) { - putchar(' '); - BN_print_dec_fp(stdout, x); - } else - pollard_pminus1(x); + if (BN_is_prime_ex(x, PRIME_CHECKS, NULL, NULL) == 1) + pr_print(x, hflag, xflag); + else + pollard_pminus1(x, hflag, xflag); fflush(stdout); BN_div(num, NULL, val, x, ctx); if (BN_is_one(num)) return; - if (BN_is_prime(num, PRIME_CHECKS, NULL, NULL, + if (BN_is_prime_ex(num, PRIME_CHECKS, NULL, NULL) == 1) { - putchar(' '); - BN_print_dec_fp(stdout, num); + pr_print(num, hflag, xflag); fflush(stdout); return; } BN_copy(val, num); } - BN_add_word(i, 1); + if (!BN_add_word(i, 1)) + errx(1, "error in BN_add_word()"); } } -#else -char * -BN_bn2dec(const BIGNUM *val) + +/* + * Sigh.. No _decimal_ output to file functions in BN. + */ +static void +BN_print_dec_fp(FILE *fp, const BIGNUM *num) { char *buf; - buf = malloc(100); - if (!buf) - return buf; - snprintf(buf, 100, "%ld", (long)*val); - return buf; + buf = BN_bn2dec(num); + if (buf == NULL) + return; /* XXX do anything here? */ + fprintf(fp, "%s", buf); + free(buf); +} + +#else + +static void +BN_print_fp(FILE *fp, const BIGNUM *num) +{ + fprintf(fp, "%lx", (unsigned long)*num); +} + +static void +BN_print_dec_fp(FILE *fp, const BIGNUM *num) +{ + fprintf(fp, "%lu", (unsigned long)*num); +} + +static int +BN_dec2bn(BIGNUM **a, const char *str) +{ + char *p; + + errno = 0; + **a = strtoul(str, &p, 10); + return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */ +} + +static int +BN_hex2bn(BIGNUM **a, const char *str) +{ + char *p; + + errno = 0; + **a = strtoul(str, &p, 16); + return (errno == 0 ? 1 : 0); /* OpenSSL returns 0 on error! */ } static BN_ULONG @@ -353,4 +439,31 @@ BN_div_word(BIGNUM *a, BN_ULONG b) *a /= b; return mod; } + +static BIGNUM * +BN_dup(const BIGNUM *a) +{ + BIGNUM *b = BN_new(); + BN_copy(b, a); + return b; +} + #endif + +/* 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[1] == 'x' || p[1] == 'X')) { + n = BN_hex2bn(val, p + 2); + } else { + n = BN_dec2bn(val, p); + } + if (n == 0) + errx(1, "%s: illegal numeric format.", p); +}