Added errno.h to includes.
[unix-history] / usr / src / games / factor / factor.c
CommitLineData
bc2e2efb
KB
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Landon Curt Noll.
7 *
badc70cc 8 * %sccs.include.redist.c%
bc2e2efb
KB
9 */
10
6708b7e4 11#ifndef lint
bc2e2efb
KB
12char copyright[] =
13"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
14 All rights reserved.\n";
15#endif /* not lint */
16
17#ifndef lint
badc70cc 18static char sccsid[] = "@(#)factor.c 4.4 (Berkeley) %G%";
bc2e2efb
KB
19#endif /* not lint */
20
21/*
22 * factor - factor a number into primes
23 *
24 * By: Landon Curt Noll chongo@toad.com, ...!{sun,tolsoft}!hoptoad!chongo
25 *
26 * chongo <for a good prime call: 391581 * 2^216193 - 1> /\oo/\
27 *
28 * usage:
29 * factor [number] ...
30 *
18a3e3ca 31 * The form of the output is:
bc2e2efb 32 *
18a3e3ca
KB
33 * number: factor1 factor1 factor2 factor3 factor3 factor3 ...
34 *
35 * where factor1 < factor2 < factor3 < ...
36 *
37 * If no args are given, the list of numbers are read from stdin.
bc2e2efb
KB
38 */
39
40#include <stdio.h>
41#include <ctype.h>
42#include "primes.h"
6708b7e4
SL
43
44/*
bc2e2efb 45 * prime[i] is the (i-1)th prime.
6708b7e4 46 *
bc2e2efb
KB
47 * We are able to sieve 2^32-1 because this byte table yields all primes
48 * up to 65537 and 65537^2 > 2^32-1.
6708b7e4 49 */
bc2e2efb
KB
50extern ubig prime[];
51extern ubig *pr_limit; /* largest prime in the prime array */
52
53#define MAX_LINE 255 /* max line allowed on stdin */
54
55void pr_fact(); /* print factors of a value */
56long small_fact(); /* find smallest factor of a value */
57char *read_num_buf(); /* read a number buffer */
58char *program; /* name of this program */
6708b7e4
SL
59
60main(argc, argv)
bc2e2efb
KB
61 int argc; /* arg count */
62 char *argv[]; /* the args */
6708b7e4 63{
bc2e2efb
KB
64 int arg; /* which arg to factor */
65 long val; /* the value to factor */
66 char buf[MAX_LINE+1]; /* input buffer */
6708b7e4 67
bc2e2efb
KB
68 /* parse args */
69 program = argv[0];
6708b7e4 70 if (argc >= 2) {
bc2e2efb
KB
71
72 /* factor each arg */
73 for (arg=1; arg < argc; ++arg) {
74
75 /* process the buffer */
76 if (read_num_buf(NULL, argv[arg]) == NULL) {
77 fprintf(stderr, "%s: ouch\n", program);
78 exit(1);
79 }
80
81 /* factor the argument */
82 if (sscanf(argv[arg], "%ld", &val) == 1) {
83 pr_fact(val);
84 } else {
85 fprintf(stderr, "%s: ouch\n", program);
86 exit(1);
87 }
88 }
89
90 /* no args supplied, read numbers from stdin */
6708b7e4 91 } else {
bc2e2efb
KB
92 /*
93 * read asciii numbers from input
94 */
95 while (read_num_buf(stdin, buf) != NULL) {
96
97 /* factor the argument */
98 if (sscanf(buf, "%ld", &val) == 1) {
99 pr_fact(val);
100 }
101 }
6708b7e4 102 }
bc2e2efb 103 exit(0);
6708b7e4
SL
104}
105
106/*
bc2e2efb
KB
107 * read_num_buf - read a number buffer from a stream
108 *
109 * Read a number on a line of the form:
110 *
111 * ^[ \t]*\([+-]?[0-9][0-9]\)*.*$
112 *
113 * where ? is a 1-or-0 operator and the number is within \( \).
114 *
115 * If does not match the above pattern, it is ignored and a new
116 * line is read. If the number is too large or small, we will
117 * print ouch and read a new line.
118 *
119 * We have to be very careful on how we check the magnitude of the
120 * input. We can not use numeric checks because of the need to
121 * check values against maximum numeric values.
122 *
123 * This routine will return a line containing a ascii number between
124 * NEG_SEMIBIG and SEMIBIG, or it will return NULL.
125 *
126 * If the stream is NULL then buf will be processed as if were
127 * a single line stream.
128 *
129 * returns:
130 * char * pointer to leading digit, + or -
131 * NULL EOF or error
6708b7e4 132 */
bc2e2efb
KB
133char *
134read_num_buf(input, buf)
135 FILE *input; /* input stream or NULL */
136 char *buf; /* input buffer */
6708b7e4 137{
bc2e2efb
KB
138 static char limit[MAX_LINE+1]; /* ascii value of SEMIBIG */
139 static int limit_len; /* digit count of limit */
140 static char neg_limit[MAX_LINE+1]; /* value of NEG_SEMIBIG */
141 static int neg_limit_len; /* digit count of neg_limit */
142 int len; /* digits in input (excluding +/-) */
143 char *s; /* line start marker */
144 char *d; /* first digit, skip +/- */
145 char *p; /* scan pointer */
146 char *z; /* zero scan pointer */
147
148 /* form the ascii value of SEMIBIG if needed */
149 if (!isascii(limit[0]) || !isdigit(limit[0])) {
150 sprintf(limit, "%ld", SEMIBIG);
151 limit_len = strlen(limit);
152 sprintf(neg_limit, "%ld", NEG_SEMIBIG);
153 neg_limit_len = strlen(neg_limit)-1; /* exclude - */
154 }
155
156 /*
157 * the search for a good line
158 */
159 if (input != NULL && fgets(buf, MAX_LINE, input) == NULL) {
160 /* error or EOF */
161 return NULL;
6708b7e4 162 }
bc2e2efb
KB
163 do {
164
165 /* ignore leading whitespace */
166 for (s=buf; *s && s < buf+MAX_LINE; ++s) {
167 if (!isascii(*s) || !isspace(*s)) {
168 break;
169 }
170 }
171
172 /* skip over any leading + or - */
173 if (*s == '+' || *s == '-') {
174 d = s+1;
175 } else {
176 d = s;
177 }
178
179 /* note leading zeros */
180 for (z=d; *z && z < buf+MAX_LINE; ++z) {
181 if (*z != '0') {
182 break;
183 }
184 }
185
186 /* scan for the first non-digit */
187 for (p=d; *p && p < buf+MAX_LINE; ++p) {
188 if (!isascii(*p) || !isdigit(*p)) {
189 break;
190 }
191 }
192
193 /* ignore empty lines */
194 if (p == d) {
195 continue;
196 }
197 *p = '\0';
198
199 /* object if too many digits */
200 len = strlen(z);
201 len = (len<=0) ? 1 : len;
202 if (*s == '-') {
203 /* accept if digit count is below limit */
204 if (len < neg_limit_len) {
205 /* we have good input */
206 return s;
207
208 /* reject very large numbers */
209 } else if (len > neg_limit_len) {
210 fprintf(stderr, "%s: ouch\n", program);
211 exit(1);
212
213 /* carefully check against near limit numbers */
214 } else if (strcmp(z, neg_limit+1) > 0) {
215 fprintf(stderr, "%s: ouch\n", program);
216 exit(1);
217 }
218 /* number is near limit, but is under it */
219 return s;
220
221 } else {
222 /* accept if digit count is below limit */
223 if (len < limit_len) {
224 /* we have good input */
225 return s;
226
227 /* reject very large numbers */
228 } else if (len > limit_len) {
229 fprintf(stderr, "%s: ouch\n", program);
230 exit(1);
231
232 /* carefully check against near limit numbers */
233 } else if (strcmp(z, limit) > 0) {
234 fprintf(stderr, "%s: ouch\n", program);
235 exit(1);
236 }
237 /* number is near limit, but is under it */
238 return s;
239 }
240 } while (input != NULL && fgets(buf, MAX_LINE, input) != NULL);
241
242 /* error or EOF */
243 return NULL;
6708b7e4
SL
244}
245
bc2e2efb 246
6708b7e4 247/*
bc2e2efb
KB
248 * pr_fact - print the factors of a number
249 *
250 * If the number is 0 or 1, then print the number and return.
251 * If the number is < 0, print -1, negate the number and continue
252 * processing.
253 *
254 * Print the factors of the number, from the lowest to the highest.
255 * A factor will be printed numtiple times if it divides the value
256 * multiple times.
6708b7e4 257 *
bc2e2efb 258 * Factors are printed with leading tabs.
6708b7e4 259 */
bc2e2efb
KB
260void
261pr_fact(val)
262 long val; /* factor this value */
6708b7e4 263{
bc2e2efb
KB
264 ubig *fact; /* the factor found */
265
266 /* firewall - catch 0 and 1 */
267 switch (val) {
268 case -2147483648:
269 /* avoid negation problems */
270 puts("-2147483648: -1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\n");
271 return;
272 case -1:
273 puts("-1: -1\n");
274 return;
275 case 0:
276 exit(0);
277 case 1:
278 puts("1: 1\n");
279 return;
280 default:
281 if (val < 0) {
282 val = -val;
283 printf("%ld: -1", val);
284 } else {
285 printf("%ld:", val);
6708b7e4 286 }
bc2e2efb
KB
287 fflush(stdout);
288 break;
6708b7e4
SL
289 }
290
bc2e2efb
KB
291 /*
292 * factor value
293 */
294 fact = &prime[0];
295 while (val > 1) {
6708b7e4 296
bc2e2efb
KB
297 /* look for the smallest factor */
298 do {
299 if (val%(long)*fact == 0) {
300 break;
6708b7e4 301 }
bc2e2efb 302 } while (++fact <= pr_limit);
6708b7e4 303
bc2e2efb
KB
304 /* watch for primes larger than the table */
305 if (fact > pr_limit) {
306 printf(" %ld\n", val);
307 return;
308 }
6708b7e4 309
bc2e2efb
KB
310 /* divide factor out until none are left */
311 do {
312 printf(" %ld", *fact);
313 val /= (long)*fact;
314 } while ((val % (long)*fact) == 0);
315 fflush(stdout);
316 ++fact;
317 }
318 putchar('\n');
319 return;
6708b7e4 320}