| 1 | /* $Id: prime.c,v 1.9 2006/05/13 09:20:36 joko Exp $ */ | 
| 2 |  | 
| 3 | #include <stdio.h> | 
| 4 | #include <stdlib.h> | 
| 5 | #include <limits.h> | 
| 6 | #include <errno.h> | 
| 7 |  | 
| 8 | #define BOOL int | 
| 9 | #define TRUE 1 | 
| 10 | #define FALSE 0 | 
| 11 |  | 
| 12 | #define PRINTPRIME(x) if (is_prime(x)) printf("%i\n", x) | 
| 13 | #define PRINTERROR(message) fprintf(stderr, "ERROR: %s\n", message) | 
| 14 | #define PRINTWARNING(message) fprintf(stderr, "WARNING: %s\n", message) | 
| 15 |  | 
| 16 | /* check for prime number */ | 
| 17 | BOOL is_prime(long int number) | 
| 18 | { | 
| 19 | int i; | 
| 20 |  | 
| 21 | /* negative values, 0 and 1 are never prime numbers */ | 
| 22 | if (number < 2) return FALSE; | 
| 23 |  | 
| 24 | /* check all numbers 2..sqrt(number) for being a prime number */ | 
| 25 | for (i=2; i*i <= number; i++) { | 
| 26 | if ((number % i) == 0) | 
| 27 | return FALSE; | 
| 28 | } | 
| 29 | return TRUE; | 
| 30 | } | 
| 31 |  | 
| 32 | /* convert from string to long int, with error checking */ | 
| 33 | long int convert_number(const char *nptr) { | 
| 34 |  | 
| 35 | char * endptr; | 
| 36 | long int number = strtol(nptr, &endptr, 10); | 
| 37 |  | 
| 38 | errno = 0; | 
| 39 |  | 
| 40 | /* invalid characters? */ | 
| 41 | if (*endptr != '\0') { | 
| 42 | char message[254]; | 
| 43 | snprintf(message, 256, "Could not convert '%s' to a valid number.", nptr); | 
| 44 | PRINTERROR(message); | 
| 45 | exit(EXIT_FAILURE); | 
| 46 | } | 
| 47 |  | 
| 48 | /* invalid range? */ | 
| 49 | /* if (number == LONG_MAX || number == LONG_MIN) { */ | 
| 50 | if (errno == ERANGE) { | 
| 51 | char message[254]; | 
| 52 | snprintf(message, 256, "Number is not in range of 'long int': %s", nptr); | 
| 53 | PRINTERROR(message); | 
| 54 | exit(EXIT_FAILURE); | 
| 55 | } | 
| 56 |  | 
| 57 | return number; | 
| 58 |  | 
| 59 | } | 
| 60 |  | 
| 61 | int main(int argc, char * argv[]) | 
| 62 | { | 
| 63 |  | 
| 64 | if (argc == 1) { | 
| 65 | PRINTERROR("No arguments given."); | 
| 66 | exit(EXIT_FAILURE); | 
| 67 | } | 
| 68 |  | 
| 69 | /* (3) range mode */ | 
| 70 | if (argc > 2) { | 
| 71 | long int i, j; | 
| 72 | i = convert_number(argv[1]); | 
| 73 | j = convert_number(argv[2]); | 
| 74 | for (i; i< j; i++) { | 
| 75 | PRINTPRIME(i); | 
| 76 | } | 
| 77 |  | 
| 78 | /* other modes */ | 
| 79 | } else { | 
| 80 |  | 
| 81 | /* try to open file for reading */ | 
| 82 | FILE * fp = fopen(argv[1], "r"); | 
| 83 |  | 
| 84 | /* (1) test-single-number mode: first argument is not a filename */ | 
| 85 | if (fp == NULL) { | 
| 86 | long int number = convert_number(argv[1]); | 
| 87 | PRINTPRIME(number); | 
| 88 |  | 
| 89 | /* (2) file mode: read numbers from file */ | 
| 90 | } else { | 
| 91 | char entry[81]; | 
| 92 | long int number; | 
| 93 | long int lineno = 0; | 
| 94 | while (fgets(entry, 81, fp)) { | 
| 95 |  | 
| 96 | /* count line number (for warnings) */ | 
| 97 | lineno++; | 
| 98 |  | 
| 99 | /* skip empty lines */ | 
| 100 | if (strlen(entry) < 2) continue; | 
| 101 |  | 
| 102 | /* line handling: policy = skip exceeding lines */ | 
| 103 |  | 
| 104 | /* if last char is newline, strip it */ | 
| 105 | if (entry[strlen(entry)-1] == '\n') { | 
| 106 | entry[strlen(entry)-1] = '\0'; | 
| 107 |  | 
| 108 | /* line exceeds max length */ | 
| 109 | } else { | 
| 110 | char message[254]; | 
| 111 | snprintf(message, 256, "Line too long (max 80 chars) in line number: %i", lineno); | 
| 112 | PRINTWARNING(message); | 
| 113 |  | 
| 114 | /* eat all characters until newline */ | 
| 115 | while (fgetc(fp) != 10); | 
| 116 |  | 
| 117 | /* skip this line from prime calculation */ | 
| 118 | continue; | 
| 119 | } | 
| 120 |  | 
| 121 | number = convert_number(entry); | 
| 122 | PRINTPRIME(number); | 
| 123 | } | 
| 124 | fclose(fp); | 
| 125 | } | 
| 126 | } | 
| 127 | } |