Aiemmasta versiosta on korjattu pari bugia. Ensimmäisessä variaatioissa on vain pieniä ketjuja, ja 1,6 rajaa pienten ja suurien ketjujen välillä ei löydy. Tällöin lim1 ja lim2 kentät täytettiin joskus -1:llä. Tietue ensimmäisestä bugista:
round: 0 1:1 2:1 3:3 5:2 6:1 7:1 8:1 9:1 10:1 11:1 12:1 13:1 14:4 15:6 lim1:6 lim2:-1 clockbytes:244 rndbits:25
Toisessa bugissa on eripituisia variaatioita aina 1 kappaletta: jolloin isojen ketjujen ensimmäinen päätyy teoreettisiin bitteihin ja _genbytes rutiinista palataan liian nopeasti. Tässä esimerkki vanhasta ohjelmasta:
round: 1 1:1 2:1 3:1 4:1 5:1 6:1 7:1 8:1 9:1 10:1 12:1 14:1161 15:1096 lim1:1161 lim2:1161 clockbytes:32761 rndbits:1107
round: 1 1:1 2:1 3:1 5:1 6:1 7:1 8:1 9:1 10:1 12:1 13:1 14:1158 15:1099 lim1:1158 lim2:1158 clockbytes:32773 rndbits:1110
round: 1 1:1 2:1 4:1 5:1 8:1 9:1 10:1 11:1 13:1 14:1168 15:1090 lim1:1168 lim2:1168 clockbytes:32765 rndbits:1099
Muutoksissa on –sample optio, jolla voidaan tulostaa 8gb:n pituinen mallitiedosto, jolla voidaan testata satunnaisuutta esimerkiksi Dieharder ohjelmalla.
Lisäksi pääohjelmasta on palasteltu useampaan kertaan käytettyjä rutiineja omiksi funktioikseen.
Bugikorjaukset ovat lim=0 rivillä, if(prevbyte==-1 && f!=-1) rivillä ja if(f!=-1) rivillä.
Tässä toisaalta koodikorjaukset edellisistä bugeista ja muista muutoksista. Tässä aluksi koodi varsinaisesta korjatusta generaattorista:
unsigned char ressu_clockbyte() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
void ressu_genbytes_fast(int size, unsigned char *buffer)
{
int c, d, e, byte;
static int f = 0, prevbyte = -1, count = 0;
for(c=0; c<8; c++) {
for(d=0; d<size; d++) {
e = buffer[d];
e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
//e=((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
//e=((e&0xfe)>>1) | ((e&0x1)<<7); // rotate right 1
byte = ressu_clockbyte();
if(prevbyte==-1)
prevbyte=byte;
buffer[d] = e^byte;
if(prevbyte!=byte) {
periods[count]++;
clockbytes+=count;
count=0;
prevbyte=byte;
}
count++;
}
for(d=0; d<size; d++) {
f = (f+buffer[d])%size;
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
}
}
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c,d,e;
static int ressut_first=1,
ressut_pos = 0,
ressut_f = 0;
static unsigned char ressut[RESSUT_BYTES];
for(c=0; c<size; c++) {
if(ressut_pos == 0) {
if(ressut_first) {
memset(ressut,0,ressut_bytes);
ressut_first=0;
}
clockbytes=0;
for(d=0;d<1024;d++)
periods[d]=0;
int rndbits=0;
int lim, lim1, lim2;
for(d=0; rndbits<ressu_bits_needed ||
d<RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
ressu_genbytes_fast(ressut_bytes,ressut);
lim=0;
int ok=1, f, prevf=-1;
while(ok==1) {
ok=0;
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f)) {
f=periods[e];
}
}
if((prevf==-1 && f!=-1)|| (f!=-1 && f<=(double)prevf*1.6)) {
lim=f;
prevf=f;
ok=1;
}
} // while(ok==1)
lim1=lim;
// find next greater than lim
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f))
f=periods[e];
}
if(f!=-1)
lim=f;
lim2=lim;
int prev_rndbits=rndbits;
rndbits=0;
for(e=0;e<1024;e++) {
if(periods[e]>0 && periods[e]<lim) {
rndbits+=periods[e];
}
}
if(rndbits==0 || prev_rndbits == rndbits) { // restart
clockbytes=0;
for(e=0;e<1024;e++)
periods[e]=0;
rndbits=0;
}
} // for(d=0;
if(stats) {
fprintf(stdout,"round: %d",d);
for(e=0;e<1024;e++) {
if(periods[e]>0)
fprintf(stdout," %d:%lu",e,periods[e]);
}
fprintf(stdout," lim1:%d",lim1);
fprintf(stdout," lim2:%d",lim2);
fprintf(stdout," clockbytes:%ld",clockbytes);
fprintf(stdout," rndbits:%d",rndbits);
fprintf(stdout,"\n");
fflush(stdout);
}
} // if(ressut_pos == 0)
ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
buffer[c] ^= ressut[ressut_f];
ressut_pos = (ressut_pos+1) % ressut_bytes;
} // for(c=0; c<size; c++)
genbytes+=size;
}
Pääohjelmasta palastellut rutiinit: line_number_length() pääsi ulkoistettujen seuraan vaikka sillä oli vain yksi kutsukohta.
int line_number_length()
{
int c;
out_word(sizeof(linenobuf),linenobuf,"0123456789",lines-1);
c=strlen(linenobuf);
if(c<5)
c=5;
return(c);
}
void print_line_number()
{
unsigned char linenobuf[1024];
if(pchars==0 && !quiet && slineno) {
sprintf(linenobuf,"%0*d",plinesdigits,plines);
fprintf(stdout,"%s",linenobuf);
pchars +=strlen(linenobuf);
fprintf(stdout," ");
pchars++;
}
}
void print_spaces()
{
if(sspace && pchars>0 && !quiet) {
if(sspace==3 && pwords%2==0) {
fprintf(stdout," ");
pchars++;
}
fprintf(stdout," ");
pchars++;
}
}
void print_word(unsigned char *buf)
{
if(size!=0) {
if(!quiet)
fprintf(stdout,"%*s",size,buf);
pchars += size;
pwords++;
} else {
if(!quiet)
fprintf(stdout,"%s",buf);
pchars += strlen(wordbuf);
pwords++;
}
}
Ja palastelun takia muutetut palat pääohjelmasta:
for(;;) {
if(!sort) { // also lotto
pchars=0;
pwords=0;
while(pwords<linew) {
readword(wordbuf);
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
} // while(pwords<linew) {
} else { // if(!sort)
pchars=0;
pwords=0;
line_clear(&linecnt,&line);
// fetch and save words on this row
while(pwords<linew) {
readword(wordbuf);
if(line_add_string_sort(&linecnt,&line,wordbuf)) {
pwords++;
}
} // while(pwords<linew) {
pchars=0;
pwords=0;
// print words on this row
while(pwords<linew) {
line_get_string(sizeof(wordbuf),wordbuf,pwords,line);
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
} // while(pwords<linew) {
} // if(!sort)
// line full?
if(!quiet) {
fprintf(stdout,"\n");
}
plines++;
if(sspace==3 && plines<lines && plines%5==0)
fprintf(stdout,"\n");
// all needed lines printed?
if(plines >= lines)
break;
} // for(;;)
Lisätty sample optio, jolla voidaan tulostaa newressusample.rnd tiedosto satunnaisbittien testaamiseen vaikka dieharder ohjelmalla. –sample parametrin käyttämät palat parametrien käsittelyssä:
} else if(!strcmp("--lotto",argv[c])) {
sort=!sort;
if(sspace==0)
sspace=1;
//sort=1;
//unique=1;
} else if(!strcmp("--sample",argv[c])) {
sample=!sample;
} else if(!strcmp("--copyright",argv[c]) ||
!strcmp("--version",argv[c])) {
fprintf(stderr,"%s",programname);
fprintf(stderr,", %s",copyright);
fprintf(stderr,"\n\n");
help=1;
–sample esimerkkitiedoston tulostus: tiedoston koko on tässä 8GB, eli 1048576*4096*2
if(sample) {
FILE *fp1;
unsigned char buffer[4096];
fp1=fopen("newressusample.rnd","w");
for(c=0;c<1048576;c++) {
ressu_genbytes(sizeof(buffer),buffer);
fwrite(buffer,1,sizeof(buffer),fp1);
ressu_genbytes(sizeof(buffer),buffer);
fwrite(buffer,1,sizeof(buffer),fp1);
}
fclose(fp1);
exit(0);
}
Voit tulostaa samplen:
$ newressu --sample
komennolla ja dieharder ohjelmaa voit ajaa:
$ dieharder -a -g 201 -f newressusample.rnd
komennolla.
Tässä sorsa kokonaisuudessaan:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/time.h>
unsigned char *procname;
static char *programname = "newressu version 2.2 ©";
static unsigned char *copyright = "Copyright (c) 2013-2021 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
unsigned long periods[1024];
unsigned long genbytes=0;
unsigned long clockbytes=0;
#define RESSUT_BYTES 4096
#define RESSU_BITS_NEEDED 128
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16384+1024
int ressu_bits_needed=RESSU_BITS_NEEDED;
int ressut_bytes = RESSUT_BYTES;
int stats=0;
unsigned char ressu_clockbyte() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
void ressu_genbytes_fast(int size, unsigned char *buffer)
{
int c, d, e, byte;
static int f = 0, prevbyte = -1, count = 0;
for(c=0; c<8; c++) {
for(d=0; d<size; d++) {
e = buffer[d];
e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
//e=((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
//e=((e&0xfe)>>1) | ((e&0x1)<<7); // rotate right 1
byte = ressu_clockbyte();
if(prevbyte==-1)
prevbyte=byte;
buffer[d] = e^byte;
if(prevbyte!=byte) {
periods[count]++;
clockbytes+=count;
count=0;
prevbyte=byte;
}
count++;
}
for(d=0; d<size; d++) {
f = (f+buffer[d])%size;
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
}
}
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c,d,e;
static int ressut_first=1,
ressut_pos = 0,
ressut_f = 0;
static unsigned char ressut[RESSUT_BYTES];
for(c=0; c<size; c++) {
if(ressut_pos == 0) {
if(ressut_first) {
memset(ressut,0,ressut_bytes);
ressut_first=0;
}
clockbytes=0;
for(d=0;d<1024;d++)
periods[d]=0;
int rndbits=0;
int lim, lim1, lim2;
for(d=0; rndbits<ressu_bits_needed ||
d<RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
ressu_genbytes_fast(ressut_bytes,ressut);
lim=0;
int ok=1, f, prevf=-1;
while(ok==1) {
ok=0;
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f)) {
f=periods[e];
}
}
if((prevf==-1 && f!=-1)|| (f!=-1 && f<=(double)prevf*1.6)) {
lim=f;
prevf=f;
ok=1;
}
} // while(ok==1)
lim1=lim;
// find next greater than lim
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f))
f=periods[e];
}
if(f!=-1)
lim=f;
lim2=lim;
int prev_rndbits=rndbits;
rndbits=0;
for(e=0;e<1024;e++) {
if(periods[e]>0 && periods[e]<lim) {
rndbits+=periods[e];
}
}
if(rndbits==0 || prev_rndbits == rndbits) { // restart
clockbytes=0;
for(e=0;e<1024;e++)
periods[e]=0;
rndbits=0;
}
} // for(d=0;
if(stats) {
fprintf(stdout,"round: %d",d);
for(e=0;e<1024;e++) {
if(periods[e]>0)
fprintf(stdout," %d:%lu",e,periods[e]);
}
fprintf(stdout," lim1:%d",lim1);
fprintf(stdout," lim2:%d",lim2);
fprintf(stdout," clockbytes:%ld",clockbytes);
fprintf(stdout," rndbits:%d",rndbits);
fprintf(stdout,"\n");
fflush(stdout);
}
} // if(ressut_pos == 0)
ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
buffer[c] ^= ressut[ressut_f];
ressut_pos = (ressut_pos+1) % ressut_bytes;
} // for(c=0; c<size; c++)
genbytes+=size;
}
#define DEBUG4 2
#ifdef DEBUG4
unsigned char cc[256*1048576]; // clock_chain
unsigned char *ccp;
int cc_bytes;
#endif
unsigned char ressu_clockbyte_debug() /* JariK 2013 */
{
unsigned char c;
struct timeval tv;
gettimeofday(&tv, NULL);
c=tv.tv_usec & 0xff;
#ifdef DEBUG4
if(cc_bytes<sizeof(cc)) {
*ccp++ = c;
cc_bytes++;
}
#endif
return(c);
}
void ressu_genbytes_fast_debug(int size, unsigned char *buffer)
{
int c, d, e, byte;
static int f = 0, prevbyte = -1, count = 0;
for(c=0; c<8; c++) {
for(d=0; d<size; d++) {
e = buffer[d];
e = ((e&0x80)>>7) | ((e&0x7f)<<1); // rotate left 1
//e=((e&0xe0)>>5) | ((e&0x1f)<<3); // rotate left 3
//e=((e&0xfe)>>1) | ((e&0x1)<<7); // rotate right 1
byte = ressu_clockbyte_debug();
if(prevbyte==-1)
prevbyte=byte;
buffer[d] = e^byte;
if(prevbyte!=byte) {
periods[count]++;
clockbytes+=count;
count=0;
prevbyte=byte;
}
count++;
}
for(d=0; d<size; d++) {
f = (f+buffer[d])%size;
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
}
}
void ressu_genbytes_debug(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c,d,e;
static int ressut_first=1,
ressut_pos = 0,
ressut_f = 0;
static unsigned char ressut[RESSUT_BYTES];
for(c=0; c<size; c++) {
if(ressut_pos == 0) {
if(ressut_first) {
memset(ressut,0,ressut_bytes);
ressut_first=0;
}
clockbytes=0;
for(d=0;d<1024;d++)
periods[d]=0;
#ifdef DEBUG4
ccp=cc;
cc_bytes=0;
while(ressu_clockbyte_debug()!=0);
while(ressu_clockbyte_debug()==0);
ccp=cc;
cc_bytes=0;
#endif
int rndbits=0, rounds=0;
int lim, lim1, lim2;
for(d=0; rndbits<ressu_bits_needed ||
d<RESSU_MIN_ROUNDS; d++) {
rounds++;
ressu_genbytes_fast_debug(ressut_bytes,ressut);
lim=0;
int ok=1, f, prevf=-1;
while(ok==1) {
ok=0;
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f)) {
f=periods[e];
}
}
if((prevf==-1 && f!=-1)|| (f!=-1 && f<=(double)prevf*1.6)) {
lim=f;
prevf=f;
ok=1;
}
} // while(ok==1)
lim1=lim;
// find next greater than lim
f=-1;
for(e=0;e<1024;e++) {
if(periods[e]>lim && (f==-1 || periods[e]<f))
f=periods[e];
}
if(f!=-1)
lim=f;
lim2=lim;
int prev_rndbits=rndbits;
rndbits=0;
for(e=0;e<1024;e++) {
if(periods[e]>0 && periods[e]<lim) {
rndbits+=periods[e];
}
}
if(rndbits==0 || prev_rndbits == rndbits) { // restart
clockbytes=0;
for(e=0;e<1024;e++)
periods[e]=0;
ccp=cc;
cc_bytes=0;
rndbits=0;
}
} // for(d=0;
#ifdef DEBUG4
FILE *fp1;
if((fp1=fopen("newressu.deb","a"))!=NULL) {
//if(lim1==-1 || lim2==-1 || lim1==lim2) {
for(d=0;d<32;d++)
fprintf(fp1,"%02x",ressut[d]);
fprintf(fp1,", ressut_bytes: %d",ressut_bytes);
fprintf(fp1,", ressu_bits_needed: %d",ressu_bits_needed);
fprintf(fp1,", ressu_min_rounds: %d",RESSU_MIN_ROUNDS);
fprintf(fp1,", clockbytes: %ld",clockbytes);
unsigned long total=0;
fprintf(fp1,", fluctuations:");
for(d=0;d<1024;d++) {
if(periods[d]!=0) {
fprintf(fp1," %d:%lu",d,periods[d]);
total+=(periods[d]*d);
}
}
fprintf(fp1,", total: %lu",total);
fprintf(fp1,", limit1: %d",lim1);
fprintf(fp1,", limit2: %d",lim2);
fprintf(fp1,", limit: %d",lim);
fprintf(fp1,", skipped:");
for(d=0;d<1024;d++) {
if(periods[d]>=lim) {
fprintf(fp1," %d:%lu",d,periods[d]);
}
}
fprintf(fp1,", counted:");
for(d=0;d<1024;d++) {
if(periods[d]>0 && periods[d]<lim) {
fprintf(fp1," %d:%lu",d,periods[d]);
}
}
fprintf(fp1,", rndbits: %d",rndbits);
fprintf(fp1,", rounds: %d",rounds);
int prevbyte=-1, count=0, count2=0;
unsigned char byte, small=-1;
fprintf(fp1,", small chains:");
for(d=0;d<cc_bytes;d++) {
byte=cc[d];
if(prevbyte==-1) {
prevbyte=byte;
count=1;
}
if(prevbyte!=byte) {
if(periods[count]>=lim) {
if(small==1 || small==-1)
fprintf(fp1," *");
small=0;
} else small=1;
if(small) {
fprintf(fp1," %d",count);
count2++;
}
count=0;
prevbyte=byte;
}
count++;
}
if(small) {
fprintf(fp1," %d",count);
count2++;
}
fprintf(fp1,", count: %d",count2);
fprintf(fp1,"\n");
fflush(fp1);
//}
fclose(fp1);
} // if((fp1=fopen
#endif
} // if(ressut_pos == 0)
ressut_f = (ressut_f + ressut[ressut_pos]) % ressut_bytes;
buffer[c] ^= ressut[ressut_f];
ressut_pos = (ressut_pos+1) % ressut_bytes;
} // for(c=0; c<size; c++)
genbytes+=size;
}
static void readfile_xor(int len,
unsigned char *buf,
unsigned char *filename)
{
int c, n, n2;
unsigned char temp[64];
FILE *fp1;
if((fp1 = fopen(filename, "rb"))
!= NULL) {
while(len != 0) {
n = (len < sizeof(temp)) ?
len : sizeof(temp);
n2=fread(temp, 1, n, fp1);
for(c = 0; c < n2; c++)
buf[c] ^= temp[c];
len -= n2;
buf += n2;
}
fclose(fp1);
}
}
int input=0;
#define GENT_SIZE 2048
#define aUSE_RANDOM 2
#define aDEBUG9 2
char *randomgen[] = { "ressu", "debug","fast","single","4","5","6","7","urandom","random" };
int ressu_genbyte()
{
int c;
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos=0; // Little bug
unsigned char ch;
if(input==0) { // ressu prod
ressu_genbytes(sizeof(ch), &ch);
} else if(input==1) { // ressu debug
ressu_genbytes_debug(sizeof(ch), &ch);
} else {
if(gent_pos==0) {
if(input==2) { // ressu_fast
clockbytes=0;
for(c=0; c<RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES;c++) {
ressu_genbytes_fast(sizeof(gent),gent);
}
} else if(input==3) { // ressu_single
ressu_genbytes_fast(sizeof(gent),gent);
} else if(input==8) { // urandom
readfile_xor(sizeof(gent),gent,"/dev/urandom");
#ifdef USE_RANDOM
} else if(input==9) { // random
readfile_xor(sizeof(gent),gent,"/dev/random");
#endif
}
} // if(gent_pos==0
ch=gent[gent_pos];
gent_pos=(gent_pos+1)%sizeof(gent);
}
return(ch);
}
int ressu_genbyte_limit(int limit)
{
int c;
while((c=ressu_genbyte()) >= (256/limit)*limit);
return(c%limit);
}
int ressu_genshort()
{
return(ressu_genbyte() | ressu_genbyte()<<8);
}
int ressu_genshort_limit(int limit)
{
int c;
while((c=ressu_genshort()) >= (65536/limit)*limit);
return(c%limit);
}
unsigned int ressu_genint()
{
return(ressu_genshort() | ressu_genshort()<<16);
}
unsigned int ressu_genint_limit(unsigned long limit)
{
unsigned int c;
while((c=ressu_genint()) >= (((unsigned long)65536*65536)/limit)*limit);
return(c%limit);
}
unsigned long ressu_genlong()
{
return(((unsigned long)ressu_genint()) | ((unsigned long)ressu_genint())<<32);
}
unsigned long ressu_genlong_limit(unsigned long limit)
{
unsigned long c;
while((c=ressu_genlong()) >= (((unsigned long)0xffffffffffffffff)/limit)*limit);
return(c%limit);
}
unsigned long ressu_gen_limit(unsigned long limit)
{
if(limit<=256)
return(ressu_genbyte_limit(limit));
else if(limit<=65536)
return(ressu_genshort_limit(limit));
else if(limit<=(unsigned long)65536*65536)
return(ressu_genint_limit(limit));
else if(limit<=(unsigned long)0xffffffffffffffff)
return(ressu_genlong_limit(limit));
else
return(-1);
}
#define MAIN 2
#ifdef MAIN
int help=0;
int utf8len(unsigned char *buf)
{
int len;
unsigned char *p;
p=buf;
len=0;
while(*p!='\0') {
if(*p<0x80 || // ascii char
*p>0xbf) // first utf8 byte
len++;
p++;
}
return(len);
}
#define aDEBUG38 2
void utf8getchar(int size, unsigned char *buf, int n, unsigned char *string)
{
int d;
unsigned char *p,*q;
d=0;
p=string;
q=buf;
// find first byte of character
while(*p!='\0') {
if(*p<0x80 || // ascii char
*p>0xbf) { // first utf8 char
if(d==n)
break;
d++;
}
p++;
}
// copy first byte and rest
// of character
if(*p!='\0') {
*q++=*p; // copy first byte
if(*p>0xbf) { // if first is utf8 char
p++;
for(;;) {
if(*p>0xbf || // first utf8 char
*p<0x80 || // ascii char
*p=='\0') // end of file
break;
*q++=*p++; // copy rest of the bytes
}
}
}
*q='\0';
#ifdef DEBUG38
fprintf(stdout,"%s: utf8getchar:",procname);
fprintf(stdout," string: %s",string);
fprintf(stdout,", n: %d",n);
fprintf(stdout,", character: %s",buf);
fprintf(stdout,"\n");
#endif
}
#define aDEBUG45
void out_word(int size, unsigned char *buf, unsigned char *digits, unsigned long word2) // 8.5.2021 JariK
{
int c, d, len, digitslen;
unsigned long word;
unsigned char string[132], character[32];
digitslen = utf8len(digits);
word=word2;
len=0;
string[0]='\0';
if(word==0 || digitslen<2) {
// zero
utf8getchar(sizeof(character),character,0,digits);
if(len+strlen(character)<sizeof(string)) {
strcat(string,character);
len+=strlen(character);
}
} else {
// non zero
while(word>0) {
utf8getchar(sizeof(character),character,word%digitslen,digits);
if(len+strlen(character)<sizeof(string)) {
strcat(string,character);
len+=strlen(character);
}
word/=digitslen;
}
}
// reverse string
*buf='\0';
len=0;
d=utf8len(string);
for(c=d-1;c>=0;c--) {
utf8getchar(sizeof(character),character,c,string);
if(len+strlen(character)<size) {
strcat(buf,character);
len+=strlen(character);
}
}
#ifdef DEBUG45
fprintf(stdout,"]\n%s: out_word: ",procname);
fprintf(stdout," reverse string: %s",string);
fprintf(stdout,", digits: %s",digits);
fprintf(stdout,", int: %lu",word2);
fprintf(stdout,"\n[");
#endif
}
#define aDEBUG58 2
void in_word(unsigned long *word, unsigned char *digits, unsigned char *buf)
{
int c,d,e,f,ok;
unsigned char character[32], character2[32];
*word=0;
d=utf8len(buf);
f=utf8len(digits);
for(c=0;c<d;c++) {
utf8getchar(sizeof(character2),character2,c,buf);
ok=0;
for(e=0;e<f;e++) {
utf8getchar(sizeof(character),character,e,digits);
if(!strcmp(character,character2)) {
ok=1;
break;
}
}
if(ok) {
*word=((*word)*f)+e;
} else {
fprintf(stdout,"%s: in_word:",procname);
fprintf(stdout," illegal digit '%s'\n",character2);
help=1;
}
}
#ifdef DEBUG58
fprintf(stdout,"%s: in_word:",procname);
fprintf(stdout," word: %lu",*word);
fprintf(stdout,", digits: %s",digits);
fprintf(stdout,", string: %s",buf);
fprintf(stdout,"\n");
#endif
}
void line_clear(int *len, unsigned char **buf)
{
if(*len<1) {
*len=129;
*buf=realloc(*buf,*len);
}
**buf='\0';
}
int line_add_string_sort(int *len, unsigned char **buf, unsigned char *string)
{
int cmp,count,add;
unsigned char *p;
p=*buf;
add=1;
while(*p!='\0') {
cmp=strncmp(string,p,strlen(string));
if(cmp>0) {
while(*p!=' ' && *p!='\0') // find next space
p++;
while(*p==' ' && *p!='\0') // find next non space
p++;
} else if(cmp==0) {
add=0;
break;
} else {
break;
}
}
if(add) {
count=strlen(*buf)+strlen(string)+1+1;
if(*buf==NULL || count>*len) {
int diff=p-*buf;
*len = *len + 128;
*buf=realloc(*buf,*len);
p=*buf+diff;
}
memmove(p+strlen(string)+1,p,strlen(p)+1);
memmove(p,string,strlen(string));
p+=strlen(string);
*p=' ';
}
return(add);
}
void line_get_string(int len, unsigned char *buf, int n, unsigned char *string)
{
int e,ok,count;
unsigned char *p,*q;
ok=0;
p=string;
e=0;
while(*p!='\0') {
if(e==n) {
ok=1;
break;
}
while(*p!=' ' && *p!='\0') // find next space
p++;
while(*p==' ' && *p!='\0') // find next non space
p++;
e++;
}
if(ok) {
q=buf;
count=0;
while(*q!=' ' && *q!='\0') {
if(++count<len)
*q++=*p;
p++;
}
*q='\0';
} else {
buf[0]='\0';
}
}
void line_dump(unsigned char *string)
{
int e,n;
unsigned char *p;
p=string;
n=0;
while(*p!='\0') {
fprintf(stdout," %d:",n++);
while(*p!=' ' && *p!='\0') // find next space
putchar(*p++);
while(*p==' ' && *p!='\0') // find next non space
p++;
e++;
}
fprintf(stdout,"\n");
}
static int size=5, zero=1, sspace=0, scrlf=1,
chars=72, pchars=0, words=0, pwords=0,
lines=10, plines=0, plinesdigits=5, slineno=1,
quiet=0, sort=0, unique=0, sample=0;
static unsigned long limit, word;
static unsigned char *digits="0123456789", character[32];
static unsigned char digitstemp[256];
static unsigned char linenobuf[1024];
unsigned char wordbuf[1024];
void readword(unsigned char *buf)
{
int d,e;
unsigned char temp1024[1024];
if(limit!=0) {
word=0;
if(zero) {
word=ressu_gen_limit(limit); // include zeroes
//fprintf(stdout,"(%02ld)",word);
} else if(limit>=1) {
while((word=ressu_gen_limit(limit))==0); // skip zeroes
}
out_word(sizeof(temp1024),temp1024,digits,word);
// fill leading zeroes
buf[0]='\0';
utf8getchar(sizeof(character),character,0,digits);
for(d=size-utf8len(temp1024);d>0;d--) {
strcat(buf,character);
}
// rest of the number
strcat(buf,temp1024);
} else if(digits!=NULL) {
int digitslen;
buf[0]='\0';
digitslen=utf8len(digits);
// fill whole word digit by digit
//fprintf(stdout,"[");
for(d=0;d<size;d++) {
if(digits[0]=='0' && !zero)
e=ressu_gen_limit(digitslen-1)+1;
else
e=ressu_gen_limit(digitslen);
utf8getchar(sizeof(temp1024),temp1024,e,digits);
//fprintf(stdout,"%s",temp1024);
strcat(buf,temp1024);
}
//fprintf(stdout,"]");
}
}
int line_number_length()
{
int c;
out_word(sizeof(linenobuf),linenobuf,"0123456789",lines-1);
c=strlen(linenobuf);
if(c<5)
c=5;
return(c);
}
void print_line_number()
{
unsigned char linenobuf[1024];
if(pchars==0 && !quiet && slineno) {
sprintf(linenobuf,"%0*d",plinesdigits,plines);
fprintf(stdout,"%s",linenobuf);
pchars +=strlen(linenobuf);
fprintf(stdout," ");
pchars++;
}
}
void print_spaces()
{
if(sspace && pchars>0 && !quiet) {
if(sspace==3 && pwords%2==0) {
fprintf(stdout," ");
pchars++;
}
fprintf(stdout," ");
pchars++;
}
}
void print_word(unsigned char *buf)
{
if(size!=0) {
if(!quiet)
fprintf(stdout,"%*s",size,buf);
pchars += size;
pwords++;
} else {
if(!quiet)
fprintf(stdout,"%s",buf);
pchars += strlen(wordbuf);
pwords++;
}
}
#define aDEBUG86 2
#define aDEBUG87 2
#define aDEBUG88 2
#define aDEBUG89 2
int main(int argc, char *argv[])
{
int c,d;
procname=argv[0];
limit=0;
#ifdef DEBUG4
ccp=cc;
cc_bytes=0;
#endif
clockbytes=0;
for(d=0;d<1024;d++)
periods[d]=0;
// look thru command line parameters
for(c=1;c<argc;c++) {
if(!strncmp("-",argv[c],1)) {
if(!strcmp("--lineno",argv[c])) {
slineno=!slineno;
} else if(!strcmp("--crlf",argv[c])) {
scrlf=!scrlf;
slineno=0;
} else if(!strcmp("--quiet",argv[c])) {
quiet=!quiet;
} else if(!strcmp("--stats",argv[c]) ||
!strcmp("--stat",argv[c])) {
stats=!stats;
} else if(!strcmp("--space",argv[c])) {
sspace=!sspace;
} else if(!strcmp("--zero",argv[c])) {
zero=!zero;
} else if(!strcmp("--sort",argv[c])) {
sort=!sort;
if(sspace==0)
sspace=1;
} else if(!strcmp("--unique",argv[c])) {
unique=!unique;
if(sspace==0)
sspace=1;
} else if(!strcmp("--lotto",argv[c])) {
sort=!sort;
if(sspace==0)
sspace=1;
//sort=1;
//unique=1;
} else if(!strcmp("--sample",argv[c])) {
sample=!sample;
} else if(!strcmp("--copyright",argv[c]) ||
!strcmp("--version",argv[c])) {
fprintf(stderr,"%s",programname);
fprintf(stderr,", %s",copyright);
fprintf(stderr,"\n\n");
help=1;
} else if(!strncmp("--lim",argv[c],5)) {
if(*(argv[c]+5)!='\0') {
in_word(&limit, digits, argv[c]+5);
} else if(c+1<argc) {
in_word(&limit, digits, argv[c+1]);
c++;
}
if(sspace<1) // 23.6.2021
sspace=1;
} else if(!strncmp("-s",argv[c],2)) {
if(*(argv[c]+2)!='\0') {
size=atoi(argv[c]+2);
} else if(c+1<argc) {
size=atoi(argv[c+1]);
c++;
}
limit=0; // 23.6.2021
if(size==0)
size=1;
if(size>1024)
size=1024;
} else if(!strncmp("--bits",argv[c],6)) {
if(*(argv[c]+6)!='\0') {
ressu_bits_needed=atoi(argv[c]+6);
} else if(c+1<argc) {
ressu_bits_needed=atoi(argv[c+1]);
c++;
}
} else if(!strncmp("--bytes",argv[c],7)) {
if(*(argv[c]+7)!='\0') {
ressut_bytes=atoi(argv[c]+7);
} else if(c+1<argc) {
ressut_bytes=atoi(argv[c+1]);
c++;
}
} else if(!strncmp("-w",argv[c],2)) { // words per line
if(*(argv[c]+2)!='\0') {
words=atoi(argv[c]+2);
} else if(c+1<argc) {
words=atoi(argv[c+1]);
c++;
}
if(words<1)
words=1;
chars = 0;
} else if(!strncmp("-c",argv[c],2)) { // characters per line
if(*(argv[c]+2)!='\0') {
chars=atoi(argv[c]+2);
} else if(c+1<argc) {
chars=atoi(argv[c+1]);
c++;
}
words=0;
} else if(!strncmp("-l",argv[c],2)) { // lines
if(*(argv[c]+2)!='\0') {
lines=atoi(argv[c]+2);
} else if(c+1<argc) {
lines=atoi(argv[c+1]);
c++;
}
if(lines<1)
lines=1;
} else if(!strcmp("-x",argv[c])) {
digits = "0123456789abcdef";
size=4;
} else if(!strcmp("-d",argv[c])) {
digits = "0123456789";
size=5;
} else if(!strcmp("-o",argv[c])) {
digits = "01234567";
size=3;
} else if(!strcmp("-b",argv[c])) {
digits = "01";
size=8;
} else if(!strcmp("-1",argv[c])) {
digits=
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
size=8;
} else if(!strcmp("-2",argv[c])) {
digits=
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"_-";
size=8;
} else if(!strcmp("-3",argv[c])) { // 9.5.2021 JariK
digits=
"!\"#$%&'()*+,-./0123456789:;<=>?@" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
"abcdefghijklmnopqrstuvwxyz{|}~";
size=8;
} else if(!strcmp("-4",argv[c])) {
digits=
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ" \
"абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
size=8;
} else if(!strcmp("--isalnum",argv[c]) || // 9.5.2021 JariK
!strcmp("--isalpha",argv[c]) ||
!strcmp("--isdigit",argv[c]) ||
!strcmp("--isgraph",argv[c]) ||
!strcmp("--islower",argv[c]) ||
!strcmp("--isprint",argv[c]) ||
!strcmp("--ispunct",argv[c]) ||
!strcmp("--isupper",argv[c]) ||
!strcmp("--isxdigit",argv[c])) {
unsigned char *p=digitstemp;
for(d=0;d<256;d++) {
if((!strcmp("--isalnum",argv[c]) && isalnum(d)) ||
(!strcmp("--isalpha",argv[c]) && isalpha(d)) ||
(!strcmp("--isdigit",argv[c]) && isdigit(d)) ||
(!strcmp("--isgraph",argv[c]) && isgraph(d)) ||
(!strcmp("--islower",argv[c]) && islower(d)) ||
(!strcmp("--isprint",argv[c]) && isprint(d)) ||
(!strcmp("--ispunct",argv[c]) && ispunct(d)) ||
(!strcmp("--isupper",argv[c]) && isupper(d)) ||
(!strcmp("--isxdigit",argv[c]) && isxdigit(d))) {
*p++=d;
}
}
*p='\0';
digits=digitstemp;
size=8;
} else if(!strcmp("--rand",argv[c])) {
digits = "0123456789";
sspace=3;
slineno=1;
words=10;
chars=0;
limit=100000;
//size=5;
//lines=20000;
} else if(!strncmp("-i",argv[c],2)) {
digits=NULL;
if(*(argv[c]+2)!='\0') {
digits=argv[c]+2;
} else if(c+1 < argc) {
digits=argv[c+1];
c++;
}
if(digits==NULL || utf8len(digits)<2) {
fprintf(stderr,"%s: not enough digits \"%s\"\n",procname,argv[c]);
help = 1;
}
size=1;
} else if(!strcmp("--ressu",argv[c])) {
input=0;
} else if(!strcmp("--debug",argv[c])) {
input=1;
} else if(!strcmp("--fast",argv[c])) {
input=2;
} else if(!strcmp("--single",argv[c])) {
input=3;
} else if(!strcmp("--urandom",argv[c])) {
input=8;
#ifdef USE_RANDOM
} else if(!strcmp("--random",argv[c])) {
input=9;
#endif
} else {
fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
help = 1;
}
} else {
help = 1;
} // if(!strncmp
} // for(c=0
if(sample) {
FILE *fp1;
unsigned char buffer[4096];
fp1=fopen("newressusample.rnd","w");
for(c=0;c<1048576;c++) {
ressu_genbytes(sizeof(buffer),buffer);
fwrite(buffer,1,sizeof(buffer),fp1);
ressu_genbytes(sizeof(buffer),buffer);
fwrite(buffer,1,sizeof(buffer),fp1);
}
fclose(fp1);
exit(0);
}
// get linenumber length in digits
plinesdigits=line_number_length();
// get data length in digits
if(limit!=0) {
unsigned char wordbuf[128];
out_word(sizeof(wordbuf),wordbuf,digits,limit-1);
size=utf8len(wordbuf);
}
pchars=0;
pwords=0;
int linew=0;
// in beginning of line, count printed line number
if(!quiet && slineno) {
sprintf(linenobuf,"%0*d",plinesdigits,plines);
pchars += strlen(linenobuf);
pchars++;
}
// count words
while((chars>0 && pchars+size < chars) ||
(words>0 && pwords < words)) {
linew++;
if(sspace && pchars>0 && !quiet) {
if(sspace==3 && pwords%2==0)
pchars++;
pchars++;
}
pchars+=size;
pwords++;
}
unsigned long wordvalues=1;
for(c=0;c<size;c++) {
if(wordvalues!=0 && wordvalues*utf8len(digits)<(unsigned long)65536*65536*65536) {
wordvalues*=utf8len(digits);
} else {
wordvalues=0;
}
}
if(limit > 0) {
if(sort==1 && limit-!zero<words) {
fprintf(stderr,"%s: limit is less than words (zero)",procname);
fprintf(stderr,", limit:%lu",limit);
fprintf(stderr,", words:%d",words);
fprintf(stderr,", zero:%d",zero);
fprintf(stderr,"\n");
help=1;
lines=0;
}
} else {
if(sort==1 && size>0 && wordvalues>0 && wordvalues<linew) {
fprintf(stderr,"%s:",procname);
fprintf(stderr," digits is less than calculated words");
fprintf(stderr,", digits:%d(%lu)",utf8len(digits),wordvalues);
fprintf(stderr,", words:%d\n",linew);
help=1;
lines=0;
}
}
// small words as single ressu_gen_limit()
if(limit==0 && wordvalues>0)
limit=wordvalues;
if(stats) {
fprintf(stdout,"randomsource: %s",randomgen[input]);
fprintf(stdout,", size: %d",size);
fprintf(stdout,", linew: %d",linew);
fprintf(stdout,", pchars: %d",pchars);
fprintf(stdout,", pwords: %d",pwords);
if(wordvalues>0)
fprintf(stdout,", wordvalues: %lu",wordvalues);
if(limit>0)
fprintf(stdout,", limit: %lu",limit);
fprintf(stdout,"\n");
}
if(help) {
struct helpline {
char *command;
char *text;
} helplines[] = {
{ "newressu -d", "print random decimal digits" },
{ "newressu -o", "print octal digits" },
{ "newressu -x", "print hexadecimal digits" },
{ "newressu -b", "print binary digits" },
{ "newressu -d --space", "print decimal digits, with spaces between \"words\"" },
{ "newressu -b --space", "print binary digits, with spaces between \"words\"" },
{ "newressu -d -l30", "print decimal digits, 30 lines" },
{ "newressu -d -l30 --lineno", "print decimal digits, 30 lines, no linenumbers" },
{ "newressu -d -c128", "print decimal digits, 128 characters per line" },
{ "newressu -d --lim10", "print decimal numbers between 0-9" },
{ "newressu -d --lim10 -x","print hexadecimal numbers with decimal limit" },
{ "newressu -d -s10 --space","print decimal numbers with spaces and wordsize 10" },
{ "newressu -d --space --zero --lim7","print rollings of dice (1-6)" },
{ "newressu -b -s1 --space","print throws of coin (0,1)" },
{ "newressu -d --lim41 -w7 --zero --lotto","print lotto numbers for finnish lotto 7x(1-40)" },
{ "newressu -d -s5 --sort -w16","print 16 sorted decimal numbers from 0 to 99999" },
{ "newressu --isalnum", "print alphanumeric characters" },
{ "newressu --isalpha", "print alphabetic characters" },
{ "newressu --isgraph", "print printables excluding space" },
{ "newressu --islower", "print lowercase characters" },
{ "newressu --ispunct", "print punctuation characters" },
{ "newressu --isupper", "print uppercase characters" },
{ "newressu -1", "print material for passwords" },
{ "newressu -iаэыуояеёюи", "print russian vowels" },
{ "newressu --ressu", "use randomness from ressu (default)" },
{ "newressu --debug", "use randomness from debugging ressu" },
{ "newressu --fast", "use randomness from fast ressu" },
{ "newressu --single", "use randomness from single round of ressu" },
{ "newressu --urandom", "use randomness from /dev/urandom" },
#ifdef USE_RANDOM
{ "newressu --random", "use randomness from /dev/random" },
#endif
};
for(c=0;c<sizeof(helplines)/sizeof(helplines[0]);c++) {
fprintf(stderr,"%-50s",helplines[c].text);
fprintf(stderr,"%-25s",helplines[c].command);
fprintf(stderr,"\n");
}
for(c=0;c<chars;c++)
fprintf(stdout,"*");
fprintf(stdout,"\n");
if(lines>1)
lines=1; // print one line below help as a sample
}
if(lines==0)
exit(1);
int linecnt=0;
unsigned char *line=NULL;
unsigned char wordbuf[1025];
for(;;) {
if(!sort) { // also lotto
pchars=0;
pwords=0;
while(pwords<linew) {
readword(wordbuf);
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
} // while(pwords<linew) {
} else { // if(!sort)
pchars=0;
pwords=0;
line_clear(&linecnt,&line);
// fetch and save words on this row
while(pwords<linew) {
readword(wordbuf);
if(line_add_string_sort(&linecnt,&line,wordbuf)) {
pwords++;
}
} // while(pwords<linew) {
pchars=0;
pwords=0;
// print words on this row
while(pwords<linew) {
line_get_string(sizeof(wordbuf),wordbuf,pwords,line);
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces();
// print word
print_word(wordbuf);
} // while(pwords<linew) {
} // if(!sort)
// line full?
if(!quiet) {
fprintf(stdout,"\n");
}
plines++;
if(sspace==3 && plines<lines && plines%5==0)
fprintf(stdout,"\n");
// all needed lines printed?
if(plines >= lines)
break;
} // for(;;)
fflush(stdout);
}
#endif // MAIN