Files
haiku-beta6/src/bin/factor.cpp
T

316 lines
6.4 KiB
C++
Raw Normal View History

2004-01-10 22:07:53 +00:00
/*
** Copyright (c) 2004 OBOS
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
*/
/*
** Thanks go to:
** Eli Dayan, Jeremy Friesner, Jonathan Thompson,
** Matthijs Hollemans, Jack Burton, and more.
*/
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <String.h>
static int char_to_int(char in);
static uint64 to_uint64(char *input);
2004-01-27 21:03:54 +00:00
static int process_potential_number(char *fromString);
static int factor_number(uint64 bigNumber, uint64 factorBy);
static int suggest_help(void);
static int warn_invalid(char *fromString);
static void usage(void);
static void version(void);
2004-01-10 22:07:53 +00:00
#define MAX_INT_CALCULATED "18446744073709551615" // a fairly big number, 2^64 minus 1
#define MAX_TOKEN_LENGTH 20 // Hopefully we can change this upper limit in the future. ;)
2004-01-27 21:03:54 +00:00
char* progName;
bool suggestHelp = false;
2004-01-10 22:07:53 +00:00
static int
2004-01-27 21:03:54 +00:00
char_to_int(char in)
2004-01-10 22:07:53 +00:00
{
if (in >= '0' && in <= '9')
return in - '0';
return(0);
}
static uint64
2004-01-27 21:03:54 +00:00
to_uint64(char *input)
2004-01-10 22:07:53 +00:00
{
uint64 output = 0;
while (*input && isdigit (*input)) {
output = output * 10 + char_to_int (*input++);
}
return output;
}
static int
2004-01-27 21:03:54 +00:00
read_line(char *buf, int len)
2004-01-10 22:07:53 +00:00
{
int i = 0;
char ch;
while (true) {
ch = getchar();
switch (ch) {
// backspace, erase the last character written
case '\b':
if (i > 0) {
printf("\b");
--i;
}
break;
// enter key pressed
case '\n':
buf[i] = 0;
return(i);
default:
buf[i] = ch;
i++;
break;
}
}
return(0);
}
static int
2004-01-27 21:03:54 +00:00
process_potential_number(char *fromString)
2004-01-10 22:07:53 +00:00
{
2004-01-27 21:03:54 +00:00
char *testForChar;
bool foundChar = false;
uint64 numberToFactor;
int baseFactor = 2;
2004-01-10 22:07:53 +00:00
char str[1024];
2004-01-27 21:03:54 +00:00
char *token;
const char *token_set = " \t";
2004-01-10 22:07:53 +00:00
bool factorNumber = true;
int i;
char maxint[] = MAX_INT_CALCULATED;
BString chrptr; // predefined character pointer
BString usrptr; // user submitted pointer
2004-01-27 21:03:54 +00:00
strcpy(str,fromString);
token = strtok(str, token_set);
2004-01-10 22:07:53 +00:00
while (1) {
2004-01-27 21:03:54 +00:00
testForChar = token;
foundChar = false;
2004-01-10 22:07:53 +00:00
2004-01-27 21:03:54 +00:00
while (*testForChar) {
if (! isdigit (*testForChar) ) {
foundChar = true;
2004-01-10 22:07:53 +00:00
break;
}
2004-01-27 21:03:54 +00:00
*testForChar++;
2004-01-10 22:07:53 +00:00
}
2004-01-27 21:03:54 +00:00
if (foundChar) {
warn_invalid(token);
2004-01-10 22:07:53 +00:00
} else {
2004-01-27 21:03:54 +00:00
if ( strlen(token) >= MAX_TOKEN_LENGTH ) {
2004-01-10 22:07:53 +00:00
for(i=0; i < MAX_TOKEN_LENGTH; i++) {
chrptr << maxint[i];
2004-01-27 21:03:54 +00:00
usrptr << token[i];
2004-01-10 22:07:53 +00:00
if ( usrptr > chrptr ) {
2004-01-27 21:03:54 +00:00
warn_invalid(token);
suggestHelp = true;
2004-01-10 22:07:53 +00:00
factorNumber = false;
break;
}
}
}
if ( factorNumber ) {
2004-01-27 21:03:54 +00:00
numberToFactor = to_uint64(token);
fprintf(stdout, "%Lu:", numberToFactor);
factor_number(numberToFactor, baseFactor);
fprintf(stdout, "\n");
2004-01-10 22:07:53 +00:00
}
}
2004-01-27 21:03:54 +00:00
token = strtok(NULL, token_set);
2004-01-10 22:07:53 +00:00
2004-01-27 21:03:54 +00:00
if (token == NULL)
2004-01-10 22:07:53 +00:00
break;
}
return(0);
}
static int
2004-01-27 21:03:54 +00:00
factor_number(uint64 bigNumber, uint64 factorBy)
2004-01-10 22:07:53 +00:00
{
2004-01-27 21:03:54 +00:00
if ( ( bigNumber == 1 ) || ( bigNumber == 0 ) ) {
if ( bigNumber == 1 )
fprintf(stdout, " %d", 1);
2004-01-10 22:07:53 +00:00
return(0);
}
2004-01-27 21:03:54 +00:00
uint64 rootNumber = (uint64)sqrt(bigNumber) + 1 ;
2004-01-10 22:07:53 +00:00
2004-01-27 21:03:54 +00:00
while ( factorBy <= rootNumber ) {
if ( (bigNumber % factorBy) == 0 ) {
fprintf(stdout, " %Lu", factorBy);
2004-01-10 22:07:53 +00:00
break;
}
2004-01-27 21:03:54 +00:00
factorBy++;
2004-01-10 22:07:53 +00:00
}
2004-01-27 21:03:54 +00:00
if ( factorBy > rootNumber ) {
fprintf(stdout, " %Lu", bigNumber);
2004-01-10 22:07:53 +00:00
return(0);
}
2004-01-27 21:03:54 +00:00
factor_number(bigNumber/factorBy, factorBy);
2004-01-10 22:07:53 +00:00
return(0);
}
static int
2004-01-27 21:03:54 +00:00
suggest_help()
2004-01-10 22:07:53 +00:00
{
2004-01-27 21:03:54 +00:00
fprintf(stderr, "Try `%s --help' for more information.\n", progName);
2004-01-10 22:07:53 +00:00
return(0);
}
static int
2004-01-27 21:03:54 +00:00
warn_invalid(char *fromString)
2004-01-10 22:07:53 +00:00
{
2004-01-27 21:03:54 +00:00
fprintf(stderr, "%s: `%s' is not a valid positive integer\n", progName, fromString);
2004-01-10 22:07:53 +00:00
return(0);
}
2004-01-27 21:03:54 +00:00
static void
2004-01-10 22:07:53 +00:00
usage(void)
{
2004-01-27 21:03:54 +00:00
(void)fprintf(stdout, "%s OBOS (http://www.openbeos.org/)
2004-01-10 22:07:53 +00:00
Usage: %s [NUMBER]...
or: %s OPTION
2004-01-27 21:03:54 +00:00
--help display this help and exit
--version output version information and exit
2004-01-10 22:07:53 +00:00
Print the prime factors of all specified positive integer NUMBERs.
If no NUMBERS are specified on the command line, they are read from standard input.
You may use a delimiter characters such as space and tab to separate NUMBERS.
2004-01-27 21:03:54 +00:00
", progName, progName, progName );
2004-01-10 22:07:53 +00:00
}
2004-01-27 21:03:54 +00:00
static void
2004-01-10 22:07:53 +00:00
version(void)
{
2004-01-27 21:03:54 +00:00
fprintf(stdout, "%s OBOS (http://www.openbeos.org/)\n", progName);
2004-01-10 22:07:53 +00:00
}
int
main(int argc, char *argv[])
{
int argOption;
int indexptr = 0;
char * const * optargv = argv;
2004-01-27 21:03:54 +00:00
bool processed = false;
2004-01-10 22:07:53 +00:00
int i;
char buf[1024];
2004-01-27 21:03:54 +00:00
progName = argv[0];
2004-01-10 22:07:53 +00:00
2004-01-27 21:03:54 +00:00
struct option helpOption = { "help", no_argument, 0, 1 } ;
struct option versionOption = { "version", no_argument, 0, 2 } ;
2004-01-10 22:07:53 +00:00
struct option options[] = {
2004-01-27 21:03:54 +00:00
helpOption, versionOption, {0}
2004-01-10 22:07:53 +00:00
};
for ( i=1; i<argc; i++ ) {
if ((argv[i][0] >= '0') && (argv[i][0] <= '9')) {
2004-01-27 21:03:54 +00:00
processed = true;
process_potential_number(argv[i]);
2004-01-10 22:07:53 +00:00
} else {
if ( ( argv[i][0] == '-' ) && (argv[i][1] >= '0') && (argv[i][1] <= '9') ) {
2004-01-27 21:03:54 +00:00
processed = true;
warn_invalid(argv[i]);
suggestHelp = true;
2004-01-10 22:07:53 +00:00
}
}
}
2004-01-27 21:03:54 +00:00
if ( suggestHelp == true ) {
suggest_help();
2004-01-10 22:07:53 +00:00
exit(0);
}
while ((argOption = getopt_long(argc, optargv, "", options, &indexptr)) != -1) {
switch (argOption) {
default:
switch (options[indexptr].val) {
case 1: // help
usage();
exit(0);
case 2: // version
version();
exit(0);
default:
break;
}
break;
}
}
argc -= optind;
2004-01-27 21:03:54 +00:00
if ( (argc == 0) || (processed == false) ) {
2004-01-10 22:07:53 +00:00
// read stdin
for (;;) {
int chars_read;
2004-01-27 21:03:54 +00:00
chars_read = read_line(buf, sizeof(buf));
2004-01-10 22:07:53 +00:00
if (chars_read > 0)
2004-01-27 21:03:54 +00:00
process_potential_number(buf);
2004-01-10 22:07:53 +00:00
}
}
return B_NO_ERROR;
}