# It is nothing short of embarrassing to feel the need to ask for help on
# this. I can't see how I would make the main control for this. What I want
# is a for loop and a test condition. And while I know, from things I
# pondered 2 decades ago, that a fella can write code without a goto, I'm
# stuck.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void error(char *message) {
fprintf(stderr,"%s\n",message);
exit(1);
}
static char *readline(FILE *A) {
char *buffer = 0; int n = 0,m = 0,ch;
for (;
{
int ch = fgetc(A);
switch (ch) {
case EOF: if (buffer==0) return 0;
case '\n': ch = 0;
}
if (n+1>=m) {
m = 2*(n+1); buffer = realloc(buffer,m);
if (!buffer) error("out of memory");
}
buffer[n++] = ch;
if (!ch) break;
}
return buffer;
}
static void writeline(FILE *B,char *n) {
fputs(n,B); fputc('\n',B);
}
static char *number(int n) {
char b[50],*c;
sprintf(b,"%d",n);
c = malloc(strlen(b)+1);
if (!c) error("out of memory");
strcpy(c,b);
return c;
}
static char *increment(char *n) {
char *digit = n+strlen(n); int carry = 1;
while (carry) {
if (digit==n) {
char *n1 = malloc(1+strlen(n)+1);
if (!n1) error("out of memory");
*n1 = '1'; strcpy(n1+1,n);
carry = 0;
free(n); n = n1;
}else if (*--digit=='9') {
*digit = '0';
carry = 1;
}else {
*digit += 1;
carry = 0;
}
}
return n;
}
static int decrement(char *n) {
char *digit = n+strlen(n); int borrow = 1;
int zero = 1;
while (borrow) {
if (digit==n) {
error("Attempted to decrement zero.");
}else if (*--digit=='0') {
*digit = '9';
borrow = 1;
}else {
*digit -= 1;
borrow = 0;
}
}
while (*n && zero) zero = *n++=='0';
return zero;
}
static int sieveStep(FILE *A,FILE *B) {
int isprime = 1;
while (1) {
char *prime = readline(A);
char *counter = readline(A);
if (!prime) break;
if (prime && !counter) return -1;
writeline(B,prime);
if (decrement(counter)) {
writeline(B,prime);
isprime = 0;
}else {
writeline(B,counter);
}
free(prime); free(counter);
}
return isprime;
}
static void addPrime(char *current,FILE *PR,FILE *B) {
if (PR) writeline(PR,current);
writeline(B,current);
writeline(B,current);
}
int main(int N,char **P) {
char *limit = 0; int restart = 0;
FILE *A = 0,*B = 0,*PR = stdout;
char *Apath = "A.sve";
char *Bpath = "B.sve";
char *PRpath = 0;
char *current = 0;
while (++P,--N>0) {
char *p = *P;
if (isdigit(p[0])) {
limit = malloc(strlen(p)+1);
if (!limit) error("out of memory");
strcpy(limit,p);
}else if (p[0]=='-' && p[1]=='o' && N>0) {
PRpath = P[1]; P++,N--;
}else {
fprintf(stderr,"unrecognised option: %s\n",p);
return 1;
}
}
A = fopen(Apath,"r");
B = fopen(Bpath,"r");
if (!A && B) rename((const char*)B,(const char*)A);
if (B) fclose(B);
A = fopen(Apath,"r");
if (A) {
current = readline(A);
if (current && limit) {
char *t = malloc(strlen(limit)+1);
if (!t) error("out of memory");
strcpy(t,limit);
current = increment(current);
for (restart=1; restart; ) {
char *prime = readline(A);
char *counter = readline(A);
if (!prime) break;
free(prime);
if (prime && !counter) restart = 0;
free(counter);
if (decrement(t)) {
restart = 0;
}else {
break;
}
}
if (restart) {free(limit); limit = t;}
else {free(t);}
}else {
restart = 1;
}
if (!restart) free(current);
fclose(A);
}
if (!PRpath) {
;
}else if (strcmp(PRpath,"none")==0) {
PR = 0;
}else {
PR = fopen(PRpath,restart?"a":"w");
if (!PR) {
perror(PRpath);
return 1;
}
}
if (!restart) {
A = fopen(Apath,"w");
if (!A) {
perror(Apath);
return 1;
}
current = number(2);
writeline(A,current);
fclose(A);
}
while (1) {
A = fopen(Apath,"r"); if (!A) {perror(Apath); return 1;}
B = fopen(Bpath,"w"); if (!B) {perror(Bpath); return 1;}
free(readline(A)); writeline(B,current);
switch (sieveStep(A,B)) {
case 1:
addPrime(current,PR,B);
if (limit && decrement(limit)) return 0;
break;
case -1:
return 1;
}
current = increment(current);
fclose(A);
fclose(B);
if (rename(Bpath,Apath)<0) {
fprintf(stderr,"rename %s: ",Bpath); perror(Apath);
return 1;
}
}
}