Kaikki oikeudet pidätetään ©. Maailman parhaat satunnaisbitit: https://moijari.com:5006.
Versionumeron kasvatuksen yhteydessä käyn läpi kaikki uudet ja vanhat pääfunktiot.
Edit: korjailen raporttia vielä seuraavien viikkojen aikana
Edit: olen jatkanut ressun tutkimista ja lisäilen illan mittaan uusia kappaleita raporttiin. Lisätty kaksi uutta tilastoohjelmaa, uudelleenkirjoituskappaleet stat_line funktioista ja sample() rutiinista. Toinen tilastoohjelma sisältää tertun ytimelle toivottavasti sopivan kenttien ja tietueiden hallinnan pohjan.
Edit Lisätty loppuun kappaleita exfat bugin korjaamisesta. Bugi korjautui osittain lisäämällä tulostettavaan tiedostoon fflush ja sync.
Edit: vähennetty stat_line:n “nykimistä”. Numerokentät (readable) ovat nyt useimmiten neljän pituisia.
Edit: Lisää exfat ongelman tutkimista. Lisätty ohjelma newressutest12, joka kirjoittaa kiinteän pituisia tietueita ja lukee ja tarkistaa tietueet. (vrt newressutest10)
Edit: Muutettu komentoriviparametrejä samankaltaisiksi. Ennen parametrit olivat esimerkiksi -b, –bytes, –lines, ne olivat erilaisia joka ohjelmassa. Nyt ne on samanlaisia eli –filesize 1g, –binsize 10, –linesize 21, –lines 1m, –blocksize 1024, –blocks 1m jne. Muutenkin näiden parametrien laskentaa ja tarkistusta on järkeistetty. Huomaa, että raportin komentoesimerkeissä vanhat versiot eivät enää toimi. Myös ,/newressu –sample –filesize 1g ja muut koko-parametrit toimivat.
Edit: Lisätty stream_open -funktion avaimen muodostukseen stream_keyn lisäksi cvar. Tämä tekee uudesta stream_key:stä satunnaisemman. Näin samoja stream_key avaimia ei kierretä uudelleen ja uudelleen. Jos jostain syystä päädymme samaan stream_key:in toistamiseen, seuraavan avaimen laskemiseen käytetään erilaista cvar kenttää, jolloin saman sarjan läpikäyminen loppuu heti.
Edit: lisätty newressu ohjelmaan –columns kytkin, jolla saa sarakenumerot sarakkeiden yläpuolelle.
Edit Vähennetty lisää stat_line:n nykimistä. Nyt myös left ja end kentät heiluvat vähemmän.
Edit: lisätty sample() satunnaislukutiedoston muodostukseen grep:illä tulostettava automaattinen ongelmien lista.
Edit: Lisätty –som komento-optio, jolla tulostetaan somalian merkkijonoja. Ensimmäisessä versiossa ei
Edit: Lisätty integrity testi, jossa aina (DEBUG72) ./newressu ajon alussa kirjoitetaan useimmilla –kytkimillä rivejä newressutest14.rnd* tiedostoon. Jokaiselle päivälle luodaan oma tiedostonsa.
Edit: Vielä listaus ressun ytimestä ilman copy/reverseä ja tilastollisia laskelmia, jotta nopeasti ymmärrät mikä tämä ressun sydän on. Seuraavassa on yksi kahdeksan bitin kierros ressua. Ydintä ajetaan kunnes kaikki tilastolliset satunnaisbittien määrän arvioinnit täyttyvät:
#define RR8(byte, bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte, bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
{
int c, d;
unsigned char e;
static int f = 0;
for(c = 0; c < 8; c++) {
for(d = 0; d < size; d++) {
e = buffer[d];
e = RL8(e, 1); // rotate byte left 1 bits
//e = RL8(e, 3); // rotate byte left 3 bits
//e = RR8(e, 1); // rotate byte right 1 bits
buffer[d] = e ^ ressu_clockbyte();
}
for(d = 0; d < size; d++) {
f = (f + buffer[d] + 2) % size; // + 2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
}
}
Asiasta toiseen tuo edellisen koodin + 2 on ns + 2 bugi, joka korjataan tässä raportissa. Tuo clockbyte() palauttaa käytettävän kellojonon, sisältää copy/reverse koodin ja perus tilastojen laskennan koodin. Kutsuvassa rutiinissa taas on teoreettisten satunnaisbittien laskennan toiminnot ja vertailut.
Edit: lisäsin flags rakenteen tähän alkuun, jotta se löytyisi raportista helpommin:
struct idflags { // 202307 JariK
unsigned char *id;
unsigned char *flags;
} idsflags[] = {
{ "🇫🇮", "🇫🇮: fi, fin, Finland, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC, FINLAND" },
{ "🇦🇽", "🇦🇽: ax, ala, Åland, aland, NORDIC, FINLAND" },
{ "🇸🇪", "🇸🇪: se, swe, Sweden, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇳🇴", "🇳🇴: no, nor, Norway, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇩🇰", "🇩🇰: dk, dnk, Denmark, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC, DENMARK" },
{ "🇫🇴", "🇫🇴: fo, fro, FaroeIslands, NORDIC, DENMARK" },
{ "🇮🇸", "🇮🇸: is, isl, Iceland, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇬🇱", "🇬🇱: gl, grl, Greenland, NORTHAMERICA, NORDIC, DENMARK" },
{ "🇪🇪", "🇪🇪: ee, est, Estonia, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇱🇻", "🇱🇻: lv, lva, Latvia, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇱🇹", "🇱🇹: lt, ltu, Lithuania, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇺🇦", "🇺🇦: ua, ukr, Ukraine, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇱", "🇦🇱: al, alb, Albania, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇩", "🇦🇩: ad, and, Andorra, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇲", "🇦🇲: am, arm, Armenia, EASTERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇦🇹", "🇦🇹: at, aut, Austria, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇿", "🇦🇿: az, aze, Azerbaijan, EASTERNEUROPE, EUROPE, WESTASIA, ASIA, EURASIA" },
{ "🇧🇾", "🇧🇾: by, blr, Belarus, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇧🇪", "🇧🇪: be, bel, Belgium, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇧🇦", "🇧🇦: ba, bih, BosniaandHerzegovina, EASTERNEUROPE, EUROPE" }, // Bosnia and Herzegovina
{ "🇧🇬", "🇧🇬: bg, bgr, Bulgaria, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇭🇷", "🇭🇷: hr, hrv, Croatia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇨🇾", "🇨🇾: cy, cyp, Cyprus, EU, SOUTHERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇨🇿", "🇨🇿: cz, cze, CzechRepublic, EU, EASTERNEUROPE, EUROPE, EURASIA" }, // Czech Republic Czechia
{ "🇫🇷", "🇫🇷: fr, fra, France, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇬🇪", "🇬🇪: ge, geo, Georgia, EASTERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇩🇪", "🇩🇪: de, deu, Germany, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇬🇷", "🇬🇷: gr, grc, Greece, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇭🇺", "🇭🇺: hu, hun, Hungary, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇪", "🇮🇪: ie, irl, Ireland, UK, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇹", "🇮🇹: it, ita, Italy, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇻🇦", "🇻🇦: va, vat, Vatican, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇰🇿", "🇰🇿: kz, kaz, Kazakhstan, EUROPE, EURASIA, CENTRALASIA, ASIA" },
{ "🇱🇮", "🇱🇮: li, lie, Liechtenstein, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇱🇺", "🇱🇺: lu, lux, Luxembourg, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇹", "🇲🇹: mt, mlt, Malta, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇩", "🇲🇩: md, mda, Moldova, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇪", "🇲🇪: me, mne, Montenegro, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇨", "🇲🇨: mc, mco, Monaco, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇪", "🇲🇪: me, mne, Montenegro, EUROPE, EURASIA" },
{ "🇳🇱", "🇳🇱: nl, nld, Netherlands, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇰", "🇲🇰: mk, mkd, Northmacedonia, EASTERNEUROPE, EUROPE, EURASIA" }, // North Macedonia
{ "🇵🇱", "🇵🇱: pl, pol, Poland, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇵🇹", "🇵🇹: pt, prt, Portugal, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇷🇴", "🇷🇴: ro, rou, Romania, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇷🇺", "🇷🇺: ru, rus, Russia, EASTERNEUROPE, EUROPE, EURASIA, NORTHASIA, ASIA, BRICS" },
{ "🇸🇲", "🇸🇲: sm, smr, SanMarino, SOUTHERNEUROPE, EUROPE, EURASIA" }, // San Marino
{ "🇷🇸", "🇷🇸: rs, srb, Serbia, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇸🇰", "🇸🇰: sk, svk, Slovakia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇸🇮", "🇸🇮: si, svn, Slovenia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇪🇸", "🇪🇸: es, esp, Spain, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇨🇭", "🇨🇭: ch, che, Switzerland, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇹🇷", "🇹🇷: tr, tur, Turkey, SOUTHERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇬🇧", "🇬🇧: gb, gbr, UnitedKingdom, UK, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇪", "🇮🇪: gb, gbr, England, UK" },
{ "🇮🇪", "🇮🇪: gb, gbr, Scotland, UK" },
{ "🇮🇪", "🇮🇪: gb, gbr, Wales, UK" },
{ "🇬🇮", "🇬🇮: gi, gib, Gibraltar, UK" },
{ "🇸🇯", "🇸🇯: sj, sjm, JanMayen, NORWAY" }, // Jan Mayen
{ "🇦🇮", "🇦🇮: ai, aia, Anguilla, NORTHAMERICA, UK" },
{ "🇦🇬", "🇦🇬: ag, atg, AntiguaAndBarbuda, NORTHAMERICA" }, // Antigua and Barbuda
{ "🇦🇼", "🇦🇼: aw, sbw, Aruba, NORTHAMERICA" },
{ "🇧🇸", "🇧🇸: bs, bhs, Bahamas, NORTHAMERICA" },
{ "🇧🇧", "🇧🇧: bb, brb, Barbados, NORTHAMERICA" },
{ "🇧🇿", "🇧🇿: bz, blz, Belize, NORTHAMERICA" },
{ "🇧🇲", "🇧🇲: bm, bmu, Bermuda, UK, NORTHAMERICA" },
{ "🇧🇶", "🇧🇶: bq, bes, Bonaire, NETHERLANDS, NORTHAMERICA" },
{ "🇻🇬", "🇻🇬: vg, vgb, BritishVirginIslands, UK, NORTHAMERICA" }, // British Virgin Islands
{ "🇨🇦", "🇨🇦: ca, can, Canada, NORTHAMERICA" },
{ "🇰🇾", "🇰🇾: ky, cym, CaymanIslands, UK, NORTHAMERICA" },
{ "🇫🇷", "🇫🇷: fr, fra, ClippertonIsland, FRANCE, NORTHAMERICA" },
{ "🇨🇷", "🇨🇷: cr, cri, CostaRica, NORTHAMERICA" },
{ "🇨🇺", "🇨🇺: cu, cub, Cuba, NORTHAMERICA" },
{ "🇨🇼", "🇨🇼: cw, cuw, Curaçao, curacao, NORTHAMERICA" },
{ "🇩🇲", "🇩🇲: dm, dma, Dominica, NORTHAMERICA" },
{ "🇩🇴", "🇩🇴: do, dom, DominicanRepublic, NORTHAMERICA" }, // Dominican Republic
{ "🇸🇻", "🇸🇻: sv, slv, ElSalvador, NORTHAMERICA" },
{ "🇬🇱", "🇬🇱: gl, grl, Greenland, DENMARK, NORTHAMERICA" },
{ "🇬🇩", "🇬🇩: gd, grd, Grenada, NORTHAMERICA" },
{ "🇬🇵", "🇬🇵: gp, glp, Guadeloupe, FRANCE, NORTHAMERICA" },
{ "🇬🇹", "🇬🇹: gt, gtm, Guatemala, NORTHAMERICA" },
{ "🇭🇹", "🇭🇹: ht, hti, Haiti, NORTHAMERICA" },
{ "🇭🇳", "🇭🇳: hn, hnd, Honduras, NORTHAMERICA" },
{ "🇯🇲", "🇯🇲: jm, jam, Jamaica, NORTHAMERICA" },
{ "🇲🇶", "🇲🇶: mq, mtq, Martinique, FRANCE, NORTHAMERICA" },
{ "🇲🇽", "🇲🇽: mx, mex, Mexico, NORTHAMERICA" },
{ "🇲🇸", "🇲🇸: ms, msr, Montserrat, UK, NORTHAMERICA" },
{ "🇳🇮", "🇳🇮: ni, nic, Nicaragua, NORTHAMERICA" },
{ "🇵🇦", "🇵🇦: pa, pan, Panama, NORTHAMERICA" },
{ "🇵🇷", "🇵🇷: pr, pri, PuertoRico, NORTHAMERICA" },
{ "🇧🇶", "🇧🇶: bq, bes, Saba, NORTHAMERICA" },
{ "🇧🇱", "🇧🇱: bl, blm, SaintBarthélemy, saintbarthelemy, NORTHAMERICA" }, // Saint Barthélemy
{ "🇰🇳", "🇰🇳: kn, kna, SaintKitts, NORTHAMERICA" }, // Saint Kitts and Nevis
{ "🇱🇨", "🇱🇨: lc, lca, SaintLucia, NORTHAMERICA" }, // Saint Lucia
{ "🇲🇫", "🇲🇫: mf, maf, SaintMartin, NORTHAMERICA" }, // Collectivity of Saint Martin
{ "🇸🇽", "🇸🇽: sx, sxm, SintMaarten, NORTHAMERICA" }, // Sint Maarten
{ "🇹🇹", "🇹🇹: tt, tto, TrinidadandTobago, NORTHAMERICA" }, // Trinidad and Tobago
{ "🇹🇨", "🇹🇨: tc, tca, TurksandCaicos, UK, NORTHAMERICA" }, // Turks and Caicos Islands
{ "🇵🇲", "🇵🇲: pm, spm, SaintPierre, NORTHAMERICA" }, // Saint Pierre and Miquelon
{ "🇻🇨", "🇻🇨: vc, vct, SaintVincent, NORTHAMERICA" }, // Saint Vincent and the Grenadines
{ "🇺🇸", "🇺🇸: us, usa, UnitedStatesofAmerica, USA, NORTHAMERICA" }, // United States of America
{ "🇻🇮", "🇻🇮: vi, vir, VirginIslands, USA, NORTHAMERICA" }, // United States Virgin Islands
{ "🇧🇻", "🇧🇻: bv, bvt, BouvetIsland" }, // Bouvet Island
{ "🇺🇲", "🇺🇲: um, umi, Navassa" },
{ "🇸🇭", "🇸🇭: sh, shn, SaintHelena" }, // Saint Helena
{ "🇦🇷", "🇦🇷: ar, arg, Argentina, SOUTHAMERICA" },
{ "🇧🇴", "🇧🇴: bo, bol, Bolivia, SOUTHAMERICA" },
{ "🇧🇷", "🇧🇷: br, bra, Brazil, SOUTHAMERICA, BRICS" },
{ "🇨🇱", "🇨🇱: cl, chl, Chile, SOUTHAMERICA" },
{ "🇨🇴", "🇨🇴: co, col, Colombia, SOUTHAMERICA" },
{ "🇪🇨", "🇪🇨: ec, ecu, Ecuador, SOUTHAMERICA" },
{ "🇫🇰", "🇫🇰: fk, flk, FalklandIslands, UK, SOUTHAMERICA" }, // Falkland Islands
{ "🇬🇫", "🇬🇫: gf, guf, FrenchGuiana, SOUTHAMERICA, FRANCE" }, // French Guiana
{ "🇬🇾", "🇬🇾: gy, guy, Guyana, SOUTHAMERICA" },
{ "🇵🇾", "🇵🇾: py, pry, Paraguay, SOUTHAMERICA" },
{ "🇵🇪", "🇵🇪: pe, per, Peru, SOUTHAMERICA" },
{ "🇬🇸", "🇬🇸: gs, sgs, SouthGeorgia, SOUTHAMERICA" }, // South Georgia and the South Sandwich Islands
{ "🇸🇷", "🇸🇷: sr, sur, Suriname, SOUTHAMERICA" },
{ "🇺🇾", "🇺🇾: uy, ury, Uruguay, SOUTHAMERICA" },
{ "🇻🇪", "🇻🇪: ve, ven, Venezuela, SOUTHAMERICA" },
{ "🇦🇪", "🇦🇪: ae, are, UnitedArabEmirates, WESTASIA, ASIA, EURASIA" }, // United Arab Emirates
{ "🇦🇫", "🇦🇫: af, afg, Afghanistan, SOUTHASIA, ASIA, EURASIA" },
{ "🇧🇩", "🇧🇩: bd, bgd, Bangladesh, SOUTHASIA, ASIA, EURASIA" },
{ "🇧🇭", "🇧🇭: bh, bhr, Bahrain, EASTASIA, ASIA, EURASIA" },
{ "🇧🇳", "🇧🇳: bn, brn, Brunei, ASIA, EURASIA" },
{ "🇧🇹", "🇧🇹: bt, btn, Bhutan, SOUTHASIA, ASIA, EURASIA" },
{ "🇨🇳", "🇨🇳: cn, chn, China, EASTASIA, ASIA, EURASIA, BRICS" },
{ "🇭🇰", "🇭🇰: hk, hkg, HongKong, EASTASIA, ASIA, EURASIA" },
{ "🇮🇩", "🇮🇩: id, idn, Indonesia, ASIA, EURASIA" },
{ "🇮🇱", "🇮🇱: il, isr, Israel, WESTASIA, ASIA, EURASIA" },
{ "🇮🇳", "🇮🇳: in, ind, India, SOUTHASIA, ASIA, EURASIA, BRICS" },
{ "🇮🇶", "🇮🇶: iq, irq, Iraq, WESTASIA, ASIA, EURASIA" },
{ "🇮🇷", "🇮🇷: ir, irn, Iran, WESTASIA, ASIA, EURASIA" },
{ "🇯🇴", "🇯🇴: jo, jor, Jordan, WESTASIA, ASIA, EURASIA" },
{ "🇯🇵", "🇯🇵: jp, jpn, Japan, EASTASIA, ASIA, EURASIA" },
{ "🇰🇬", "🇰🇬: kg, kgz, Kyrgyzstan, CENTRALASIA, ASIA, EURASIA" },
{ "🇰🇭", "🇰🇭: kh, khm, Cambodia, ASIA, EURASIA" },
{ "🇰🇷", "🇰🇷: kr, kor, SouthKorea, EASTASIA, ASIA, EURASIA" },
{ "🇰🇼", "🇰🇼: kw, kwt, Kuwait, WESTASIA, ASIA, EURASIA" },
{ "🇱🇦", "🇱🇦: la, lao, Laos, ASIA, EURASIA" },
{ "🇱🇧", "🇱🇧: lb, lbn, Lebanon, WESTASIA, ASIA, EURASIA" },
{ "🇱🇰", "🇱🇰: lk, lka, SriLanka, SOUTHASIA, ASIA, EURASIA" },
{ "🇲🇳", "🇲🇳: mn, mng, Mongolia, EASTASIA, ASIA, EURASIA" },
{ "🇲🇴", "🇲🇴: mo, mac, Macao, EASTASIA, ASIA, EURASIA" },
{ "🇲🇻", "🇲🇻: mv, mdv, Maldives, SOUTHASIA, ASIA, EURASIA" },
{ "🇲🇲", "🇲🇲: mm, mmr, Myanmar, ASIA, EURASIA" },
{ "🇲🇾", "🇲🇾: my, mys, Malaysia, ASIA, EURASIA" },
{ "🇰🇵", "🇰🇵: kp, prk, NorthKorea, EASTASIA, ASIA, EURASIA" },
{ "🇳🇵", "🇳🇵: np, npl, Nepal, SOUTHASIA, ASIA, EURASIA" },
{ "🇴🇲", "🇴🇲: om, omn, Oman, WESTASIA, ASIA, EURASIA" },
{ "🇵🇭", "🇵🇭: ph, phl, Philippines, ASIA, EURASIA" },
{ "🇵🇰", "🇵🇰: pk, pak, Pakistan, SOUTHASIA, ASIA, EURASIA" },
{ "🇵🇸", "🇵🇸: ps, pse, Palestine, WESTASIA, ASIA, EURASIA" },
{ "🇶🇦", "🇶🇦: qa, qat, Qatar, WESTASIA, ASIA, EURASIA" },
{ "🇸🇦", "🇸🇦: sa, sau, SaudiArabia, WESTASIA, ASIA, EURASIA" },
{ "🇸🇬", "🇸🇬: sg, sgb, Singapore, ASIA, EURASIA" },
{ "🇸🇾", "🇸🇾: sy, syr, Syria, WESTASIA, ASIA, EURASIA" },
{ "🇹🇭", "🇹🇭: th, tha, Thailand, ASIA, EURASIA" },
{ "🇹🇯", "🇹🇯: tj, tjk, Tajikistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇹🇱", "🇹🇱: tl, tls, EastTimor, ASIA, EURASIA" },
{ "🇹🇲", "🇹🇲: tm, tkm, Turkmenistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇹🇼", "🇹🇼: tw, twn, Taiwan, EASTASIA, ASIA, EURASIA" },
{ "🇺🇿", "🇺🇿: uz, uzb, Uzbekistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇻🇳", "🇻🇳: vn, vnm, Vietnam, ASIA, EURASIA" },
{ "🇾🇪", "🇾🇪: ye, yem, Yemen, WESTASIA, ASIA, EURASIA" },
{ "🇳🇪", "🇳🇪: ne, ner, Nigeria, AFRICA, WESTAFRICA" },
{ "🇪🇹", "🇪🇹: et, eth, Ethiopia, AFRICA, AFRICA, EASTAFRICA" },
{ "🇪🇷", "🇪🇷: er, eri, Eritrea, AFRICA, EASTAFRICA" },
{ "🇨🇬", "🇨🇬: cg, cog, Congo, AFRICA, CENTRALAFRICA" }, // Rebublic of the Congo
{ "🇨🇩", "🇨🇩: cd, cod, DemocraticCongo, AFRICA, CENTRALAFRICA" }, // Democratic Rebublic of the Congo
{ "🇹🇿", "🇹🇿: tz, tza, Tanzania, AFRICA, EASTAFRICA" },
{ "🇿🇦", "🇿🇦: za, zaf, SouthAfrica, AFRICA, SOUTHAFRICA, BRICS" },
{ "🇰🇪", "🇰🇪: ke, ken, Kenya, AFRICA, EASTAFRICA" },
{ "🇺🇬", "🇺🇬: ug, uga, Uganda, AFRICA, EASTAFRICA" },
{ "🇸🇸", "🇸🇸: ss, ssd, SouthSudan, AFRICA, EASTAFRICA" },
{ "🇸🇩", "🇸🇩: sd, sdn, Sudan, AFRICA, EASTAFRICA" },
{ "🇩🇿", "🇩🇿: dz, dza, Algeria, AFRICA, NORTHAFRICA" },
{ "🇪🇬", "🇪🇬: eg, egy, Egypt, AFRICA, NORTHAFRICA, WESTASIA, ASIA, EURASIA" },
{ "🇱🇾", "🇱🇾: ly, lby, Libya, AFRICA, NORTHAFRICA" },
{ "🇱🇾", "🇱🇾: ly, lby, Madeira, AFRICA, NORTHAFRICA" },
{ "🇲🇦", "🇲🇦: ma, mar, Morocco, AFRICA, NORTHAFRICA" },
{ "🇦🇴", "🇦🇴: ao, ago, Angola, AFRICA, CENTRALAFRICA" },
{ "🇬🇭", "🇬🇭: gh, gha, Ghana, AFRICA, WESTAFRICA" },
{ "🇲🇿", "🇲🇿: mz, moz, Mozambique, AFRICA" },
{ "🇲🇬", "🇲🇬: mg, mdg, Madagascar, AFRICA, EASTAFRICA" },
{ "🇾🇹", "🇾🇹: yt, myt, Mayotte, FRANCE, AFRICA, EASTAFRICA" },
{ "🇨🇮", "🇨🇮: ci, civ, IvoryCoast, AFRICA, WESTAFRICA" },
{ "🇨🇲", "🇨🇲: cm, cmr, Cameroon, AFRICA, CENTRALAFRICA" },
{ "🇳🇪", "🇳🇪: ne, ner, Niger, AFRICA, WESTAFRICA" },
{ "🇧🇫", "🇧🇫: bf, bfa, BurkinaFaso, AFRICA, WESTAFRICA" }, // Burkina Faso
{ "🇲🇱", "🇲🇱: ml, mli, Mali, AFRICA, WESTAFRICA" },
{ "🇲🇼", "🇲🇼: mw, mwi, Malawi, AFRICA, EASTAFRICA" },
{ "🇿🇲", "🇿🇲: zm, zmb, Zambia, AFRICA, EASTAFRICA" },
{ "🇹🇩", "🇹🇩: td, tcd, Chad, AFRICA, CENTRALAFRICA" },
{ "🇸🇴", "🇸🇴: so, som, Somalia, AFRICA, EASTAFRICA" },
{ "🇸🇳", "🇸🇳: sn, sen, Senegal, AFRICA, WESTAFRICA" },
{ "🇿🇼", "🇿🇼: zw, zwe, Zimbabwe, AFRICA, EASTAFRICA" },
{ "🇬🇳", "🇬🇳: gn, gin, Guinea, AFRICA, WESTAFRICA" },
{ "🇷🇪", "🇷🇪: re, reu, Réunion, reunion, FRANCE, AFRICA, EASTAFRICA" }, // Réunion
{ "🇷🇼", "🇷🇼: rw, rwa, Rwanda, AFRICA, EASTAFRICA" },
{ "🇧🇯", "🇧🇯: bj, ben, Benin, AFRICA, WESTAFRICA" },
{ "🇧🇮", "🇧🇮: bi, bdi, Burundi, AFRICA, EASTAFRICA" },
{ "🇹🇳", "🇹🇳: tn, tun, Tunisia, AFRICA, NORTHAFRICA" },
{ "🇹🇬", "🇹🇬: tg, tgo, Togo, AFRICA, WESTAFRICA" },
{ "🇸🇱", "🇸🇱: sl, sle, SierraLeone, AFRICA, WESTAFRICA" }, // Sierra Leone
{ "🇨🇩", "🇨🇩: cd, cod, Congo, AFRICA, CENTRALAFRICA" },
{ "🇨🇫", "🇨🇫: cf, caf, CentralAfrican, CENTRALAFRICA" }, // Central African Republic
{ "🇱🇷", "🇱🇷: lr, lbr, Liberia, AFRICA, WESTAFRICA" },
{ "🇲🇷", "🇲🇷: mr, mrt, Mauritania, AFRICA, WESTAFRICA" },
{ "🇪🇷", "🇪🇷: er, eri, Eritrea, AFRICA, EASTAFRICA" },
{ "🇬🇲", "🇬🇲: gm, gmb, Gambia, AFRICA, WESTAFRICA" },
{ "🇧🇼", "🇧🇼: bw, bwa, Botswana, AFRICA, SOUTHAFRICA" },
{ "🇳🇦", "🇳🇦: na, nam, Namibia, AFRICA, SOUTHAFRICA" },
{ "🇬🇦", "🇬🇦: ga, gab, Gabon, AFRICA, CENTRALAFRICA" },
{ "🇱🇸", "🇱🇸: ls, lso, Lesotho, AFRICA, SOUTHAFRICA" },
{ "🇬🇼", "🇬🇼: gw, gnb, GuineaBissau, AFRICA, WESTAFRICA" }, // Guinea-Bissau
{ "🇬🇶", "🇬🇶: gq, gnq, EquatorialGuinea, CENTRALAFRICA" }, // Equatorial Guinea
{ "🇲🇺", "🇲🇺: mu, mus, Mauritius, AFRICA, EASTAFRICA" },
{ "🇲🇺", "🇲🇺: mz, moz, Mozambique, AFRICA, EASTAFRICA" },
{ "🇸🇿", "🇸🇿: sz, swz, Eswatini, AFRICA, SOUTHAFRICA" },
{ "🇩🇯", "🇩🇯: dj, dji, Djibouti, AFRICA, EASTAFRICA" },
{ "🇰🇲", "🇰🇲: km, com, Comoros, AFRICA" },
{ "🇨🇻", "🇨🇻: cv, cpv, CapeVerde, AFRICA, WESTAFRICA" },
{ "🇪🇭", "🇪🇭: eh, esh, WesternSahara, SPAIN, AFRICA, NORTHAFRICA" }, // Western Sahara
{ "🇸🇹", "🇸🇹: st, stp, SãoToméandPríncipe, saotomeandprincipe, CENTRALAFRICA" }, // São Tomé and Príncipe
{ "🇸🇨", "🇸🇨: sc, syc, Seychelles, AFRICA, EASTAFRICA" },
{ "🇸🇭", "🇸🇭: sh, shn, TristandaCunha, UK" }, // Tristan da Cunha
{ "🇦🇺", "🇦🇺: au, aus, Australia, AUSTRALASIA, OCEANIA" },
{ "🇨🇽", "🇨🇽: cx, cxr, Christmasisland, AUSTRALIA" }, // Christmas Island
{ "🇨🇨", "🇨🇨: cc, cck, CocosIslands, AUSTRALIA" }, // Cocos (Keeling) Islands
{ "🇮🇲", "🇮🇲: im, imn, ManIsle, UK" }, // Isle of Man
{ "🇰🇮", "🇰🇮: ki, kir, Kiribati, MICRONESIA, OCEANIA" },
{ "🇳🇷", "🇳🇷: nr, nru, Nauru, MICRONESIA, OCEANIA" },
{ "🇳🇨", "🇳🇨: nc, ncl, NewCaledonia, FRANCE, OCEANIA" }, // New Caledonia
{ "🇫🇯", "🇫🇯: fj, fji, Fiji, MELANESIA, OCEANIA" },
{ "🇫🇲", "🇫🇲: fm, fsm, Micronesia, MICRONESIA, OCEANIA" },
{ "🇵🇬", "🇵🇬: pg, png, PapuanewGuinea, MELANESIA, OCEANIA" }, // Papua New Guinea
{ "🇻🇺", "🇻🇺: vu, vut, Vanuatu, MELANESIA, OCEANIA" },
{ "🇸🇧", "🇸🇧: sb, slb, SolomonIslands, MELANESIA, OCEANIA" }, // Solomon Islands
{ "🇬🇺", "🇬🇺: gu, gum, Guam, USA, MICRONESIA, OCEANIA" },
{ "🇲🇭", "🇲🇭: mh, mhl, MarshallIslands, MICRONESIA, OCEANIA" }, // Marshall Islands
{ "🇲🇵", "🇲🇵: mp, mnp, NorthernMariana, MICRONESIA, OCEANIA" }, // Northern Mariana Islands
{ "🇵🇫", "🇵🇫: pf, pyf, FrenchPolynesia, FRANCE, POLYNESIA, OCEANIA" }, // French Polynesia
{ "🇼🇸", "🇼🇸: ws, wsm, Samoa, POLYNESIA, OCEANIA" },
{ "🇼🇫", "🇼🇫: wf, wlf, WallisandFutuna, FRANCE, OCEANIA" }, // Wallis and Futuna
{ "🇹🇻", "🇹🇻: tv, tuv, Tuvalu, OCEANIA" },
{ "🇦🇸", "🇦🇸: as, asm, Americansamoa, USA, POLYNESIA, OCEANIA" }, // American Samoa
{ "🇵🇳", "🇵🇳: pn, pcn, Pitcairn, UK, POLYNESIA, OCEANIA" }, // Pitcairn Islands
{ "🇵🇼", "🇵🇼: pw, plw, Palau, MICRONESIA, OCEANIA" },
{ "🇯🇪", "🇯🇪: je, jey, Jersey, FRANCE" },
{ "🇦🇶", "🇦🇶: aq, ata, Antarctica, ANTARCTICA" },
{ "🇳🇫", "🇳🇫: nf, nfk, NorFolkIsland, AUSTRALASIA, POLYNESIA, OCEANIA" }, // Norfolk Island
{ "🇨🇰", "🇨🇰: ck, cok, Cookisland, NEWZEALAND, POLYNESIA, OCEANIA" }, // Cook Islands
{ "🇳🇿", "🇳🇿: nz, nzl, NewZealand, NEWZEALAND, AUSTRALASIA, OCEANIA" }, // New Zealand
{ "🇳🇺", "🇳🇺: nu, niu, Niue, NEWZEALAND, POLYNESIA, OCEANIA" },
{ "🇹🇰", "🇹🇰: tk, tkl, Tokelau, NEWZEALAND, POLYNESIA, OCEANIA" },
{ "🇹🇴", "🇹🇴: to, ton, Tonga, POLYNESIA, OCEANIA" },
// still missing
{ "🇮🇴", "🇮🇴: io, iot, BritishIndianOcean" }, // British Indian Ocean Territory
{ "🇹🇫", "🇹🇫: tf, atf, FrenchSouthernandaAtarctic" }, // French Southern and Antarctic Lands
{ "🇬🇬", "🇬🇬: gg, ggy, Guernsey, GUERNSEY" },
{ "🇭🇲", "🇭🇲: hm, hmd, HeardandMacDonaldsIslands" }, // Heard Island and McDonald Islands
{ "🇺🇲", "🇺🇲: um, umi, UsMinorOutlyingIslands, US" }, // United States Minor Outlying Islands
};
Edit: Nämä liput taitaa olla suurempi projeksi. Lisätty tähän alkuun lippujen DEBUG77 tuloste, että sekin löytyy helposti.
area:FINLAND, Finland(fi), Åland(ax), count:2
area:DENMARK, Denmark(dk), FaroeIslands(fo), Greenland(gl), Greenland(gl), count:4
area:NORDIC, Finland(fi), Åland(ax), Sweden(se), Norway(no), Denmark(dk), FaroeIslands(fo), Iceland(is), Greenland(gl), count:8
area:BALTIC, Estonia(ee), Latvia(lv), Lithuania(lt), count:3
area:FRANCE, ClippertonIsland(fr), Guadeloupe(gp), Martinique(mq), FrenchGuiana(gf), Mayotte(yt), Réunion(re), NewCaledonia(nc), FrenchPolynesia(pf), WallisandFutuna(wf), Jersey(je), count:10
area:UK, Ireland(ie), UnitedKingdom(gb), England(gb), Scotland(gb), Wales(gb), Gibraltar(gi), Anguilla(ai), Bermuda(bm), BritishVirginIslands(vg), CaymanIslands(ky), Montserrat(ms), TurksandCaicos(tc), FalklandIslands(fk), TristandaCunha(sh), ManIsle(im), Pitcairn(pn), count:16
area:SPAIN, WesternSahara(eh), count:1
area:EU, Finland(fi), Sweden(se), Denmark(dk), Estonia(ee), Latvia(lv), Lithuania(lt), Austria(at), Belgium(be), Bulgaria(bg), Croatia(hr), Cyprus(cy), CzechRepublic(cz), France(fr), Germany(de), Greece(gr), Hungary(hu), Ireland(ie), Italy(it), Luxembourg(lu), Malta(mt), Netherlands(nl), Poland(pl), Portugal(pt), Romania(ro), Slovakia(sk), Slovenia(si), Spain(es), Switzerland(ch), count:28
area:NORTHERNEUROPE, Finland(fi), Sweden(se), Norway(no), Denmark(dk), Iceland(is), Estonia(ee), Latvia(lv), Lithuania(lt), count:8
area:EASTERNEUROPE, Ukraine(ua), Albania(al), Armenia(am), Azerbaijan(az), Belarus(by), BosniaandHerzegovina(ba), Bulgaria(bg), Croatia(hr), CzechRepublic(cz), Georgia(ge), Hungary(hu), Moldova(md), Montenegro(me), Northmacedonia(mk), Poland(pl), Romania(ro), Russia(ru), Serbia(rs), Slovakia(sk), Slovenia(si), count:20
area:SOUTHERNEUROPE, Cyprus(cy), Greece(gr), Italy(it), Vatican(va), Malta(mt), Portugal(pt), SanMarino(sm), Spain(es), Turkey(tr), count:9
area:WESTERNEUROPE, Andorra(ad), Austria(at), Belgium(be), France(fr), Germany(de), Ireland(ie), Liechtenstein(li), Luxembourg(lu), Monaco(mc), Netherlands(nl), Switzerland(ch), UnitedKingdom(gb), count:12
area:EUROPE, Finland(fi), Sweden(se), Norway(no), Denmark(dk), Iceland(is), Estonia(ee), Latvia(lv), Lithuania(lt), Ukraine(ua), Albania(al), Andorra(ad), Armenia(am), Austria(at), Azerbaijan(az), Belarus(by), Belgium(be), BosniaandHerzegovina(ba), Bulgaria(bg), Croatia(hr), Cyprus(cy), CzechRepublic(cz), France(fr), Georgia(ge), Germany(de), Greece(gr), Hungary(hu), Ireland(ie), Italy(it), Vatican(va), Kazakhstan(kz), Liechtenstein(li), Luxembourg(lu), Malta(mt), Moldova(md), Montenegro(me), Monaco(mc), Montenegro(me), Netherlands(nl), Northmacedonia(mk), Poland(pl), Portugal(pt), Romania(ro), Russia(ru), SanMarino(sm), Serbia(rs), Slovakia(sk), Slovenia(si), Spain(es), Switzerland(ch), Turkey(tr), UnitedKingdom(gb), count:51
area:EURASIA, Finland(fi), Sweden(se), Norway(no), Denmark(dk), Iceland(is), Estonia(ee), Latvia(lv), Lithuania(lt), Ukraine(ua), Albania(al), Andorra(ad), Armenia(am), Austria(at), Azerbaijan(az), Belarus(by), Belgium(be), Bulgaria(bg), Croatia(hr), Cyprus(cy), CzechRepublic(cz), France(fr), Georgia(ge), Germany(de), Greece(gr), Hungary(hu), Ireland(ie), Italy(it), Vatican(va), Kazakhstan(kz), Liechtenstein(li), Luxembourg(lu), Malta(mt), Moldova(md), Montenegro(me), Monaco(mc), Montenegro(me), Netherlands(nl), Northmacedonia(mk), Poland(pl), Portugal(pt), Romania(ro), Russia(ru), SanMarino(sm), Serbia(rs), Slovakia(sk), Slovenia(si), Spain(es), Switzerland(ch), Turkey(tr), UnitedKingdom(gb), UnitedArabEmirates(ae), Afghanistan(af), Bangladesh(bd), Bahrain(bh), Brunei(bn), Bhutan(bt), China(cn), HongKong(hk), Indonesia(id), Israel(il), India(in), Iraq(iq), Iran(ir), Jordan(jo), Japan(jp), Kyrgyzstan(kg), Cambodia(kh), SouthKorea(kr), Kuwait(kw), Laos(la), Lebanon(lb), SriLanka(lk), Mongolia(mn), Macao(mo), Maldives(mv), Myanmar(mm), Malaysia(my), NorthKorea(kp), Nepal(np), Oman(om), Philippines(ph), Pakistan(pk), Palestine(ps), Qatar(qa), SaudiArabia(sa), Singapore(sg), Syria(sy), Thailand(th), Tajikistan(tj), EastTimor(tl), Turkmenistan(tm), Taiwan(tw), Uzbekistan(uz), Vietnam(vn), Yemen(ye), Egypt(eg), count:96
area:NORTHASIA, Russia(ru), count:1
area:EASTASIA, Bahrain(bh), China(cn), HongKong(hk), Japan(jp), SouthKorea(kr), Mongolia(mn), Macao(mo), NorthKorea(kp), Taiwan(tw), count:9
area:CENTRALASIA, Kazakhstan(kz), Kyrgyzstan(kg), Tajikistan(tj), Turkmenistan(tm), Uzbekistan(uz), count:5
area:SOUTHASIA, Afghanistan(af), Bangladesh(bd), Bhutan(bt), India(in), SriLanka(lk), Maldives(mv), Nepal(np), Pakistan(pk), count:8
area:WESTASIA, Armenia(am), Azerbaijan(az), Cyprus(cy), Georgia(ge), Turkey(tr), UnitedArabEmirates(ae), Israel(il), Iraq(iq), Iran(ir), Jordan(jo), Kuwait(kw), Lebanon(lb), Oman(om), Palestine(ps), Qatar(qa), SaudiArabia(sa), Syria(sy), Yemen(ye), Egypt(eg), count:19
area:ASIA, Armenia(am), Azerbaijan(az), Cyprus(cy), Georgia(ge), Kazakhstan(kz), Russia(ru), Turkey(tr), UnitedArabEmirates(ae), Afghanistan(af), Bangladesh(bd), Bahrain(bh), Brunei(bn), Bhutan(bt), China(cn), HongKong(hk), Indonesia(id), Israel(il), India(in), Iraq(iq), Iran(ir), Jordan(jo), Japan(jp), Kyrgyzstan(kg), Cambodia(kh), SouthKorea(kr), Kuwait(kw), Laos(la), Lebanon(lb), SriLanka(lk), Mongolia(mn), Macao(mo), Maldives(mv), Myanmar(mm), Malaysia(my), NorthKorea(kp), Nepal(np), Oman(om), Philippines(ph), Pakistan(pk), Palestine(ps), Qatar(qa), SaudiArabia(sa), Singapore(sg), Syria(sy), Thailand(th), Tajikistan(tj), EastTimor(tl), Turkmenistan(tm), Taiwan(tw), Uzbekistan(uz), Vietnam(vn), Yemen(ye), Egypt(eg), count:53
area:NORTHAFRICA, Algeria(dz), Egypt(eg), Libya(ly), Madeira(ly), Morocco(ma), Tunisia(tn), WesternSahara(eh), count:7
area:EASTAFRICA, Ethiopia(et), Eritrea(er), Tanzania(tz), Kenya(ke), Uganda(ug), SouthSudan(ss), Sudan(sd), Madagascar(mg), Mayotte(yt), Malawi(mw), Zambia(zm), Somalia(so), Zimbabwe(zw), Réunion(re), Rwanda(rw), Burundi(bi), Eritrea(er), Mauritius(mu), Mozambique(mz), Djibouti(dj), Seychelles(sc), count:21
area:CENTRALAFRICA, Congo(cg), DemocraticCongo(cd), Angola(ao), Cameroon(cm), Chad(td), Congo(cd), CentralAfrican(cf), Gabon(ga), EquatorialGuinea(gq), SãoToméandPríncipe(st), count:10
area:SOUTHAFRICA, SouthAfrica(za), Botswana(bw), Namibia(na), Lesotho(ls), Eswatini(sz), count:5
area:WESTAFRICA, Nigeria(ne), Ghana(gh), IvoryCoast(ci), Niger(ne), BurkinaFaso(bf), Mali(ml), Senegal(sn), Guinea(gn), Benin(bj), Togo(tg), SierraLeone(sl), Liberia(lr), Mauritania(mr), Gambia(gm), GuineaBissau(gw), CapeVerde(cv), count:16
area:AFRICA, Nigeria(ne), Ethiopia(et), Eritrea(er), Congo(cg), DemocraticCongo(cd), Tanzania(tz), SouthAfrica(za), Kenya(ke), Uganda(ug), SouthSudan(ss), Sudan(sd), Algeria(dz), Egypt(eg), Libya(ly), Madeira(ly), Morocco(ma), Angola(ao), Ghana(gh), Mozambique(mz), Madagascar(mg), Mayotte(yt), IvoryCoast(ci), Cameroon(cm), Niger(ne), BurkinaFaso(bf), Mali(ml), Malawi(mw), Zambia(zm), Chad(td), Somalia(so), Senegal(sn), Zimbabwe(zw), Guinea(gn), Réunion(re), Rwanda(rw), Benin(bj), Burundi(bi), Tunisia(tn), Togo(tg), SierraLeone(sl), Congo(cd), Liberia(lr), Mauritania(mr), Eritrea(er), Gambia(gm), Botswana(bw), Namibia(na), Gabon(ga), Lesotho(ls), GuineaBissau(gw), Mauritius(mu), Mozambique(mz), Eswatini(sz), Djibouti(dj), Comoros(km), CapeVerde(cv), WesternSahara(eh), Seychelles(sc), count:58
area:NORTHAMERICA, Greenland(gl), Anguilla(ai), AntiguaAndBarbuda(ag), Aruba(aw), Bahamas(bs), Barbados(bb), Belize(bz), Bermuda(bm), Bonaire(bq), BritishVirginIslands(vg), Canada(ca), CaymanIslands(ky), ClippertonIsland(fr), CostaRica(cr), Cuba(cu), Curaçao(cw), Dominica(dm), DominicanRepublic(do), ElSalvador(sv), Greenland(gl), Grenada(gd), Guadeloupe(gp), Guatemala(gt), Haiti(ht), Honduras(hn), Jamaica(jm), Martinique(mq), Mexico(mx), Montserrat(ms), Nicaragua(ni), Panama(pa), PuertoRico(pr), Saba(bq), SaintBarthélemy(bl), SaintKitts(kn), SaintLucia(lc), SaintMartin(mf), SintMaarten(sx), TrinidadandTobago(tt), TurksandCaicos(tc), SaintPierre(pm), SaintVincent(vc), UnitedStatesofAmerica(us), VirginIslands(vi), count:44
area:SOUTHAMERICA, Argentina(ar), Bolivia(bo), Brazil(br), Chile(cl), Colombia(co), Ecuador(ec), FalklandIslands(fk), FrenchGuiana(gf), Guyana(gy), Paraguay(py), Peru(pe), SouthGeorgia(gs), Suriname(sr), Uruguay(uy), Venezuela(ve), count:15
area:USA, UnitedStatesofAmerica(us), VirginIslands(vi), Guam(gu), Americansamoa(as), count:4
area:OCEANIA, Australia(au), Kiribati(ki), Nauru(nr), NewCaledonia(nc), Fiji(fj), Micronesia(fm), PapuanewGuinea(pg), Vanuatu(vu), SolomonIslands(sb), Guam(gu), MarshallIslands(mh), NorthernMariana(mp), FrenchPolynesia(pf), Samoa(ws), WallisandFutuna(wf), Tuvalu(tv), Americansamoa(as), Pitcairn(pn), Palau(pw), NorFolkIsland(nf), Cookisland(ck), NewZealand(nz), Niue(nu), Tokelau(tk), Tonga(to), count:25
area:AUSTRALASIA, Australia(au), NorFolkIsland(nf), NewZealand(nz), count:3
area:MELANESIA, Fiji(fj), PapuanewGuinea(pg), Vanuatu(vu), SolomonIslands(sb), count:4
area:MICRONESIA, Kiribati(ki), Nauru(nr), Micronesia(fm), Guam(gu), MarshallIslands(mh), NorthernMariana(mp), Palau(pw), count:7
area:POLYNESIA, FrenchPolynesia(pf), Samoa(ws), Americansamoa(as), Pitcairn(pn), NorFolkIsland(nf), Cookisland(ck), Niue(nu), Tokelau(tk), Tonga(to), count:9
area:BRICS, Russia(ru), Brazil(br), China(cn), India(in), SouthAfrica(za), count:5
area:ALL, Finland(fi), Åland(ax), Sweden(se), Norway(no), Denmark(dk), FaroeIslands(fo), Iceland(is), Greenland(gl), Estonia(ee), Latvia(lv), Lithuania(lt), Ukraine(ua), Albania(al), Andorra(ad), Armenia(am), Austria(at), Azerbaijan(az), Belarus(by), Belgium(be), BosniaandHerzegovina(ba), Bulgaria(bg), Croatia(hr), Cyprus(cy), CzechRepublic(cz), France(fr), Georgia(ge), Germany(de), Greece(gr), Hungary(hu), Ireland(ie), Italy(it), Vatican(va), Kazakhstan(kz), Liechtenstein(li), Luxembourg(lu), Malta(mt), Moldova(md), Montenegro(me), Monaco(mc), Montenegro(me), Netherlands(nl), Northmacedonia(mk), Poland(pl), Portugal(pt), Romania(ro), Russia(ru), SanMarino(sm), Serbia(rs), Slovakia(sk), Slovenia(si), Spain(es), Switzerland(ch), Turkey(tr), UnitedKingdom(gb), England(gb), Scotland(gb), Wales(gb), Gibraltar(gi), JanMayen(sj), Anguilla(ai), AntiguaAndBarbuda(ag), Aruba(aw), Bahamas(bs), Barbados(bb), Belize(bz), Bermuda(bm), Bonaire(bq), BritishVirginIslands(vg), Canada(ca), CaymanIslands(ky), ClippertonIsland(fr), CostaRica(cr), Cuba(cu), Curaçao(cw), Dominica(dm), DominicanRepublic(do), ElSalvador(sv), Greenland(gl), Grenada(gd), Guadeloupe(gp), Guatemala(gt), Haiti(ht), Honduras(hn), Jamaica(jm), Martinique(mq), Mexico(mx), Montserrat(ms), Nicaragua(ni), Panama(pa), PuertoRico(pr), Saba(bq), SaintBarthélemy(bl), SaintKitts(kn), SaintLucia(lc), SaintMartin(mf), SintMaarten(sx), TrinidadandTobago(tt), TurksandCaicos(tc), SaintPierre(pm), SaintVincent(vc), UnitedStatesofAmerica(us), VirginIslands(vi), BouvetIsland(bv), Navassa(um), SaintHelena(sh), Argentina(ar), Bolivia(bo), Brazil(br), Chile(cl), Colombia(co), Ecuador(ec), FalklandIslands(fk), FrenchGuiana(gf), Guyana(gy), Paraguay(py), Peru(pe), SouthGeorgia(gs), Suriname(sr), Uruguay(uy), Venezuela(ve), UnitedArabEmirates(ae), Afghanistan(af), Bangladesh(bd), Bahrain(bh), Brunei(bn), Bhutan(bt), China(cn), HongKong(hk), Indonesia(id), Israel(il), India(in), Iraq(iq), Iran(ir), Jordan(jo), Japan(jp), Kyrgyzstan(kg), Cambodia(kh), SouthKorea(kr), Kuwait(kw), Laos(la), Lebanon(lb), SriLanka(lk), Mongolia(mn), Macao(mo), Maldives(mv), Myanmar(mm), Malaysia(my), NorthKorea(kp), Nepal(np), Oman(om), Philippines(ph), Pakistan(pk), Palestine(ps), Qatar(qa), SaudiArabia(sa), Singapore(sg), Syria(sy), Thailand(th), Tajikistan(tj), EastTimor(tl), Turkmenistan(tm), Taiwan(tw), Uzbekistan(uz), Vietnam(vn), Yemen(ye), Nigeria(ne), Ethiopia(et), Eritrea(er), Congo(cg), DemocraticCongo(cd), Tanzania(tz), SouthAfrica(za), Kenya(ke), Uganda(ug), SouthSudan(ss), Sudan(sd), Algeria(dz), Egypt(eg), Libya(ly), Madeira(ly), Morocco(ma), Angola(ao), Ghana(gh), Mozambique(mz), Madagascar(mg), Mayotte(yt), IvoryCoast(ci), Cameroon(cm), Niger(ne), BurkinaFaso(bf), Mali(ml), Malawi(mw), Zambia(zm), Chad(td), Somalia(so), Senegal(sn), Zimbabwe(zw), Guinea(gn), Réunion(re), Rwanda(rw), Benin(bj), Burundi(bi), Tunisia(tn), Togo(tg), SierraLeone(sl), Congo(cd), CentralAfrican(cf), Liberia(lr), Mauritania(mr), Eritrea(er), Gambia(gm), Botswana(bw), Namibia(na), Gabon(ga), Lesotho(ls), GuineaBissau(gw), EquatorialGuinea(gq), Mauritius(mu), Mozambique(mz), Eswatini(sz), Djibouti(dj), Comoros(km), CapeVerde(cv), WesternSahara(eh), SãoToméandPríncipe(st), Seychelles(sc), TristandaCunha(sh), Australia(au), Christmasisland(cx), CocosIslands(cc), ManIsle(im), Kiribati(ki), Nauru(nr), NewCaledonia(nc), Fiji(fj), Micronesia(fm), PapuanewGuinea(pg), Vanuatu(vu), SolomonIslands(sb), Guam(gu), MarshallIslands(mh), NorthernMariana(mp), FrenchPolynesia(pf), Samoa(ws), WallisandFutuna(wf), Tuvalu(tv), Americansamoa(as), Pitcairn(pn), Palau(pw), Jersey(je), Antarctica(aq), NorFolkIsland(nf), Cookisland(ck), NewZealand(nz), Niue(nu), Tokelau(tk), Tonga(to), BritishIndianOcean(io), FrenchSouthernandaAtarctic(tf), Guernsey(gg), HeardandMacDonaldsIslands(hm), UsMinorOutlyingIslands(um), count:262
Edit: lisätty uusi satunnaisuuden lähde –twist (ressu with twist). Siitä haettavien bittien pitäisi olla otp kelpoisia. Eli jos ressu on one time pad kelpoinen, ja se säilyy otp kelpoisena kun siihen summataan toinen generaattori (tässä pseudoressu), –twist:in tulos on otp kelpoinen.
Edit: korjattu “bad for randomness” bugi ressu_genbytes():ssä.
Edit: lisätty test_bytes() funktio, johon voit kirjoittaa oman satunnaislukugeneraattorisi, ja ajaa sitä newressun –test komentoriviparametrillä.
Edit: lisätty ressun satunnaisuutta käyttävä ohjelma newressusudoku, jolla voi etsiä sudokuja.
Edit: lisätty satunnaisluvut heprean merkistöllä (hebrew, –heb)
Edit: lisätty –depth kytkin uuden copy-reversen testaamiseksi.
Edit: lisätty satunnaisluvut foinikialaisella merkistöllä (Phoenician, –pho).
Esimmäiset funktiot sisältävät varsinaisen kellon luvun ja kellon esikäsittelyn. Esikäsittely on uusi ominaisuus, jossa kellojono jaetaan satunnaisesti 2-257 merkkiä sisältäviin “blokkeihin”, ja joka toinen blokki palautetaan sellaisenaan (copy) ja joka toinen palautetaan käännetyssä järjestyksessä (reverse). Tällä tavalla sain kellojonon aiemman esikäsittelyn “symmetrisemmäksi”, ja koska kellojonon käsittelyssä ei enää ole aiemman version ohituksia (skip) myös kellojonon “tuhlaus” loppuu. Tämän esikäsittelyn pitäisi tehdä mahdottomaksi kellojonon arvaaminen.
Kellojonon käsittelyyn on myös lisätty uusi –fixedclock toiminto, jolla kellojonon ketjut ovat aina yhtä pitkiä. Tällä voidaan ensinnäkin miettiä muodostaako pelkkä copy-reverse ilman kellojonon vaihtelua tarvittavasti satunnaisuutta sellaisenaan, ja toisaalta taas sen ymmärtäminen, miten uusi copy-reverse vaikuttaa.
Ensiksi alkuperäinen kellojonon luku.
static unsigned char ressu_clockbyte2() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
Sitten ns kiinteämittaista kellojonoa tarjoava rutiini:
#define FIXEDCLOCKCHAINLENGTH 80
unsigned int fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
static unsigned char ressu_fixedclockbyte2() /* JariK 2022 */
{
static unsigned int clockbyte = 0, counter = 0;
if(counter == 0) {
clockbyte++;
counter += fixedclockchainlength;
}
counter--;
return(clockbyte & 0xff);
}
Tässä fixed/normal valinnan tekevä rutiini. Ensimmäisen kerran näissä raporteissa osoite funktioon (pointer to function) tyyppinen muuttuja:
unsigned char (*clockfunc)()= &ressu_clockbyte2; // normal
void ressu_setclock(int clockmode)
{
if(!clockmode)
clockfunc = &ressu_clockbyte2; // normal
else
clockfunc = &ressu_fixedclockbyte2; // fixed
}
Seuraavana “mukamas” satunnaisia lukuja tekevä rutiini. Tulos on kuitenkin satunnainen, koska sitä käytetään indeksinä satunnaislukupuskuriin. Tämä funktio oli jo copy-skip versiossa, tässä se on ulkoistettu koska sitä käytetään kaksi kertaa, kerran copy:lle ja kerran reverse:lle.
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
rando = rando +
clockbytes +
genbytes +
time(NULL) +
clock() +
get_useconds() +
ch * ch;
return(rando);
}
Tässä kellojonon esikäsittely joka kopioi tai kääntää seuraavan lohkon: (huomaa ch = (*clockfunc)() joka palauttaa joko tavallisen tai kiinteänmittaisen kellojonon).
unsigned char *ressuct; // ressu random buffer lookup
unsigned int ressuct_bytes;
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[256];
static unsigned int count = 0;
if(reverse) {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"rev: %03x ", count);
#endif
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)();
//reversebytes[c] = ressu_clockbyte2();
#ifdef DEBUG2A
fprintf(stdout," %02x", reversebytes[c]);
newressu_output = 1;
#endif
}
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
ch = reversebytes[--count];
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
#endif
if(count == 0) {
reverse = 0;
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
} else {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"copy: %03x ", count);
#endif
}
ch = (*clockfunc)();
//ch = ressu_clockbyte2();
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
newressu_output = 1;
#endif
if(--count == 0) {
reverse = 1;
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
}
#ifdef DEBUG2A
fflush(stdout);
#endif
return(ch);
}
Tässä vielä edellinen ilman #ifdef DEBUG2A rivejä: (debukilla voi muuten katsella miten copy reverse käyttäytyy).
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[256];
static unsigned int count = 0;
if(reverse) {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)();
//reversebytes[c] = ressu_clockbyte2();
}
}
ch = reversebytes[--count];
if(count == 0) {
reverse = 0;
}
} else {
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 1;
rndbits2 += 8;
}
ch = (*clockfunc)();
//ch = ressu_clockbyte2();
if(--count == 0) {
reverse = 1;
}
}
return(ch);
}
Seuraavassa fixed moodissa tehtyjä satunnaisbittejä : (–stat optio tuo tulosteeseen myös kaksi statistics riviä. Huomaa että pisin kellojono on tuo 80 merkkiä, kaikki muut ketjut ovat satunnaisista kohdista katkaistuja saman mittaisia ketjuja)
$ ./newressu --fixedclock --stat
randomsource: ressu, clockmode: 1, clockchainlength: 80, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:10 1:38 2:37 3:25 4:20 5:30 6:37 7:30 8:27 9:25 10:29 11:32 12:19 13:28 14:36 15:31 16:35 17:19 18:31 19:18 20:28 21:28 22:24 23:31 24:25 25:30 26:38 27:29 28:29 29:39 30:27 31:26 32:29 33:24 34:22 35:26 36:24 37:44 38:25 39:32 40:32 41:28 42:21 43:40 44:23 45:23 46:21 47:24 48:27 49:27 50:23 51:33 52:26 53:26 54:31 55:23 56:23 57:28 58:19 59:29 60:22 61:17 62:28 63:20 64:27 65:22 66:29 67:23 68:16 69:24 70:20 71:21 72:23 73:30 74:27 75:26 76:18 77:15 78:27 79:26 80:1041, chains:3156, sorted: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 36 37 38 39 40 44 1041, high1:1041, high2:44, lim1a:37, lim1b:38, lim1:37, lim2:38, div:1.027027, clockbytes:163760, rndbits1:1916, rndbits2:16488, rndbits3high:1041, rndbits3:2115, rndbits4highdigits:4, rndbits4:2115, rndbits5:3156, rndbits6high:1041, rndbits6:10576, rndbits7high:1041, rndbits7:21067
00000 22294132938409767835685350193923839292365996595976935862826433282
00001 48488719945788375230776214888393776008587235060334557977496406293
00002 80431275143976461305838453114822706361730974050477594023459017094
00003 93206417217628250656515986177836863340864892051316267057597113916
00004 61731938638333708609330161928363100282423290987243662193954403192
00005 94982923919430464067869481643568801481659685690996569554171263466
00006 73313649799714726811829474731299233472648891876654506268759611113
00007 71330815013503135793796350332802986281525959248136439352537631481
00008 80520675067022116837313859689861210963143997805965619140693304090
00009 27529324544421024520929292748015725933677643980607578142560612229
Sitten DEBUG2A tulostetta normal moodissa: (ch: on palautettava merkki, copy: sanan jälkeen tulee merkkien lukumäärä ja kopioitava blokki, rev: sanan jälkeen merkkien lukumäärä, merkit alkuperäisessä järjestyksessä ja sitten käännetyssä järjestyksessä).
copy: 015 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
rev: 019 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21
ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
copy: 016 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
rev: 00a 21 21 21 21 21 21 21 22 22 22
ch:22 ch:22 ch:22 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21 ch:21
copy: 010 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
rev: 018 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
copy: 014 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
rev: 00f 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22 ch:22
Mielenkiintoista on, voiko teoreettisten satunnaismerkkien laskennan (rndbits1, rndbits3 jne) jättää kokonaan pois kun copy-reverse on toiminnassa, sitä voi yrittää hahmottaa newressu –single komennolla.
$ ./newressu --stat --single
randomsource: single, clockmode: 0, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:1 1:38 2:35 3:6 4:13 5:13 6:9 7:11 8:9 9:9 10:7 11:5 12:7 13:9 14:62 15:169 16:8 17:1 18:6 19:122 20:68, chains:607, clockbytes:8187, rndbits2:1128
00000 32262283161809391678657136366555756828967803578676610526738617216
00001 69511031437775242989469007588191015483302697394274894700778823040
00002 76140983583748585072353786938410170011199037634650689281079597904
00003 93729335401437288771146924781560699584385747294818636367091300176
00004 05265892091793398109092431528679114647250196564188868255370175310
00005 32662058346170613285279049952971968089134474619682155846073978431
00006 37542509108789762598062162668902832635630435392168038872003862287
00007 49867796710786537902924653466617634225652081735463098061052717754
00008 40532647329764438978005136772857284492053527665773437979327537731
00009 68916755542984513818470885899001010383458534877845952219318341042
Vielä fast versio, jossa oletetaan, että copy-reversen 8 bittiä blokki (rndbits2) on oikea satunnaisuuden määrä. Tässä ei siis testata noita muita teoreettisen satunnaisuuden kenttiä:
$ ./newressu --stat --fast
randomsource: fast, clockmode: 0, size: 5, lines: 10, linew: 13, pchars: 71, pwords: 13, tchars: 650, digitscount: 10, wordvalues: 100000, limit: 100000
rounds:3 1:18 2:19 3:19 4:13 5:11 6:23 7:16 8:18 9:22 10:10 11:18 12:14 13:12 14:11 15:14 16:13 17:14 18:16 19:11 20:16 21:27 22:301 23:99 24:16 25:10 26:13 27:10 28:11 29:7 30:9 31:5 32:72 33:181 34:16 35:11 36:5 37:6 40:3 41:3, chains:1113, sorted: 3 5 6 7 9 10 11 12 13 14 16 18 19 22 23 27 72 99 181 301, clockbytes:24556, rndbits2:1736
00000 68784755242708765294394273037319039572739737000724542275166407714
00001 06972592691192404285861495591371050958299735095969537656132751909
00002 67574262177835663992021063370107991617814973885686637190673088094
00003 23737673519966062499715155344625118562351368088477401742394627022
00004 03263216076372320938776167737005047546185162611650283796001101369
00005 51407508376549070991359975767652992476157609203411915065410641295
00006 12655893530487345584253510097815082335938955217832759445595250214
00007 24937072376561882973994015071952414930388304299234767961731321584
00008 05580710011089642452809116400909876953773223311014848926770989925
00009 80053600376650552642904242376127515525297384309817394907301522152
Joka tapauksessa perusversio: teoreettisten satunnaismerkkien laskemisineen ja copy-reverse:n kanssa on mielestäni versio korotuksen arvoinen. (Teiltä pitäisi kysyä onko se valmis…) Suorittelen kuitenkin, kuten aina, sen käyttämistä muiden generaattorien kanssa, ja viimeinen tietysti omassa ohjelmassa. Näistä omistani –pseudoressu tulee mieleen, siitä jatkossa.
$ ./newressu
00000 37623172794213955845654028970142043156650464162378618125059418215
00001 44770808876162322824064917059041951056355916863064355533513084242
00002 75485713017878047234034253933802355371072968018532606905129869680
00003 96551784242102846132000149967407451652050029473735516535627149942
00004 91453561873005997442161145845169261020298914882602023854201229781
00005 72203425783242175112239728887442139124665422626613641888668562931
00006 01828527840750137347400562529323569375142224887300242484404778626
00007 34038142372693997824692927661290471630937124920642848309126302336
00008 71422612084979552308234145197900652207559401420147297100214334402
00009 64387847336829223605559797922477255813426710680768085663528529936
Vielä ressun “ydin” ja liitännäistoiminnot. Uudelleen nimetty pääfunktio.
#define RR8(byte,bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte,bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )
#define aDEBUG5 2
void ressu_genbytes_single_do(int size, unsigned char *buffer)
{
int c, d;
unsigned char e, byte;
static int f = 0, prevbyte = -1, count = 0;
//ressuct = buffer; // ressu random buffer lookup
//ressuct_bytes = size;
for(c = 0; c < 8; c++) {
for(d = 0; d < size; d++) {
e = buffer[d];
e = RL8(e, 1); // rotate byte left 1 bits
//e = RL8(e, 3); // rotate byte left 3 bits
//e = RR8(e, 1); // rotate byte right 1 bits
byte = ressu_clockbyte();
if(prevbyte == -1)
prevbyte = byte;
buffer[d] = e ^ byte;
if(prevbyte != byte) {
periods[count]++;
clockbytes += count;
count = 0;
prevbyte = byte;
}
count++;
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout, "\n");
ressu_dump("single 1", 32, buffer, 32);
#endif
for(d = 0; d < size; d++) {
f = (f + buffer[d] + 2) % size; // +2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
#ifdef DEBUG5
if(newressu_output)
fprintf(stdout,"\n");
ressu_dump("single 2", 32, buffer, 32);
#endif
}
}
Ja uusi versio ressu_genbytes_single() funktiosta, johon on lisättu –stat rivit, ja uusi genbytes_single_do() -kutsu:
Nuo ensimmäiset ressu_ct ja _bytes kertovat paikan josta uusi copy-reverse hakee blokin pituuden. Pituudet haetaan aina käsittelyn alla olevasta satunnaisbittipuskurista.
void ressu_genbytes_single(int size, unsigned char *buffer)
{
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
ressu_genbytes_single_do(size, buffer);
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:1");
long chains = 0;
for(int e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
}
Sitten ressu ressu_genbytes(): jossa lisätyt ressuct ja _bytes muuttujat kellojonon pituuden hakemista varten ja muutettu kutsu ressu_genbytes_single_do “ydintä” varten.
#define aDEBUG7 2
#define aDEBUG2 2
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c, d, e, f;
static unsigned char ressut[RESSUT_BYTES];
static int ressut_first = 1,
ressut_pos = 0,
ressut_f = 0;
unsigned long prevperiods[1024];
#ifdef DEBUG2
static unsigned char counts[RESSUT_BYTES];
#endif
ressuct = ressut; // ressu random buffer lookup
ressuct_bytes = ressut_bytes; // table used in ressu_genbytes_single_do
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 DEBUG2
for(d = 0; d < size; d++)
counts[d] = 0;
#endif
rndbits1 = 0;
rndbits2 = 0;
rndbits3 = 0;
rndbits4 = 0;
rndbits5 = 0;
rndbits6 = 0;
rndbits7 = 0;
int lim, lim1 = 0, lim2 = 0;
int lim1a, lim1b;
int high1, high2;
int rndbits3high;
int rndbits4highdigits;
int rndbits6high;
int rndbits6pos;
int rndbits7high;
for(d = 0;
rndbits1 < ressu_bits1_needed ||
rndbits2 < ressu_bits2_needed ||
rndbits3 < ressu_bits3_needed ||
rndbits4 < ressu_bits4_needed ||
rndbits5 < ressu_bits5_needed ||
rndbits6 < ressu_bits6_needed ||
rndbits7 < ressu_bits7_needed ||
d < RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
#define aDEBUG6 2
//
// calculate rndbits1
//
// save previous round
for(e = 0; e < 1024; e++) {
prevperiods[e] = periods[e];
}
ressu_genbytes_single_do(ressut_bytes, ressut);
// find new lim1
lim = lim1;
f = -1;
for(e = 0; e < 1024; e++) {
if(prevperiods[e] > 0 && prevperiods[e] == lim) {
if(f == -1 || (periods[e]>0 && f<periods[e])) {
f = periods[e];
}
}
}
if(f != -1)
lim = f;
lim1a = lim;
// find highest amount of chains
high1 = -1;
for(e = 0; e < 1024; e++) {
if(high1 == -1 || high1 < periods[e]) {
high1 = periods[e];
}
}
// and second highest
high2 = -1;
for(e = 0; e < 1024; e++) {
if( (high2 == -1 && periods[e] < high1) ||
(high2 < periods[e] && periods[e] < high1) ) {
high2 = periods[e];
}
}
// and average
int psum = 0;
int pcnt = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
psum += periods[e];
pcnt++;
}
}
lim1b = (int)((double)psum / pcnt);
// find next smaller than average
f = -1;
for(e = 0; e < 1024; e++) {
if( (f == -1 && periods[e] < lim1b) ||
(f < periods[e] && periods[e] < lim1b) ) {
f = periods[e];
}
}
if(f != -1)
lim1b = f;
if(lim == 0 || lim > lim1b)
lim = lim1b;
// if lim greater that second highest,
// set to second highest
if(lim > high2) {
lim = high2;
}
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;
// calculate rndbits1
#define aDEBUG6 2
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
}
}
//
// calculate rndbits3
//
#define aDEBUG8 2
rndbits3high = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high < periods[e])
rndbits3high = periods[e];
}
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e]) {
rndbits3 += periods[e];
}
}
//
// calculate rndbits4
//
#define aDEBUG9 2
rndbits4highdigits = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
rndbits4highdigits = (int)log10((double)periods[e]) + 1;
}
}
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
rndbits4 += periods[e];
}
}
//
// calculate rndbits5
//
#define aDEBUG10 2
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
rndbits5 += periods[e];
}
//
// calculate rndbits6
//
#define aDEBUG11 2
rndbits6high = 0;
rndbits6pos = 0;
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high < periods[e]) {
rndbits6high = periods[e];
rndbits6pos = e;
}
}
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] && periodsl[e] > 0) {
if(rndbits6pos > e)
rndbits6 += log2((double)rndbits6pos - e) * periods[e];
else
rndbits6 += log2((double)e - rndbits6pos) * periods[e];
}
}
//
// calculate rndbits7
//
#define aDEBUG12 2
rndbits7high = 0;
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high < periods[e])
rndbits7high = periods[e];
}
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] && periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
}
}
} // for(d=0;
//
// debug display for rndbits1
//
#ifdef DEBUG6
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits1+prev:%d", rndbits1);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits3
//
#ifdef DEBUG8
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e] &&
periods[e] > 0) {
rndbits3 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits3+prev:%d", rndbits3);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits4
//
#ifdef DEBUG9
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1 &&
periods[e] > 0) {
rndbits4 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits4+prev:%d", rndbits4);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits5
//
#ifdef DEBUG10
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
rndbits5 += periods[e];
fprintf(stderr,", rndbits5+prev:%d", rndbits5);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits6
//
#ifdef DEBUG11
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] &&
periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%lu", periods[e]);
double l2;
if(rndbits6pos > e) {
fprintf(stderr,", pos-e:%d", rndbits6pos - e);
l2 = log2((double)rndbits6pos - e);
} else {
fprintf(stderr,", e-pos:%d", e - rndbits6pos);
l2 = log2((double)e - rndbits6pos);
}
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
rndbits6 += l2 * periods[e];
fprintf(stderr,", rndbits6+prev:%d", rndbits6);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits7
//
#ifdef DEBUG12
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] &&
periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", high-prev:%ld", rndbits7high-periods[e]);
double l2=log2((double)rndbits7high-periods[e]);
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
fprintf(stderr,", rndbits7+prev:%d", rndbits7);
fprintf(stderr,"\n");
}
}
#endif
if(stats) {
if(newressu_output == 1)
fprintf(stderr,"\n");
newressu_output = 0;
//
// display statistics
//
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
#ifdef DEBUG_SORTED
fprintf(stderr, ", sorted:");
int g = 0;
for(;;) {
f = -1;
for(e = 0; e < 1024; e++) {
if( (f == -1 && periods[e] > g) ||
(periods[e] > g && f > periods[e]) )
f = periods[e];
}
if(f == -1)
break;
g = f;
fprintf(stderr," %d", g);
}
#endif
fprintf(stderr, ", high1:%d", high1);
fprintf(stderr, ", high2:%d", high2);
fprintf(stderr, ", lim1a:%d", lim1a);
fprintf(stderr, ", lim1b:%d", lim1b);
fprintf(stderr, ", lim1:%d", lim1);
fprintf(stderr, ", lim2:%d", lim2);
fprintf(stderr, ", div:%f", (double)lim2 / lim1);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits1:%d", rndbits1);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, ", rndbits3high:%d", rndbits3high);
fprintf(stderr, ", rndbits3:%d", rndbits3);
fprintf(stderr, ", rndbits4highdigits:%d", rndbits4highdigits);
fprintf(stderr, ", rndbits4:%d", rndbits4);
fprintf(stderr, ", rndbits5:%d", rndbits5);
fprintf(stderr, ", rndbits6high:%d", rndbits6high);
fprintf(stderr, ", rndbits6:%d", rndbits6);
fprintf(stderr, ", rndbits7high:%d", rndbits7high);
fprintf(stderr, ", rndbits7:%d", rndbits7);
fprintf(stderr, "\n");
fflush(stderr);
}
} // 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++)
if(verbose) {
fprintf(stdout,"ressu ");
for(c = 0; c < size; c++) {
if(c > 0 && c % 32 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x", buffer[c]);
newressu_output = 1;
}
fprintf(stdout,"\n");
}
#ifdef DEBUG7
ressu_dump("genbytes", size, buffer, 32);
#endif
genbytes += size;
}
Mielestäni ressu (./newressu –ressu tai ./newressu) on kelvollista jopa one time pad materiaaliksi (jokainen bitti irtonainen, ei ole laskennallista yhteyttä muihin bitteihin paitsi tilastollinen todennäköisyys), ja jos noin olisi voisimme tehdä nopeamman satunnaisgeneraattorin käyttämällä ressua satunnaisbittien lähteenä ja tehdä uusia satunnaisbittejä tiivistefunktiolla (tässä sha256) (vertaa fort). Tässä generattoriehdokas: (ehdokas ei tietenkään ole one time pad materiaalia sha256 funktion vuoksi).
Edit: Miksi sitten ressun bitit ovat riippumattomia. Helpoimmin päättelyni jäljille pääsee, jos kuvittelee että kellomerkit on and:atty ykkösellä. Tällöin vain alin bitti kellojonosta jää jäljelle. Kun and:atyllä kellojonolla xor:ataan puskuri vain sen alin bitti muuttuu. Shift:issä alin bitti siirretään talteen kakkosbittiin ja kakkosbitti kolmosbittiin jne. Merkkien paikkaa muutetaan satunnaisesti ja aloitetaan alusta. Merkkien paikkojen satunnainen muuttaminen poistaa yhteyden yksittäisten “samalla rivillä” olevien bittien välillä. Se että yhden merkin eri bitit otetaan eri kohdasta kellojonosta ja vaihdetusta puskurinpaikasta varmistaa että merkin biteille ei muodostu yhteyttä. (Huomaa että myös merkin paikka puskurissa vaikuttaa siihen mikä merkki kellojonosta otetaan.) Jos tähän lisätään muut bitit (ei tehdä and:iä ykkösellä) muut bitit vain sekoittavat lisää, yhteyttä ei uudestaan synny.
Edit: toisaalta, jos pseudoressun tulosjono summataan (xor) ressun tulosjonon kanssa yhteinen tulos on mielestäni taas one time pad kelpoinen. Siis ressun tuloste on one time pad materiaalia, vaikka siihen summataan mitä, summaamisen jälkeen se on edelleen one time pad materiaalia.
Edit: seuraavassa esimerkki, jossa on listattuna yhdellä and:ätyt puskurien alut: (ensimmäisellä rivillä vain nollabitti, eli arvot 0 ja 1. Seuraavalla rivillä lisätty ykkösbitti eli arvo 2 (tällöin arvot ovat 0 1 2 ja 3). Seuraavalla kakkosbitti (4) eli arvot 0, 1, 2, 3, 4, 5, 6 ja 7. Rivejä on tässä 8 kappaletta eli oma rivi jokaiselle uudelle bitille, viimeisen bitin arvo on 80 eli 128d. Seuraavan listan joissa on single 1 rivillä single_do()-funktion shift ja xor ja single 2 rivillä swap saat DEBUG5:lla. Lista on heksana että voidaan tarkistaa että viimeinen rivi on todella varsinaisella satunnaislukulistalla rivi 1. Huomaa ensimmäisen rivin swap:it. Kun swappailemme merkkejä joissa on vain ykköstä ja nollaa, ilmeni että niissä molemmissa on epäsymmetriaa verrattuna muihin merkkeihin.
$ ./newressu --single -x --fixedclock5| more
single 1 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01
single 2 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 00 00 00 01 01 01
single 1 02 03 02 02 00 00 01 01 01 03 03 02 02 02 00 00 01 01 01 03 02 03 02 02 00 01 00 01 01 03 03 02
single 2 02 02 01 00 00 01 01 00 01 03 01 01 00 02 01 02 02 01 03 00 00 01 03 03 02 03 00 02 00 02 01 02
single 1 04 05 02 01 01 03 03 00 02 06 02 03 00 05 03 05 05 02 06 00 00 02 07 07 05 07 01 04 00 04 02 05
single 2 07 07 01 06 06 03 05 04 05 03 03 06 00 06 02 02 03 02 06 06 03 00 07 00 02 04 02 00 05 05 04 04
single 1 0f 0f 03 0c 0c 06 0a 08 0a 07 07 0d 01 0d 04 04 06 04 0d 0d 07 01 0f 00 04 08 04 00 0b 0a 08 09
single 2 0b 0f 09 01 01 0b 04 03 05 09 09 08 0d 07 09 05 0a 09 04 0b 04 0f 03 04 0b 04 08 09 08 06 02 0f
single 1 16 1e 12 02 02 17 09 07 0b 13 12 10 1a 0e 12 0b 15 13 09 16 08 1e 06 08 17 09 11 13 11 0c 04 1e
single 2 0f 1f 00 0e 02 15 12 15 09 16 19 16 10 0f 07 19 13 0a 16 1e 05 1b 01 15 08 08 19 0f 1a 0a 16 0a
single 1 1f 3f 01 1d 05 2a 24 2a 12 2c 33 2d 21 1f 0f 32 26 14 2c 3c 0b 37 03 2b 11 10 32 1e 34 14 2d 15
single 2 17 01 28 33 16 19 2b 1f 1f 15 28 2b 35 0f 37 16 32 18 0d 28 27 1f 11 11 3e 0a 3f 10 3b 26 0a 30
single 1 2f 03 50 66 2c 32 56 3f 3f 2b 51 57 6a 1e 6e 2c 64 31 1b 51 4f 3f 22 22 7c 14 7e 21 77 4d 15 61
single 2 56 55 2b 3b 3d 70 22 52 79 6d 52 57 3e 29 24 1e 50 5c 36 13 2a 5b 00 54 43 0f 18 5e 13 5d 21 70
single 1 ad ab 57 76 7a e0 44 a4 f3 db a5 af 7d 52 48 3c a0 b8 6d 27 55 b7 01 a8 86 1e 30 bc 27 bb 43 e1
single 2 41 b1 01 14 dc a8 a2 36 48 a8 6a 97 85 13 62 3f 0b e0 b5 34 8d b9 c4 fa 65 bc 8c 93 b8 f9 f2 ef
00000 41b10114dca8a23648a86a978513623f0be0b5348db9c4fa65bc8c93b8f9f2ef
00001 119f2a30b1a5b7737d92f5ca7d55b2991bca8da85db795278876a0cc66cd7fee
00002 40fe7e3eb56ee10680053fb69f00aa9e05b470490270875180bf545609d55db4
00003 af82f8756838045d6d8b8bf2ada39b43456690bd7ca56cba3fa592ec660680a2
00004 6f4370a240850ad1951fe555c1ef377b0b0fa20af3b1cd5381ac4a2916764eb2
00005 5b59d45d9d19280b9115405c92a25a75cd4c53b051d5df45a0cd4b39163c5060
00006 f4524aad74b97cab5bb6b6ae4baff0b609562aab71ddbd10b9473fb4f0be6940
00007 587979249184244f17740e5a9e4a5047fd46c94b1721fad3ff964363a313b8b3
00008 49724491c0ab1b9933c3a2f83caed2c97ea5482d5f0e5dfc775effde59a40bd4
00009 2a558f2f09776189a4b812fa741b423172ad619853a5eddbc21674a1564c5701
Nolla toimi seuraavalla tavalla: swapissähän f muuttujaan eli swapin kohteeseen lisätään merkki swapin puskurin d:n kohdasta. Jos siis puskuri d:n sisältö (bufferd) on nolla, f ei kasva, ja koko nollia sisältävä ketju jää “ripottelematta” puskuriin. Seuraavassa d käy läpi koko puskurin, f ei muutu mihinkään, ja näin koko nollaketju jää samanlaiseksi. Kun nollaketju loppuu swap:pi palaa takaisin normaaliin toimintaan.
ressu 1 00 00 00 00 00 01 01 01 01 01 00 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00
d:0, f:0, bufferd:0, bufferf:0
d:1, f:0, bufferd:0, bufferf:0
d:2, f:0, bufferd:0, bufferf:0
d:3, f:0, bufferd:0, bufferf:0
d:4, f:0, bufferd:0, bufferf:0
d:5, f:0, bufferd:1, bufferf:0
d:6, f:1, bufferd:1, bufferf:1
d:7, f:2, bufferd:1, bufferf:1
d:8, f:3, bufferd:1, bufferf:1
d:9, f:4, bufferd:1, bufferf:1
d:10, f:5, bufferd:0, bufferf:1
d:11, f:5, bufferd:0, bufferf:0
d:12, f:5, bufferd:0, bufferf:0
Ykkösellä ongelma oli seuraava: d kulkee taas puskurin alusta puskurin loppuun ja f:ää kasvatetaan d:n sisällöllä (bufferd), siis f:ää kasvatetaan yhdellä, tällöin laitetaan ykkönen seuraavaan f:ään, joka on tietenkin seuraava d:n sisältö. Näin f kasvaa joka kierroksella yhdellä kunnes ykkönen on siirretty puskurin viimeiseen merkkiin. Ykkösversio ei siis palaa normaaliksi ykkösten jälkeen vaan jatkuu puskurin loppuun.
ressu 1 01 01 01 01 01 00 00 00 00 00 01 01 01 01 00 01 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01
d:0, f:0, bufferd:1, bufferf:1
d:1, f:1, bufferd:1, bufferf:1
d:2, f:2, bufferd:1, bufferf:1
d:3, f:3, bufferd:1, bufferf:1
d:4, f:4, bufferd:1, bufferf:1
d:5, f:5, bufferd:1, bufferf:1
d:6, f:6, bufferd:1, bufferf:1
d:7, f:7, bufferd:1, bufferf:1
d:8, f:8, bufferd:1, bufferf:1
d:9, f:9, bufferd:1, bufferf:1
d:10, f:10, bufferd:1, bufferf:1
d:11, f:11, bufferd:1, bufferf:1
d:12, f:12, bufferd:1, bufferf:1
d:13, f:13, bufferd:1, bufferf:1
Korjaus on tietenkin ohittaa nämä tapaukset eli kasvattaa f:ää d:n sisällön lisäksi kakkosella. (d muuttujaa ei voi muuttaa, varsinaista swäppiä ei voi muuttaa, datan perusteella ei voi tehdä logiikkaa (esim if data = “1”), joten ainoa vaihtoehto on muuttaa f:ää) Seuraavassa uusi swap:pi osuus:
Ongelma ennen 0 ja 1 muutostakaan ei ollut tilastollisesti kovin yleinen. Suurin osa korjautui sillä että seuraavalla xor:lla nuo nollabitit ja ykkösbitit muuttuvat toisiksi ja taas swappaytyvät normaalisti. Periaatteessa puskurin viimeinen merkki oli hieman useammin ykkönen, joten siitä olisi voinut tehdä tunnistuksen käytetystä ressusta. +2 muutoksen jälkeen tunnistus ei tietenkään onnistu, nyt kaikki dataarvot toimivat uudessa versiossa symmetrisesti. Asiaa on tietysti tutkittava, ja osin uudelleen koska “sydän” (ressu_genbytes_single_do()) on muuttunut.
#define aDEBUG5A 2
#define aDEBUG5B 2
#define aDEBUG5C 2
#define aLOWCLOCKBITONLY 2 // off by default //
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
...
for(d = 0; d < size; d++) {
#ifdef DEBUG5B
fprintf(stdout,"d:%d", d);
fprintf(stdout,", f:%d", f);
fprintf(stdout,", bufferd:%d", buffer[d]);
fprintf(stdout,", bufferf:%d", buffer[f]);
fprintf(stdout,"\n");
#endif
f = (f + buffer[d] + 2) % size; // +2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
...
}
F:än kasvattaminen yhdellä ei riitä, sillä sitten nolla toimii kuten yksi äsken eli kulkee kaikkien puskuripaikkojen läpi puskurin loppuun:
ressu 1 00 00 00 00 00 01 01 01 01 01 00 00 00 00 01 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00
d:0, f:0, bufferd:0, bufferf:0
d:1, f:1, bufferd:0, bufferf:0
d:2, f:2, bufferd:0, bufferf:0
d:3, f:3, bufferd:0, bufferf:0
d:4, f:4, bufferd:0, bufferf:0
d:5, f:5, bufferd:0, bufferf:0
d:6, f:6, bufferd:0, bufferf:0
d:7, f:7, bufferd:0, bufferf:0
d:8, f:8, bufferd:0, bufferf:0
d:9, f:9, bufferd:0, bufferf:0
d:10, f:10, bufferd:0, bufferf:0
d:11, f:11, bufferd:0, bufferf:0
d:12, f:12, bufferd:0, bufferf:0
d:13, f:13, bufferd:0, bufferf:0
Lista, jossa aiempi ensimmäinen swappirivi oli melkein muuttumaton, tässä se näyttää jo kohtuulliselta (+2 version): Tässä on otettava huomioon että tämä on ensimmäinen swappi puskurille joka sisältää pelkästään ykkösiä ja nollia pitkinä jonoina. Seuraavat swap:it lisäävät tietysti satunnaisuutta.
$ ./newressu --single -x
ressu 1 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00
ressu 2 00 01 01 01 01 00 01 00 01 00 00 01 01 00 01 01 00 00 01 00 01 01 01 01 00 00 00 01 01 01 00 01
ressu 1 01 02 02 02 02 00 02 00 02 01 01 03 03 01 03 03 01 01 03 01 03 03 03 03 01 01 01 03 03 03 01 03
ressu 2 02 00 01 02 03 02 02 01 01 03 01 03 03 00 01 03 01 03 00 01 01 01 01 03 01 03 01 03 01 00 01 02
ressu 1 04 00 02 04 06 05 05 03 03 07 03 07 07 01 03 07 03 07 01 03 03 03 03 07 03 07 03 07 03 01 03 05
ressu 2 00 02 00 06 03 03 03 00 06 00 06 02 01 01 04 02 02 05 01 00 04 03 04 02 01 07 06 05 01 06 02 06
ressu 1 00 04 00 0c 06 06 06 00 0c 00 0c 04 02 02 08 04 04 0b 03 01 09 07 09 05 03 0f 0d 0b 03 0d 05 0d
ressu 2 09 03 0e 03 07 0a 00 08 0b 0f 0a 08 07 0e 08 0c 08 07 0a 0d 05 05 08 06 02 0b 01 04 07 0c 0d 0d
ressu 1 13 07 1d 07 0f 15 01 11 17 1f 15 11 0f 1d 11 19 11 0f 15 1b 0b 0b 11 0d 05 17 03 09 0f 19 1b 1b
ressu 2 15 1b 0d 05 0f 1c 04 0c 01 1f 1b 05 07 0d 18 19 04 04 10 06 08 18 14 08 0a 0e 1c 1e 04 15 15 1a
ressu 1 2a 36 1a 0a 1e 38 08 18 02 3f 37 0b 0f 1b 31 33 09 09 21 0d 11 31 29 11 15 1d 39 3d 09 2b 2b 35
ressu 2 27 0f 16 25 24 05 02 0b 37 0d 36 20 1b 0c 08 2e 3b 22 29 30 27 01 28 16 02 05 2b 1c 08 2b 0a 33
ressu 1 4e 1e 2c 4a 48 0a 04 16 6e 1a 6c 40 36 18 10 5c 76 44 52 60 4e 02 50 2d 05 0b 57 39 11 57 15 67
ressu 2 7f 5c 6a 0a 47 3b 40 21 2e 5a 29 0e 3f 12 60 23 4b 45 37 73 77 53 3e 42 70 68 20 49 52 25 58 57
ressu 1 fe b8 d4 14 8e 76 80 42 5c b4 52 1d 7f 25 c1 47 97 8b 6f e7 ef a7 7d 85 e1 d1 41 93 a5 4b b1 af
ressu 2 87 ee b4 41 69 fc 4e 70 0a b3 d6 46 73 40 a0 0c 01 76 64 73 7e 98 0c e3 9a e3 3e b1 c2 b4 88 e2
00000 87eeb44169fc4e700ab3d6467340a00c017664737e980ce39ae33eb1c2b488e2
00001 1a6ea6583d89530e1e1455442446f3cf1ef119d28334f674db7ac30757fd0691
00002 b777adfc58cf9d4bdf8029a6df98ffd44aa4adfc52675306e72a38193a337da7
00003 c184bde3d90783c51df7ae206a245449f4c9ad78f2fa052c2113543c69753cf0
00004 c600776f4299a0729aabac97cc07956a6c3b616b499430c7c6165bbba81febaf
00005 e817ad5bece64ffcb8a7ca1b1d85a3b2eebbec925403d802c11612e99914531e
00006 619a2e82b7b321608dbf28d67044b542e2bdc3428d098430662f639c5af26963
00007 e76d4bf95ddd078a958bd537deb70bce2d6df7f8a0b49aa326565e64161acbbb
00008 736d9bbcae75d5037da8c545b78ff0042ee45b6a337384b8c389276ab7db962f
00009 94f2f4ef5cd97591af58c3e4669f64386d05f8cc890eb49946ed451372278168
Koko ensimmäinen swap:ätty blokki DEBUG5c päällä:
ressu 3 01 00 01 01 01 01 00 00 01 01 00 00 00 00 01 01 01 01 01 01 01 01 00 01 00 01 01 01 00 01 01 00
ressu 3 01 01 00 00 00 01 01 00 00 00 00 01 01 01 00 00 00 00 00 01 01 00 00 01 00 00 01 00 01 01 00 01
ressu 3 00 01 01 01 01 00 00 00 00 00 01 00 00 00 00 00 00 01 00 00 01 00 01 00 01 01 00 01 00 01 00 01
ressu 3 01 00 00 00 00 00 01 00 01 01 00 00 00 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 01 01 00 01
ressu 3 01 01 01 01 01 01 01 01 01 01 01 01 01 00 01 01 00 01 01 00 01 01 00 00 01 01 01 01 01 01 01 01
ressu 3 01 01 01 01 01 01 00 00 00 00 01 00 00 01 00 01 01 01 01 01 01 00 01 01 01 01 00 01 00 01 01 00
ressu 3 00 00 00 00 01 01 00 00 00 00 01 01 01 00 00 01 01 01 00 01 00 00 00 00 00 00 00 00 01 00 00 01
ressu 3 00 00 01 00 01 00 01 00 01 00 00 01 00 00 00 00 01 00 00 01 00 00 01 00 01 01 01 01 00 00 01 00
ressu 3 01 00 01 00 00 00 00 00 00 01 00 01 01 00 00 01 01 01 00 01 00 01 01 00 01 00 01 00 01 00 00 01
ressu 3 00 01 01 00 00 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 01 00 01 00 00 01 01 00 01 01 00
ressu 3 01 00 01 00 01 01 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00 01 00 01 01 01
ressu 3 00 00 00 00 00 00 00 00 00 01 01 01 00 01 00 01 00 01 00 01 00 01 00 00 00 00 00 00 00 00 00 00
ressu 3 00 01 00 00 01 00 00 00 01 00 01 01 01 01 00 01 00 01 01 00 01 00 00 01 01 01 01 00 01 01 01 01
ressu 3 01 01 00 00 01 01 01 01 01 01 01 01 00 01 01 01 01 01 00 00 01 01 00 01 01 01 00 01 01 01 00 00
ressu 3 01 00 01 01 01 01 01 00 01 01 01 01 01 00 01 00 01 00 01 01 01 00 01 00 00 00 00 00 01 01 01 00
ressu 3 01 01 00 01 00 01 00 01 01 01 00 00 00 01 01 00 01 00 00 00 01 01 00 00 01 01 00 01 00 01 00 01
ressu 3 00 00 00 01 01 00 01 00 00 00 01 01 00 01 00 00 00 00 00 01 01 01 01 01 01 01 00 00 00 00 01 01
ressu 3 00 01 01 01 00 00 00 00 01 01 00 01 01 01 01 00 00 00 01 00 00 01 01 01 01 00 00 00 01 01 00 00
ressu 3 01 01 00 00 01 00 01 01 00 00 01 01 00 01 01 00 01 01 00 01 01 00 00 01 01 01 00 00 00 00 01 00
ressu 3 00 00 01 01 00 00 00 01 00 00 00 01 00 00 00 01 00 01 01 00 00 00 01 00 00 00 01 00 00 00 00 01
ressu 3 01 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 00 01 00 00 01 01 01
ressu 3 00 01 01 01 01 00 01 01 01 01 01 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 01
ressu 3 01 01 01 01 01 01 01 01 01 01 00 01 00 00 00 00 00 00 00 00 00 01 01 01 01 00 01 00 01 01 01 01
ressu 3 01 00 01 00 00 00 01 01 01 01 01 01 01 01 01 00 01 01 01 01 01 01 00 01 00 00 00 00 00 00 00 00
ressu 3 01 00 00 00 01 01 01 01 01 01 01 00 01 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 01 01 00
ressu 3 01 01 01 01 01 01 00 00 00 00 00 01 01 01 01 01 00 00 01 01 01 01 01 01 00 00 00 00 00 01 01 01
ressu 3 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 01 00 01 01 00 01 01 00 00 00 01 01 01 01 01 00 00
ressu 3 00 01 01 01 01 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01 01 01 01 00 00
ressu 3 00 00 00 00 01 01 01 00 01 00 00 00 00 00 01 01 01 01 01 01 00 00 00 00 01 01 01 01 00 01 00 00
ressu 3 00 01 00 01 01 01 01 00 00 00 01 01 01 01 00 00 00 00 00 00 00 01 01 01 00 00 01 00 00 00 00 01
ressu 3 00 00 00 00 01 00 00 00 00 01 01 00 00 01 01 01 01 00 00 00 00 00 01 00 00 01 00 00 01 01 00 00
ressu 3 01 01 00 00 01 00 00 01 00 01 00 00 01 00 00 00 01 00 00 00 01 01 00 00 00 00 00 00 00 00 00 01
Edellistä DEBUG5C:llä tehtyä blokkia voi tietenkin verrata seuraavaan ressulla tehtyyn blokkiin:
$ ./newressu -w32 -l32 --lim2 -x
00000 0 0 0 1 0 0 0 0 0 1 0 1 1 0 1 0 1 0 0 1 0 1 0 1 1 0 1 0 0 1 1 0
00001 1 0 0 1 1 0 0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 1 1 0 1 0 1 0 1 1 0 0
00002 1 0 1 0 1 0 0 1 1 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1
00003 1 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 0
00004 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 0 1 1 0 1
00005 1 0 1 0 1 1 0 1 1 0 1 0 1 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0
00006 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 1 0 0 0 0 1 1 1 1 0
00007 0 1 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 1
00008 0 0 1 1 0 1 1 0 1 0 0 1 0 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
00009 1 1 1 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1
00010 0 1 0 0 0 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 0 0 0 1 1 0 0 1 1 0 0 1
00011 0 1 1 0 0 1 1 1 0 1 0 0 0 0 1 1 1 0 1 1 0 1 1 0 0 0 1 0 0 1 0 0
00012 0 1 0 0 1 1 1 1 0 1 1 0 0 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0 0 1 1
00013 0 1 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 1 0 1 1 1 1
00014 1 0 0 0 0 0 1 0 1 1 1 1 1 1 0 0 1 0 1 0 1 0 0 0 1 1 0 0 1 1 1 1
00015 1 1 1 0 1 1 1 1 0 0 1 0 0 0 0 1 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 1
00016 0 0 1 0 1 1 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0
00017 0 0 1 1 0 1 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 1
00018 1 0 0 1 1 1 1 0 1 0 0 1 0 0 0 1 0 0 0 1 0 1 0 1 0 1 1 0 0 0 0 0
00019 0 1 1 1 0 1 1 1 1 0 0 1 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0
00020 0 1 0 0 0 1 1 1 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0
00021 1 1 1 1 0 0 1 1 1 1 0 1 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 1 0
00022 1 0 0 0 1 0 1 0 0 0 1 1 1 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 0 1 1
00023 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 1 1 1 1 0 1 0 0
00024 0 1 0 1 0 0 0 1 0 1 0 0 0 1 1 1 1 1 1 1 0 0 1 0 1 1 0 0 0 0 1 0
00025 0 1 1 1 1 0 0 1 0 0 1 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1 1 1 1 0 0 1
00026 1 1 0 0 0 1 0 0 1 1 1 0 1 1 0 0 1 0 1 1 0 1 1 0 0 0 0 0 0 1 1 0
00027 0 0 1 0 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 1 1 0 0
00028 0 1 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 1 1 0
00029 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1 1 0 0 0
00030 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1
00031 1 0 1 1 1 1 1 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 0 1 1
Vihdoinkin pseudoressu:n koodi:
#define PSEUDORESSU_LIMIT 1048576 // limit between rekeys
#define TOPUP_BYTES 32*1024 // bytes between topups
#define TOPUP_SIZE 32 // topup size in bytes (256 bits)
#define aTOPUP_TWICE 2
static unsigned char pseudoressu_key[HashLen]; // 32 bytes, 256 bits
static void pseudoressu_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash));
}
static void pseudoressu_addrandomness(int size, unsigned char *buffer)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashUpdate(&hash, buffer, size);
HashFinal(pseudoressu_key, &hash);
memset(&hash, 0, sizeof(hash));
}
#define aDEBUG23 2
static void pseudoressu_topup()
{
unsigned char topup[TOPUP_SIZE]; // 256 bits
ressu_genbytes(sizeof(topup), topup);
#ifdef DEBUG23
ressu_dump("topup", sizeof(topup), topup, 32);
#endif
pseudoressu_addrandomness(sizeof(topup), topup);
memset(&topup, 0, sizeof(topup));
}
void pseudoressu_bytes(int size, unsigned char *buffer) // JariK 2022
{
unsigned int n, blockbytes = 0;
unsigned char digest[HashLen]; // 256 bits
static int init = 1, topup_counter = 0;
if(verbose)
fprintf(stdout,"pseudoressu");
while(size > 0) {
if(topup_counter <= 0) {
if(init) {
ressu_genbytes(sizeof(pseudoressu_key), pseudoressu_key); // set first key
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
init = 0;
}
pseudoressu_topup(); // add randomness to key
#ifdef TOPUP_TWICE
pseudoressu_topup(); // add randomness to key
#endif
topup_counter = TOPUP_BYTES;
blockbytes = 0;
} // end of if(topup_counter <= 0)
pseudoressu_internalbytes(digest); // get random bits using the key
n = (size < sizeof(digest) ? size : sizeof(digest));
#ifdef DEBUG23
ressu_dump("olddata", n, buffer, 32);
ressu_dump("bytes", n, digest, 32);
#endif
for(int c = 0; c < n; c++)
buffer[c] ^= digest[c];
#ifdef DEBUG23
ressu_dump("newdata", n, buffer, 32);
#endif
if(verbose) {
fprintf(stdout," ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
newressu_output = 1;
}
buffer += n;
size -= n;
blockbytes += n;
if(blockbytes >= PSEUDORESSU_LIMIT && size > 0) {
pseudoressu_internalbytes(pseudoressu_key); // replace key with new one
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
blockbytes = 0;
}
topup_counter -= n;
} // end of while(size>0)
pseudoressu_internalbytes(pseudoressu_key); // replace key with new one
#ifdef DEBUG23
ressu_dump("key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
}
Satunnaislukuja käyttäen pseudoressua:
$ ./newressu --pseudoressu
00000 84853369290958902675757388129617632217440385931707856776591439954
00001 84069858194199352061363652567853332957999714525446940392234062860
00002 06427212315998791561126209640856360958935692530455051657986936746
00003 99723974440113428246576863396953005265581100052913290239102752500
00004 63388725437541198987187227629631506871622828013283331007442216631
00005 62030931043545661111647127241062935062281796958567659952167029594
00006 47921575029802383061270050124800729975762794596462783830401317795
00007 52987926964317577756871259541040138838013643538942551182236203384
00008 24214738687464482704041761961902906703331010263554656580505243598
00009 70022632015150824436120131748799624755065262077649254711408046279
Newressu:un on lisätty –rdrand ja –rdseed kytkimet, jotka antavat satunnaisbitit käyttäen Intel (ja Amd) -piirien sisäistä satunnaislukuominaisuutta.
Aluksi määritellään fort.h:ssa käytetäänkö prosessorin satunnaisbittitoimintoa: Voit itse arvioida haluatko käyttää niitä ja poistaa ‘a’:t #define kentän nimen alusta.
...
#define aUSE_RDRAND 2
#define aUSE_RDSEED 2
...
Sitten komentorivikytkimet ohjelman parametreista:
int main(int argc, char *argv[])
{
...
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strncmp("-", argv[c], 1)) {
...
#ifdef USE_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
#endif
#ifdef USE_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
#endif
...
}
Tässä newressu_genbyte(), jolla luetaan yksi satunnaismerkki:
int newressu_genbyte()
{
...
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(sizeof(gent), gent);
#endif
...
}
Sitten edellisen kutsumat rdrand_bytes() ja rdseed_bytes() ja niihin liittyvät funktiot:
void _cpuid(unsigned int leaf, unsigned int subleaf,
unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
{
asm volatile("cpuid"
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
: "a" (leaf), "c" (subleaf) );
}
int _is_cpu_vendor(unsigned char *cpuvendor)
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(0, 0, &a, &b, &c, &d);
if(memcmp((char *)(&b), cpuvendor,4) == 0 &&
memcmp((char *)(&d), cpuvendor+4,4) == 0 &&
memcmp((char *)(&c), cpuvendor+8,4) == 0)
ok = 1;
return(ok);
}
#endif
#ifdef USE_RDRAND
int _has_rdrand()
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(1, 0, &a, &b, &c, &d);
if((c & 0x40000000) == 0x40000000) {
ok = 1;
}
return(ok);
}
int _rdrand_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdrand %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdrand_bytes(int buflen, unsigned char *buf)
{
int c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"Intel rdrand");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"AMD rdrand");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 100) {
if((ret = _rdrand_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %016lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
newressu_output = 1;
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x", ((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout, "\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDRAND
#ifdef USE_RDSEED
int _has_rdseed()
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(7, 0, &a, &b, &c, &d);
if((b & 0x40000) == 0x40000) {
ok = 1;
}
return(ok);
}
int _rdseed_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdseed %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdseed_bytes(int buflen, unsigned char *buf)
{
int c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"Intel rdseed");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"AMD rdseed");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 1000) {
if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x",((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDSEED
Malliksi satunnaismerkkejä käyttäen –rdrand kytkintä:
$ ./newressu --rdrand
00000 57048164604700389892252604030891636280086112647667058413598950180
00001 85367873337798713870018921407256662622610378059375065346728579858
00002 40986136534533462054903474522649995512196495543741784079574936983
00003 19055247425244842196365427052268075190944922987923879712193930459
00004 21073317923966805747341619816756386934943889348941261188118170090
00005 84441244015826068846216962049544449876189313909490716280827133529
00006 89457709125843616301547827199781195854625633078477767222494900843
00007 26441810410958757585870825129671642480172920546092127710214865492
00008 92825666443631689925831354003095669316518706333179728966151922253
00009 38425570261919457665391336241936521204556331228537091197184239827
Vielä satunnaismerkkejä käyttäen –rdseed kytkintä
$ ./newressu --rdseed
00000 12575858142151541705315577158406477909851976391447353896413900561
00001 31060686344418670883795387123181915659843252785862515386243566233
00002 37717242735083622828533570787786938380359683416949578017028253663
00003 76962160083573864191170336613298614371660291690167147688816903087
00004 97599344559430802834845481925548516864857260161367980227215829024
00005 12924393487151440110103592153782827999940152135987584643269997020
00006 42239941915393566338139392085782443821230059081997751313044879649
00007 84190993998746466726787014147375771575146210681898092888312165521
00008 57327160340778195555246548554777557059408338779546380301502448897
00009 04224922038814950584933722703301666911868454852489894234206320375
Lisätty hindi satunnaislukuaakkosiin kieliin:
$ ./newressu --hin
00000 पठझुनफञौि्ीरमञपआिनरवफहनसजकगढटणथइॉउघयथईवशऔछऔठदौेॉि्झलऊऊडछरखॉऐठुथड
00001 ॉशौाृॅफीऊःनऋकनीौनभठरसॅतचचमठझखफऑरषढगॅीनअटजईचठँऐबरभवॉोपूबे्लञकबअइफ
00002 उ्चीएहःणॅभयरैऐणखलुऋिचौौःढईझोँखफगभशऐछऊइघृउकवगउषटआड़पभछफटॉखथौ़उबीठ
00003 हटऋहथफमगौूउएंौजेेलएौषकऐइरएैपवदमधॅचऊखचिचगधवबमटवगमईआअ्ढ्ःभोचलटथ़ऋए
00004 ीिफतंटप्ीिडँभवदगः्मगऋएगआकऐश्आढऑेअचमणसऐसोइर्ेएयकौीघझथफककःणछओीएॅबद
00005 अटिढछधेऋठऑऔएछॅझढिृतॅधखऋाफणधपइचणेकबछईॅेञ़ढविंकगऋऑतजीुतबइ़्छुछईओधफ
00006 धऋथाइञगगअठओयौवटगएॅेगऑऐडएएञञटवॉतँॉिजामठुढऑलशछदउछॉठटजणूयगौैैीशघेॉझ
00007 डऋकनकउअआऐ़जनअषऊाञिइजीउगंचल़ँबठीमफठॅडहईऑतहंवटतंऊिधखोऋणाओृजञकखऋेएी
00008 ंओण़ुचषछषओञएफचऑौजूऋफानअइठठठइॅआउंऊइऊवौँतवटडषरछघपःइऋचझहँऔझःएछऔीजवक
00009 ँएऑडइॉऔ़्िमृओमादईुणठेघकधेकओकाचमशखऋृँखशढबोफुवलताॅैरझफदखऑझॉशघृँनेघ
Vielä koodi newressuun:
...
} else if(!strcmp("--ind", argv[c]) // not ready
|| !strcmp("--hin", argv[c])) { // Hindi alphabet
//unsigned char *signs = "ऀँंःऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॕॖॗॢॣ॒॑॓॔";
digits =
"ऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढण"
"तथदधनऩपफबभमयरऱलळऴवशषसहऽॐक़ख़ग़ज़ड़"
"ढ़फ़य़ॠॡ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॸॹॺॻॼॽॾ"
"ॿ"; // 97 characters
//digits_add_limits(&digits,0x900,0x97f); // Hindi (0900-097f)
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
...
Lisätty vielä somalian ensimmäinen versio (seuraavassa versiossa ei vielä kaksoiskirjaimia: KH, SH, DH): (mukana myös columns rivit, joista lisää seuraavassa kappaleessa:)
$ ./newressu --som --columns
---------1111111111222222222233333333334444444444555555555566666666667
1234567890123456789012345678901234567890123456789012345678901234567890
======================================================================
00000 GDSBGHQOOAOHRJNLYGARTSELJDJLAJYYOTLEWEBWRXDNLQWTTMRYFOTJHGTWTYNF
00001 TCDCJXCNLCJJLCJORFYNALEYNTQNTKGTKAJNJFACAECQTJWKJLFJTXMLFMMYQCCC
00002 CWCYJKNEMGNQXMNRQYYAYQXDXSQEWWNSESTNGEGMBMKHCROKBMKCLAOSHCOJMGFA
00003 ARBTQCJNJOQOBRRGCXTMHNTOETNJXTOSRGSRFAOLKXGOLXDHGTCTBCCNTJFQCKAS
00004 WXGKLSXHEXXTXLKQRQSDYRWRTHXQBBKGTADDEXNGCXFBSROJXEHSDQEBLSCYCQQR
00005 HGOOEEKYHHEFGYGLQLCOXSNMSTGOKBQGJKHJJYJTOJOWNDGBGELFFFXWWHQGCGTG
00006 SJTQFSHOEYARAHOQSFBKSMXYOFXAEHFATSTYRAEWTNOSDQDATJNAGTXCYFCKCQHX
$
Vielä koodi somalian ensimmäisen version kirjaimiin:
} else if(!strcmp("--som", argv[c]) ||
!strcmp("--SOM", argv[c]) ||
!strcmp("--SO", argv[c])) { // Somalia alphabet
#ifdef KOK
// A, B, T, J, X, KH, D, R, S, SH, DH, C, G, F, Q, K, L, M, N, W, H, Y, E, and O
digitsstrings = "A", "B", "T", "J", "X", "KH", "D", "R", "S", "SH", "DH", "C", "G", "F", "Q", "K", "L", "M", "N", "W", "H", "Y", "E", "O", "";
int first = 1;
unsigned char **pp;
pp = digitsstrings;
for(c = 0; strcmp(*pp, ""); c++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"%s", *pp);
first = 0;
pp++;
}
// missing KH SH DH
#endif
digits = "ABTJXDRSCGFQKLMNWHYEO";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
Lisätty –columns komentoriviparametri, jolla voidaan tulostaa sarakkeittain sarakkeen numero: ajo esimerkki
---------11111111112222222222333333333344444444445555555555666666666677
12345678901234567890123456789012345678901234567890123456789012345678901
=======================================================================
00000 22258382806296729238178486166796544611755807164847927666922883010
00001 28418563167711867913647921768757420667110694576793471041747264318
00002 99804558335755889341259131631520927482583107862745929217530498421
00003 51760111177576244043527804917085407731383726282400768462117274375
00004 89648866862627378375043043971820779839978322370961568999705923913
00005 29058447822637409075394304381942641680239167678291358293770305216
00006 02068139412914507088518193191859344515532139033119514656041976727
Ja koodi: (huomaa reilusti yli menevä maksimi sarakkeiden määrä, ylin rivi kertoo miljoonat. Toki vasta ensimmäinen rivi joka tarvitaan tulostetaan. mallilistassa ensimmäisellä rivillä on kymmenet)
//
// look thru command line parameters
//
for(c = 1; c < argc; c++) {
...
} else if(!strcmp("--columns", argv[c])) {
columns = !columns; // print column numbers
...
}
}
...
if(columns) {
//---------11111111112222222222333333333344444444445555555555666666666677
//12345678901234567890123456789012345678901234567890123456789012345678901
//=======================================================================
//00000 86747100388687087416829400778878989202760594993130062980826178851
//00001 36862623069143814543525935285460059703805218323534266522497684582
int digit, clines = 0, nonzero;
for(c = 1000000; c >= 1; c /= 10) { // lines, 100000's, 10000's, 1000's ... 1's
if(pchars < c)
continue;
nonzero = 0;
for(d = 1; d <= pchars; d++) { // column numbers
digit = (d / c) % 10;
if(digit != 0)
nonzero = 1;
if(nonzero)
fprintf(stdout,"%d", digit); // nonzero digits after first nonzero
else
fprintf(stdout,"-"); // zeroes in beginning of row
}
fprintf(stdout,"\n");
clines++;
}
for(d = 1; d <= pchars; d++)
fprintf(stdout,"=");
fprintf(stdout,"\n");
clines++;
lines -= clines
} // if(columns
Muutettu komentoriviparametrien tiedoston kokoa määrittelevät parametrit samankaltaisiksi kaikissa testi ja newressu.c ohjelmissa: aluksi newressu.c:n tarvitsemat muuttujat: _set loppuiset parametrit muutetaan ykkösiksi jos ko parametri määritellään.
unsigned long long filesize = FILESIZE, blocks = BLOCKS;
unsigned int blocksize = BLOCKSIZE;
int filesize_set = 0, blocks_set = 0, blocksize_set = 0;
Sitten komentoriviparametri iffit: ensimmäinen kappale määrittelee –filesize parametrin, toinen kappale –blocksize parametrin ja viimeinen –blocks kappale määrittelee –blocks parametrin (blokkien lukumäärä).
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--blocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
blocksize = getlonglong(argv[c] + 11);
} else if(c + 1 < argc) {
blocksize = getlonglong(argv[c + 1]);
c++;
}
blocksize_set = 1;
} else if(!strncmp("--blocks", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
blocks = getlonglong(argv[c] + 8);
} else if(c + 1 < argc) {
blocks = getlonglong(argv[c + 1]);
c++;
}
blocks_set = 1;
Parametrien tarkistus ja puuttuvien laskenta: huomaa exfat korjaus, jossa tarkastetaan että blokin koko ei ylitä megaa merkkejä, ja jos ylittää se pyöristetään megaan ja blokkien määrä ja tiedoston koko lasketaan uudelleen. Ensimmäinen kappale laskee puuttuvan parametrin, ensimmäisenä lasketaan tiedoston koko (filesize), jos sitä ei ole parametreissa, sitten blokin koko ja viimeisenä blokkien lukumäärä, jos niitä ei ole annettu parametrinä.
Toinen kappale laskee miljoonaa merkkiä suuremman blokin koon miljoonaan, ja laskee uudelleen blokkien määrän ja tiedoston koon (kun blokin koko laskee, myös blokkien määrä ja tiedoiston koko muuttuu).
Kolmannessa kappaleessa tarkistetaan tiedoston koko (filesize) parametrin ylivuoto ja että blokkeja on vähintään yksi ja blokin koko on ainakin yksi.
Neljättä kappaletta tarvititaan silloin kun tarkistetaan että tiedoston koko(filesize), blokin koko (blocksize) ja blokkien määrä (blocks) parametrit on annettu oikein, kun ne on kaikki syötetty. Toki se vielä lopputarkastaa myös lasketut parametrit.
// calculate missing file size parameters
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks; // round up
filesize = blocks * blocksize;
} else if(!blocks_set) {
blocks = (filesize + blocksize - 1)/ blocksize; // round up
filesize = blocks * blocksize;
}
#define aEXFAT_FIX 2 // on for now
#ifdef EXFAT_FIX
if(blocksize > KILO * KILO) { // max "blocksize" 1m (exfat)
blocksize = KILO * KILO;
blocks = (filesize + blocksize - 1) / blocksize;
filesize = blocks * blocksize;
}
#endif
if(filesize != blocks * blocksize ||
blocks < 1 || blocksize < 1) {
fflush(stdout);
fprintf(stderr,"%s: sample(): mismatched parameters", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / blocks != blocksize) {
fflush(stdout);
fprintf(stderr,"%s: sample(): parameter overflow", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
Parametrien käsittelyssä käytetty getlonglong() funktio: getlonglong() käyttää getdigit():iä lukeakseen yhden numeromuotoisen merkin. Tässä numero voi mikä tahansa numero 0-9 tai kirjain a-z. Käytössä on vain binääri “01”, oktaali “01234567”, desimaali “0123456789”, heksa “0123456789abcdef”.
getlonglong():n ensimmäinen osuus lukee asiakkaan parametrin numerojärjestelmän (0b…, 0o…, 0d… tai 0x…), (esimerkiksi (0b1111 on 15, 0o10 on 8, 0xff on 255). Jos numerojärjestelmää ei ole annettu oletuksena on desimaali.
Toinen osuus laskee yhteen asiakkaan parametrin numeromerkit (esimerkiksi 8192) ja laskee ne yhteen huomioiden asiakkaan antaman numerojärjestelmin (binääri jne).
Kolmas osuus lukee asiakkaan antaman kertoimen (kilo, mega, giga, tera, peta tai eksa) esimerkiksi 1k, 1m, 2t. 8 merkin pituiseen kokonaislukuun mahtuu 15 eksaa ja rapiat.
Neljäs osuus tarkistaa ennettavan parametrin ylivuodon ja ynnää samaan parametriin liittyvät numero osuudet yhteen (esimerkiksi –filesize1g1m). Lopuksi poistetaan b tai ‘B’ lauseista kuten ‘100kb’ tai ‘1gb’.
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
#define DEBUG32
//#define KILO 1000
#define KILO 1024
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %llu", prevll);
fprintf(stderr,", multiplier: %llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
DEBUG32 on oletuksena päällä ja se tulostaa rivin näistä parametrien laskennoista: string kentässä on käsiteltävä parametri merkkijonona base on käyttäjän antama numerojärjestelmä, multiplier on käyttäjän antama kerroin (k, m, g, t, p, e), prevll on asiakkaan antama numero, ll on kerroin * numero, totll on samaan numeroon liittyvät numerot yhteensä.
$ ./newressu --sample --filesize 1g100m --blocksize1k
string:'1g100m', base:10(10B), multiplier:1073741824(1G), prevll:1(1B), ll:1073741824(1G), totll:1073741824(1G)
string:'1g100m', base:10(10B), multiplier:1048576(1M), prevll:100(100B), ll:104857600(100M), totll:1178599424(~1G)
string:'1k', base:10(10B), multiplier:1024(1K), prevll:1(1B), ll:1024(1K), totll:1024(1K)
blocksize:1024(1K), blocks:1150976(~1M), filesize:1178599424(~1G)
...
$
Edellisessä kuvassa on haluttu yhden gigan ja sadan megan kokoinen satunnaisbittitiedosto, jossa blokin koko (fwrite:n koko) on 8192. Ensimmäinen string: rivi edellisssä sisältää 1g tiedoston koosta, toinen rivi 100m tiedoston koosta, ja kolmas rivi 8192 blokin koon. viimeinen blocksize: rivi kertoo vielä yhteenvedon asetetuista tiedostokoon parametreista.
Vielä aiemmissa ohjelmissa käytetyt aliohjelmat: readablelonglong() tulostaa desimaalikokonaisluvun ja sen suuruusluokan (100g, 10m, 2t jne): toinen aliohjelma fprintfcharacter() tulostaa ufh merkin kokonaisuudessaan:
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
Newressuun on lisätty uusi merkkijono salausmalli (stream cipher) –stream, jolla voidaan tehdä satunnaisbittejä merkkijonosta: seuraavat bitit on tehty merkkijonosta “kalakala”. Jatkossa merkkijonosalausta käytetään tiedoston kirjoituksen tarkastamiseen.
$ ./newressu --stream --key kalakala
./newressu: stream_open(): randomness from key, key=kalakala
00000 097007647538070452095222876773364032014848877614885432576274114682
00001 069076802144253754847369390425580418083695093228828897799956369200
00002 166962649730107510677372501914913551333963649770546607920656167530
00003 123872208527077508554473908037757655294059571650948600601580541243
00004 959069120976810662076442907983660853450311026021709027187795181219
00005 958500289994828533504137325466090300723020468339411775941540872433
00006 103918486603641932851463892918552658439592999940967471423412165257
00007 067647133783366171502688214398736241529441281236178360416684844342
00008 827011090709785699618541893769244994414243921218781696849617463710
00009 826005683785268736980725472626588977843361269856648811013296399762
jarik@jarik-HP-250-G8:~/f/ressurngd$
Lisätty integriteettitarkistus aina ./newressun ajon alkuun (DEBUG72). Sitä varten on lisätty seuraavat koodinpätkät.
#define DEBUG72 // default is on
#ifdef DEBUG72
int flagint = 1;
#endif
....
for(c = 1; c < argc; c++) {
...
#ifdef DEBUG72
} else if(!strcmp("--int", argv[c])) {
flagint = !flagint;
//fprintf(stdout,"Integrity test skipped...");
#endif
...
}
....
#ifdef DEBUG72
if(flagint) {
unsigned char command[128];
fprintf(stderr,"%s: Running integrity test(s)...",procname);
fflush(stderr);
sprintf(command,"./newressutest14.sh >newressutest14.rnd.`date +%%Y%%m%%d`");
system(command);
fprintf(stderr," done.\n");
fflush(stderr);
}
#endif
Lisäksi tuo edellisessä kappaleessa käynnistetty scripti newressutest.sh:
/bin/newressu --int --single --space2 --newline 5 -l1 $@
/bin/newressu --int --single --space3 --newline 5 -l1 $@
/bin/newressu --int --single --space4 --newline 5 -l1 $@
/bin/newressu --int --single --space5 --newline 5 -l1 $@
/bin/newressu --int --single --space6 --newline 5 -l1 $@
/bin/newressu --int --single --6bits --space -s1 -l1 $@
/bin/newressu --int --single --6bits --space -s2 -l1 $@
/bin/newressu --int --single --6bits --space -s3 -l1 $@
/bin/newressu --int --single --6bits --space -s4 -l1 $@
/bin/newressu --int --single --6bits --space -s5 -l1 $@
/bin/newressu --int --single --6bits --space -s6 -l1 $@
/bin/newressu --int --single --6bits --space -s7 -l1 $@
/bin/newressu --int --single --6bits --space -s8 -l1 $@
/bin/newressu --int --single --6bits --space -s9 -l1 $@
/bin/newressu --int --single --6bits --space -s10 -l1 $@
/bin/newressu --int --single --rand -l1 $@
/bin/newressu --int --single --alnum -l1 $@
/bin/newressu --int --single --alpha -l1 $@
/bin/newressu --int --single --graph -l1 $@
/bin/newressu --int --single --lower -l1 $@
/bin/newressu --int --single --punct -l1 $@
/bin/newressu --int --single --upper -l1 $@
/bin/newressu --int --single -d --lim41 -w7 --zero -l1 --lotto$@
/bin/newressu --int --single --1bit -l1 $@
/bin/newressu --int --single --2bits -l1 $@
/bin/newressu --int --single --3bits -l1 $@
/bin/newressu --int --single --oct -l1 $@
/bin/newressu --int --single --4bits -l1 $@
/bin/newressu --int --single --hex -l1 $@
/bin/newressu --int --single --HEX -l1 $@
/bin/newressu --int --single --5bits -l1 $@
/bin/newressu --int --single --6bits -l1 $@
/bin/newressu --int --single --dnk -l1 $@
/bin/newressu --int --single --nor -l1 $@
/bin/newressu --int --single --fin -l1 $@
/bin/newressu --int --single --swe -l1 $@
/bin/newressu --int --single --rus -l1 $@
/bin/newressu --int --single --est -l1 $@
/bin/newressu --int --single --ltu -l1 $@
/bin/newressu --int --single --lva -l1 $@
/bin/newressu --int --single --fra -l1 $@
/bin/newressu --int --single --gbr -l1 $@
/bin/newressu --int --single --usa -l1 $@
/bin/newressu --int --single --ita -l1 $@
/bin/newressu --int --single --eng -l1 $@
/bin/newressu --int --single --deu -l1 $@
/bin/newressu --int --single --grc -l1 $@
/bin/newressu --int --single --jp -l1 $@
/bin/newressu --int --single --jp1 -l1 $@
/bin/newressu --int --single --hir -l1 $@
/bin/newressu --int --single --jp2 -l1 $@
/bin/newressu --int --single --kat -l1 $@
/bin/newressu --int --single --jp3 -l1 $@
/bin/newressu --int --single --cn -l1 $@
/bin/newressu --int --single --kan -l1 $@
/bin/newressu --int --single --kor -l1 $@
/bin/newressu --int --single --ind -l1 $@
/bin/newressu --int --single --hin -l1 $@
/bin/newressu --int --single --som -l1 $@
/bin/newressu --int --single --SOM -l1 $@
/bin/newressu --int --single --SO -l1 $@
/bin/newressu --int --single --braille -l1 $@
/bin/newressu --int --single --dna -l1 $@
/bin/newressu --int --single --DNA -l1 $@
Raportti, joka tässä tapauksessa kirjoitettiin newressutest14.rnd.* tiedostoon on seuraavankaltainen:
00000 43547 02424 77426 40520 24483 85853 60125 09060 27766 91983
00000 90226 00953 26685 66371 98917 68085 20508 58887 33858 26510
00000 36046 40837 05103 72057 02162 62838 77719 36899 29862 14697
00000 36556 28423 75766 79658 12445 83960 32923 60357 04934 69935
00000 29071 78822 29171 57055 83957 60222 54011 66685 51620 90995
00000 x a d N 6 9 1 1 f A X t R p s B Z p B I Z Q E x N R l - f I d y j
00000 Z3 TR -s UJ dF bm L1 Uf iC w0 _m sK 2k bg vA LU W8 83 3R tA if x2
00000 F7K Ypn cRV fqT Sgd -nH xCg lfx mKa 1bO AQE OFH pfU Ytq xpH tw6
00000 -s0J cK8N FZpP rd2c tqQn 3gKJ 4vqB 6mC6 yA97 0S7P 3EBM 30vu LBP5
00000 2_lY0 N5uo4 Bf_uu EAEaU vyXiT Nm5BD 4004V 8sHqa fTjlL rdgiV IwJQo
00000 8-2Zwx gVbEem 0Mj1Eg yuUJfx perUOH TGNBnp jaNiOK RulLWh IpfY9P
00000 K-GfdFW wAsO75R xjhpfXE HxMtnkr sLY1620 zJimadt xYbLTvQ LOqwtmy
00000 jjDtKyoH MV2tEJ4p 8SywDwv- svDXLQbu Img1Xe-4 vfFnoIQg 81354mXg
00000 -V7ui7PEs xczU8mdRB LuRUcHPGt XzbIR427y yyDMjByDH v5fDDGYL8
00000 KNU_kIR7_g R_G2vivdDi urouyAaGdT YdtjjAl-Hj aCJCUgUdnL mx6j3PdM3Z
00000 41712 25645 39695 88861 41948 33840 36298 59751 77600 74349
00000 UBWuGDDcGpFkKNo244N5TVrH8TwEsl2eKypdBOIyBDkMoCaKwkT5IwTZo2yYum2dg
00000 kknksuixobxgyelguaxyknlbkotypickbqfxqcafuyshzflujousbwiykgyaxvfdy
00000 6EoMqaSuRdDe7m*xZ4-}ND%T';6MmD@KK~sZ`8^Lv*w2$,dv9(SC(.;Nx:6.vib(@
00000 stshrhhiupnmovnaovkzuifoohqivxyzrahmprolgqhjfbaaeigvueeuoqtqvyofk
00000 {%~')`%,%#;\<"\#}{#'<?]<)>>_!(:]~;~>=$+|<=!~-!:$,{]:+~.&}))^=!-`|
00000 HJGGZIRMQRWPXNELYARMBNDJLXCJMIOHEKVCKBQDUAGWJXAYMJTNPMTWNIQTKQMHA
00000 03 04 14 18 24 29 36
00000 1110110011100100110111111111011010110010111011110011011001000000
00000 3102022001303221331223300321321003220321212030231122110223131121
00000 742074745673401760037715534423267357677510113274147215471160147115
00000 154564406714644140021565367601517766620126222517076751422000524201
00000 2e5408c76d6619cfe329f7d133647d9252a5c207fa6591f863998a6711e85570
00000 04d2c38c643fa8f8307658a931256b3dc878adf7ea1ef6df9387351fe4eabb05
00000 CC807E1CB27065460191405263BDE3102150881F7E34A5190EE04E69EC6AF271
00000 D8TV7UC8P601U16IBA6TKUTECL49GV1LLPLAJ5I8G7KDEQ0BOUIUFKIEUCNVHL6K
00000 j7YBjWvXCovQdzVhONSoCArNTWzg5Gv0OX6jjMbzRi2ZUXHtazO85ZynzF6V-UwB
00000 zjDzoquNXiaxPTqØUDCifØqaGwÆnChKzfVXoKNDøxsoÅNmpoCpCAkRqiCÅTyÅLnw
00000 hoÅNMEhehæSYxktZNhCxvBÅZLkÅULXLyePDkobFQOÆcjmuizyUmGrKCAØuvvRNII
00000 VEåRÖtUObVVNoyDCÄjQWOälVäwtÅBAQNWqnYhJCAåGÖXqHyWäåXfåYJöSöRNCXEi
00000 jäHGrryvocÄoBVhwAÖÄHKTnMfOzUkwÄlZlxUöåhllÄnuÄkjCnLuEryjUiKNVSååt
00000 йЪлцЙощьрцСсЙьдрьжтсОфйхнЪгэрОйЭыЗФфЭеьЩэСлсиЕМоаЦеЫтХёлыЛЭЬаМиО
00000 UmTNPqcnötMmOCLUjZPŠmaKrqTiõSKCqŽÖmLdüHäöõmFjÜFeÜlÄjEÜWMgwyejÕqS
00000 keųzotDcVČųCŪyPmgcCinvueeįčšPIGUČIdųsEŪŪzjMSŲTŲfEFbĮIŽčsžBnūągČg
00000 uMĀĀbPģVBĢbAĀŪmrDhsnhĢhāUPžĪkzPAFdĀeķļčĶChēljmaaGIRŠĪŪaĪŽļķJjbtF
00000 foRubnHSkBtkPRptozSvDkwElsbHIIXerpLqfwzuigBxnSMoUQefFxkCOfXWYnSK
00000 wDasgHAgMzdATKKUyYiltXbvLgVPgHilhklyyNUNGYTAyBHXYJpktfBUmFVBfnPp
00000 zTTpcRUDmJLElleTngPqqznspGXOjlibUeafTYPrfhtmOTLvyVgIQlTECHlosAVc
00000 hzyItLFHUjOfeoiOEqwrkKNLwFjfMzHsGqnQcygUIdJQqgAcqsbjcQfDOOdqJKnr
00000 BFPJszetXmOVAoloouHdLmrdyePkRnucovlhqWYAKIPeYOoqcqLiMWBcgtFdWXzi
00000 zQrfpGßTVSöBzRYWyRDbieFcNOQniXßäTHRtYöwPiuaJGQẞzäEÜsSLOänTOaKItp
00000 ΠΤΑΚκιΥνυΗΧξΗΗΚαΨχΨαΟυΚεΠβΓΔΟΙδΔΟΚΠΓκΕαφΤζψΘΙΒνθμπαδΥΦΗθφΣραΖΔΝρ
00000 萳示柍璭忾驒蘼崰橚吅廊負稽郱鿠億唍沪瞵瀩駤靿睘虶驚蒡滫恻埤鞇朿郖
00000 ゕゖいにっげもぐんぃりくぇすでひゅょぉゖもえゑあざりはのえゎゃう
00000 せゕほへへうはじさげうべぴめれたぉをわばあんぞゎひきへゖょだむゎ
00000 チ・デペカヵヹヶゼペ・チヵヒヿニクレカニラュ゠エラセジナヰパロナ
00000 ヮェタヨ゠グゴャヺパウキジホゾダーパワズチフュョェサスヾペペゼル
00000 啊鯡螟酠晜嬕饅鈿岚勂戍來顕憠奠芍榠耍榬太闳媀軳嫔藇嚦璨散寠分蓪螛
00000 茴夲邛嵸詠乧過仧窅惸懸究昱堿猗橦碁縺佅畞碜鄫俩潚罇綰荸曛胐蒀芜饎
00000 灧僕蘀鴐暍項縅篸焜埾宧蝗鿉乪醩鰆僧襅歹珛捫釧賄馂穩祘虓栏财果睊芧
00000 얆뺖귄톹쭅쑣찰깃뤢텀횾첮죏옩춺퇄셱텧볾짣궭픒흽좪쯏듖헕홲뉡둵혧쯣
00000 ॷएॼऎ९एधऄॺॼक़९पॴॶॠऍॾमतॴआॽॡझषऱॳॠ॥औॴ१ॠ६खॷळओढ।७५ऴॸऱञऄअव८भॵऱलहतऴ५ऍग़६९॥
00000 ॶ।ॐब३थएढडखॵहकभमतऎङऩऔऽवअसग़ऐझखॹ७ॷॱकउयड़ञगआॻ७ॱओढ़ॱ८॥ऋ।ऱफ़७ॿरग़३ऴखछ६ॐझऱड़
00000 YNEETLLWFJHRFRCWQOESWRTJHQQHXLWFTYWBDOGKGFBBREGEOBJXFCRBBHMHAMOX
00000 MRJYXJENQXKMANSBYAWOKSSYLHXNWKDGCHFGKXQLHJKWYLWDSABFALDDJKBYBLFM
00000 FOXQWXXNEACXWNSCLBLYETARFTLGMCQKRDYEQCYGXAQRHNOOWADYGTTMAGKAHXNK
00000 ⣓⣕⢋⠀⣉⠄⢭⡞⢅⠑⢜⢙⠭⠾⣖⢵⡎⡩⡜⣾⢢⡳⡳⠡⢸⢨⡆⣠⡐⣲⢩⡔⠻⢄⠌⡹⡗⡕⢏⢛⠈⠾⣦⠾⡹⢔⠻⢱⡴⡰⢪⡬⡜⡔⠷⣆⣼⣬⡦⢏⢢⢚⡻⡛
00000 cactttgttggactatttcaagtggcgatcatctctttctgagaatctgaggttggcggagcat
00000 TAAAACACCCAGAATCCGACCATCTATGGTCGGCACACTAAAATAATACCCTCAAAAATTGAGA
Lisätty pistekirjoitus (–braille) satunnaislukujen raportti “kieleksi”, tässä mallituloste:
$ ./newressu --braille
00000 ⡚⡤⣤⣒⡯⣃⡝⣾⡎⣂⣭⡕⣹⠸⢗⢋⠇⡛⡎⡹⣝⣑⠅⠰⡵⠑⠝⠙⢗⡞⡤⣎⣉⡫⡺⠥⣇⠣⡟⣺⣃⠊⠞⢰⡝⠋⢅⡞⢀⣋⢷⠐⢄⢯⢰⠛⠳⣡⠽⢋⠃⢌⢺⢒
00001 ⠇⣤⣌⢚⣅⢯⠐⡄⡮⠅⢺⣸⠛⡞⡋⣋⢿⢌⡸⠢⢠⡋⡕⣼⠀⢾⡉⠆⡗⣋⢖⠞⢌⣤⣶⠦⠟⣛⠩⢼⣌⢛⠥⠤⡭⠉⡈⢜⢄⡑⣟⠯⡓⢺⣈⡅⠔⡿⠞⠍⢩⢸⣭⠛
00002 ⣥⠚⡓⢵⢎⡶⡕⡦⣹⠞⡜⡼⢳⣆⡇⣎⡭⣱⣽⡒⡉⡙⠌⢲⡄⡲⣸⣒⢷⠜⣧⠊⢺⠫⢚⠦⡷⠑⢬⢓⣲⢧⠼⠏⡃⡰⣀⢱⠚⣨⣓⣌⣌⢜⡣⣐⡝⡠⡉⣎⣃⣫⢍⢁
00003 ⡝⠞⢃⢡⣬⣾⢡⣁⠈⣐⡡⢆⡩⣉⡓⠃⣃⣡⡤⡊⢕⡯⣽⠋⣅⠞⡛⣠⢰⣏⠎⣱⡣⣄⡀⠂⣏⣶⠠⢜⣦⢦⣸⣴⠏⣬⢩⡗⡳⣬⣊⡙⠁⠜⢆⠃⢒⣤⣐⠞⡞⠹⣞⠦
00004 ⡷⠎⢩⠊⡎⡔⡁⠶⢞⡡⢧⡑⠿⠃⢀⡌⠰⠹⡐⢘⠔⢞⠶⠚⠁⢜⢸⣬⣋⢦⣩⢱⢺⠢⣯⡂⢁⠡⠕⣟⠏⢠⡧⡻⢾⠂⠰⡫⡘⢦⢍⠨⢰⠽⡑⢝⠩⠛⢕⡾⡰⣕⣪⣩
00005 ⢻⣞⡯⢫⢹⠳⠗⡚⢻⢒⣪⡞⢑⣀⡙⠀⡺⡯⡥⣯⠊⣭⢋⠼⠇⡝⢿⣀⡢⡞⢉⢫⠨⢕⢕⠳⣶⡥⠙⠐⠐⡭⡎⣜⣭⠆⡋⣤⡕⡨⡮⠙⣷⢧⡞⠛⡝⢤⢒⠊⢉⣡⠗⡧
00006 ⣀⣚⡌⡌⢫⣎⢭⢰⣿⣠⡖⣯⢖⢞⡿⠼⢘⠚⠫⠏⢺⠯⠌⠖⠠⣥⠓⠋⠓⠫⡮⣱⡙⡻⣴⠰⠺⣺⣙⢕⢞⠛⣗⠘⡻⡑⠛⢛⠎⣋⢌⡣⠙⢮⠒⢾⡢⢸⠭⠈⠙⡘⡚⢽
00007 ⣜⣇⢺⣨⡮⡞⡧⢰⣲⡑⢵⡕⡄⠜⠴⣎⡂⢷⡕⢓⣤⡥⠠⡉⣼⠼⣗⢥⡨⠏⣕⠯⣰⣙⡾⠗⡬⡐⢈⠓⢳⠻⡺⢩⠺⣼⢯⠐⣠⢰⡆⠍⣏⣌⢕⠉⡖⣸⡗⠄⡌⢔⢗⡀
00008 ⣓⢪⣙⠔⣣⡦⠊⢖⢪⢌⣍⠶⢑⡗⡟⠔⡊⡖⢒⡚⣜⠧⣧⠚⣕⢩⣀⣚⠥⢎⢪⢫⢙⡉⠬⣤⠯⡒⡉⠝⢠⡅⣷⢠⣬⡁⠂⠼⢕⣪⢕⡍⣸⡞⡨⢼⠙⡪⣳⢄⢱⡫⢪⢗
00009 ⡌⣟⠠⡵⡛⠍⣙⡤⡻⠽⢈⢗⢄⢯⣒⢳⠘⢺⣸⠚⠘⢍⠜⢊⣿⢅⢗⡀⢩⠶⠴⡰⠎⡁⡽⣦⢉⣍⠽⡿⣲⠞⢩⠤⠜⡌⢰⣒⢬⢹⢨⣭⣆⢠⠽⢿⡄⠊⣳⡎⠈⣺⡲⣺
$
Ja koodi braillen tulostamiseen:
...
} else if(!strcmp("--braille", argv[c])) { // Braille alphabet
digits = // 0x2800 - 0x2900
"⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
"⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿"
"⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿"
"⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
...
Lisätty newressu:un uusi komentorivikytkin –utf8, joka tulostaa listan utf8 merkeistä, lista on seuraavanlainen:
----------------111111111111111122222222222222223333333333333333
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
================================================================
0 --- control characters --- !"#$%&'()*+,-./0123456789:;<=>?
40 @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
80 --- utf8 characters --- --- utf8 characters ---
c0 --- utf8 characters --- --- utf8 characters ---
100 ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ
140 ŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ
180 ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ
1c0 ǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ
200 ȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ
240 ɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ
280 ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿ
2c0 ˀˁ˂˃˄˅ˆˇˈˉˊˋˌˍˎˏːˑ˒˓˔˕˖˗˘˙˚˛˜˝˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿
300 ̀́̂̃̄̅̆̇̈̉
340 ͇͈͉̀́͂̓̈́͆ͅͰͱͲͳʹ͵Ͷͷͺͻͼͽ;Ϳ
380 ΄΅Ά·ΈΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξο
3c0 πρςστυφχψωϊϋόύώϏϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿ
400 ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп
440 рстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿ
480 Ҁҁ҂҃҄҅҆҇҈҉ҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿ
4c0 ӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӏӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹӺӻӼӽӾӿ
500 ԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԐԑԒԓԔԕԖԗԘԙԚԛԜԝԞԟԠԡԢԣԤԥԦԧԨԩԪԫԬԭԮԯԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿ
540 ՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖՙ՚՛՜՝՞՟ՠաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտ
Vielä koodi, joka tulostaa edellisen listan:
#ifdef DEBUG59
if(utf8) {
fprintf(stdout,"%5s ","");
fprintf(stdout,"----------------");
fprintf(stdout,"1111111111111111");
fprintf(stdout,"2222222222222222");
fprintf(stdout,"3333333333333333");
fprintf(stdout,"\n");
fprintf(stdout,"%5s ","");
fprintf(stdout,"0123456789abcdef");
fprintf(stdout,"0123456789abcdef");
fprintf(stdout,"0123456789abcdef");
fprintf(stdout,"0123456789abcdef");
fprintf(stdout,"\n");
fprintf(stdout,"%5s ","");
fprintf(stdout,"================");
fprintf(stdout,"================");
fprintf(stdout,"================");
fprintf(stdout,"================");
fprintf(stdout,"\n");
int utf8output = 0;
for(c = 0; c < 65535*4; c++) { // skip control chars
//for(c = 0x2800; c < 0x2900; c++) { // braille
unsigned char buffer10[10];
if(c % 64 == 0) {
if(c > 0) {
fprintf(stdout,"\n");
utf8output = 0;
}
fprintf(stdout,"%5x ",c);
utf8output = 1;
}
if(c >= 0 && c < 32) {
c += 31;
fprintf(stdout, "--- control characters --- ");
utf8output = 1;
} else if(c >= 128 && c < 256) {
c += 31;
fprintf(stdout, "--- utf8 characters --- ");
utf8output = 1;
} else {
codetoutf8(buffer10, c);
fprintf(stdout,"%s",buffer10);
utf8output = 1;
}
}
if(utf8output)
fprintf(stdout,"\n");
fflush(stdout);
return(0);
}
#endif
Koodaamisen lisäksi tutkin ressun tuottamaa satunnaisuutta parilla ohjelmalla (koodasin ne tietysti myös). Tässä ensimmäinen: Ennen se nimi oli cstat, uusi nimi on newressutest7.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "cstat/newressutest7 version 0.4 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
int main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1, ctrl = 1, chars = 1,
cdiff = 1, cstats = 1, multiple1 = 1, m1expect = 1,
m1diff = 1, multiple2 = 1, m2expect = 1, m2diff = 1,
m2dist = 1, monobit = 1, poker2 = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
cstats = all;
multiple1 = all;
m1expect = all;
m1diff = all;
multiple2 = all;
m2expect = all;
m2diff = all;
m2dist = all;
monobit = all;
poker2 = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--cstats", argv[c])) {
cstats = !cstats;
} else if(!strcmp("--m1", argv[c])) {
multiple1 = !multiple1;
m1expect = !m1expect;
m1diff = !m1diff;
} else if(!strcmp("--multiple1", argv[c])) {
multiple1 = !multiple1;
} else if(!strcmp("--m1expect", argv[c])) {
m1expect = !m1expect;
} else if(!strcmp("--m1diff", argv[c])) {
m1diff = !m1diff;
} else if(!strcmp("--m2", argv[c])) {
multiple2 = !multiple2;
m2expect = !m2expect;
m2diff = !m2diff;
m2dist = !m2dist;
} else if(!strcmp("--multiple2", argv[c])) {
multiple2 = !multiple2;
} else if(!strcmp("--m2expect", argv[c])) {
m2expect = !m2expect;
} else if(!strcmp("--m2diff", argv[c])) {
m2diff = !m2diff;
} else if(!strcmp("--m2dist", argv[c])) {
m2dist = !m2dist;
} else if(!strcmp("--monobit", argv[c])) {
monobit = !monobit;
} else if(!strcmp("--poker2", argv[c])) {
poker2 = !poker2;
} else {
fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
// print help message if needed
if(help) {
fprintf(stderr,"%s",procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--cstats]");
fprintf(stderr," [--multiple1]");
fprintf(stderr," [--m1expect]");
fprintf(stderr," [--m1diff]");
fprintf(stderr," [--multiple2]");
fprintf(stderr," [--m2expect]");
fprintf(stderr," [--m2diff]");
fprintf(stderr," [--monobit]");
fprintf(stderr," [--poker2]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename, "-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
int currentchar = 0;
unsigned char prevchars[MAX];
unsigned long int m1counts[MAX];
unsigned long int m2counts[MAX];
for(c = 0; c < MAX; c++) {
prevchars[c] = 0;
m1counts[c] = 0;
m2counts[c] = 0;
}
unsigned long int singles = 0;
int ch, lastch, prevch;
unsigned long m2length;
first = 1;
// read input file and calculate
// statistics
while((ch = fgetc(fp1)) != EOF) {
if(verbose) {
fputc(ch, stdout);
}
lastch = ch;
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) // ctrl or space, skip
continue;
// calculate m1 multiple
// counts
prevchars[currentchar] = ch;
for(c = 0; c < MAX; c++) {
d = currentchar - c;
if(d < 0)
d += MAX;
if(ch != prevchars[d])
break;
m1counts[c]++;
}
if(++currentchar >= MAX)
currentchar -= MAX;
// calculate m2 multiple
// counts
if(first) {
prevch = ch;
m2length = 1;
first = 0;
} else {
if(prevch == ch) {
m2length++;
} else {
prevch = ch;
m2counts[m2length - 1]++;
m2length = 1;
}
}
singles++;
} // end of while((ch = fgetc(fp1)) != EOF)
if(singles > 0)
m2counts[m2length - 1]++; // add last m2 multiple
if(lastch != '\n') // last char not lf, print lf
fputc('\n', stdout);
fflush(stdout);
if(singles == 0) {
fprintf(stderr,"%s: no data\n", procname);
exit(2);
}
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
}
fprintf(stdout, "\n");
fflush(stdout);
} // end of if(ctrl)
// print character counts if needed
long int min, max;
long int total;
if(chars) {
min = LONG_MAX;
max = LONG_MIN;
total = 0;
fprintf(stdout,"chars ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
long int temp = charcounts[c];
fprintf(stdout,":%lu", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(chars)
// calculate character statistics
unsigned long int ctotal = 0, count = 0, average = 0,
characters = 0, utf8first = 0, utf8other = 0,
asciicnt = 0, ctrlcnt = 0;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c < 0x20) { // ctrl, count & skip
ctrlcnt += charcounts[c];
continue;
}
if(c < 0x80)
asciicnt += charcounts[c];
if(c == 0x20) // space, skip
continue;
ctotal += charcounts[c];
count++;
if(c < 0x80 || c > 0xbf) // ascii or utf8 first char
characters += charcounts[c];
if(c > 0xbf) // utf8 first char
utf8first += charcounts[c];
if(c >= 0x80 && c <= 0xbf) // utf8 other char
utf8other += charcounts[c];
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
double entropy = 0;
// calculate entropy
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20) // ctrl or space, skip
continue;
if(charcounts[c] > 0)
entropy += (double)charcounts[c] / ctotal * log2((double) charcounts[c] / ctotal);
}
if(entropy < 0)
entropy = -entropy;
// calculate average
average = ctotal / count;
// calculate character differences
if(cdiff) {
fprintf(stdout,"cdiff ");
min = LONG_MAX;
max = LONG_MIN;
long int total = 0;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
long int temp;
temp = average - charcounts[c];
fprintf(stdout,":%ld", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cdiff)
// print character statistics
if(cstats) {
fprintf(stdout,"cstats ");
fprintf(stdout,"total:%lu", ctotal);
fprintf(stdout,", count:%lu", count);
if((double)ctotal / count != ctotal / count)
fprintf(stdout,", average:%f", (double)ctotal / count);
else
fprintf(stdout,", average:%ld", ctotal / count);
fprintf(stdout,", characters:%lu", characters);
fprintf(stdout,", utf8first:%lu", utf8first);
fprintf(stdout,", utf8other:%lu", utf8other);
fprintf(stdout,", ascii:%lu", asciicnt);
fprintf(stdout,", ctrl:%lu", ctrlcnt);
fprintf(stdout,", entropy:%f", entropy);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cstats)
// print statistics on m1 multiples
if(multiple1) {
fprintf(stdout,"multiple1 ");
long int total = 0;
for(c = 0; c < MAX; c++) {
if(m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
fprintf(stdout,":%lu", m1counts[c]);
total += m1counts[c];
}
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple1)
// expected m1 multiple statistics
if(m1expect) {
fprintf(stdout,"m1expect ");
long int expect;
long int total = 0;
expect = singles;
for(c = 0; c < MAX; c++) {
if(expect > 0 || m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
fprintf(stdout,":%lu", expect);
total += expect;
}
if(count == 1)
break;
expect /= count;
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m1expect)
// difference between statistics and
// real m1 counts
if(m1diff) {
fprintf(stdout,"m1diff ");
min = LONG_MAX;
max = LONG_MIN;
long int expect;
long int diffall = 0;
expect = singles;
for(c = 0; c < MAX; c++) {
if(expect > 0 || m1counts[c] > 0) {
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,", twins"); break;
case 2: fprintf(stdout,", triplets"); break;
case 3: fprintf(stdout,", quadruplets"); break;
case 4: fprintf(stdout,", quintuplets"); break;
case 5: fprintf(stdout,", sixlets"); break;
default: fprintf(stdout,", %dlets", c + 1); break;
}
long int temp = expect - m1counts[c];
fprintf(stdout,":%ld", temp);
diffall += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
expect /= count;
}
if(count == 1)
break;
}
fprintf(stdout,", total:%ld", diffall);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // if(m1diff)
// print statistics on m2 multiples
if(multiple2) {
fprintf(stdout, "multiple2 ");
unsigned long int total = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", m2counts[c]);
total += m2counts[c] * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%lu",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple2)
unsigned long int m2expects[MAX];
double base;
for(c = 0; c < MAX; c++) {
m2expects[c] = 0;
}
base = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
if(base * ctotal > 0) {
m2expects[c] = (unsigned long int) (base * ctotal);
base *= ((double)1 / count);
}
}
// expected m2 multiple statistics
if(m2expect) {
fprintf(stdout,"m2expect ");
long int expectall = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c]> 0 || m2expects[c]) {
if(!first)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", m2expects[c]);
expectall += m2expects[c] * (c + 1);
first = 0;
}
}
fprintf(stdout,", total:%lu", expectall);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m2expect)
// difference between statistics and
// real m2 counts
if(m2diff) {
fprintf(stdout,"m2diff ");
min = LONG_MAX;
max = LONG_MIN;
long int diffall = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0 || m2expects[c] > 0) {
if(!first)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
long int temp = m2expects[c] - m2counts[c];
fprintf(stdout,":%ld", temp);
diffall += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
}
fprintf(stdout,", total:%ld", diffall);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(m2diff)
if(m2dist) {
fprintf(stdout,"m2dist ");
unsigned long int total;
first = 1;
total = 0;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
switch(c) {
case 0: fprintf(stdout,"singles"); break;
case 1: fprintf(stdout,"twins"); break;
case 2: fprintf(stdout,"triplets"); break;
case 3: fprintf(stdout,"quadruplets"); break;
case 4: fprintf(stdout,"quintuplets"); break;
case 5: fprintf(stdout,"sixlets"); break;
default: fprintf(stdout,"%dlets", c + 1); break;
}
fprintf(stdout,":%lu", ctotal / m2counts[c]);
total += m2counts[c] * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%lu",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(multiple2)
#define aDEBUG84 2
// print monobit statistics if needed
if(monobit) {
unsigned long monobitzeroes = 0;
unsigned long monobitones = 0;
if(count == 2 && charcounts['0'] > 0 && charcounts['1'] > 0) {
monobitzeroes += charcounts['0'];
monobitones += charcounts['1'];
}
int ok = 0;
if(count == 16) {
unsigned char hex[] = "0123456789abcdef";
ok = 1;
for(c = 0; c < strlen(hex); c++) {
if(charcounts[hex[c]] < 1)
ok = 0;
}
if(ok) {
for(c = 0; c < strlen(hex); c++) {
#ifdef DEBUG84
fprintf(stdout,"c:%3d", c);
fprintf(stdout,", count:%ld", charcounts[hex[c]]);
fprintf(stdout,", bits:");
for(d = 3 ; d >= 0; d--) {
fprintf(stdout,"%1d", (c >> d & 1));
}
#endif
for(d = 0 ; d < 4; d++) {
monobitzeroes += charcounts[hex[c]] * !(c >> d & 1);
monobitones += charcounts[hex[c]] * (c >> d & 1);
}
#ifdef DEBUG84
fprintf(stdout,", zeroes:%ld", monobitzeroes);
fprintf(stdout,", ones:%ld", monobitones);
fprintf(stdout,"\n");
#endif
}
}
} // end of if(count == 16)
if(ok) {
fprintf(stdout,"monobit ");
fprintf(stdout,"0:%ld", monobitzeroes);
fprintf(stdout,", 1:%ld", monobitones);
fprintf(stdout,", total:%ld", monobitzeroes + monobitones);
fprintf(stdout,"\n");
}
fflush(stdout);
} // end of if(monobit)
#define aDEBUG87 2
// print poker2 statistics if needed
if(poker2) {
unsigned long poker2[4];
for(c = 0; c < sizeof(poker2); c++)
poker2[c] = 0;
int ok = 0;
if(count == 16) {
unsigned char hex[] = "0123456789abcdef";
ok = 1;
for(c = 0; c < strlen(hex); c++) {
if(charcounts[hex[c]] < 1)
ok = 0;
}
if(ok) {
for(c = 0; c < strlen(hex); c++) {
#ifdef DEBUG87
fprintf(stdout,"c:%3d", c);
fprintf(stdout,", count:%ld", charcounts[hex[c]]);
fprintf(stdout,", bits:");
for(d = 3 ; d >= 0; d--) {
fprintf(stdout,"%1d", (c >> d & 1));
}
#endif
for(d = 0 ; d < 2; d++) {
poker2[c >> (d * 2) & 3] += charcounts[hex[c]];
}
#ifdef DEBUG87
fprintf(stdout,", poker2 ");
first = 1;
for(d = 0 ; d < 4; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"%d:%ld", d, poker2[d]);
first = 0;
}
fprintf(stdout,"\n");
#endif
} // end of for(c = 0; c < strlen(hex); c++)
} // end of if(ok)
} // end of if(count == 16)
if(ok) {
long int total = 0;
fprintf(stdout,"poker2 ");
first = 1;
for(d = 0; d < 4; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"%d:%ld", d, poker2[d]);
total += poker2[d];
first = 0;
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
} // end of if(ok)
fflush(stdout);
} // end of if(poker2)
}
Seuraavassa ohjelman tuloste 8 merkkiä pitkille heksajonoille, joita on kahdeksan kappaletta. Tulosteelle tulostetaan 1000 riviä: “ctrl” rivillä on kontrollimerkkien määrät tässä LF (linefeed, rivinvaihto) merkkejä on yksi jokaiselle riville eli 1000 kpl. Seuraava “chars” rivi listaa materiaalissa olleet merkit. Tässä merkit ovat heksaa eli merkkilaskureita on 16 kpl, nollasta viiteentoista (f). “cdiff” rivillä on erotus keskiarvoon (4000). “cstats” rivillä on erilaisia tilastollisia lukuja.
Entropy lähenee tässä nelosta, koska yhdessä heksamerkissä on 4 bittiä (1, 2, 4 ja 8). Kasvattamalla rivimäärää entropy saavuttaa nelosen.
“multiple1” listaa materiaalissa olevien eri pituisten monikkojen määrän. “m1expect” kertoo eri monikkojen odotetun tilastollisen määrän. “m1diff” kertoo edellisten erotuksen. “multiple2”, “m2expect” ja “m2diff” ovat samalla tavalla monikkojen lukumääriä, mutta ne eroavat siten, että ykkösluvuissa merkki voi kuulua useampaan monikkoon. Merkki (esim ‘2’) voi kuulua kolmosmonikkoon (esim ‘222’), kakkosmonikkoon (’22’) ja ykkösmonikkoon. Toisin sanoen kolmosmonikko (‘222’) sisältää kolme ykkösmonikkoa (‘2′) (singles), kaksi kakkosmonikkoa (’22’) (twins) ja yhden kolmosmonikon (‘222’) (triplets). Kakkosvaihtoehdossa merkki voi kuulua vain yhteen monikkoon.
“m1expect” ja “m2expect”, tilastolliset rivimäärät, lähenevät havaittuja rivimääriä “multiple1” ja “multiple2” materiaalin kasvaessa, ja osan erotuksista “diff” pitäisi olla negatiivisia ja osan positiivisia. Kaavat tilastollisille määrille ovat tietysti ohjelmassa, mielestäni ne ovat aika lähellä oikeita.
Huomaa, että tässä monikot voivat jatkua yli välilyönnin tai rivinvaihdon.
$ ./newressu --single --lineno -x -s8 -w8 -l1000 | ./cstat
ctrl LF:1000
chars 0:4052, 1:3863, 2:4019, 3:3964, 4:4021, 5:4007, 6:4015, 7:4119, 8:3955, 9:3877, a:3929, b:4114, c:4061, d:3987, e:4060, f:3957, total:64000
cdiff 0:-52, 1:137, 2:-19, 3:36, 4:-21, 5:-7, 6:-15, 7:-119, 8:45, 9:123, a:71, b:-114, c:-61, d:13, e:-60, f:43
cstats min:3863, max:4119, total:64000, count:16, average:4000, characters:64000, utf8first:0, utf8other:0, ascii:64000, ctrl:1000, entropy:3.999767
multiple1 singles:64000, twins:3944, triplets:227, quadruplets:12, total:68183
m1expect singles:64000, twins:4000, triplets:250, quadruplets:15, total:68265
m1diff singles:0, twins:56, triplets:23, quadruplets:3, total:82
multiple2 singles:56339, twins:3502, triplets:203, quadruplets:12, total:64000
m2expect singles:56250, twins:3515, triplets:219, quadruplets:13, total:63989
m2diff singles:-89, twins:13, triplets:16, quadruplets:1, total:-59
monobit 0:127768, 1:128232, total:256000
poker2 0:31987, 1:31896, 2:31898, 3:32219, total:128000
Seuraavassa ajossa satunnaislukujen välissä on välilyöntejä (–space), jolloin ctrl riville tulostuu myös välilyönnit. Välilyönnit eivät kuitenkaan vaikuta tuloksiin:
$ ./newressu --single --lineno -x -s8 -w8 -l1000 --space| ./cstat
ctrl LF:1000, space:7000
chars 0:4006, 1:3882, 2:3965, 3:3955, 4:3879, 5:4093, 6:4029, 7:3915, 8:4062, 9:4095, a:4105, b:3991, c:4023, d:4018, e:4014, f:3968, total:64000
cdiff 0:-6, 1:118, 2:35, 3:45, 4:121, 5:-93, 6:-29, 7:85, 8:-62, 9:-95, a:-105, b:9, c:-23, d:-18, e:-14, f:32
cstats min:3879, max:4105, total:64000, count:16, average:4000, characters:64000, utf8first:0, utf8other:0, ascii:71000, ctrl:1000, entropy:3.999789
multiple1 singles:64000, twins:3953, triplets:234, quadruplets:11, total:68198
m1expect singles:64000, twins:4000, triplets:250, quadruplets:15, total:68265
m1diff singles:0, twins:47, triplets:16, quadruplets:4, total:67
multiple2 singles:56328, twins:3496, triplets:212, quadruplets:11, total:64000
m2expect singles:56250, twins:3515, triplets:219, quadruplets:13, total:63989
m2diff singles:-78, twins:19, triplets:7, quadruplets:2, total:-50
monobit 0:127926, 1:128074, total:256000
poker2 0:31778, 1:32004, 2:32366, 3:31852, total:128000
Jos ajosta puuttuu –lineno parametri, eli rivinumero tulostetaan, rivinumero kenttä vääristää raporttia, tässä esimerkiksi suuri nollien määrä. Lisäksi ctrl-riville tulevat rivinumeron ja satunnaismerkkien väliset välilyönnit:
./newressu --single -x -s8 -w8 -l1000| ./cstat
ctrl LF:1000, space:1000
chars 0:6103, 1:4307, 2:4289, 3:4325, 4:4235, 5:4329, 6:4237, 7:4327, 8:4362, 9:4276, a:3972, b:4115, c:3985, d:4019, e:4023, f:4096, total:69000
cdiff 0:-1791, 1:5, 2:23, 3:-13, 4:77, 5:-17, 6:75, 7:-15, 8:-50, 9:36, a:340, b:197, c:327, d:293, e:289, f:216
cstats min:3972, max:6103, total:69000, count:16, average:4312.500000, characters:69000, utf8first:0, utf8other:0, ascii:70000, ctrl:1000, entropy:3.991895
multiple1 singles:69000, twins:5364, triplets:405, quadruplets:39, quintuplets:3, total:74811
m1expect singles:69000, twins:4312, triplets:269, quadruplets:16, quintuplets:1, total:73598
m1diff singles:0, twins:-1052, triplets:-136, quadruplets:-23, quintuplets:-2, total:-1213
multiple2 singles:58677, twins:4593, triplets:330, quadruplets:33, quintuplets:3, total:69000
m2expect singles:60644, twins:3790, triplets:236, quadruplets:14, quintuplets:0, total:68988
m2diff singles:1967, twins:-803, triplets:-94, quadruplets:-19, quintuplets:-3, total:1048
monobit 0:142723, 1:133277, total:276000
poker2 0:37709, 1:34059, 2:33246, 3:32986, total:138000
Binääristen satunnaislukujen (-b) tilastossa entropy (tässä satunnaisbittiä per merkki) lähenee ykkostä: Lisäksi chars rivillä on vain ‘0’ ja ‘1’ ja count = 2. Satunnaismateriaali koostuu nollista ja ykkösistä.
./newressu --single -b -s8 -w8 -l10000 --lineno | ./cstat
ctrl LF:10000
chars 0:319983, 1:320017, total:640000
cdiff 0:17, 1:-17
cstats min:319983, max:320017, total:640000, count:2, average:320000, characters:640000, utf8first:0, utf8other:0, ascii:640000, ctrl:10000, entropy:1.000000
multiple1 singles:640000, twins:319593, triplets:159651, quadruplets:79760, quintuplets:39885, sixlets:19962, 7lets:10030, 8lets:5021, 9lets:2520, 10lets:1300, 11lets:669, 12lets:340, 13lets:167, 14lets:76, 15lets:37, 16lets:14, 17lets:3, 18lets:1, total:1279029
m1expect singles:640000, twins:320000, triplets:160000, quadruplets:80000, quintuplets:40000, sixlets:20000, 7lets:10000, 8lets:5000, 9lets:2500, 10lets:1250, 11lets:625, 12lets:312, 13lets:156, 14lets:78, 15lets:39, 16lets:19, 17lets:9, 18lets:4, 19lets:2, 20lets:1, total:1279995
m1diff singles:0, twins:407, triplets:349, quadruplets:240, quintuplets:115, sixlets:38, 7lets:-30, 8lets:-21, 9lets:-20, 10lets:-50, 11lets:-44, 12lets:-28, 13lets:-11, 14lets:2, 15lets:2, 16lets:5, 17lets:6, 18lets:3, 19lets:2, 20lets:1, total:966
multiple2 singles:160465, twins:80051, triplets:40016, quadruplets:19952, quintuplets:9991, sixlets:4923, 7lets:2508, 8lets:1281, 9lets:589, 10lets:302, 11lets:156, 12lets:82, 13lets:52, 14lets:16, 15lets:12, 16lets:9, 17lets:1, 18lets:1, total:640000
m2expect singles:160000, twins:80000, triplets:40000, quadruplets:20000, quintuplets:10000, sixlets:5000, 7lets:2500, 8lets:1250, 9lets:625, 10lets:312, 11lets:156, 12lets:78, 13lets:39, 14lets:19, 15lets:9, 16lets:4, 17lets:2, 18lets:1, total:639921
m2diff singles:-465, twins:-51, triplets:-16, quadruplets:48, quintuplets:9, sixlets:77, 7lets:-8, 8lets:-31, 9lets:36, 10lets:10, 11lets:0, 12lets:-4, 13lets:-13, 14lets:3, 15lets:-3, 16lets:-5, 17lets:1, 18lets:0, total:-412
Oktaalisten satunnaislukujen entropy lähenee kolmosta: tietenkin chars rivillä on numerot ‘0’:sta ‘7’:aan ja count on 8. Materiaali koostuu merkeistä ‘0’:sta ‘7’:ään.
$ ./newressu --single -o -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:7997975, 1:8000644, 2:7998781, 3:7998010, 4:8005153, 5:7997054, 6:8002654, 7:7999729, total:64000000
cdiff 0:2025, 1:-644, 2:1219, 3:1990, 4:-5153, 5:2946, 6:-2654, 7:271
cstats min:7997054, max:8005153, total:64000000, count:8, average:8000000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:3.000000
multiple1 singles:64000000, twins:7999189, triplets:998260, quadruplets:124870, quintuplets:15650, sixlets:2015, 7lets:239, 8lets:41, 9lets:8, 10lets:2, total:73140274
m1expect singles:64000000, twins:8000000, triplets:1000000, quadruplets:125000, quintuplets:15625, sixlets:1953, 7lets:244, 8lets:30, 9lets:3, 10lets:0, total:73142855
m1diff singles:0, twins:811, triplets:1740, quadruplets:130, quintuplets:-25, sixlets:-62, 7lets:5, 8lets:-11, 9lets:-5, 10lets:-2, total:2581
multiple2 singles:48999882, twins:6127539, triplets:764170, quadruplets:95585, quintuplets:11859, sixlets:1578, 7lets:165, 8lets:27, 9lets:4, 10lets:2, total:64000000
m2expect singles:49000000, twins:6125000, triplets:765625, quadruplets:95703, quintuplets:11962, sixlets:1495, 7lets:186, 8lets:23, 9lets:2, 10lets:0, total:63999971
m2diff singles:118, twins:-2539, triplets:1455, quadruplets:118, quintuplets:103, sixlets:-83, 7lets:21, 8lets:-4, 9lets:-2, 10lets:-2, total:-815
Desimaalilukujen entropy lähenee 3.321928:aa (desimaalimerkki koostuu biteistä 1, 2 ja 4 ja osa bitistä 8) ja chars rivin numerot ovat välillä 0-9:
$ ./newressu --single -d -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:6396007, 1:6400047, 2:6402915, 3:6401529, 4:6404519, 5:6397437, 6:6398466, 7:6397870, 8:6397703, 9:6403507, total:64000000
cdiff 0:3993, 1:-47, 2:-2915, 3:-1529, 4:-4519, 5:2563, 6:1534, 7:2130, 8:2297, 9:-3507
cstats min:6396007, max:6404519, total:64000000, count:10, average:6400000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:3.321928
multiple1 singles:64000000, twins:6404055, triplets:640874, quadruplets:64161, quintuplets:6447, sixlets:625, 7lets:54, 8lets:1, total:71116217
m1expect singles:64000000, twins:6400000, triplets:640000, quadruplets:64000, quintuplets:6400, sixlets:640, 7lets:64, 8lets:6, total:71111110
m1diff singles:0, twins:-4055, triplets:-874, quadruplets:-161, quintuplets:-47, sixlets:15, 7lets:10, 8lets:5, total:-5107
multiple2 singles:51832764, twins:5186468, triplets:518999, quadruplets:51892, quintuplets:5251, sixlets:518, 7lets:52, 8lets:1, total:64000000
m2expect singles:51840000, twins:5184000, triplets:518400, quadruplets:51840, quintuplets:5184, sixlets:518, 7lets:51, 8lets:5, total:63999985
m2diff singles:7236, twins:-2468, triplets:-599, quadruplets:-52, quintuplets:-67, sixlets:0, 7lets:-1, 8lets:4, total:4053
Vielä uudestaan heksadesimaali, jossa entropy lähenee nelosta ja chars rivillä ja materiaalissa on heksanumerot(ita) ‘0’ – ‘f’:
$ ./newressu --single -x -s8 -w8 -l1000000 --lineno | ./cstat
ctrl LF:1000000
chars 0:4002235, 1:4000771, 2:3999619, 3:4000456, 4:3995918, 5:4000856, 6:4003044, 7:3999699, 8:3998536, 9:4000183, a:4001238, b:3998398, c:4000312, d:4001384, e:3999341, f:3998010, total:64000000
cdiff 0:-2235, 1:-771, 2:381, 3:-456, 4:4082, 5:-856, 6:-3044, 7:301, 8:1464, 9:-183, a:-1238, b:1602, c:-312, d:-1384, e:659, f:1990
cstats min:3995918, max:4003044, total:64000000, count:16, average:4000000, characters:64000000, utf8first:0, utf8other:0, ascii:64000000, ctrl:1000000, entropy:4.000000
multiple1 singles:64000000, twins:4001492, triplets:249591, quadruplets:15572, quintuplets:959, sixlets:62, 7lets:3, total:68267679
m1expect singles:64000000, twins:4000000, triplets:250000, quadruplets:15625, quintuplets:976, sixlets:61, 7lets:3, total:68266665
m1diff singles:0, twins:-1492, triplets:409, quadruplets:53, quintuplets:17, sixlets:-1, 7lets:0, total:-1014
multiple2 singles:56246607, twins:3517882, triplets:219406, quadruplets:13716, quintuplets:838, sixlets:56, 7lets:3, total:64000000
m2expect singles:56250000, twins:3515625, triplets:219726, quadruplets:13732, quintuplets:858, sixlets:53, 7lets:3, total:63999985
m2diff singles:3393, twins:-2257, triplets:320, quadruplets:16, quintuplets:20, sixlets:-3, 7lets:0, total:1489
monobit 0:128004472, 1:127995528, total:256000000
poker2 0:32000082, 1:32002711, 2:32001597, 3:31995610, total:128000000
cstat sisältää –help parametrin, joka kertoo komennon kirjoitusasun: cstat tulostaa komennon kirjoitusasun myös, jos sen parametri on väärin kirjoitettu. Jos halutaan lukea stdin (oletus) tiedostoa, parametriksi voi laittaa pelkän miinusmerkin (‘-‘). Jos parametrin edellä ei ole miinusmerkkiä, se katsotaan tiedostoksi. Vain viimeinen tiedoston nimi katsotaan.
$ ./cstat --help
./cstat [-]/[filename] [--verbose] [--help] [--all] [--ctrl] [--chars] [--cdiff] [--cstats] [--multiple1] [--m1expect] [--m1diff] [--multiple2] [--m2expect] [--m2diff] [--monobit] [--poker2]
–verbose kytkimellä voit tulostaa sekä tilastot että datan samalle sivulle:
$ ./newressu --lineno| ./cstat --verbose
4351803043136516056288856573724573262070985983534430590448419963596642
3456174389372153988786921278046617965667514985321851793216687887157932
1902255648112995719416628601644736570744967017380038762966609076622811
1281509743204688618205185045706022024422762995194550322958445377790472
3784413827708402970490417813213564250017238858771981034500700507530704
9055168367119912878629899714626335171522022670864908592668742446542918
0191677706669306365217622375825024795059935366760530044265382851611997
3416723466929675866231727509034129352233311007024186331113208959024698
2335185850752231213099177908357629831877249743371602035678155510036859
7946039351097931583962995307389998234628068269367172182854699685499923
ctrl LF:10
chars 0:69, 1:69, 2:76, 3:70, 4:56, 5:70, 6:77, 7:73, 8:66, 9:74, total:700
cdiff 0:1, 1:1, 2:-6, 3:0, 4:14, 5:0, 6:-7, 7:-3, 8:4, 9:-4, total:0
cstats min:56, max:77, total:700, count:10, average:70, characters:700, utf8first:0, utf8other:0, ascii:700, ctrl:10, entropy:3.316983
multiple1 singles:700, twins:87, triplets:11, total:798
m1expect singles:700, twins:70, triplets:7, total:777
m1diff singles:0, twins:-17, triplets:-4, total:-21
multiple2 singles:537, twins:65, triplets:11, total:700
m2expect singles:567, twins:56, triplets:5, total:694
m2diff singles:30, twins:-9, triplets:-6, total:15
m2dist singles:1, twins:10, triplets:63, total:700
Oletuksena kaikki tulostettavat tilastorivit tulostetaan. –all kääntää kaikki rivit (ei tulosteta/tulostetaan). Jos haluat tulostaa pelkästään –chars rivin, se voidaan tehdä näin:
$ ./newressu --single -x -s8 -w8 -l1000 --lineno | ./cstat --all --chars
chars 0:4072, 1:3952, 2:3970, 3:4189, 4:4014, 5:3898, 6:4055, 7:3969, 8:3934, 9:4000, a:4089, b:3957, c:4013, d:3944, e:3971, f:3973, total:64000
Seuraavassa ajossa newressua ajetaan useita kertoja, ja tulostetaan raportti ensimmäisen merkin satunnaisuudesta:
$ cat newressuruns.sh
#!/bin/bash
echo "Statistics for first character on multiple runs of newressu: (./newressu --single --bin $@ -w1 -s1 --lineno -l1)"
rm -f newressuruns.rnd; for ((c=0;c<10000;c++)); do ./newressu --single --bin $@ -w1 -s1 --lineno -l1 >>newressuruns.rnd; done; cat newressuruns.rnd | ./newressutest7; rm -f newressuruns.rnd
$ ./newressuruns.sh
Statistics for first character on multiple runs of newressu: (./newressu --single --bin -w1 -s1 --lineno -l1)
ctrl LF:10000
chars 0:5046, 1:4954, total:10000, min:4954, max:5046
cdiff 0:-46, 1:46, total:0, min:-46, max:46
cstats min:4954, max:5046, total:10000, count:2, average:5000, characters:10000, utf8first:0, utf8other:0, ascii:10000, ctrl:10000, entropy:0.999939
multiple1 singles:10000, twins:4950, triplets:2457, quadruplets:1236, quintuplets:608, sixlets:308, 7lets:150, 8lets:71, 9lets:36, 10lets:18, 11lets:7, 12lets:1, total:19842
m1expect singles:10000, twins:5000, triplets:2500, quadruplets:1250, quintuplets:625, sixlets:312, 7lets:156, 8lets:78, 9lets:39, 10lets:19, 11lets:9, 12lets:4, 13lets:2, 14lets:1, total:19995
m1diff singles:0, twins:50, triplets:43, quadruplets:14, quintuplets:17, sixlets:4, 7lets:6, 8lets:7, 9lets:3, 10lets:1, 11lets:2, 12lets:3, 13lets:2, 14lets:1, total:153, min:0, max:50
multiple2 singles:2557, twins:1272, triplets:593, quadruplets:328, quintuplets:142, sixlets:79, 7lets:44, 8lets:17, 9lets:7, 10lets:5, 11lets:5, 12lets:1, total:10000
m2expect singles:2500, twins:1250, triplets:625, quadruplets:312, quintuplets:156, sixlets:78, 7lets:39, 8lets:19, 9lets:9, 10lets:4, 11lets:2, 12lets:1, total:9951
m2diff singles:-57, twins:-22, triplets:32, quadruplets:-16, quintuplets:14, sixlets:-1, 7lets:-5, 8lets:2, 9lets:2, 10lets:-1, 11lets:-3, 12lets:0, total:-55, min:-57, max:32
m2dist singles:3, twins:7, triplets:16, quadruplets:30, quintuplets:70, sixlets:126, 7lets:227, 8lets:588, 9lets:1428, 10lets:2000, 11lets:2000, 12lets:10000, total:10000
$
Raportin rivit puhuvat sen puolesta että tilastot toteutuvat myös eri ajot ylittävissä raporteissa. Tässä raportti jakautuu puoliksi nolliin ja ykkösiin, ja se tietysti johtaa siihen että myös datan monikot ovat tilaston mukaisia. Jos meillä on datana nolla, todennäköisyys on 50% että sen perään tulee toinen nolla, ja kahden nollan perään tulee nolla 50% tapauksista. Ressuhan satunnaistaa koko puskurin ennen ensimmäisen merkin palauttamista.
Toinen ohjelma jonka kirjoitin: tässä ideana on etsiä satunnaisjonoista tuplia. Tuplien maksimipituuden ja määrän pitäisi korreloida tiedoston tietueiden määrän kanssa. Esimerkiksi 64 merkkiä pitkiä tuplia ei pitäisi tulla, niiden todennäköisyys on niin pieni. –stat kytkimellä on aloiteltu tilaston laskemista, se on kuitenkin kesken. Ohjelma on nimetty uudelleen newressutest11:ksi ja komentoriviparametrejä on muutettu selkeämmäksi. Toki ohjelman mallikomennot jatkussa tarvitsevat uudet parametrit.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
unsigned char *procname;
static unsigned char *programname = "newressutest11/newressutest version 0.5 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 210
#define BINSIZE 10 // bytes per line
#define LINESIZE 21 // BINSIZE * 2 + 1
#define LINES 10
#define BLOCKSIZE 1024
#define GENT_SIZE 128
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
extern int verbose;
#define INPUT_RESSU 0
#define INPUT_PSEUDORESSU 1
#define INPUT_FASTRESSU 2
#define INPUT_SINGLERESSU 3
#define INPUT_RDRAND 4
#define INPUT_RDSEED 5
#define INPUT_URANDOM 6
#define INPUT_RANDOM 7
#define USE_RDRAND 2
#define USE_RDSEED 2
static unsigned char urandomfilename[128] = "/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128] = "/dev/random";
#endif
static void readfile_xor(int size,
unsigned char *buffer,
unsigned char *filename)
{
int c, n, n2;
unsigned char temp[64];
FILE *fp1;
if((fp1 = fopen(filename, "rb")) != NULL) {
while(size != 0) {
n = (size < sizeof(temp)) ? size : sizeof(temp);
n2 = fread(temp, 1, n, fp1);
for(c = 0; c < n2; c++)
buffer[c] ^= temp[c];
size -= n2;
buffer += n2;
}
fclose(fp1);
}
}
int input = 0;
void ressu_genbytes(int size, unsigned char *buffer);
void pseudoressu_bytes(int size, unsigned char *buffer);
void ressu_genbytes_fast(int size, unsigned char *buffer);
void ressu_genbytes_single(int size, unsigned char *buffer);
#if defined INPUT_RDRAND || defined INPUT_RDSEED
#include "fort.h"
#endif
int ressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(gent), gent);
#ifdef SHA256
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_FASTRESSU) // ressu_fast
ressu_genbytes_fast(sizeof(gent), gent);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(gent), gent);
#ifdef INPUT_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef INPUT_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_URANDOM) // urandom
readfile_xor(sizeof(gent), gent, urandomfilename);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
readfile_xor(sizeof(gent), gent, randomfilename);
#endif
else {
fprintf(stderr,"%s: mode '%d' not available\n",
procname, input);
exit(2);
}
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long ressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | ressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
#include <string.h>
#include <stdlib.h>
//#define KILO 1000
#define KILO 1024
int stat = 0;
#ifdef NOTUSED
void fprintfdouble(FILE *fp1, unsigned char *text, double number)
{
int c;
unsigned char buffer[64];
sprintf(buffer,"%f", number);
// remove ending zeroes
for(c = strlen(buffer) - 1; c > 0 && buffer[c] == '0'; c--)
buffer[c] = '\0';
// remove ending dot
if(buffer[strlen(buffer) - 1] == '.')
buffer[strlen(buffer) - 1] = '\0';
fprintf(fp1, "%s", buffer);
fprintf(fp1, "%s", text);
}
#endif
#ifdef KOK
double fact(long n)
{
unsigned long l;
double result = 1;
for(l = 1; l <= n; l++) {
result = result * l;
}
return(result);
}
#endif
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
#define DEBUG45 2
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG45
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x", final[c]);
}
}
#endif
#define DEBUG79 2
extern unsigned int fixedclockchainlength;
int clockmode; // 0 = normal, 1 = fixed
void ressu_setclock(int);
int main(int argc, char *argv[])
{
int c, percentageline = 1, prevpros, pros, quiet = 0, help = 0;
int filesize_set = 0, binsize_set = 0, linesize_set = 0, lines_set = 0;
unsigned long long filesize = FILESIZE, lines = LINES;
unsigned int binsize = BINSIZE, linesize = LINESIZE;
int stdoutflag = 0;
unsigned long long plines = 0;
unsigned char *buffer, filename[128] = "";
FILE *fp1;
procname = argv[0];
#ifdef KOK
long l, l2;
for(long l = 1; l < 10; l++) {
fprintf(stderr,"c:%ld", l);
l2 = fact(l);
fprintf(stderr,", result:%ld", l2);
fprintf(stderr,"\n");
}
#endif
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) { // last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(strncmp("-", argv[c], 1)) { // filename not expected
fprintf(stderr,"%s: filename not expected", procname);
fprintf(stderr,", parameter:%s", argv[c]);
fprintf(stderr,"\n");
exit(1);
}
if(!strncmp("-", argv[c], 1)) { // option starting with hyphen
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
stdoutflag = 0;
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
filename[0] = '\0';
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--verbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--quiet", argv[c])) {
quiet = !quiet;
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--linesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
linesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
linesize = getlonglong(argv[c + 1]);
c++;
}
linesize_set = 1;
} else if(!strncmp("--lines", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
lines = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
lines = getlonglong(argv[c + 1]);
c++;
}
lines_set = 1;
} else if(!strncmp("--binsize", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
binsize = getlonglong(argv[c] + 9);
} else if(c + 1 < argc) {
binsize = getlonglong(argv[c + 1]);
c++;
}
binsize_set = 1;
} else if(!strcmp("--stat", argv[c])) {
stat = !stat;
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
} else if(!strcmp("--pseudoressu", argv[c])) {
input = INPUT_PSEUDORESSU;
} else if(!strcmp("--fastressu", argv[c]) ||
!strcmp("--fast", argv[c])) {
input = INPUT_FASTRESSU;
} else if(!strcmp("--singleressu", argv[c]) ||
!strcmp("--single", argv[c])) {
input = INPUT_SINGLERESSU;
#ifdef INPUT_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
#endif
#ifdef INPUT_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
#endif
} else if(!strcmp("--urandom", argv[c])) {
input = INPUT_URANDOM;
#ifdef USE_RANDOM
} else if(!strcmp("--random", argv[c])) {
input = INPUT_RANDOM;
#endif
} else if(!strncmp("--fixedclock", argv[c], 12)) {
if(*(argv[c] + 12)!='\0' && atoi(argv[c] + 12) > 1) {
fixedclockchainlength = atoi(argv[c] + 12);
clockmode = 1;
} else if(c + 1 < argc && atoi(argv[c + 1]) > 1) {
fixedclockchainlength = atoi(argv[c + 1]);
clockmode = 1;
c++;
} else {
clockmode = !clockmode;
}
if(fixedclockchainlength < 5 ||
fixedclockchainlength > 255)
fixedclockchainlength = 50;
ressu_setclock(clockmode);
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
}
if(!linesize_set)
linesize = binsize * 2 + 1;
else if(!binsize_set)
binsize = (linesize - 1) / 2;
if(!filesize_set)
filesize = lines * linesize;
else if(!lines_set) {
lines = (filesize + linesize - 1) / linesize; // round up
filesize = lines * linesize;
} else if(!linesize_set) {
linesize = (filesize + lines - 1) / lines; // round up
if((linesize & 1) == 0) // up to x * 2 + 1
linesize++;
binsize = (linesize - 1) / 2;
filesize = lines * linesize;
}
#define aEXFAT_FIX 2
#ifdef EXFAT_FIX
if(linesize >= KILO * KILO) { // max linesize 1m (exfat)
linesize = KILO * KILO - 1;
binsize = (linesize - 1) / 2;
lines = (filesize + linesize - 1) / linesize;
filesize = lines * linesize;
}
#endif
if(linesize != binsize * 2 + 1 ||
linesize < 3 || binsize < 1) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize != lines * linesize ||
lines < 1 || linesize < 3) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / lines != linesize) { // test overflow too
fflush(stdout);
fprintf(stderr,"%s: parameter overflow", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr,"\n\t[-o filename]");
//fprintf(stderr," [--stdout]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr,"\n\t[--lines base-number-multiplier]");
fprintf(stderr," [--linesize base-number-multiplier]");
fprintf(stderr,"\n\t[--binsize base-number-multiplier]");
fprintf(stderr,"\n\t[--ressu]");
fprintf(stderr," [--pseudoressu]");
fprintf(stderr," [--fastressu]");
fprintf(stderr," [--singleressu]");
#ifdef INPUT_RDRAND
fprintf(stderr," [--rdrand]");
#endif
#ifdef INPUT_RDSEED
fprintf(stderr," [--rdseed]");
#endif
fprintf(stderr," [--urandom]");
#ifdef USE_RANDOM
fprintf(stderr," [--random]");
#endif
fprintf(stderr," [--fixedclock]");
fprintf(stderr,"\n\t[--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--stat]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--quiet]");
fprintf(stderr,"\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\t$ %s --single --filesize1g\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --lines1m\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --linesize25\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --binsize12\n", procname);
exit(1);
} // end of if(help)
#ifdef DEBUG79
// print filesize parameters
fprintf(stderr,"input:%d", input);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest11.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
percentageline = 0;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-\n");
else
fprintf(stderr,"filename:%s\n", filename);
if(stdoutflag == 1) {
fp1 = stdout;
} else if((fp1 = fopen(filename, "w")) == NULL) {
fprintf(stderr,"%s: cannot open file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
if(stat) {
}
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if((buffer = malloc(linesize + 1)) == NULL) { // space for '\0' too
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
memset(buffer, 0, linesize + 1);
#ifdef EXFAT_FIX
int mbinlines = (KILO * KILO) / linesize;
if(mbinlines == 0)
mbinlines = 1;
fprintf(stderr,"mbinlines:%d\n", mbinlines);
#endif
prevpros = -1;
// fill first hex string
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", (unsigned int)ressu_gen_limit(256));
buffer[linesize - 1] = '\n';
buffer[linesize] = '\0';
for(;;) {
// bug! this program produces fixed length records
// and for some reason records end up being variable
// length records when they reach my removable usb
// drive (exfat). I am hoping this is silly one.
// next if() checks record length, and prints stars for
// variable length records. Havent seen stars yet...
// seems that fflush(), sync() fixes the problem.
if(linesize != strlen(buffer)) {
fprintf(stderr,"*");
fflush(stderr);
}
#ifdef FILE_HASH
HashUpdate(&hash, buffer, linesize); // calculate hash
#endif
if(fwrite(buffer, 1, linesize, fp1) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef EXFAT_FIX
if(plines > 0 && plines % mbinlines == 0) { // fflush and sync (EXFAT)
fflush(stdout);
sync();
}
#endif
plines++;
if(plines >= lines)
break;
// remove first byte
memmove(buffer, buffer + 2, linesize - 1);
// add new last byte
sprintf(buffer + linesize - 3, "%02x", (unsigned int)ressu_gen_limit(256));
buffer[linesize - 1] = '\n';
buffer[linesize] = '\0';
if(percentageline) { // && !quiet) {
pros = (int)((double) plines / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
}
}
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
if(percentageline) { // && !quiet) {
fprintf(stderr,"\rDone:100.0%% \n");
}
#ifdef EXFAT_FIX
fflush(stdout); // fflush and sync (EXFAT)
sync();
#endif
if(!stdoutflag)
fclose(fp1);
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n", hashstring);
fclose(fp1);
}
} // end of if(filename[0] != '\0'
fprintf(stderr,", sha256:%s\n", hashstring);
if(!stdoutflag) {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
free(buffer);
return(0);
}
Ohjelma tulostaa seuraavanlaisen raportin: raportin voi kirjoittaa suurelle kovalevylle, sortata ja tulostaa “tuplatietueet” uniq –check-chars=x optiolla. Lisää -b toiminnolla riville tulostettavia heksamerkkejä, ja -l optiolla rivejä sopivasti: seuraavassa rivillä on 30 merkkiä ja rivejä on 30. Katso tulostettavan tiedoston koko input: riviltä. Tässä 1030 merkkiä eli ~1 kb.
$ ./newressutest -b30 -l30
input:0, lines:30(0x1e), bytes:30(0x1e), total:1830b(0Tb,0Gb,0Mb,1Kb)
a4721b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f9
721b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f938
1b581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804
581d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d8
1d93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88a
93beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad8
beb37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f
b37b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4f
7b3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc2
3de11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258
e11d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4
1d86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9
86064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c901
064be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b
4be32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07
e32c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e1
2c14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114
14ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4
ffecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e495
ecee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d
ee00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d69
00b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947
b14e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1
4e8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd
8abfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52
bfa27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca
a27b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca66
7b63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b
63f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b0a
f93804d88ad87f4fc258c4c9017b07e114e4951d6947c1cd52ca662b0a36
$
$ ./newressutest
input:0, lines:10(0xa), bytes:16(0x10), total:330b(0Tb,0Gb,0Mb,0Kb)
c80275eea3c4485e51afafaef99ed554
0275eea3c4485e51afafaef99ed554b1
75eea3c4485e51afafaef99ed554b16f
eea3c4485e51afafaef99ed554b16fdc
a3c4485e51afafaef99ed554b16fdc12
c4485e51afafaef99ed554b16fdc12ec
485e51afafaef99ed554b16fdc12ecda
5e51afafaef99ed554b16fdc12ecda9f
51afafaef99ed554b16fdc12ecda9f3d
afafaef99ed554b16fdc12ecda9f3d3e
Pieni bugivälike: Edellinen ohjelma tuottaa kiinteän mittaisia tietueita, mutta jostain syystä tietueen pituudet vaihtelevat neljä teraisella usb levylläni. Siksi tietueen pituuden tarkistava iffi edellisessä ohjelmassa. Mielestäni ongelman ei pitäisi olla ohjelmassa.
Pituuden tarkistusohjelma, joilla yritin etsiä ongelmapaikkaa. Tässä ohjelma, jolla voi tarkistaa inputin tietueiden pituudet:
#include <stdio.h>
#include <string.h>
#define BUFLEN 1024
void main(int argc, unsigned char *argv[])
{
unsigned long count;
unsigned char buffer[BUFLEN];
unsigned int inputlen = -1;
count = 0;
while(fgets(buffer, BUFLEN, stdin)) {
if(inputlen == -1) {
inputlen = strlen(buffer);
fprintf(stdout,"line length: %d\n",inputlen);
fflush(stdout);
} else if(inputlen != strlen(buffer)) {
fprintf(stdout," %lu",count);
}
count += strlen(buffer);
}
fprintf(stdout,"\n");
fflush(stdout);
}
Esimerkkejä tarkistusohjelman ajosta: ensimmäinen esimerkki
$ ./newressutest --pseudoressu -b20 -l1000 | ./newressutest6
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
line length: 41
Toinen esimerkki, joka tarkastaa sortin:
$ ./newressutest --pseudoressu -b20 -l1000 | sort | ./newressutest6
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
line length: 41
Kolmas. jossa tarkistetaan tehty tiedosto:
$ ./newressutest --pseudoressu -b20 -l1000 | sort > newressutest.deb
input:1, lines:1000(0x3e8), bytes:20(0x14), total:41000b(0Tb,0Gb,0Mb,41Kb)
$ cat newressutest.deb | ./newressutest6
line length: 41
Bugilisäke jatkuu: Yksi löytämäni bugikohta:
365827042:d717d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82\
e556be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3\
b94a38f3bc80e1fc97da6571
365827043:17d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82e5\
56be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3b9\
4a38f3bc80e1fc97da65712f
365827044:d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff89859fad697720c494f8cb33189cab70d7dd4fc648f4f90dbfb9f56f82e556\
be36aa2928151f3957d5b859dc8930b954d042b7479d24d17300c88cdd3652a746a0f22339686ab42582bd661d28b28a0664bb9333964e271c7d3b94a\
38f3bc80e1fc97da65712fd2
365848983:8e4431f3089c25af75df2677b0f511e1a690be147c4e01d766825d0220701b2a796cf75a13ae23a483cb1477968bca63ba43d2d3f8e555d\
a7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792c55bb3d25f0f8f334ff8
365848984:d5103f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f4371\
46981e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f77\
92c55bb3d25f0f8f334ff898
365848985:103f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f437146\
981e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792\
c55bb3d25f0f8f334ff89859
365848986:3f7429fc7e930327d21a283ced3798d280005fcf34e29ab15d3e50259d137ab5cc3fab3ebc4bb3fbfcc5ea90cdb3310f961de4f43714698\
1e282292099c137e555da7e742164c3e0495b3520359ca985c8908e5618d24e9a22b15febb22f7cff226ed717d9ccb5635fbf20a67feac0113f7792c5\
5bb3d25f0f8f334ff89859fa
Vielä esimerkki tuplaohjelman ajosta: voit esimerkiksi kasvatella rivimäärää -l1000 kytkimen numeroa kasvattamalla, ja tulostettavien tuplien pituutta –check-chars=6 numeroa kasvattamalla. Varmistathan että -b32 on riittävän suuri, Tässä on löytynyt 2 tuplaa, 07-alkuinen ja 19-alkuinen. Tietenkin tuplat ovat 6 merkin pituisia. Maksimituplien pituuden ja määrän pitäisi korreloida rivimäärän kanssa. Tässä haittana on että satunnaisrivit eivät jää talteen, eli niille ei voi tehdä jatkotutkimusta (esimerkiksi ajaa useampia uniq:ita samalle materiaalille). Voit tarkistaa myös että rivin lopussa (raportoidun tuplan jälkeen) ei ole liikaa lisää samanlaisia merkkejä, liian pitkä tupla olisi ongelma.
$ ./newressutest -b32 -l10000 | sort | uniq -D --check-chars=6
input:0, lines:10000(0x2710), bytes:32(0x20), total:650000b(0Tb,0Gb,0Mb,650Kb)
0764007efc362b5ddeaee81fe76561cae82728f988a70d3938eab5cc41b0e590
076400c3ad198728dc05d74862dbe2380696efc580f1f809c3eafa4c333d9ff5
1919f52e36204b0f2cb49ecd5a59b756fcb020db2c7dbf6d87005e8232c86f37
1919f5f0e0f85884ea321fb0692989e02a281e0bec91201d5e062f10c2f3bf2d
Tässä on ajettu newressutest11:sta exfat levyllä. Tässä versiossa on jo fflush ja sync kutsut. 256 gigainen tiedosto on ajettu onnistuneesti. Ajossa löytyi 4 tuplaa 32, 55, 77 ja 97 alkuiset. Kaikki tuplat ovat 16 pitkiä, eikä niissä ole samoja merkkejö 16 merkin jälkeen.
media$ ./newressutest11 --single --filesize256g | sort -T./temp/ | uniq -D --check-chars=16
string:'256g', base:10, multiplier:1073741824, prevll:256, ll:274877906944, totll:274877906944
input:3, lines:13089424141(~12G), binsize:10(10B), linesize:21(21B), filesize:274877906961(~256G)
filename:-
done:100.0%
./newressutest11: hashed file, sha256:f459507a66824e6e83b98d044c49bb39243bb320fb475158d9a6acedb8e34bcd
32630a8e6ddcc9406ba7
32630a8e6ddcc940be5d
5548db9879bbd10c5499
5548db9879bbd10c62c2
777432efb42ea3a89ca3
777432efb42ea3a8ce06
971fd08fa651e6980065
971fd08fa651e6985c9c
media$
Kolmas ohjelma tulostaa raportin, josta voi vertailla monikkojen eri merkkien esiintymistä. Chars rivi on kuten ennenkin yksittäisten eri merkkien esiintymät yhteensä. Chars rivillä on myös keskiarvo kokonaislukuna. Diff(eillä) rivillä on ero tilastolliseen määrään. m1digits singles rivillä on yksösten määrät (erikseen ‘0’, ‘1’, … ‘f’) tällä tulosteella (–hex). Vastaavasti m1digdiff rivillä on erot tilastoon. Erojen pitäisi olla sekä positiivisia että negatiivisia suhteellisen pieniä arvoja. dexp kentässä on odotettu määrä. Twins, triplets, quadruplets ja quintuplets rivejä luetaan samalla tavalla kun singles rivejä. Multiple1, m1exp, m1diff, multiple2, m2exp ja m2diff rivit ovat samankaltaisia kun edellisellä tulosteella.
$ ./newressu --lineno --space --hex -l10000 | ./newressutest8
ctrl LF:10000, space:130000
chars 0:35215, 1:34828, 2:34811, 3:34884, 4:34798, 5:35748, 6:35354, 7:34477, 8:35022, 9:34711, a:35015, b:34997, c:35401, d:34890, e:34756, f:35093, total:560000, count:16, average:35000, total:560000, min:34477, max:35748
cdiff 0:-215, 1:172, 2:189, 3:116, 4:202, 5:-748, 6:-354, 7:523, 8:-22, 9:289, a:-15, b:3, c:-401, d:110, e:244, f:-93, total:0, min:-748, max:523
multiple1 singles:560000, twins:35117, triplets:2606, quadruplets:328, quintuplets:39, sixlets:3, total:598093
m1exp singles:560000, twins:35000, triplets:2187, quadruplets:136, quintuplets:8, sixlets:0, total:597331
m1diff singles:0, twins:-117, triplets:-419, quadruplets:-192, quintuplets:-31, sixlets:-3, total:-762
m1digits singles 0:35215, 1:34828, 2:34811, 3:34884, 4:34798, 5:35748, 6:35354, 7:34477, 8:35022, 9:34711, a:35015, b:34997, c:35401, d:34890, e:34756, f:35093, dexp:35000, total:560000, texp:560000, min:34477, max:35748
m1digdiff singles 0:-215, 1:172, 2:189, 3:116, 4:202, 5:-748, 6:-354, 7:523, 8:-22, 9:289, a:-15, b:3, c:-401, d:110, e:244, f:-93, total:0, min:-748, max:523
m1digits twins 0:2219, 1:2285, 2:2248, 3:2223, 4:2128, 5:2185, 6:2244, 7:2049, 8:2216, 9:2263, a:2142, b:2137, c:2233, d:2226, e:2189, f:2130, dexp:2187, total:35117, texp:35000, min:2049, max:2285
m1digdiff twins 0:-32, 1:-98, 2:-61, 3:-36, 4:59, 5:2, 6:-57, 7:138, 8:-29, 9:-76, a:45, b:50, c:-46, d:-39, e:-2, f:57, total:-125, min:-98, max:138
m1digits triplets 0:167, 1:178, 2:180, 3:163, 4:128, 5:154, 6:153, 7:160, 8:161, 9:170, a:136, b:162, c:173, d:182, e:192, f:147, dexp:136, total:2606, texp:2187, min:128, max:192
m1digdiff triplets 0:-31, 1:-42, 2:-44, 3:-27, 4:8, 5:-18, 6:-17, 7:-24, 8:-25, 9:-34, a:0, b:-26, c:-37, d:-46, e:-56, f:-11, total:-430, min:-56, max:8
m1digits quadruplets 0:24, 1:27, 2:27, 3:21, 4:10, 5:13, 6:22, 7:19, 8:21, 9:17, a:20, b:15, c:23, d:24, e:29, f:16, dexp:8, total:328, texp:136, min:10, max:29
m1digdiff quadruplets 0:-16, 1:-19, 2:-19, 3:-13, 4:-2, 5:-5, 6:-14, 7:-11, 8:-13, 9:-9, a:-12, b:-7, c:-15, d:-16, e:-21, f:-8, total:-200, min:-21, max:-2
m1digits quintuplets 0:6, 1:3, 2:2, 3:2, 4:1, 6:4, 7:3, 8:3, a:4, c:3, d:2, e:5, f:1, dexp:0, total:39, texp:8, min:1, max:6
m1digdiff quintuplets 0:-6, 1:-3, 2:-2, 3:-2, 4:-1, 6:-4, 7:-3, 8:-3, a:-4, c:-3, d:-2, e:-5, f:-1, total:-39, min:-6, max:-1
m1digits sixlets 0:1, a:1, e:1, dexp:0, total:3, texp:0, min:1, max:1
m1digdiff sixlets 0:-1, a:-1, e:-1, total:-3, min:-1, max:-1
multiple2 singles:492372, twins:30233, triplets:1989, quadruplets:253, quintuplets:33, sixlets:3, total:560000
m2exp singles:492187, twins:30761, triplets:1922, quadruplets:120, quintuplets:7, sixlets:0, total:559990
m2diff singles:-185, twins:528, triplets:-67, quadruplets:-133, quintuplets:-26, sixlets:-3, total:-10
m2digits singles 0:30944, 1:30436, 2:30495, 3:30601, 4:30670, 5:31532, 6:31019, 7:30539, 8:30751, 9:30355, a:30867, b:30885, c:31108, d:30620, e:30570, f:30980, dexp:30761, total:492372, texp:492187, min:30355, max:31532
m2digdiff singles 0:-183, 1:325, 2:266, 3:160, 4:91, 5:-771, 6:-258, 7:222, 8:10, 9:406, a:-106, b:-124, c:-347, d:141, e:191, f:-219, total:-196, min:-771, max:406
m2digits twins 0:1909, 1:1956, 2:1915, 3:1918, 4:1882, 5:1890, 6:1960, 7:1748, 8:1915, 9:1940, a:1890, b:1828, c:1910, d:1886, e:1834, f:1852, dexp:1922, total:30233, texp:30761, min:1748, max:1960
m2digdiff twins 0:13, 1:-34, 2:7, 3:4, 4:40, 5:32, 6:-38, 7:174, 8:7, 9:-18, a:32, b:94, c:12, d:36, e:88, f:70, total:519, min:-38, max:174
m2digits triplets 0:125, 1:127, 2:128, 3:123, 4:109, 5:128, 6:113, 7:125, 8:122, 9:136, a:100, b:132, c:130, d:136, e:139, f:116, dexp:120, total:1989, texp:1922, min:100, max:139
m2digdiff triplets 0:-5, 1:-7, 2:-8, 3:-3, 4:11, 5:-8, 6:7, 7:-5, 8:-2, 9:-16, a:20, b:-12, c:-10, d:-16, e:-19, f:4, total:-69, min:-19, max:20
m2digits quadruplets 0:13, 1:21, 2:23, 3:17, 4:8, 5:13, 6:14, 7:13, 8:15, 9:17, a:13, b:15, c:17, d:20, e:20, f:14, dexp:7, total:253, texp:120, min:8, max:23
m2digdiff quadruplets 0:-6, 1:-14, 2:-16, 3:-10, 4:-1, 5:-6, 6:-7, 7:-6, 8:-8, 9:-10, a:-6, b:-8, c:-10, d:-13, e:-13, f:-7, total:-141, min:-16, max:-1
m2digits quintuplets 0:4, 1:3, 2:2, 3:2, 4:1, 6:4, 7:3, 8:3, a:2, c:3, d:2, e:3, f:1, dexp:0, total:33, texp:7, min:1, max:4
m2digdiff quintuplets 0:-4, 1:-3, 2:-2, 3:-2, 4:-1, 6:-4, 7:-3, 8:-3, a:-2, c:-3, d:-2, e:-3, f:-1, total:-33, min:-4, max:-1
m2digits sixlets 0:1, a:1, e:1, dexp:0, total:3, texp:0, min:1, max:1
m2digdiff sixlets 0:-1, a:-1, e:-1, total:-3, min:-1, max:-1
$
Tässä vielä bash:iin perustuva näkemys tuplista: (en ole varma näkyvätkö tuplat jossain selaimessa, minulla ne näkyvät bashissa punaisella)
$./newressu | grep "00\|11\|22\|33\|44\|55\|66\|77\|88\|99"
00000 50601770965858790287746351436604015693184573567799066517653601656
00001 48694546975015201968596666905183123871308274139328912966079898679
00002 79811004632452834690694925920237574068709382185064173509186665896
00003 67948756258916859329418821550901897658164278464642949542074825264
00004 33624858011285146428020109871734597275263223498277932780645159687
00005 17971792316063297502277999536969560242964320788109401452364923409
00006 35291566680695002181737688811100316149439988651827176360642157605
00007 11370134868289458957910751111498131857275527242659407122148439815
00008 26708050136430661831450323981723744901224836837055153985157327353
00009 26529141654263551049396906874524955288851596692074733373992155155
$
Vielä ohjelma:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "newressutest8 version 0.3 ©";
static unsigned char *copyright = "Copyright (c) 2022-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
void fprintfmultipletype(FILE *fp1, int c)
{
switch(c) {
case 0: fprintf(fp1, "singles"); break;
case 1: fprintf(fp1, "twins"); break;
case 2: fprintf(fp1, "triplets"); break;
case 3: fprintf(fp1, "quadruplets"); break;
case 4: fprintf(fp1, "quintuplets"); break;
case 5: fprintf(fp1, "sixlets"); break;
default: fprintf(fp1, "%dlets", c + 1); break;
}
}
int main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1,
ctrl = 1, chars = 1, cdiff = 1,
multiple1 = 1, m1exp = 1, m1diff = 1,
m1digits = 1, m1digdiff = 1,
multiple2 = 1, m2exp = 1, m2diff = 1,
m2digits = 1, m2digdiff = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
multiple1 = all;
m1exp = all;
m1diff = all;
m1digits = all;
m1digdiff = all;
multiple2 = all;
m2exp = all;
m2diff = all;
m2digits = all;
m2digdiff = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--m1", argv[c])) {
multiple1 = !multiple1;
m1exp = !m1exp;
m1diff = !m1diff;
m1digits = !m1digits;
m1digdiff = !m1digdiff;
} else if(!strcmp("--m1dig", argv[c])) {
m1digits = !m1digits;
m1digdiff = !m1digdiff;
} else if(!strcmp("--multiple1", argv[c])) {
multiple1 = !multiple1;
} else if(!strcmp("--m1exp", argv[c])) {
m1exp = !m1exp;
} else if(!strcmp("--m1diff", argv[c])) {
m1diff = !m1diff;
} else if(!strcmp("--m1digits", argv[c])) {
m1digits = !m1digits;
} else if(!strcmp("--m1digdiff", argv[c])) {
m1digdiff = !m1digdiff;
} else if(!strcmp("--m2", argv[c])) {
multiple2 = !multiple2;
m2exp = !m2exp;
m2diff = !m2diff;
m2digits = !m2digits;
m2digdiff = !m2digdiff;
} else if(!strcmp("--m2dig", argv[c])) {
m2digits = !m2digits;
m2digdiff = !m2digdiff;
} else if(!strcmp("--multiple2", argv[c])) {
multiple2 = !multiple2;
} else if(!strcmp("--m2exp", argv[c])) {
m2exp = !m2exp;
} else if(!strcmp("--m2diff", argv[c])) {
m2diff = !m2diff;
} else if(!strcmp("--m2digits", argv[c])) {
m2digits = !m2digits;
} else if(!strcmp("--m2digdiff", argv[c])) {
m2digdiff = !m2digdiff;
} else {
fprintf(stderr,"%s: invalid option %s\n",procname,argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
#ifdef DEBUG17
fprintf(stdout,"multiple1:%d", multiple1);
fprintf(stdout,", m1exp:%d", m1exp);
fprintf(stdout,", m1diff:%d", m1diff);
fprintf(stdout,"\n");
#endif
// print help message if needed
if(help) {
fprintf(stderr,"%s",procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--multiple1]");
fprintf(stderr," [--m1exp]");
fprintf(stderr," [--m1diff]");
fprintf(stderr," [--m1digits]");
fprintf(stderr," [--m1digdiff]");
fprintf(stderr," [--multiple2]");
fprintf(stderr," [--m2exp]");
fprintf(stderr," [--m2diff]");
fprintf(stderr," [--m2digits]");
fprintf(stderr," [--m2digdiff]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename,"-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
int currentchar = 0;
unsigned char prevchars[MAX];
unsigned long int m1counts[MAX];
unsigned long int m2counts[MAX];
for(c = 0; c < MAX; c++) {
prevchars[c] = 0;
m1counts[c] = 0;
m2counts[c] = 0;
}
unsigned long int singles = 0;
int ch, prevch;
unsigned long m2length;
first = 1;
unsigned char buffer[1024];
unsigned char *ifile = NULL;
unsigned long long ifilelength = 0;
// read input file to buffer
while(fgets(buffer,sizeof(buffer),fp1)!=NULL) {
if(verbose) {
fprintf(stdout,"%s",buffer);
}
int bytes = 0;
if(ifile != NULL)
bytes += strlen(ifile);
bytes += strlen(buffer);
bytes += 1;
if(ifilelength < bytes) {
ifilelength = bytes;
if((ifile = realloc(ifile, ifilelength)) == NULL) {
fprintf(stderr,"%s:",procname);
fprintf(stderr," realloc(): cannot allocate memory");
fprintf(stderr,", %lld bytes",ifilelength);
fprintf(stderr,"\n");
exit(2);
}
}
strcat(ifile, buffer);
}
if(verbose)
fflush(stdout);
unsigned char *p;
p = ifile;
while((ch = *p++) != '\0') {
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) // ctrl or space, skip
continue;
singles++;
} // end of for(c = 0; c < ifilelength; c++)
if(singles == 0) {
fprintf(stderr,"%s: no data\n", procname);
exit(2);
}
int charnum[MAXCOUNT];
int charascii[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++) {
charnum[c] = -1;
charascii[c] = -1;
}
int num = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20) // ctrl or space, skip
continue;
if(charcounts[c] != 0) {
charnum[c] = num;
charascii[num] = c;
num++;
}
}
#define aDEBUG25 2
#ifdef DEBUG25
fprintf(stdout,"charnum ");
for(c = 0; c < MAXCOUNT; c++) {
if(charnum[c] != -1)
fprintf(stdout," %d:%d", c, charnum[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
fprintf(stdout,"charascii");
for(c = 0; c < MAXCOUNT; c++) {
if(charascii[c] != -1)
fprintf(stdout," %d:%d", c, charascii[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
#endif
unsigned long int count = 0, ctotal = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c <= 0x20) // ctrl or space, skip
continue;
ctotal += charcounts[c];
count++;
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
long m1multiplecounts[MAX][count];
long m2multiplecounts[MAX][count];
for(c = 0; c < MAX; c++) {
for(d = 0; d < count; d++) {
m1multiplecounts[c][d] = 0;
m2multiplecounts[c][d] = 0;
}
}
p = ifile;
first = 1;
m2length = 0;
while((ch = *p++) != '\0') {
if(ch <= 0x20) // ctrl or space, skip
continue;
// calculate m1 multiple
// counts
prevchars[currentchar] = ch;
for(c = 0; c < MAX; c++) {
d = currentchar - c;
if(d < 0)
d += MAX;
if(ch != prevchars[d])
break;
m1counts[c]++;
m1multiplecounts[c][charnum[ch]]++;
}
if(++currentchar >= MAX)
currentchar -= MAX;
// calculate m2 multiple
// counts
if(first) {
prevch = ch;
m2length = 1;
first = 0;
} else {
if(prevch == ch) {
m2length++;
} else {
m2counts[m2length - 1]++;
m2multiplecounts[m2length - 1][charnum[prevch]]++;
m2length = 1;
prevch = ch;
}
}
} // end of for(c = 0; c < ifilelength; c++)
if(m2length > 0) {
m2counts[m2length - 1]++; // add last m2 multiple
m2multiplecounts[m2length - 1][charnum[prevch]]++;
}
#ifdef DEBUG46
for(c = 0; c < MAX; c++) {
for(d = 0; d < count; d++) {
fprintf(stdout," %lu",m2multiplecounts[c][d]);
}
fprintf(stdout,"\n");
}
#endif
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
}
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(ctrl)
// calculate average
unsigned long int average;
average = ctotal / count;
long int min;
long int max;
min = LONG_MAX;
max = LONG_MIN;
// print character counts if needed
if(chars) {
long int allchars;
fprintf(stdout,"chars ");
first = 1;
allchars = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%lu", charcounts[c]);
allchars += charcounts[c];
if(min > charcounts[c])
min = charcounts[c];
if(max < charcounts[c])
max = charcounts[c];
first = 0;
}
}
fprintf(stdout,", total:%ld", allchars);
fprintf(stdout,", count:%ld", count);
fprintf(stdout,", average:%ld", average);
fprintf(stdout,", total:%ld", allchars);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(chars)
// calculate and print character
// differences
min = LONG_MAX;
max = LONG_MIN;
if(cdiff) {
fprintf(stdout,"cdiff ");
long int chardiff = 0;
long int chardifftotal = 0;
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
fprintf(stdout,":%ld", average - charcounts[c]);
chardiff = (average - charcounts[c]);
chardifftotal += chardiff;
if(min > chardiff)
min = chardiff;
if(max < chardiff)
max = chardiff;
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,", total:%ld", chardifftotal);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(cdiff)
// print statistics on m1 multiples,
// multiple1, m1exp and m1diff
for(int e = 0; e < 3; e++) {
if(e==0) {
if(!multiple1)
continue;
fprintf(stdout, "multiple1 ");
} else if(e==1) {
if(!m1exp)
continue;
fprintf(stdout, "m1exp ");
} else {
if(!m1diff)
continue;
fprintf(stdout, "m1diff ");
}
long int total = 0;
long int expect = singles;
first = 1;
for(c = 0; c < MAX; c++) {
if(m1counts[c] > 0) {
if(!first)
fprintf(stdout,", ");
fprintfmultipletype(stdout, c);
long int temp;
if(e == 0)
temp = m1counts[c];
else if(e == 1)
temp = expect;
else
temp = expect - m1counts[c];
total += temp;
fprintf(stdout,":%ld", temp);
}
expect /= count;
first = 0;
}
fprintf(stdout,", total:%ld", total);
fprintf(stdout,"\n");
fflush(stdout);
} // end of for(int e = 0; e < 3; e++)
// print statistics on m1 multiples,
// m1digits and m1digdiff
long int m1expected = singles;
for(c = 0; c < MAX; c++) {
int print = 0;
for(d = 0; d < count; d++) {
if(m1multiplecounts[c][d] != 0)
print = 1;
}
if(print) {
for(int e = 0; e < 2; e++) { // 0 -> digits, 1 -> diff
if(e==0) {
if(!m1digits)
continue;
fprintf(stdout,"m1digits ");
} else if(e==1) {
if(!m1digdiff)
continue;
fprintf(stdout,"m1digdiff ");
}
min = LONG_MAX;
max = LONG_MIN;
fprintfmultipletype(stdout, c);
unsigned long total = 0;
first = 1;
for(d = 0; d < count; d++) {
if(m1multiplecounts[c][d] != 0) {
unsigned char ch = charascii[d];
if(!first)
fprintf(stdout,",");
fprintf(stdout," ");
if(isprint(ch) && ch > ' ')
fprintf(stdout,"%c", ch);
else
fprintf(stdout,"%02x", ch);
long temp;
if(e == 0)
temp = m1multiplecounts[c][d];
else if(e == 1)
temp = m1expected / count - m1multiplecounts[c][d];
fprintf(stdout,":%ld", temp);
total += temp;
first = 0;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
}
}
if(!first) {
if(e == 0)
fprintf(stdout,", dexp:%ld", m1expected / count);
fprintf(stdout,", total:%ld", total);
if(e == 0)
fprintf(stdout,", texp:%ld", m1expected);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
}
fprintf(stdout,"\n");
} // end of for(int e = 0; e < 2; e++)
}
m1expected /= count;
}
unsigned long int m2expects[MAX];
double base;
for(c = 0; c < MAX; c++) {
m2expects[c] = 0;
}
base = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
if(base * ctotal > 0) {
m2expects[c] = (unsigned long int) (base * ctotal);
base *= ((double)1 / count);
}
}
// print statistics on m2 multiples
// multiple1 m2exp and m2diff
for(int e = 0; e < 3; e++) {
if(e==0) {
if(!multiple2)
continue;
fprintf(stdout,"multiple2 ");
} else if(e==1) {
if(!m2exp)
continue;
fprintf(stdout,"m2exp ");
} else {
if(!m2diff)
continue;
fprintf(stdout,"m2diff ");
}
unsigned long int total = 0;
first = 1;
for(c = 0; c < MAX; c++) {
if(m2counts[c] > 0) {
if(first == 0)
fprintf(stdout,", ");
fprintfmultipletype(stdout, c);
long int temp;
if(e == 0) {
temp = m2counts[c];
//total += temp * (c + 1);
} else if(e == 1) {
temp = m2expects[c];
//total += temp * (c + 1);
} else {
temp = m2expects[c] - m2counts[c];
//total += temp;
}
fprintf(stdout,":%ld", temp);
total += temp * (c + 1);
first = 0;
}
} // end of for(c = 1; c < MAX; c++)
fprintf(stdout,", total:%ld",total);
fprintf(stdout,"\n");
fflush(stdout);
} // end if for(int e = 0; e < 3; e++)
// print statistics on m2 multiples
// m2digits and m2digdiff
double m2expectedbase = (((double)count - 1) / count) * (((double)count - 1) / count);
for(c = 0; c < MAX; c++) {
int print = 0;
for(d = 0; d < count; d++) {
if(m2multiplecounts[c][d] != 0)
print = 1;
}
if(print) {
unsigned long m2exp = m2expectedbase * ctotal;
for(int e = 0; e < 2; e++) { // 0 -> digits, 1 -> diff
if(e==0) {
if(!m2digits)
continue;
fprintf(stdout,"m2digits ");
} else {
if(!m2digdiff)
continue;
fprintf(stdout,"m2digdiff ");
}
min = LONG_MAX;
max = LONG_MIN;
fprintfmultipletype(stdout, c);
first = 1;
long int total = 0;
for(d = 0; d < count; d++) {
if(m2multiplecounts[c][d] != 0) {
unsigned char ch = charascii[d];
if(!first)
fprintf(stdout,",");
fprintf(stdout," ");
if(isprint(ch) && ch > ' ')
fprintf(stdout,"%c", ch);
else
fprintf(stdout,"%02x", ch);
long temp;
if(e==0)
temp = m2multiplecounts[c][d];
else
temp = m2exp / count - m2multiplecounts[c][d];
fprintf(stdout,":%ld", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
}
if(!first) {
if(e == 0)
fprintf(stdout,", dexp:%lu", (unsigned long) m2exp / count);
fprintf(stdout,", total:%ld", total);
if(e == 0)
fprintf(stdout,", texp:%lu", (unsigned long) m2exp);
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
}
fprintf(stdout,"\n");
} // end of for(int e = 0; e < 2; e++)
m2expectedbase *= ((double)1 / count);
}
}
}
Neljäs ohjelma jonka kirjoitin tekee edelleen tilastoja satunnaisuudesta: tällä kertaa tilastoidaan newressu tulosteen sanoja (words), eli välilyönneillä eroteltuja satunnaismerkkisarjoja. Seuraavassa raportissa sanan pituus on 1, jolloin tuotettu raportti on vastaa aiemmin laskettua chars riviä. Tällä voi debukata words toimintoa. Raportin –set toiminnolla voidaan tulostaa tietue, johon words rakenne lasketaan (vrt terttu).
$ ./newressu --bin -s1 --lineno --space -l1000| ./newressutest9 --set
set '0' = "18112", '1' = "17888"
ctrl LF:1000, space:35000
chars 0:18112, 1:17888, words:2, total:36000, average:18000, min:17888, max:18112
cdiff 0:-112, 1:112, total:0, min:-112, max:112
words 0:18112, 1:17888, words:2, total:36000, average:18000, min:17888, max:18112
wdiff 0:-112, 1:112, total:0, min:-112, max:112
$
Varsinainen toiminta on kuitenkin siinä että verrataan useampimerkkisiä sanoja:
$ ./newressu --bin -s2 --lineno --space -l1000 | ./newressutest9 --set
set '00' = "6061", '01' = "5916", '10' = "6009", '11' = "6014"
ctrl LF:1000, space:23000
chars 0:24047, 1:23953, words:2, total:48000, average:24000, min:23953, max:24047
cdiff 0:-47, 1:47, total:0, min:-47, max:47
words 00:6061, 01:5916, 10:6009, 11:6014, words:4, total:24000, average:6000, min:5916, max:6061
wdiff 00:-61, 01:84, 10:-9, 11:-14, total:0, min:-61, max:84
$
Edellisessä on listattu binääriset 2 bittiset sanat, jotka ovat 00, 01, 10 ja 11. Koska vaihtoehtoja on neljä, yhden yhdistelmän todennäköisyys on 1/4 eli 25%.
Listaan poikkeuksellisesti ensimmäisenä newressutest9:n tietorakenteen hallinnan, koska se on tavallaan erillinen kokonaisuus. En kuitenkaan vielä laittanut sitä omaan tiedostoon:
unsigned char *db5_set = NULL;
unsigned char *db5_get_set()
{
return(db5_set);
}
void db5_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
void db5_get_element(unsigned int *namelen, unsigned char **name, unsigned int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db5_skipwhite(&p);
if(*p == '\'') { // name
p++;
*name = p;
*namelen = 0;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
}
db5_skipwhite(&p);
if(*p == '=') {
p++;
}
db5_skipwhite(&p);
if(*p == '\"') { // value
p++;
*value = p;
*valuelen = 0;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
}
db5_skipwhite(&p);
*p2 = p;
}
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
int db5_get(unsigned char *name, int valuesize, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen = strlen(name);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** get\n");
#endif
value[0] = '\0';
if(db5_set != NULL) {
firstelement = 1;
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = strlen(value);
break;
}
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(db5_set != NULL)
return(retval);
}
#define SORTED 2
void db5_put(unsigned char *name, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
unsigned int namelen = strlen(name);
unsigned int valuelen = strlen(value);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** put\n");
#endif
firstelement = 1;
lastelement = 0;
if(db5_set != NULL) {
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 &&
!strncmp(name, name2, namelen) ) {
found = 1;
thiselement = currentelement;
nextelement = p; // beginning of next element
break;
}
#ifdef SORTED
// we reached greater name
if(namelen == namelen2 &&
strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
thiselement = currentelement;
nextelement = currentelement;
break;
} else {
// common beginning of strings
int comblen = namelen;
if(comblen > namelen2)
comblen = namelen2;
int cmp = strncmp(name, name2, comblen);
if((cmp < 0) || // first characters less (aaaa, b)
(!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
thiselement = currentelement;
nextelement = currentelement;
break;
}
}
#endif
if(*p == '\0')
lastelement = 1;
firstelement = 0;
} // end of while(*p != '\0')
} else { // else of if(db5_set != NULL)
lastelement = 1;
firstelement = 1;
} // end of if(db5_set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%s' = \"%s\""; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%s' = \"%s\", "; // --> comma in the end (first new)
else
elementfmt = ", '%s' = \"%s\""; // ..> comma in the beginning (other)
// print element
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
if(elementsize < count) {
elementsize = count;
if((element = realloc(element, elementsize)) == NULL) {
fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
}
#ifdef DEBUG22
fprintf(stdout,", set: %s", db5_set);
fprintf(stdout,"\n");
#endif
// calculate change in length
long oldcount = 0;
count = 0;
if(db5_set != NULL) {
count += strlen(db5_set);
oldcount = count + 1; // + '\0'
}
if(found) // change in value only
count += valuelen - valuelen2; // no punctuation marks
else
count += strlen(element);
count++; // + '\0'
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout, "old length:%ld %s\n", oldcount, db5_set);
fflush(stdout);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempdb5_set = db5_set;
if((db5_set = realloc(db5_set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = db5_set + (thiselement - tempdb5_set);
if(nextelement != NULL)
nextelement = db5_set + (nextelement - tempdb5_set);
if(tempdb5_set == NULL)
db5_set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = db5_set + strlen(db5_set);
if(nextelement == NULL)
nextelement = db5_set + strlen(db5_set);
// move end of the set
memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too
// add new element
memmove(thiselement, element, strlen(element));
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout,"new length:%ld %s\n", count, db5_set);
fflush(stdout);
}
#endif
#ifdef DEBUG10
fprintf(stdout,", set %s(%ld)", db5_set, strlen(db5_set));
fprintf(stdout,"\n");
fflush(stdout);
#endif
}
Edellinen koodi listaa db5_put():in db5_get():in, joilla voisi olla potentiaalia myös tertun ytimeen.
Seuraavassa lista, josta näkee selvemmin datarakenteen:
$ cat newressudb5test.sh
#!/bin/bash
for ((c=0;c<5;c++)); do ./newressu --single --bin -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --oct -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --dec -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
for ((c=0;c<5;c++)); do ./newressu --single --hex -s1 --spaces $@ --lineno -l1000 | ./newressutest9 --all; done;
$ ./newressudb5test.sh
set '0' = "17983", '1' = "18017"
set '0' = "17935", '1' = "18065"
set '0' = "17851", '1' = "18149"
set '0' = "18034", '1' = "17966"
set '0' = "18086", '1' = "17914"
set '0' = "4507", '1' = "4508", '2' = "4524", '3' = "4466", '4' = "4438", '5' = "4542", '6' = "4538", '7' = "4477"
set '0' = "4535", '1' = "4541", '2' = "4467", '3' = "4589", '4' = "4449", '5' = "4510", '6' = "4390", '7' = "4519"
set '0' = "4528", '1' = "4502", '2' = "4445", '3' = "4507", '4' = "4574", '5' = "4444", '6' = "4516", '7' = "4484"
set '0' = "4442", '1' = "4493", '2' = "4505", '3' = "4394", '4' = "4600", '5' = "4531", '6' = "4494", '7' = "4541"
set '0' = "4569", '1' = "4346", '2' = "4472", '3' = "4464", '4' = "4447", '5' = "4585", '6' = "4551", '7' = "4566"
set '0' = "3572", '1' = "3571", '2' = "3573", '3' = "3633", '4' = "3596", '5' = "3616", '6' = "3743", '7' = "3492", '8' = "3622", '9' = "3582"
set '0' = "3620", '1' = "3650", '2' = "3567", '3' = "3610", '4' = "3561", '5' = "3622", '6' = "3698", '7' = "3556", '8' = "3553", '9' = "3563"
set '0' = "3598", '1' = "3616", '2' = "3594", '3' = "3732", '4' = "3587", '5' = "3603", '6' = "3511", '7' = "3598", '8' = "3562", '9' = "3599"
set '0' = "3577", '1' = "3575", '2' = "3640", '3' = "3568", '4' = "3648", '5' = "3591", '6' = "3570", '7' = "3577", '8' = "3682", '9' = "3572"
set '0' = "3584", '1' = "3643", '2' = "3621", '3' = "3696", '4' = "3522", '5' = "3698", '6' = "3526", '7' = "3611", '8' = "3630", '9' = "3469"
set '0' = "2344", '1' = "2323", '2' = "2156", '3' = "2296", '4' = "2314", '5' = "2249", '6' = "2275", '7' = "2220", '8' = "2289", '9' = "2202", 'a' = "2227", 'b' = "2262", 'c' = "2240", 'd' = "2177", 'e' = "2211", 'f' = "2215"
set '0' = "2235", '1' = "2151", '2' = "2361", '3' = "2218", '4' = "2214", '5' = "2218", '6' = "2266", '7' = "2251", '8' = "2281", '9' = "2192", 'a' = "2227", 'b' = "2313", 'c' = "2259", 'd' = "2236", 'e' = "2337", 'f' = "2241"
set '0' = "2209", '1' = "2197", '2' = "2289", '3' = "2343", '4' = "2260", '5' = "2253", '6' = "2298", '7' = "2195", '8' = "2224", '9' = "2197", 'a' = "2205", 'b' = "2308", 'c' = "2254", 'd' = "2221", 'e' = "2266", 'f' = "2281"
set '0' = "2234", '1' = "2270", '2' = "2310", '3' = "2151", '4' = "2271", '5' = "2259", '6' = "2295", '7' = "2199", '8' = "2318", '9' = "2207", 'a' = "2230", 'b' = "2206", 'c' = "2275", 'd' = "2275", 'e' = "2253", 'f' = "2247"
set '0' = "2314", '1' = "2290", '2' = "2202", '3' = "2300", '4' = "2133", '5' = "2218", '6' = "2229", '7' = "2292", '8' = "2208", '9' = "2251", 'a' = "2224", 'b' = "2239", 'c' = "2289", 'd' = "2248", 'e' = "2279", 'f' = "2284"
$
Listan alussa on laskettu binääri merkkejä (5 riviä), seuraavaksi oktaalimerkkejä, desimaalimerkkejä ja heksamerkkejä.
Datarakenteessa on tässä sanat (words) ja samanlaisten sanojen lukumäärä, mutta kun sanan tilalle laittaa kentän nimen ja lukumäärän tilalle kentän arvon, voidaan alkaa miettimään esimerkiksi appia tilaus ja siihen liittyviä kenttia ja tiedostoja (tilaus, asiakas, tilausrivit, tuote, asiakasmyynti, toimitus jne.). Edit: Tietenkin ilman kovakoodattuja sarakkeita, tauluja ja appeja.
Ja koodi kokonaisuudessaan: (huomaa että ohjelmassa on TEST80 kappale, joka ristiintarkistaa chars rivin ja words rivin luvut, se on nyt päällä)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
static unsigned char *procname;
static unsigned char *programname = "newressutest9 version 0.4 ©";
static unsigned char *copyright = "Copyright (c) 1998-2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
unsigned char *db5_set = NULL;
unsigned char *db5_get_set()
{
return(db5_set);
}
void db5_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
void db5_get_element(unsigned int *namelen, unsigned char **name, unsigned int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db5_skipwhite(&p);
if(*p == '\'') { // name
p++;
*name = p;
*namelen = 0;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
}
db5_skipwhite(&p);
if(*p == '=') {
p++;
}
db5_skipwhite(&p);
if(*p == '\"') { // value
p++;
*value = p;
*valuelen = 0;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
}
db5_skipwhite(&p);
*p2 = p;
}
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
int db5_get(unsigned char *name, int valuesize, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen = strlen(name);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** get\n");
#endif
value[0] = '\0';
if(db5_set != NULL) {
firstelement = 1;
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"get name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
db5_skipwhite(&p);
// we reached equal name
if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = strlen(value);
break;
}
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(db5_set != NULL)
return(retval);
}
#define SORTED 2
void db5_put(unsigned char *name, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
unsigned int namelen = strlen(name);
unsigned int valuelen = strlen(value);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** put\n");
#endif
firstelement = 1;
lastelement = 0;
if(db5_set != NULL) {
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
db5_skipwhite(&p);
#ifdef DEBUG9
fprintf(stdout,"put name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 &&
!strncmp(name, name2, namelen) ) {
found = 1;
thiselement = currentelement;
nextelement = p; // beginning of next element
break;
}
#ifdef SORTED
// we reached greater name
if(namelen == namelen2 &&
strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
thiselement = currentelement;
nextelement = currentelement;
break;
} else {
// common beginning of strings
int comblen = namelen;
if(comblen > namelen2)
comblen = namelen2;
int cmp = strncmp(name, name2, comblen);
if((cmp < 0) || // first characters less (aaaa, b)
(!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
thiselement = currentelement;
nextelement = currentelement;
break;
}
}
#endif
if(*p == '\0')
lastelement = 1;
firstelement = 0;
} // end of while(*p != '\0')
} else { // else of if(db5_set != NULL)
lastelement = 1;
firstelement = 1;
} // end of if(db5_set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%s' = \"%s\""; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%s' = \"%s\", "; // --> comma in the end (first new)
else
elementfmt = ", '%s' = \"%s\""; // ..> comma in the beginning (other)
// print element
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
if(elementsize < count) {
elementsize = count;
if((element = realloc(element, elementsize)) == NULL) {
fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
}
#ifdef DEBUG22
fprintf(stdout,", set: %s", db5_set);
fprintf(stdout,"\n");
#endif
// calculate change in length
long oldcount = 0;
count = 0;
if(db5_set != NULL) {
count += strlen(db5_set);
oldcount = count + 1; // + '\0'
}
if(found) // change in value only
count += valuelen - valuelen2; // no punctuation marks
else
count += strlen(element);
count++; // + '\0'
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout, "old length:%ld %s\n", oldcount, db5_set);
fflush(stdout);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempdb5_set = db5_set;
if((db5_set = realloc(db5_set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = db5_set + (thiselement - tempdb5_set);
if(nextelement != NULL)
nextelement = db5_set + (nextelement - tempdb5_set);
if(tempdb5_set == NULL)
db5_set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = db5_set + strlen(db5_set);
if(nextelement == NULL)
nextelement = db5_set + strlen(db5_set);
// move end of the set
memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too
// add new element
memmove(thiselement, element, strlen(element));
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout,"new length:%ld %s\n", count, db5_set);
fflush(stdout);
}
#endif
#ifdef DEBUG10
fprintf(stdout,", set %s(%ld)", db5_set, strlen(db5_set));
fprintf(stdout,"\n");
fflush(stdout);
#endif
}
#define aDEBUG34 2
void increment(unsigned char *name)
{
unsigned long long count;
unsigned char buffer[32];
#ifdef DEBUG9
fprintf(stdout, "********** increment\n");
#endif
count = 0;
if(db5_get(name, sizeof(buffer), buffer) != 0)
count = atoll(buffer);
count++;
sprintf(buffer,"%lld", count);
db5_put(name, buffer);
#ifdef DEBUG34
fprintf(stdout, ", '%s', \"%s\"",name, buffer);
fflush(stdout);
#endif
}
int main(int argc, char *argv[])
{
int c, d, first;
int verbose = 0, help = 0, all = 1, set = 0,
ctrl = 1, chars = 1, cdiff = 1,
words = 1, wdiff = 1;
char filename[128] = "-"; // default stdin
FILE *fp1;
procname = argv[0];
#define aTEST39 2 // default is off
#ifdef TEST39
// tests for earlier db5 routines
db5_set = "'kala' = \"kele\", 'kala2' = \"kele2\", 'kala3' = \"kele3\"";
unsigned int valuelen = 1024, valuelen2;
unsigned char value[1024];
// dbget
fprintf(stdout,"db5\n");
fflush(stdout);
db5_get("kala", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
db5_get("kala2", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
db5_get("kala3", valuelen, value);
valuelen2 = strlen(value);
fprintf(stdout,"*value:%.*s(%d)\n",
valuelen2, value, valuelen2);
fflush(stdout);
// dbput and sorting
db5_set = NULL;
db5_put("kala", "kele");
db5_put("kala1", "kele1");
db5_put("kala2", "kele2");
db5_put("kala21", "kele211111");
db5_put("kala3", "kele3");
db5_put("kala2", "kele2b");
db5_put("kala21", "kele21");
db5_put("kala21", "kele21111");
// test increment
free(db5_set);
db5_set = NULL;
increment("a");
increment("b");
increment("b");
increment("c");
increment("c");
increment("c");
// utf8 characters
free(db5_set);
db5_set = NULL;
increment("⚀");
increment("⚁");
increment("⚂");
increment("⚃");
increment("⚄");
increment("⚅");
// sorting with different lengths of name
free(db5_set);
db5_set = NULL;
db5_put("ccccc", "ccccc");
db5_put("a", "a");
db5_put("bbbb", "bbbb");
db5_put("b", "b");
db5_put("cccc", "cccc");
db5_put("c", "c");
db5_put("aaaaa", "aaaaa");
db5_put("aa", "aa");
db5_put("bb", "bb");
db5_put("aaa", "aaa");
db5_put("bbbbb", "bbbbb");
db5_put("cc", "cc");
db5_put("aaaaa", "aaaaa");
db5_put("aaaa", "aaaa");
db5_put("bbb", "bbb");
db5_put("ccc", "ccc");
fprintf(stdout,"db5_set:%s\n", db5_set);
free(db5_set);
db5_set = NULL;
//exit(1);
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("-",argv[c])) { // filename - -->stdin
strncpy(filename, argv[c], sizeof(filename));
fp1 = stdin;
} else if(strncmp("-", argv[c], 1)) { // filename
strncpy(filename, argv[c], sizeof(filename));
} else if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--verbose", argv[c])) {
verbose = 1;
} else if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--set", argv[c])) { // display db5_set
set = !set;
} else if(!strcmp("--all", argv[c])) {
all = !all;
ctrl = all;
chars = all;
cdiff = all;
words = all;
wdiff = all;
} else if(!strcmp("--ctrl", argv[c])) {
ctrl = !ctrl;
} else if(!strcmp("--chars", argv[c])) {
chars = !chars;
} else if(!strcmp("--cdiff", argv[c])) {
cdiff = !cdiff;
} else if(!strcmp("--words", argv[c])) {
words = !words;
} else if(!strcmp("--wdiff", argv[c])) {
wdiff = !wdiff;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
help = 1;
}
}
} // end of for(c = 1; c < argc; c++)
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [-]");
fprintf(stderr,"/[filename]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--all]");
fprintf(stderr," [--ctrl]");
fprintf(stderr," [--chars]");
fprintf(stderr," [--cdiff]");
fprintf(stderr," [--words]");
fprintf(stderr," [--wdiff]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
// open needed random file
if(!strcmp(filename, "-")) {
fp1 = stdin;
} else if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: fopen: cannot open file %s", procname, filename);
exit(2);
}
#define MAXCOUNT 256
long int charcounts[MAXCOUNT];
for(c = 0; c < MAXCOUNT; c++)
charcounts[c] = 0;
#define MAX 1024
unsigned long int singles = 0;
int ch;
first = 1;
unsigned char buffer[1024];
unsigned char *ifile = NULL; // input file
unsigned long long ifilelength = 0;
// read input file to buffer
while(fgets(buffer, sizeof(buffer), fp1) != NULL) {
if(verbose) {
fprintf(stdout,"%s", buffer);
}
int bytes = 0;
if(ifile != NULL)
bytes += strlen(ifile);
bytes += strlen(buffer);
bytes += 1;
if(ifilelength < bytes) {
unsigned char *tempifile = ifile;
ifilelength = bytes;
if((ifile = realloc(ifile, ifilelength)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(2);
}
if(tempifile == NULL)
ifile[0] = '\0';
}
strcat(ifile, buffer);
}
if(verbose)
fflush(stdout);
unsigned char *p;
p = ifile;
while((ch = *p++) != '\0') {
// calculate character counts for
// character statistics
charcounts[ch]++;
if(ch <= 0x20) { // ctrl or space, skip
continue;
}
singles++;
} // end of for(c = 0; c < ifilelength; c++)
if(singles == 0) {
fprintf(stderr,"%s: no data\n",procname);
exit(2);
}
int wcount = 0; // word count
p = ifile;
while(*p != '\0') {
while(*p <= 0x20 && *p != '\0') // skip control && handle end of file
p++;
int count;
unsigned char *w, word[128];
// get word
w = word;
count = 0;
while(*p > 0x20 && *p != '\0') {
if(++count < sizeof(word))
*w++ = *p;
p++;
}
*w = '\0';
if(count > 0) {
increment(word);
wcount++;
}
} // end of while(*p != '\0')
if(set) {
fprintf(stdout,"set %s\n", db5_set);
fflush(stdout);
}
unsigned long int count = 0, ctotal = 0;
for(c = 0; c < MAXCOUNT; c++) {
if(charcounts[c] > 0) {
if(c <= 0x20) // ctrl or space, skip
continue;
ctotal += charcounts[c];
count++;
} // if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
// print control line if needed
if(ctrl) {
char *ctrlchars[] = {
"NUL", "0x01", "0x02", "0x03", "0x04", "0x05", "0x06", "BEL", "BS",
"0x09", "LF", "0x0b", "0x0c", "CR", "0x0e", "0x0f",
"0x10", "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
"0x19", "0x1a", "ESC", "0x1c", "0x1d", "0x1e", "0x1f",
"space"
};
fprintf(stdout,"ctrl ");
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c > 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%s", ctrlchars[c]);
fprintf(stdout,":%lu", charcounts[c]);
first = 0;
} // end of if(charcounts[c] > 0)
} // end of for(c = 0; c < MAXCOUNT; c++)
fprintf(stdout,"\n");
fflush(stdout);
} // end of if(ctrl)
unsigned long int caverage;
// calculate average for character statistics
caverage = ctotal / count;
long int min;
long int max;
// print character statistics
for(int e = 0; e < 2; e++) {
long int total = 0;
min = LONG_MAX;
max = LONG_MIN;
if(e == 0) {
if(!chars)
continue;
fprintf(stdout,"chars ");
} else {
if(!cdiff)
continue;
fprintf(stdout,"cdiff ");
}
first = 1;
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
if(charcounts[c] > 0) {
if(!first)
fprintf(stdout, ", ");
if(isprint(c) && c > ' ')
fprintf(stdout, "%c", c);
else
fprintf(stdout,"%02x", c);
long int temp;
if(e == 0)
temp = charcounts[c];
else
temp = caverage - charcounts[c];
fprintf(stdout,":%ld", temp);
total += temp;
if(min > temp)
min = temp;
if(max < temp)
max = temp;
first = 0;
}
} // end of if(charcounts[c] > 0)
if(e == 0) {
fprintf(stdout,", words:%ld", count);
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", average:%ld", caverage);
} else {
fprintf(stdout,", total:%ld", total);
}
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} // end of for(int e = 0; e < 2: e++)
unsigned char *iset = db5_get_set();
unsigned int namelen, valuelen;
unsigned char *name, *value;
#define TEST80 2 // default on (for now)
#ifdef TEST80
for(c = 0; c < MAXCOUNT; c++) {
if(c <= 0x20)
continue;
long int tcount = 0;
p = iset;
while(*p != '\0') {
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
long int temp;
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
temp = atol(tempbuffer);
for(d = 0; d < namelen; d++) {
if(name[d] == c)
tcount += temp;
}
} // end of while(*p != '\0')
#define aDEBUG84 2
#ifdef DEBUG84
if(charcounts[c] != 0 || tcount != 0) {
fprintf(stderr,"%s: test", procname);
fprintf(stderr,", c:%d", c);
fprintf(stderr,", charcount:%ld", charcounts[c]);
fprintf(stderr,", tcount:%ld\n", tcount);
}
#endif
if(charcounts[c] != tcount) {
fprintf(stderr,"%s: internal error:", procname);
fprintf(stderr,"wordcounts and charcounts do not match");
fprintf(stderr,", char:%c(0x%02x)", c, c);
fprintf(stderr,", charcount:%ld", charcounts[c]);
fprintf(stderr,", tcount:%ld", tcount);
fprintf(stderr,"\n");
//exit(2);
}
} // for(c = 0; c < MAXCOUNT; c++)
#endif
unsigned long wtotal = 0;
unsigned long wordscnt = 0;
// calculate words statistics average
// first words total and count
p = iset;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
long int temp;
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
temp = atol(tempbuffer);
wtotal += temp;
wordscnt++;
} // end of while(*set != '\0')
// average (words statistics)
long int waverage = wtotal / wordscnt;
// print words statistics
for(int e = 0; e < 2; e++) {
unsigned long total = 0;
min = LONG_MAX;
max = LONG_MIN;
if(e == 0) {
if(!words)
continue;
fprintf(stdout,"words ");
} else {
if(!wdiff)
continue;
fprintf(stdout,"wdiff ");
}
unsigned char *iset = db5_get_set();
// read thru elements element by element
first = 1;
p = iset;
while(*p != '\0') {
if(!first)
fprintf(stdout, ", ");
db5_skipwhite(&p);
db5_get_element(&namelen, &name, &valuelen, &value, &p);
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
fprintf(stderr,"%s: excess comma, set:%s\n", procname, iset);
fflush(stderr);
exit(1);
}
}
unsigned char tempbuffer[32];
strncpy(tempbuffer, value, valuelen);
tempbuffer[valuelen] = '\0';
long int temp;
if(e == 0)
temp = atol(tempbuffer);
else
temp = waverage - atol(tempbuffer);
fprintf(stdout,"%.*s:", namelen, name);
fprintf(stdout,"%ld", temp);
if(min > temp)
min = temp;
if(max < temp)
max = temp;
total += temp;
first = 0;
} // end of while(*set != '\0')
if(e == 0) {
fprintf(stdout,", words:%ld", wordscnt);
fprintf(stdout,", total:%ld", total);
fprintf(stdout,", average:%ld", waverage);
} else {
fprintf(stdout,", total:%ld", total);
}
fprintf(stdout,", min:%ld", min);
fprintf(stdout,", max:%ld", max);
fprintf(stdout,"\n");
fflush(stdout);
} //end of for(e = 0;e < 2; e++)
}
Tässä vielä kuva DEBUG11:n tulostamasta listasta: Listalle tulee kaksi riviä (old ja new) silloin kun set:n koko muuttuu, eli käydään muuttamassa tietueen kokoa realloc:issa.
$ ./newressu --dec --space --lineno -s1 -l10 | ./newressutest9 --set | more
old length:0 (null)
new length:10 '9' = "1"
old length:10 '9' = "1"
new length:21 '0' = "1", '9' = "1"
old length:21 '0' = "1", '9' = "1"
new length:32 '0' = "1", '7' = "1", '9' = "1"
old length:32 '0' = "1", '7' = "1", '9' = "1"
new length:43 '0' = "1", '2' = "1", '7' = "1", '9' = "1"
old length:43 '0' = "1", '2' = "1", '7' = "1", '9' = "1"
new length:54 '0' = "1", '2' = "1", '4' = "1", '7' = "1", '9' = "1"
old length:54 '0' = "1", '2' = "1", '4' = "1", '7' = "1", '9' = "1"
new length:65 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '7' = "1", '9' = "1"
old length:65 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '7' = "1", '9' = "1"
new length:76 '0' = "1", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "1", '9' = "1"
old length:76 '0' = "2", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "2", '9' = "1"
new length:87 '0' = "2", '1' = "1", '2' = "1", '3' = "1", '4' = "1", '5' = "1", '7' = "2", '9' = "1"
old length:87 '0' = "5", '1' = "3", '2' = "1", '3' = "2", '4' = "1", '5' = "7", '7' = "3", '9' = "4"
new length:98 '0' = "5", '1' = "3", '2' = "1", '3' = "2", '4' = "1", '5' = "7", '7' = "3", '8' = "1", '9' = "4"
old length:98 '0' = "5", '1' = "5", '2' = "1", '3' = "3", '4' = "5", '5' = "9", '7' = "3", '8' = "3", '9' = "5"
new length:109 '0' = "5", '1' = "5", '2' = "1", '3' = "3", '4' = "5", '5' = "9", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
old length:109 '0' = "5", '1' = "5", '2' = "1", '3' = "4", '4' = "5", '5' = "9", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
new length:110 '0' = "5", '1' = "5", '2' = "1", '3' = "4", '4' = "5", '5' = "10", '6' = "1", '7' = "3", '8' = "3", '9' = "5"
old length:110 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "9", '9' = "6"
new length:111 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
old length:111 '0' = "8", '1' = "9", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
new length:112 '0' = "8", '1' = "10", '2' = "2", '3' = "5", '4' = "6", '5' = "14", '6' = "4", '7' = "4", '8' = "10", '9' = "6"
old length:112 '0' = "9", '1' = "15", '2' = "4", '3' = "6", '4' = "6", '5' = "15", '6' = "5", '7' = "5", '8' = "14", '9' = "6"
new length:113 '0' = "10", '1' = "15", '2' = "4", '3' = "6", '4' = "6", '5' = "15", '6' = "5", '7' = "5", '8' = "14", '9' = "6"
old length:113 '0' = "11", '1' = "20", '2' = "6", '3' = "9", '4' = "8", '5' = "16", '6' = "6", '7' = "8", '8' = "17", '9' = "6"
new length:114 '0' = "11", '1' = "20", '2' = "6", '3' = "10", '4' = "8", '5' = "16", '6' = "6", '7' = "8", '8' = "17", '9' = "6"
old length:114 '0' = "13", '1' = "20", '2' = "6", '3' = "10", '4' = "9", '5' = "17", '6' = "8", '7' = "8", '8' = "18", '9' = "7"
new length:115 '0' = "13", '1' = "20", '2' = "6", '3' = "10", '4' = "10", '5' = "17", '6' = "8", '7' = "8", '8' = "18", '9' = "7"
old length:115 '0' = "13", '1' = "20", '2' = "7", '3' = "11", '4' = "11", '5' = "21", '6' = "8", '7' = "9", '8' = "19", '9' = "8"
new length:116 '0' = "13", '1' = "20", '2' = "7", '3' = "11", '4' = "11", '5' = "21", '6' = "8", '7' = "10", '8' = "19", '9' = "8"
old length:116 '0' = "15", '1' = "22", '2' = "7", '3' = "11", '4' = "12", '5' = "21", '6' = "9", '7' = "10", '8' = "19", '9' = "9"
new length:117 '0' = "15", '1' = "22", '2' = "7", '3' = "11", '4' = "12", '5' = "21", '6' = "9", '7' = "10", '8' = "19", '9' = "10"
old length:117 '0' = "15", '1' = "22", '2' = "8", '3' = "11", '4' = "12", '5' = "22", '6' = "9", '7' = "10", '8' = "20", '9' = "10"
new length:118 '0' = "15", '1' = "22", '2' = "8", '3' = "11", '4' = "12", '5' = "22", '6' = "10", '7' = "10", '8' = "20", '9' = "10"
old length:118 '0' = "20", '1' = "25", '2' = "9", '3' = "14", '4' = "14", '5' = "25", '6' = "14", '7' = "15", '8' = "23", '9' = "11"
new length:119 '0' = "20", '1' = "25", '2' = "10", '3' = "14", '4' = "14", '5' = "25", '6' = "14", '7' = "15", '8' = "23", '9' = "11"
set '0' = "36", '1' = "43", '2' = "26", '3' = "28", '4' = "35", '5' = "44", '6' = "31", '7' = "40", '8' = "47", '9' = "30"
ctrl LF:10, space:350
chars 0:36, 1:43, 2:26, 3:28, 4:35, 5:44, 6:31, 7:40, 8:47, 9:30, words:10, total:360, average:36, min:26, max:47
cdiff 0:0, 1:-7, 2:10, 3:8, 4:1, 5:-8, 6:5, 7:-4, 8:-11, 9:6, total:0, min:-11, max:10
words 0:36, 1:43, 2:26, 3:28, 4:35, 5:44, 6:31, 7:40, 8:47, 9:30, words:10, total:360, average:36, min:26, max:47
wdiff 0:0, 1:-7, 2:10, 3:8, 4:1, 5:-8, 6:5, 7:-4, 8:-11, 9:6, total:0, min:-11, max:10
$
Uudelleenkirjoitin myös newressun stat_line rutiinit: uudessa versiossa ideana on että tilarivi tulostetaan vain, jos se on muuttunut. Uudessa versiossa tilarivi kootaan stat_line muuttujaan ja end() rutiinissa koko rivi tulostetaan, jos se on muuttunut. End() rutiini tallettaa stat_line muuttujan prev_stat_line muuttujaan seuraavaa vertailua varten. cursor_remove() ja cursor_start() kutsut on siirretty _end() rutiiniin.
static int cursor_on = 0;
unsigned char cursor[4] = { '|', '/', '-', '\\' };
long int prev_secs = -1;
int crs = 0;
void stat_line_cursor_start()
{
fprintf(stderr, " ");
fflush(stderr);
prev_secs = -1;
cursor_on = 1;
}
void stat_line_cursor()
{
long int secs;
secs = time(NULL) % sizeof(cursor);
if(prev_secs != secs) {
if(prev_secs != -1)
crs = (crs + 1) % sizeof(cursor);
fprintf(stderr,"\b%c", cursor[crs]);
fflush(stderr);
prev_secs = secs;
}
}
void stat_line_cursor_remove()
{
if(cursor_on) {
fprintf(stderr, "\b \b");
fflush(stderr);
prev_secs = -1;
}
cursor_on = 0;
}
#include <stdarg.h>
#define aDEBUG31 2
unsigned char *procname = NULL;
static unsigned char *prev_stat_line = NULL;
static unsigned char *stat_line = NULL;
static size_t stat_line_length = 0;
static void stat_line_begin()
{
if(stat_line != NULL)
stat_line[0] = '\0';
}
static void stat_line_printf(const unsigned char *format, ...)
{
int count;
va_list args;
static unsigned char *buffer = NULL;
static size_t buffer_length = 0;
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
if(buffer_length < count) {
buffer_length = count;
buffer = realloc(buffer, buffer_length);
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
}
count = 0;
if(stat_line != NULL)
count += strlen(stat_line);
count += strlen(buffer);
count++;
if(stat_line_length < count) {
unsigned char *stat_line2 = stat_line;
stat_line_length = count;
stat_line = realloc(stat_line, stat_line_length);
prev_stat_line = realloc(prev_stat_line, stat_line_length);
if(stat_line2 == NULL) {
stat_line[0] = '\0';
prev_stat_line[0] = '\0';
}
}
strcat(stat_line, buffer);
}
#define READABLE_NUMBER_BIN 2
#ifdef READABLE_NUMBER_BIN
#define READABLE_NUMBER_HIGH 1023
#define READABLE_NUMBER_DIVIDER 1024
#else
#define READABLE_NUMBER_HIGH 999
#define READABLE_NUMBER_DIVIDER 1000
#endif
#define READABLE_NUMBER_WIDTH 32
static void stat_line_get_readable(unsigned char buf10[10], unsigned long length)
{
int c, low;
double length2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
strcpy(buf10, "***");
low = 0;
for(c = 0; length >= low &&
c < sizeof(units) - 1; c++) {
if(length >= low &&
length <= READABLE_NUMBER_HIGH) {
if(units[c] == 'B')
sprintf(buf10, "%ld", length);
else if(units[c] == 'K' ||
units[c] == 'M' ||
units[c] == 'G' ||
units[c] == 'T')
sprintf(buf10, "%.3f", length2);
else if(length == length2)
sprintf(buf10, "%ld", length);
else
sprintf(buf10, "%.1f", length2);
if(strchr(buf10, '.') != NULL) {
int d;
d = strlen(buf10) - 1;
while(d > 3 && isdigit(buf10[d])) {
buf10[d] = '\0';
d--;
}
if(buf10[strlen(buf10)-1] == '.')
buf10[strlen(buf10)-1] ='\0';
}
if(units[c] != 'B') {
char unit[10];
sprintf(unit,"%cB",units[c]);
strcat(buf10, unit);
}
break;
}
length2 = (double)length / READABLE_NUMBER_DIVIDER;
length /= READABLE_NUMBER_DIVIDER;
low = 1;
}
}
static void stat_line_readable(unsigned long length)
{
unsigned char buf10[10];
stat_line_get_readable(buf10, length);
stat_line_printf("%s", buf10);
}
void stat_line_end()
{
int c, d;
if(stat_line != NULL && strcmp(prev_stat_line, stat_line)) { // status line changed
stat_line_cursor_remove();
#ifdef DEBUG31
fprintf(stderr, "\n");
#else
fprintf(stderr, "\r");
#endif
fprintf(stderr,"%s", stat_line);
fflush(stderr);
// previous line longer than this one,
// overwrite with spaces and backspace to
// end
d = strlen(prev_stat_line) - strlen(stat_line) + 1; // cursor too
if(d > 0) { // previous line longer
for(c = 0; c < d; c++) {
#ifdef DEBUG31
fprintf(stderr, "*");
#else
fprintf(stderr, " "); // print spaces
#endif
}
#ifndef DEBUG31
for(c = 0; c < d; c++)
fprintf(stderr, "\b"); // and backspaces
#endif
}
strcpy(prev_stat_line, stat_line);
if(strlen(stat_line) > 0)
stat_line_cursor_start();
}
}
sample() rutiini eli tiedoston muodostaminen satunnaisbiteistä sai myös uudelleenkirjoitusta. Aiemmin koodissa oli kaikkia clim ja dlim muuttujia, uudessa versiossa on vain tiedoston pituus merkkeinä ja blokin koko. Lisäksi aiemmat cursor_remove ja cursor_start rutiinit on poistettu niiden stat_line rutiiniin lisäämisen takia. Tiedoston nimeen on lisätty sarjanumero, joten sample ei poista aiempia tuloksia. Pilkkujen käyttöä tilarivissä on muutettu. Dieharder-satunnaislukuanalyysin voi myös ajaa automaattisesti sample ajon jälkeen. (–dieharder komentorivitoiminto). Die tulee ilmeisesti sanasta noppa.. Sample rutiinissa on ajon aikainen tilarivi, siinä on esimerkki aiempien rutiinien käytöstä.
static int sample = 0, dieharder = 0; // randomness analysis
// try randomness analysis with: $ dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder
#include <signal.h>
typedef void (*sighandler_t)(int);
void sample_handler()
{
static int times = 0;
times++;
fprintf(stderr,"Ctrl-c pressed %d times\n", times);
if(times >= 10) {
signal(SIGINT, SIG_DFL);
exit(1);
}
}
#define DEBUG39
#define FILESIZE 1 * 1024 * 1024 * 1024
#define BLOCKSIZE 128 * 1024
#define BLOCKS 8 * 1024
unsigned long long filesize = FILESIZE, blocks = BLOCKS;
unsigned int blocksize = BLOCKSIZE;
int filesize_set = 0, blocks_set = 0, blocksize_set = 0;
void dump_sample() // & dieharder analysis
{
#define STAT_LINE_SHOW_BLOCK 2 // on by default
#define STAT_LINE_SHOW_WRITTEN 2 // on by default
#define STAT_LINE_SHOW_SPEED 2 // on by default
#define STAT_LINE_SHOW_NOW 2 // on by default
#define STAT_LINE_SHOW_LEFT 2 // on by default
#define STAT_LINE_SHOW_READY 2 // on by default
#define STAT_LINE_LESS_WOBBLE 2 // on by default
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
unsigned long long c;
unsigned char *buffer, filename[128], command[1024];
FILE *fp1;
// find first available filename,
// or empty "fileslot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, samplefilename, c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
unsigned char filename2[138];
sprintf(filename2,"%s.dieharder",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef SAMPLE_HASH
sprintf(filename2,"%s.sha256",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
// calculate missing file size parameters
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks; // round up
filesize = blocks * blocksize;
} else if(!blocks_set) {
blocks = (filesize + blocksize - 1)/ blocksize; // round up
filesize = blocks * blocksize;
}
#define aEXFAT_FIX 2 // on for now
#ifdef EXFAT_FIX
if(blocksize > KILO * KILO) { // max "blocksize" 1m (exfat)
blocksize = KILO * KILO;
blocks = (filesize + blocksize - 1) / blocksize;
filesize = blocks * blocksize;
}
#endif
if(filesize != blocks * blocksize ||
blocks < 1 || blocksize < 1) {
fflush(stdout);
fprintf(stderr,"%s: sample(): mismatched parameters", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / blocks != blocksize) {
fflush(stdout);
fprintf(stderr,"%s: sample(): parameter overflow", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG39
fprintf(stderr,"blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
if((buffer = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: sample(): cannot allocate memory (buffer)\n", procname);
exit(1);
}
#define DEBUG40 2 // default on (for now)
#ifdef DEBUG40
fprintf(stderr,"%s: sample(): writing file", procname);
fprintf(stderr,", filename:%s", filename);
#ifndef SAMPLE_WRITE
fprintf(stderr,", no write");
#endif
fprintf(stderr,"\n");
#endif
#ifdef SAMPLE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // calculate hash
#endif
// variables for stat line fields
time_t start, now, left, end;
unsigned char speed[10], printspeed[10] = "";
#ifdef STAT_LINE_LESS_WOBBLE
time_t prevend = -1;
int countspeed = 0, countend = 0;
unsigned char prevspeed[10] = "";
unsigned int calculateleft;
#endif
time_t printleft = -1, printend = -1;
int leftprinted = 0;
if((fp1 = fopen(filename, "a")) != NULL) {
// starting time
start = time(NULL);
unsigned long long clim = (unsigned long long) filesize / blocksize;
#ifdef EXFAT_FIX
int mbinblocks = (1 * KILO * KILO) / blocksize;
if(mbinblocks == 0)
mbinblocks = 1;
fprintf(stderr,"mbinblocks:%d\n", mbinblocks);
#endif
// you have to press ctrl-c 10 times
signal(SIGINT, sample_handler);
for(c = 0; c < clim; c++) {
// current time
now = time(NULL);
// estimate for ending time
end = (time_t)start + ((((double)now - start) / c) * clim);
#ifdef STAT_LINE_LESS_WOBBLE
calculateleft = 0;
if(prevend / 60 == end / 60 &&
++countend >= 30) { // 30 times same minutes --> minutes are real
printend = end;
calculateleft = 1;
} else if(prevend / 60 != end / 60) { // minutes different
prevend = end;
countend = 0;
}
#else
printend = end;
#endif
// estimate for time left
left = printend - now;
#ifdef STAT_LINE_LESS_WOBBLE
static int onlyseconds = 0;
static long long cstart, cleft;
if(onlyseconds || (left > 0 && left < 60)) {
if(!onlyseconds) {
cstart = c;
cleft = clim - c;
onlyseconds = 1;
}
left = (time_t) 60 - ((((double) c - cstart) / cleft) * 60);
}
if(calculateleft)
printleft = left;
#else
printleft = left;
#endif
// speed
if(now - start > 1.0)
stat_line_get_readable(speed, (unsigned long long)((double)c * blocksize / (now - start)) );
else
stat_line_get_readable(speed, (unsigned long long)((double)c * blocksize));
#ifdef STAT_LINE_LESS_WOBBLE
if(!strcmp(prevspeed, speed) &&
++countspeed >= 3) { // three times same speed --> speed is real
strcpy(printspeed, speed);
} else if(strcmp(prevspeed, speed)) {
strcpy(prevspeed, speed);
countspeed = 0;
}
#else
strcpy(printspeed, speed);
#endif
// print status line:
// blk 10, written 10MB, 269KB/sec, left 8 h 38 m, ready at Sat 17 Jul 2021 01:57:43 EEST, now Fri 17:19:32 EEST
stat_line_begin();
int print = 0;
#ifdef STAT_LINE_SHOW_BLOCK
stat_line_printf("%s", randomgen[input]);
// print block from 0 to 8192
stat_line_printf("block %d", c);
print = 1;
#endif
#ifdef STAT_LINE_SHOW_WRITTEN
// print written
if(print)
stat_line_printf(", ");
stat_line_printf("written ");
stat_line_readable((unsigned long)c * blocksize);
print = 1;
#endif
if(c > 0) {
#ifdef STAT_LINE_SHOW_SPEED
// print speed
if(printspeed[0] != '\0') {
if(print)
stat_line_printf(", ");
stat_line_printf("%s/sec", printspeed);
print = 1;
}
#endif
#if defined STAT_LINE_SHOW_NOW || \
defined STAT_LINE_SHOW_READY
char timebuf[128];
#endif
#ifdef STAT_LINE_SHOW_READY
char timebuf2[128];
#endif
#ifdef STAT_LINE_SHOW_NOW
// print now
if(print)
stat_line_printf(", ");
stat_line_printf("now");
strftime(timebuf, sizeof(timebuf), TIMEFORMAT2,
localtime((time_t *)&now));
stat_line_printf(" %s", timebuf);
print = 1;
#endif
#ifdef STAT_LINE_SHOW_LEFT
// print left
if(printleft > 0) {
unsigned long int left2;
unsigned long int temp;
int timeprinted = 0;
if(print)
stat_line_printf(", ");
left2 = printleft;
stat_line_printf("left");
temp = left2 / (24 * 3600); // days
if(temp > 0) {
timeprinted = 1;
stat_line_printf(" %dd", temp);
left2 -= temp * (24 * 3600);
}
temp = left2 / 3600; // hours
if(temp > 0 || timeprinted) {
timeprinted = 1;
//hoursprinted = 1;
stat_line_printf(" %02dh", temp);
left2 -= temp * 3600;
}
temp = left2 / 60; // minutes
if(temp > 0 || timeprinted) {
timeprinted = 1;
stat_line_printf(" %02dm", temp);
left2 -= temp * 60;
}
temp = left2; // seconds
if(!timeprinted) {
stat_line_printf(" %d seconds", temp);
}
leftprinted = 1;
print = 1;
}
#endif
#ifdef STAT_LINE_SHOW_READY
//unsigned long int end = (int)start + ((((double)now - start) / c) * clim);
if(printend > 0 && leftprinted) {
if(print)
stat_line_printf(", ");
stat_line_printf("ready at");
strftime(timebuf, sizeof(timebuf), DATEFORMAT,
localtime((time_t *) & end));
strftime(timebuf2, sizeof(timebuf2), DATEFORMAT,
localtime((time_t *) & now));
if(strcmp(timebuf, timebuf2)) {
stat_line_printf(" %s", timebuf);
}
// print end time
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *) & printend));
stat_line_printf(" %s", timebuf);
print = 1;
}
#endif
}
stat_line_end();
stat_line_cursor_start();
// do the work
stat_line_cursor();
memset(buffer, 0, blocksize);
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(blocksize, buffer);
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(blocksize, buffer);
else if(input == INPUT_FASTRESSU) // ressu fast
ressu_genbytes_fast(blocksize, buffer);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(blocksize, buffer);
else if(input == INPUT_STREAM) // ressu stream
stream_bytes(blocksize, buffer);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(blocksize, buffer);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(blocksize, buffer);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(blocksize, buffer);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(blocksize, buffer);
#endif
else if(input == INPUT_URANDOM) // urandom
readfile_xor(blocksize, buffer, urandomfilename);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
readfile_xor(blocksize, buffer, randomfilename);
#endif
#ifdef USE_DUMMY
else if(input == INPUT_DUMMY) {
// no generator
}
#endif
else {
fprintf(stdout,"\n%s: mode '%d'(%s) not available\n",
procname, input, randomgen[input]);
exit(2);
}
#ifdef SAMPLE_HASH
HashUpdate(&hash, buffer, blocksize); // calculate hash
#endif
#ifdef SAMPLE_WRITE
if(input != INPUT_DUMMY) {
fwrite(buffer, 1, blocksize, fp1);
#ifdef SAMPLE_SYNC
#ifdef EXFAT_FIX
if(c % mbinblocks == 0) { // fflush and sync (EXFAT)
fflush(fp1);
sync();
//fprintf(stderr,"*\n");
}
#endif
#endif
} // end of if(input != INPUT_DUMMY
#endif
} // end of for(c = 0; c < clim; c++
#ifdef SAMPLE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fflush(fp1); // fflush and sync (EXFAT)
sync();
fclose(fp1);
} else { // if((fp1=fopen
fprintf(stderr,"%s:", procname);
fprintf(stderr," sample(): cannot open file");
fprintf(stderr,", filename: %s", filename);
fprintf(stderr,"\n");
exit(2);
}
// remove last status line
stat_line_cursor_remove();
stat_line_begin();
stat_line_printf("\rwrote ");
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf(", ");
if(now - start >= 1.0)
stat_line_readable((unsigned long)((double)c * blocksize / (now - start)) );
else
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf("/sec");
stat_line_printf(", done!");
stat_line_end();
stat_line_cursor_remove();
fprintf(stdout,"\n");
fflush(stdout);
#ifdef SAMPLE_HASH
unsigned char filename2[138];
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,"%s: sample(): hashing file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,", hashfilename:%s", filename2);
fprintf(stderr,", sha256:%s\n", hashstring);
if((fp1 = fopen(filename2, "a")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
fprintf(stderr,"%s: sample(): checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
sprintf(command,"sha256sum %s", filename);
system(command);
#endif
signal(SIGINT, SIG_DFL);
free(buffer);
if(dieharder) { // randomness analysis
sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder 2>&1", filename, filename);
//sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder", filename, filename);
fprintf(stderr,"%s: sample(): running dieharder \"%s\"\n", procname, command);
system(command);
sprintf(command,"grep \"WEAK\\|FAILED\" %s.dieharder", filename);
fprintf(stderr,"%s: sample(): grepping diehard problems \"%s\"\n", procname, command);
system(command);
sprintf(command,"grep rewound %s.dieharder | tail -n1", filename);
fprintf(stderr,"%s: sample(): grepping last rewound count \"%s\"\n", procname, command);
system(command);
exit(0);
}
}
Seuraavassa ajetaan sample() ja –dieharder analyysi: Dieharder on antanut yleensä muutamia WEAK:keja:
$ ./newressu --single --sample --dieharder
./newressu: sample: writing file, filename:newressusample1.rnd
wrote 16.0GB, 4.1MB/sec, done!
./newressu: dieharder: running dieharder "dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder"
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 10 times
# The file file_input_raw was rewound 11 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 13 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
$ fgrep WEAK newressusample1.rnd.dieharder
rgb_lagged_sum| 18| 1000000| 100|0.99605238| WEAK
media$ fgrep FAILED newressusample1.rnd.dieharder
media$
Edellisessä ajossakin tuli pari heikosti suoriuduttua riviä.
Poistettu ./newressu –sample –dieharder ohjelmasta nuo aiemman esimerkin “The file” rivit ja listattu grepillä loppuun –dieharder:in ongelmat:
Bugivälike: Tästä raportista tuli varsinainen bugiraportti, ensin ressussa löytyi tuo +2 ongelma, sitten ongelmia usb levyn kanssa (talletettu tiedosto ei ollut fixed length). Näistä +2 bugi sai korjauksen, joten jäljelle jäi usb ongelma. Kokeilin ajaa –sample –dieharderin usb levyllä, ja se meni läpi ihan ok: tällä kertaa yksi WEAK:ki. Huomaa myös että ajo on tehty –single moodilla..
media$ ./newressu --single --sample --dieharder
./newressu: sample: writing file, filename:newressusample1.rnd
wrote 16.0GB, 4.1MB/sec, done!
./newressu: dieharder: running dieharder "dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder"
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 1 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 2 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 3 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 4 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 5 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 6 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 7 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 8 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 9 times
# The file file_input_raw was rewound 10 times
# The file file_input_raw was rewound 11 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 12 times
# The file file_input_raw was rewound 13 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
# The file file_input_raw was rewound 14 times
media$ fgrep WEAK newressusample1.rnd.dieharder
rgb_lagged_sum| 18| 1000000| 100|0.99605238| WEAK
media$ fgrep FAILED newressusample1.rnd.dieharder
media$
.rnd tiedostossa oli myös oikea koko. Itse käytän usb levyjä koko ajan ja ajattelinkin ihmetellä sitä vielä hetken.. Sample():n tulos on tietysti jatkuva tiedosto, joten muutoksia siinä ei näe. Lisättyä tietoa ei ilmeisesti (koon perusteella) ole.
Tässä vielä tuloste uusimmasta –sample versiosta, joka ei tulosta aiempia “The file” -rivejä vaan vain FAIL ja WEAK rivit ja useammista tiedoston läpikäynneistä. Seuraavassa listauksessa materiaali on käyty läpi 229m kertaa ja löytyi 1 WEAK:ki. Ainakin osa weakeista aiheutuu mielestäni liian pienestä materiaalista. Huomaa myös että tässä on käytetty –single toimintoa.
$ ./newressu --single --sample --dieharder --filesize1g
string:'1g', base:10(10B), multiplier:1073741824(1G), prevll:1(1B), ll:1073741824(1G), totll:1073741824(1G)
blocksize:131072(128K), blocks:8192(8K), filesize:1073741824(1G)
./newressu: sample(): writing file, filename:newressusample432.rnd
wrote 1.00GB, 4.67MB/sec, done!
./newressu: sample(): hashing file, filename:newressusample432.rnd, hashfilename:newressusample432.rnd.sha256, sha256:c9b1f180f9c72d2549ed29d7b4c62106192efb04a199e9344feef46376923a1d
./newressu: sample(): checking sha256, filename:newressusample432.rnd
c9b1f180f9c72d2549ed29d7b4c62106192efb04a199e9344feef46376923a1d newressusample432.rnd
./newressu: sample(): running dieharder "dieharder -a -g 201 -f newressusample432.rnd > newressusample432.rnd.dieharder 2>&1"
./newressu: sample(): grepping diehard problems "grep "WEAK\|FAILED" newressusample432.rnd.dieharder"
sts_serial| 16| 100000| 100|0.99953101| WEAK
./newressu: sample(): grepping last rewound count "grep rewound newressusample432.rnd.dieharder | tail -n1"
# The file file_input_raw was rewound 229 times
$
Kirjoitin uuden ohjelman levynkirjoitusongelmaa varten. Se kirjoittaa levylle halutun pituisen tiedoston ja tarkistaa että tieto tuli kirjoitettua oikein. Ongelmaa varten kirjoitin merkkijonosalaus (stream cipher) tyyppisen ohjelman. Näissä tuotetaan satunnaisbittejä siten että kaikki satunnaisuus saadaan avaimesta, ja sen perusteella annetaan näennäissatunnaisia merkkejä. Näin voidaan tuottaa täysin sama satunnaismerkkejä sisältävä merkkijono kaksi kertaa, ensin kirjoittamiseen ja sitten tarkistukseen. Tässä aluksi tuo merkkijonosalaus:
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2 // default is on
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 secure, more than one faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", sizeof(streamt), streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
}
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
//dumpline(stderr, sizeof(key), strlen(key));
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
Edellisessä ohjelmassa avaimen käsittely stream_open:issa on aika lähellä käyttäjäsalasanan salakirjoitusta. Siinä tehtävät useammat kierrokset (tässä 1024) vaikuttavat toisaalta siihen kuinka nopeasti käyttäjän lokkaantuminen toimii, ja toisaalta siihen kuinka nopeasti hyökkääjä voi kokeilla sanalistansa sanoja. Tietysti vielä tarvitaan mukaan satunnainen salt. Salthan on satunnainen merkkijono, joka talletetaan selväkielisenä salakirjoitetun salasanan kanssa ja sitä käytetään lisänä salasanan salakirjoitetuksessa. Salt varmistaa että sama salasana ei ole aina sama salakirjoitettuna. Tietenkin hyökkääjä tarvitsee tätä hyökkäystä varten salasanan salakirjoitettuna.
Tiedostonkirjoitustestiohjelma tekee tälläisen tulosteen: ajossa merkkijonosalauksen merkkijono (tai avain tai salasana) on tässä “kalakala”. (merkkijonosalauksista lisää hakusanoilla “stream cipher”)
Ensimmäisellä kierroksella kirjoitetaan ja varmistetaan tiedosto. Varmistuksessa (–verify) kirjoitettu tiedosto luetaan uudestaan ja verrataan välittömästi. Tiedostosta lasketaan tiiviste (hash). Tiivisteitä voidaan vertailla “hashing file” -rivillä ja “checking sha256” jälkeisellä rivillä. Voit tietysti tarkastaa hashin myös $ sha256sum newressutest10.106.rnd komennolla (vaihda tiedoston nimi).
Toisella kierroksella luetaan tiedosto ja vertaillaan taas “kalakala” salasanalla saatuun merkkijonoon. Exfat:in aiemmat ongelmat saa pois lisäämällä –sync ja –flush optiot. Minulle jäi kuitenkin tutina että exfat:issa on vielä joku muu ongelma. Jos haluat ihmetellä tätä voit ajaa newressutest10, newressutest ja newressu –sample ohjelmaa itse. (en varmaan ole aiemmin sanonut tätä mutta ajamasi ohjelmat tietysti pitää tarkistaa että ne tekevät suurinpiirtein mitä sanovat, ja että niissä ei ole haitallista materiaalia). Jos ajat ohjelmia exfat levyllä ja jätät –sync ja –flush optiot pois tulee erilaisia virheilmoituksia. Mielestäni ongelmat esiintyvät vain exfat:issa suuremmilla tiedostoilla (>128g). Tavallisilla levyillä en ole niitä havainnut.
Jos käytät –verify optiota, se tarvitsee myös –flush option.
$ ./newressutest10 --bytes1g --flush --verify --sync
bytes:1073741824(0x40000000)
filename:newressutest10.106.rnd
mbinblocks:1024
./newressutest10: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write and verify done.
./newressutest10: sample: hashing file, filename:newressutest10.106.rnd, hashfilename:newressutest10.106.rnd.sha256, sha256:8a8780a51695ae69c8e3d93e940583b42fbc9bd0f7fcf3513444d1c233da6629
./newressutest10: sample: checking sha256, filename:newressutest10.106.rnd
8a8780a51695ae69c8e3d93e940583b42fbc9bd0f7fcf3513444d1c233da6629 newressutest10.106.rnd
./newressutest10: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$
Seuraavassa ohjelman newressutest10 lähdekoodi: (uusi versio, jossa on muutettu merkkijonosalakirjoitusrutiineja ja comentoriviparametreja)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname;
static unsigned char *programname = "newressutest10 version 0.4 ©";
static unsigned char *copyright = "Copyright (c) 2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 1 * 1024 * 1024 * 1024
#define BLOCKSIZE 1024
#define BLOCKS FILESIZE / BLOCKSIZE
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
void dumpline(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
fprintf(fp1,"%02x", buf[c]);
}
void dump(FILE *fp1, unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(fp1,"\n");
fprintf(fp1,"%-10s", header);
}
fprintf(fp1," %02x", buf[c]);
}
fprintf(fp1,"\n");
fflush(fp1);
}
void compareblocks(FILE *fp1, int size, unsigned char *buffer, unsigned char *buffer2)
{
int c, count;
count = 0;
for(c = 0; c < size; c++) {
if(count > 31) {
fprintf(fp1,"\n");
count = 0;
}
if(buffer[c] == buffer2[c]) {
fprintf(fp1," %02x", buffer[c]);
count++;
} else {
fprintf(fp1," %02x/%02x", buffer[c], buffer2[c]);
count +=2;
}
}
}
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
}
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 --> secure, more than one --> faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", 32, streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
} // end of if(streamt_pos == 0
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stderr);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
//#define KILO 1000
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
#define DEBUG32
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", ll: %llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", multiplier: %llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x",final[c]);
}
}
#endif
unsigned char filename[128] = "";
void check_firstblock()
{
int count;
FILE *fp1;
static unsigned char *block = NULL;
static unsigned char *check_block = NULL;
if(block == NULL) {
if((block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for block\n", procname);
fflush(stderr);
exit(1);
}
}
if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot fopen file\n", procname);
fflush(stderr);
exit(1);
}
count = fread(block, 1, BLOCKSIZE, fp1);
fclose(fp1);
if(count < BLOCKSIZE) { // not a full block
return;
} else if(check_block == NULL) {
if((check_block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for check_block\n", procname);
fflush(stderr);
exit(1);
}
memcpy(check_block, block, BLOCKSIZE);
dump(stderr, "block1", BLOCKSIZE, block, 32);
} else {
if(memcmp(block, check_block, BLOCKSIZE)) {
fprintf(stderr,"%s: check_firstblock(): first block changed\n", procname);
dump(stderr, "block", BLOCKSIZE, block, 32);
exit(1);
}
}
}
#define KILO 1024
#define aDEBUG65 2
#define DEBUG68
int main(int argc, char *argv[])
{
int c, percentageline = 1, blocksize_set = 0, blocks_set = 0, filesize_set = 0;
unsigned long long ll, lllim, blocks = BLOCKS, filesize = FILESIZE;
unsigned int blocksize = BLOCKSIZE;
int errcount = 0, pros, prevpros, help = 0, stdoutflag = 0;
int writeflag = 1, verifyflag = 0, flushflag = 0, syncflag = 0, checkflag = 1, block1flag = 0;
unsigned char *buffer, *buffer2;
unsigned char key[128] = "kalakala";
FILE *fp1, *fp2;
procname = argv[0];
#define aDEBUG46
#ifdef DEBUG46
stream_open(0, "⚀⚁⚂⚃⚄⚅"); // utf8
stream_open(0, "Hasta la vista, baby (Arnold Schwarzenegger, T2)"); // pass phrase
stream_open(0, "abcdefghijklmnopqrstuvwxyz" // long password (key)
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz");
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) {// last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(!strncmp("-",argv[c], 1)) {
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--write", argv[c])) {
writeflag = !writeflag;
} else if(!strcmp("--verify", argv[c])) {
verifyflag = !verifyflag;
} else if(!strcmp("--flush", argv[c])) {
flushflag = !flushflag;
} else if(!strcmp("--sync", argv[c])) {
syncflag = !syncflag;
} else if(!strcmp("--check", argv[c])) {
checkflag = !checkflag;
} else if(!strcmp("--block1", argv[c])) {
block1flag = !block1flag;
} else if(!strncmp("--key", argv[c], 5)) {
if(*(argv[c] + 5) != '\0') {
strcpy(key, argv[c] + 5);
} else if(c + 1 < argc) {
strcpy(key, argv[c + 1]);
c++;
}
fprintf(stderr,"key:%s", key);
fprintf(stderr,"\n");
fflush(stderr);
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--blocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
blocksize = getlonglong(argv[c] + 11);
} else if(c + 1 < argc) {
blocksize = getlonglong(argv[c + 1]);
c++;
}
blocksize_set = 1;
} else if(!strncmp("--blocks", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
blocks = getlonglong(argv[c] + 8);
} else if(c + 1 < argc) {
blocks = getlonglong(argv[c + 1]);
c++;
}
blocks_set = 1;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
}
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocks_set) {
blocks = (filesize + blocksize - 1) / blocksize; // round up
filesize = blocks * blocksize;
} else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks; // round up
filesize = blocks * blocksize;
}
#define EXFAT_FIX 2 // on for now
#ifdef EXFAT_FIX
if(blocksize > KILO * KILO) { // max "blocksize" 1m (exfat)
blocksize = KILO * KILO;
blocks = (filesize + blocksize - 1) / blocksize;
filesize = blocks * blocksize;
}
#endif
if(filesize != blocks * blocksize ||
blocks < 1 || blocksize < 1) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / blocks != blocksize) { // overflow too
fflush(stdout);
fprintf(stderr,"%s: parameter overflow", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG68
fprintf(stderr,"blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [-o filename]");
fprintf(stderr," [--stdout]");
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr," [--blocksize base-number-multiplier]");
fprintf(stderr,"\n\t[--blocks base-number-multiplier]");
fprintf(stderr,"\n\t");
fprintf(stderr,"[--write]");
fprintf(stderr," [--verify]");
fprintf(stderr," [--flush]");
fprintf(stderr," [--sync]");
fprintf(stderr," [--check]");
fprintf(stderr," [--block1]");
fprintf(stderr,"\n");
fprintf(stderr,"Options:\n");
fprintf(stderr,"\tWrite and check are on.\n");
fprintf(stderr,"\tVerify, flush, sync and block1 are off.\n");
fprintf(stderr,"\tOptions turn switch, so single --write means write off.");
fprintf(stderr,"\n\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\n");
fprintf(stderr,"Typical use:\n");
fprintf(stderr,"\t$ %s --filesize 128g (for regular drives)\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --flush --sync (for exfat)\n", procname);
fprintf(stderr,"\n");
fprintf(stderr,"Other use:\n");
fprintf(stderr,"\t$ %s --filesize 1g\n", procname);
fprintf(stderr,"\t$ %s --filesize 8g --verify\n", procname);
fprintf(stderr,"\t$ %s --filesize 64g --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --filesize 128g --verify --flush --sync --block1\n", procname);
fprintf(stderr,"\t$ %s -o newressutest10.1.rnd --write --filesize 128g\n", procname);
exit(1);
} // end of if(help)
#define aDEBUG52
#ifdef DEBUG52
unsigned char buffer128[128];
stream_open(0, key);
stream_bytes(sizeof(buffer128), buffer128);
dump(stderr, "stream", sizeof(buffer128), buffer128, 32);
#endif
if((buffer = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
if((buffer2 = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer2)\n", procname);
exit(1);
}
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest10.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
percentageline = 0;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-");
else
fprintf(stderr,"filename:%s",filename);
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if(writeflag) {
if(stdoutflag == 1)
fp1 = stdout;
else if((fp1 = fopen(filename, "w")) == NULL) { // created datafile
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
if(verifyflag) {
if((fp2 = fopen(filename, "r")) == NULL) { // for verify file
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
verifyflag = 0;
}
}
#ifdef EXFAT_FIX
int mbinblocks = (1 * KILO * KILO) / blocksize;
if(mbinblocks == 0)
mbinblocks = 1;
fprintf(stderr,"mbinblocks:%d\n", mbinblocks);
#endif
prevpros = -1;
stream_open(0, key);
lllim = (long long) filesize / blocksize;
for(ll = 0; ll < lllim; ll++) {
stream_bytes(blocksize, buffer);
#ifdef DEBUG65
fprintf(stderr,"buffer ");
dumpline(stderr, 32, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
#ifdef FILE_HASH
HashUpdate(&hash, buffer, blocksize); // calculate hash
#endif
if(fwrite(buffer, 1, blocksize, fp1) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
int flushed = 0;
#ifdef EXFAT_FIX
if(syncflag && (ll % mbinblocks == 0)) { // sync every 1m
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
sync();
//fsync(fileno(fp1));
}
#else
if(syncflag) { // sync every 1m
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
sync();
//fsync(fileno(fp1));
}
#endif
if(verifyflag) {
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
if(fread(buffer2, 1, blocksize, fp2) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fprintf(stderr,"buffer2 ");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, blocksize)) {
fflush(stderr);
fprintf(stderr,"%s: verify error", procname);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * BLOCKSIZE, ll * BLOCKSIZE);
fprintf(stderr,", is:");
dumpline(stderr, 16, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, 16, buffer);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
} // end of if(verifyflag)
if(block1flag)
check_firstblock();
if(percentageline) {
pros = (int)((double) ll / lllim * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
}
} // end of for(ll = 0; ll < lllim; ll++)
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
if(syncflag) {
fflush(fp1);
sync();
}
if(!stdoutflag)
fclose(fp1);
if(syncflag) {
sync();
}
if(verifyflag)
fclose(fp2);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," write");
if(verifyflag)
fprintf(stderr," and verify");
fprintf(stderr," done.");
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
}
fprintf(stderr,", sha256:%s\n", hashstring);
if(filename[0] != '\0') {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
} // if(writeflag)
if(!stdoutflag && checkflag) {
if((fp2 = fopen(filename, "r")) != NULL) { // for reread
prevpros = -1;
lllim = (long long) filesize / blocksize;
stream_open(0, key);
for(ll = 0; ll < lllim; ll++) {
stream_bytes(blocksize, buffer);
if(fread(buffer2, 1, blocksize, fp2) < blocksize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fflush(stdout);
fprintf(stderr,"bbuffer ");
dumpline(stderr, 32, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fprintf(stderr,"bbuffer2 ");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, blocksize)) {
fflush(stdout);
fprintf(stderr,"%s: check error", procname);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llu)", ll * BLOCKSIZE, ll * BLOCKSIZE);
fprintf(stderr,", data:");
dumpline(stderr, 32, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, 32, buffer);
fprintf(stderr,"\n");
compareblocks(stderr, blocksize, buffer, buffer2);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lllim * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lllim; ll++)
fclose(fp2);
fflush(stdout);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," read and compare");
fprintf(stderr," done.");
fprintf(stderr,"\n");
} // end of if((fp2 = fopen(filename, "r")) != NULL)
} // end of if(checkflag)
}
Myös joihinkin postin aiempiin testailuohjelmiin (newressutest9 ja newressutest) on lisätty flush ja sync, päivitän niiden versiot tässä postissa uudempiin.
Lisätty uusi testiohjelma newressutest12, joka kirjoittaa ja lukee kiinteänpituisia tietueita. Tässä ohjelman tuloste: Tässä tulostetaan 1048576 (1m) riviä jotka sisältävät 10 merkkiä tietoa. Rivit tulostetaan heksajonona, joten yksi tulostettava rivi on 10 * 2 + 1 = 21 merkkiä pitkä. Tiedostosta tulee 1m * 21 = 21m kokoinen. Tässä tiedosto on kirjoitettu ja varmistettu (vaihe 1) ja luettu ja tarkistettu (vaihe 2). Muista lisätä –flush ja –sync exfat levyille.
$ ./newressutest12 --bytes10 --lines1m --verify --flush
base:10, multiplier:1, prevll:10, ll:10, totll:10
base:10, multiplier:1048576, prevll:1, ll:1048576, totll:1048576
lines:1048576(1M), bytes:10(10B), linesize:21(21B), filesize:22020096(21M)
filename:newressutest12.108.rnd
mbinlines:49932
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write and verify done.
./newressutest12: sample: hashing file, filename:newressutest12.108.rnd, hashfilename:newressutest12.108.rnd.sha256, sha256:a328ce8d2c4d98bb4ebf8ee3f8ac6d79e561722105789ceea68ae8837b974072
./newressutest12: sample: checking sha256, filename:newressutest12.108.rnd
a328ce8d2c4d98bb4ebf8ee3f8ac6d79e561722105789ceea68ae8837b974072 newressutest12.108.rnd
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$
Seuraavassa pätkä tulostettua tiedostoa: Tässä on tulostettu 10 merkin pituisia tietueita 10 kappaletta.
$ ./newressutest12 --bytes10 --lines10
base:10, multiplier:1, prevll:10, ll:10, totll:10
base:10, multiplier:1, prevll:10, ll:10, totll:10
lines:10(10B), bytes:10(10B), linesize:21(21B), filesize:210(210B)
filename:newressutest12.109.rnd
mbinlines:49932
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write done.
./newressutest12: sample: hashing file, filename:newressutest12.109.rnd, hashfilename:newressutest12.109.rnd.sha256, sha256:d57ad8172aa54ba800829370a98a241a19777aa6759401e6ff8b5577fcae7729
./newressutest12: sample: checking sha256, filename:newressutest12.109.rnd
d57ad8172aa54ba800829370a98a241a19777aa6759401e6ff8b5577fcae7729 newressutest12.109.rnd
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% read and compare done.
$ cat newressutest12.109.rnd
c0d1bc849d6fbb01fe79
507f611bfb4b0f739177
f574c12575e932b44ae3
29c32527df32c830651d
eb4880d6183b3cf1b3c2
a8dd883ba01e469d575c
cd8686453516ecf6251f
82adacdc30d74b31560a
7ccc5e834de655424463
c1e0bf91dd1c2ff14998
$
Seuraavalla voi testata piipun (‘|’) toimivuutta: datasta lasketun tiivisteen pitää mätsätä $sha256sum komennon tulostaman tiivisteen kanssa (c255de-alkuinen merkkijono).
$ ./newressutest12 --bytes16 --lines40g --stdout | sha256sum
string:'16', base:10, multiplier:1, prevll:16, ll:16, totll:16
string:'40g', base:10, multiplier:1073741824, prevll:40, ll:42949672960, totll:42949672960
lines:42949672960(40G), bytes:16(16B), linesize:33(33B), filesize:1417339207680(~1T)
filename:
mbinlines:31775
./newressutest12: stream_open(): key:kalakala, stream_key:448cd1f8dea2f75d469e1f265cbc2658426121577335348a11c5ec7c25c07bf1
Done:100.0% write done.
./newressutest12: sample: hashing file, filename:, hashfilename:.sha256, sha256:c255de89c865c957bccc648ab7fbd9327eec338f36dfb96112ca3801fbbf2b71
c255de89c865c957bccc648ab7fbd9327eec338f36dfb96112ca3801fbbf2b71 -
$
Ja varsinainen ohjelma newressutest12.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname;
static unsigned char *programname = "newressutest12 version 0.7 ©";
static unsigned char *copyright = "Copyright (c) 2023 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 81 * 1024 * 1024
#define BINSIZE 40 // bytes per line
#define LINESIZE 81 // BINSIZE * 2 + 1
#define LINES 1 * 1024 * 1024
#define BLOCKSIZE 1024
int help = 0;
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
void dumpline(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
fprintf(fp1,"%02x", buf[c]);
}
void dump(FILE *fp1, unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(fp1,"\n");
fprintf(fp1,"%-10s", header);
}
fprintf(fp1," %02x", buf[c]);
}
fprintf(fp1,"\n");
fflush(fp1);
}
void compareblocks(FILE *fp1, int size, unsigned char *buffer, unsigned char *buffer2)
{
int c, count;
count = 0;
for(c = 0; c < size; c++) {
if(count > 31) {
fprintf(fp1,"\n");
count = 0;
}
if(buffer[c] == buffer2[c]) {
fprintf(fp1," %02x", buffer[c]);
count++;
} else {
fprintf(fp1," %02x/%02x", buffer[c], buffer2[c]);
count +=2;
}
}
}
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
}
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
#define aDEBUG8 2
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG8
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,", cvar:");
dumpline(stderr, cvarsize + 1, cvar);
fprintf(stderr,", digest:");
dumpline(stderr, HashLen, digest);
fprintf(stderr,"\n");
#endif
}
#define aDEBUG11 2
static int streamt_pos = 0;
#define STREAM_FASTER 2 // default is on
#ifdef STREAM_FASTER
static int streamt_rekey_rounds = 0;
#define STREAM_REKEY_ROUNDS 1024 // 1 secure, more than one faster
#endif
void stream_bytes(int size, unsigned char *buffer)
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next data bytes
#ifdef DEBUG11
dump(stderr, "streamt", sizeof(streamt), streamt, 32);
#endif
#ifndef STREAM_FASTER
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
#else
if(++streamt_rekey_rounds >= STREAM_REKEY_ROUNDS) {
stream_internalbytes(stream_key); // change key
#ifdef DEBUG11
dump(stderr, "rekey", 32, stream_key, 32);
#endif
streamt_rekey_rounds = 0;
}
#endif
} // end of if(streamt_pos == 0
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
#ifdef DEBUG11
dump(stderr, "buffer", size, buffer, 32);
#endif
}
#define aDEBUG19 2
#define DEBUG20 2
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
#ifdef STREAM_FASTER
streamt_rekey_rounds = 0;
#endif
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
#ifdef DEBUG19
fprintf(stderr,"prev:");
dumpline(stderr, sizeof(stream_key), stream_key);
#endif
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,", next:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#ifdef DEBUG19
fprintf(stderr,"stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
#ifdef DEBUG20
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," key:");
dumpbin(stderr, size, key);
fprintf(stderr,", stream_key:");
dumpline(stderr, sizeof(stream_key), stream_key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p)
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
//#define KILO 1000
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
#define DEBUG32 2
unsigned long long getlonglong(unsigned char *p2)
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x", final[c]);
}
}
#endif
unsigned char filename[128] = "";
void check_firstblock()
{
int count;
FILE *fp1;
static unsigned char *block = NULL;
static unsigned char *check_block = NULL;
if(block == NULL) {
if((block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for block\n", procname);
fflush(stderr);
exit(1);
}
}
if((fp1 = fopen(filename, "r")) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot fopen file\n", procname);
fflush(stderr);
exit(1);
}
count = fread(block, 1, BLOCKSIZE, fp1);
fclose(fp1);
if(count < BLOCKSIZE) { // not a full block
return;
} else if(check_block == NULL) { // read and save original block
if((check_block = malloc(BLOCKSIZE)) == NULL) {
fprintf(stderr,"%s: check_firstblock(): cannot allocate memory for check_block\n", procname);
fflush(stderr);
exit(1);
}
memcpy(check_block, block, BLOCKSIZE);
dump(stderr, "block1", BLOCKSIZE, block, 32);
} else { // compare to original block
if(memcmp(block, check_block, BLOCKSIZE)) {
fprintf(stderr,"%s: check_firstblock(): first block changed\n", procname);
dump(stderr, "block", BLOCKSIZE, block, 32);
exit(1);
}
}
}
#define aDEBUG65 2
#define DEBUG69 2
int main(int argc, char *argv[])
{
int c, percentageline = 1;
int filesize_set = 0, binsize_set = 0, linesize_set = 0, lines_set = 0;
unsigned long long ll, filesize = FILESIZE, lines = LINES;
unsigned int binsize = BINSIZE, linesize = LINESIZE;
int errcount = 0, pros, prevpros;
int writeflag = 1, stdoutflag = 0, verifyflag = 0, flushflag = 0;
int syncflag = 0, checkflag = 1, block1flag = 0;
unsigned char *binbuffer, *buffer, *buffer2;
unsigned char key[128] = "kalakala";
FILE *fp1, *fp2;
procname = argv[0];
#define aDEBUG46 2
#ifdef DEBUG46
ll = 1;
for(;;) {
fprintf(stderr,"ll:%llu", ll);
fprintf(stderr,", readablelonglong:");
readablelonglong(stderr, ll);
fprintf(stderr,"\n");
unsigned long long prevll = ll;
ll *= 2;
if(ll / 2 != prevll)
break;
}
#endif
#define aDEBUG48 2
#ifdef DEBUG48
stream_open(0, "⚀⚁⚂⚃⚄⚅"); // utf8
stream_open(0, "Hasta la vista, baby (Arnold Schwarzenegger, T2)"); // pass phrase
stream_open(0, "abcdefghijklmnopqrstuvwxyz" // long password (key)
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz");
#endif
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) { // last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(!strncmp("-",argv[c], 1)) { // option starting with hyphen
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--write", argv[c])) {
writeflag = !writeflag;
} else if(!strcmp("--verify", argv[c])) {
verifyflag = !verifyflag;
} else if(!strcmp("--flush", argv[c])) {
flushflag = !flushflag;
} else if(!strcmp("--sync", argv[c])) {
syncflag = !syncflag;
} else if(!strcmp("--check", argv[c])) {
checkflag = !checkflag;
} else if(!strcmp("--block1", argv[c])) {
block1flag = !block1flag;
} else if(!strncmp("--key", argv[c], 5)) {
if(*(argv[c] + 5) != '\0') {
strcpy(key, argv[c] + 5);
} else if(c + 1 < argc) {
strcpy(key, argv[c +1]);
}
fprintf(stderr,"key:%s", key);
fprintf(stderr,"\n");
fflush(stderr);
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--linesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
linesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
linesize = getlonglong(argv[c + 1]);
c++;
}
linesize_set = 1;
} else if(!strncmp("--lines", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
lines = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
lines = getlonglong(argv[c + 1]);
c++;
}
lines_set = 1;
} else if(!strncmp("--binsize", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
binsize = getlonglong(argv[c] + 9);
} else if(c + 1 < argc) {
binsize = getlonglong(argv[c + 1]);
c++;
}
binsize_set = 1;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
} // end of if(!strncmp("-",argv[c], 1
} // end of for(c = 1; c < argc; c++
if(!linesize_set)
linesize = binsize * 2 + 1;
else if(!binsize_set)
binsize = (linesize - 1) / 2;
if(linesize != binsize * 2 + 1 ||
linesize < 3 || binsize < 1) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(!filesize_set)
filesize = lines * linesize;
else if(!lines_set) {
lines = (filesize + linesize - 1) / linesize; // round up
filesize = lines * linesize;
} else if(!linesize_set) {
linesize = (filesize + lines - 1) / lines; // round up
filesize = lines * linesize;
}
#define aEXFAT_FIX 2
#ifdef EXFAT_FIX
if(linesize >= KILO * KILO) { // max linesize 1m (exfat)
linesize = KILO * KILO - 1;
binsize = (linesize - 1) / 2;
lines = (filesize + linesize - 1) / linesize;
filesize = lines * linesize;
}
#endif
if(filesize != lines * linesize ||
lines < 1 || linesize < 3) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / lines != linesize) { // check for overflow too
fflush(stdout);
fprintf(stderr,"%s: parameter overflow", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [-o filename]");
fprintf(stderr," [--stdout]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr," [--linesize base-number-multiplier]");
fprintf(stderr,"\n\t[--lines base-number-multiplier]");
fprintf(stderr," [--binsize base-number-multiplier]");
fprintf(stderr,"\n\t[--write]");
fprintf(stderr," [--verify]");
fprintf(stderr," [--flush]");
fprintf(stderr," [--sync]");
fprintf(stderr," [--check]");
fprintf(stderr," [--block1]");
fprintf(stderr,"\n");
fprintf(stderr,"Options:\n");
fprintf(stderr,"\tWrite and check are on.\n");
fprintf(stderr,"\tVerify, flush, sync and block1 are off.\n");
fprintf(stderr,"\tOptions turn switch, so single --write means write off.");
fprintf(stderr,"\n\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\n");
fprintf(stderr,"Typical use:\n");
fprintf(stderr,"\t$ %s --lines 128m (for regular drives)\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --flush --sync (for exfat)\n", procname);
fprintf(stderr,"\n");
fprintf(stderr,"Other use:\n");
fprintf(stderr,"\t$ %s --lines 1m\n", procname);
fprintf(stderr,"\t$ %s --lines 8m --verify\n", procname);
fprintf(stderr,"\t$ %s --lines 64m --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --verify --flush\n", procname);
fprintf(stderr,"\t$ %s --lines 128m --verify --flush --sync --block1\n", procname);
fprintf(stderr,"\t$ %s newressutest12.1.rnd --write --lines 128m\n", procname);
exit(1);
} // end of if(help)
#ifdef DEBUG69
// print filesize parameters
fprintf(stderr,"lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", binsize:%u(", binsize);
readablelonglong(stderr, binsize);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
unsigned int dumplinelength = 32;
if(dumplinelength > linesize)
dumplinelength = linesize;
if((binbuffer = malloc(binsize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (binbuffer)\n", procname);
exit(1);
}
if((buffer = malloc(linesize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
if((buffer2 = malloc(linesize)) == NULL) {
fprintf(stderr,"%s: cannot allocate memory (buffer2)\n", procname);
exit(1);
}
#define aDEBUG52
#ifdef DEBUG52
unsigned char buffer128[128];
stream_open(0, key);
stream_bytes(sizeof(buffer128), buffer128);
dump(stderr, "stream", sizeof(buffer128), buffer128, 32);
#endif
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest12.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
percentageline = 0;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-");
else
fprintf(stderr,"filename:%s",filename);
fprintf(stderr,"\n");
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if(writeflag) {
if(stdoutflag == 1)
fp1 = stdout;
else if((fp1 = fopen(filename, "w")) == NULL) { // created datafile
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
if(verifyflag) {
if((fp2 = fopen(filename, "r")) == NULL) { // for verify file
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot open file");
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
verifyflag = 0;
}
}
#ifdef EXFAT_FIX
int mbinlines = (KILO * KILO) / linesize;
if(mbinlines == 0)
mbinlines = 1;
fprintf(stderr,"mbinlines:%d\n", mbinlines);
#endif
prevpros = -1;
stream_open(0, key);
for(ll = 0; ll < lines; ll++) {
stream_bytes(binsize, binbuffer);
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", binbuffer[c]);
buffer[linesize - 1] = '\n';
#ifdef DEBUG65
fprintf(stderr,"buffer ");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
#ifdef FILE_HASH
HashUpdate(&hash, buffer, linesize); // calculate hash
#endif
if(fwrite(buffer, 1, linesize, fp1) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
int flushed = 0;
#ifdef EXFAT_FIX
if(syncflag && (ll % mbinlines == 0)) { // sync every 1m (exfat)
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
sync();
//fsync(fileno(fp1));
}
#else
if(flushflag) {
fflush(fp1);
flushed = 1;
}
if(syncflag) {
sync();
}
#endif
if(verifyflag) {
if(!flushed && flushflag) {
fflush(fp1);
flushed = 1;
}
if(fread(buffer2, 1, linesize, fp2) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fprintf(stderr,"buffer2 ");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", block:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, linesize)) {
fflush(stdout);
fprintf(stderr,"%s: verify error", procname);
fprintf(stderr,", lines:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * LINESIZE, ll * LINESIZE);
fprintf(stderr,", is:");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
} // end of if(verifyflag)
if(block1flag)
check_firstblock();
if(percentageline) {
pros = (int)((double) ll / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
}
} // end of for(ll = 0; ll < lines; ll++)
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," write");
if(verifyflag)
fprintf(stderr," and verify");
fprintf(stderr," done.");
fprintf(stderr,"\n");
fflush(stderr);
fflush(fp1);
sync();
if(!stdoutflag)
fclose(fp1);
if(verifyflag)
fclose(fp2);
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n", hashstring);
fclose(fp1);
}
}
fprintf(stderr,", sha256:%s\n", hashstring);
if(filename[0] != '\0') {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
} // if(writeflag)
if(!stdoutflag && checkflag) {
if((fp2 = fopen(filename, "r")) != NULL) { // for reread
prevpros = -1;
stream_open(0, key);
for(ll = 0; ll < lines; ll++) {
stream_bytes(binsize, binbuffer);
for(c = 0; c < binsize; c++)
sprintf(buffer + c * 2, "%02x", binbuffer[c]);
buffer[linesize - 1] = '\n';
if(fread(buffer2, 1, linesize, fp2) < linesize) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot read file");
fprintf(stderr,"\n");
exit(1);
}
#ifdef DEBUG65
fflush(stderr);
fprintf(stderr,"bbuffer ");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,"\n");
fprintf(stderr,"bbuffer2 ");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(memcmp(buffer, buffer2, linesize)) {
fflush(stdout);
fprintf(stderr,"%s: check error", procname);
fprintf(stderr,", line:%llu", ll);
fprintf(stderr,", offset:%llu(0x%llx)", ll * linesize, ll * linesize);
fprintf(stderr,", data:");
dumpline(stderr, dumplinelength, buffer2);
fprintf(stderr,", should be:");
dumpline(stderr, dumplinelength, buffer);
fprintf(stderr,"\n");
compareblocks(stderr, linesize, buffer, buffer2);
fprintf(stderr,"\n");
fflush(stderr);
if(++errcount > 9)
exit(1);
}
if(block1flag)
check_firstblock();
pros = (int)((double) ll / lines * 1000);
if(prevpros != pros) {
fflush(stdout);
prevpros = pros;
fprintf(stderr,"\rDone:%d.%d%%", pros / 10, pros % 10);
fflush(stderr);
}
} // end of for(ll = 0; ll < lllim; ll++)
fclose(fp2);
fflush(stdout);
fprintf(stderr,"\rDone:100.0%%");
fprintf(stderr," read and compare");
fprintf(stderr," done.");
fprintf(stderr,"\n");
fflush(stderr);
} // end of if((fp2 = fopen(filename, "r")) != NULL)
} // end of if(checkflag)
}
Lisätty save_path, exists_path ja set_path, joiden käytöstä voit katsoa esimerkin DEBUG72 koodista. Tässä kuitenkin vielä koodit niille:
#define DEBUG25
void save_path(int path_length, unsigned char *path)
{
if((getcwd(path, path_length)) == NULL) {
fprintf(stdout,"%s: save_path(): cannot get working directory (getcwd)\n",
procname);
}
#ifdef DEBUG25
fprintf(stdout,"%s: save_path(): saved current path (getcwd), path = %s\n",
procname,path);
#endif
}
int exists_path(unsigned char *path)
{
FILE *fp1;
if((fp1 = fopen(path,"r")) != NULL) {
fclose(fp1);
return(1);
} else
return(0);
}
void set_path(unsigned char *path)
{
if(chdir(path) != 0) {
fprintf(stdout,"%s: set_path(): cannot change directory (chdir())\n",
procname);
}
#ifdef DEBUG25
fprintf(stdout,"%s: set_path(): set path (chdir()), path = %s\n",
procname,path);
#endif
}
Ja vielä esimerkki käytöstä:
#ifdef DEBUG72
if(flagint) {
unsigned char savepath[128] = "./";
//fprintf(stderr,"%s: Running integrity test(s)...", procname);
fflush(stderr);
save_path(sizeof(savepath), savepath);
if(!strncmp(procname, "/bin/newressu", 13) && exists_path("/var/ressu")) {
set_path("/var/ressu");
fprintf(stderr,"%s: procname '/bin/newressu', path exists '%s', path set\n",
procname, "/var/ressu");
fflush(stderr);
} else if(exists_path("/var/ressu")) {
set_path("/var/ressu");
fprintf(stderr,"%s: path exists '%s', set\n",
procname,"/var/ressu");
fflush(stderr);
} else if(exists_path("/var/newressu")) {
set_path("/var/newressu");
fprintf(stderr,"%s: path exists '%s', set\n",
procname,"/var/newressu");
fflush(stderr);
} else if(exists_path("dkala")) {
set_path("dkala");
fprintf(stderr,"%s: path exists '%s', set\n",
procname, "./dkala");
fflush(stderr);
} else if(exists_path(".ressu")) {
set_path(".ressu");
fprintf(stderr,"%s: path exists '%s', set\n",
procname, ".ressu");
fflush(stderr);
} else if(exists_path("./")) {
set_path("./");
fprintf(stderr,"%s: path exists '%s', set\n",
procname, "./");
fflush(stderr);
} else {
set_path("./");
fprintf(stderr,"%s: path set '%s'\n",
procname, "./");
fflush(stderr);
}
unsigned char command[160], date[16], filename[64];
command_readline("date +%Y%m%d%H", sizeof(date), date);
//command_readline("date +%Y%m%d%H%M", sizeof(date), date);
fprintf(stdout,"readline date '%s'\n",date);
sprintf(filename,"newressutest14.rnd.%s",date);
if(!exists_path(filename)) {
sprintf(command,"./newressutest14.sh >%s",filename);
system(command);
}
//fprintf(stderr," done.\n");
fflush(stderr);
set_path(savepath);
}
#endif
Aloitin uuden ohjelman, jolla voi hakea terttu (tai sakki) muotoisesta tiedostosta haluamillaan avaimilla. Tätä voi käyttää esimerkiksi palvelimen lokin valikoituun tulostukseen.
Lisätty uuteen terttuutil1 ohjelmaan pätkä, joka parsii komentomerkkijonon, ja muodostaa siitä terttu-yhteensopivan kyselyn: esimerkkejä input kyselystä ‘a,b’, ‘a=1,b’ ‘a,b,c’ näistä tehdään terttu muotoinen kysely ‘a’, ‘b’ tai ‘a’ = “1”, ‘b’ tai ‘a’, ‘b’, ‘c’ jne.
#define aDEBUG59 2
int db6_parsequery(int querylen, unsigned char *query, unsigned char *command)
{
unsigned char *token, *p, *q;
int mode = 0, copymode = 0, count, valuetoo, exitcount = 0;
p = command;
q = query;
mode = 20;
count = 0;
while(*p != '\0') {
unsigned char *prevp = NULL;
unsigned char *prevq = NULL;
prevp = p;
prevq = q;
if(count < querylen)
*q = '\0';
switch(mode) {
case 10:
token = " ";
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
mode = 20;
case 20:
token = "'";
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
copymode = 0; // 0 = isalpha, 1 = within quotes
db5_skipwhite(&p);
if(*p == '\'') { // skip possible first quote
copymode = 1;
p++;
//db5_skipwhite(&p);
}
token = " "; // placeholder for one character
while((copymode == 0 && *p != ' ' && *p != ',' && *p != '=' && *p != '\0') ||
(copymode == 1 && *p != '\'' && *p != '\0')) {
if(count + strlen(token) < querylen) {
*q++ = *p;
*q = '\0';
}
p++;
count++;
}
if(copymode) { // skip possible second quote
if(*p == '\'') {
p++;
}
db5_skipwhite(&p); // skip space after quote
}
token = "'"; // add single quote to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
mode = 30;
break;
case 30:
valuetoo = 0;
db5_skipwhite(&p);
if(*p == '=') { // skip possible equals sign
p++;
db5_skipwhite(&p);
valuetoo = 1;
}
if(*p == '"')
valuetoo = 1;
if(isalpha(*p) || isdigit(*p) || *p == '_')
valuetoo = 1;
if(valuetoo) {
token = " = \""; // add equals to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
copymode = 0; // 0 = isalpha, 1 = within quotes
db5_skipwhite(&p);
if(*p == '"') { // skip possible first quote
copymode = 1;
p++;
//db5_skipwhite(&p); // no skipwhite after first quote
}
token = " ";
while((copymode == 0 && *p != ' ' && *p != ',' && *p != '\0') ||
(copymode == 1 && *p != '"' && *p != '\0')) {
if(count + strlen(token) < querylen) {
*q++ = *p;
*q = '\0';
}
p++;
count++;
}
if(copymode) { // skip possible second quote
//db5_skipwhite(&p); // no skipwhite before second quote
if(*p == '\"')
p++;
db5_skipwhite(&p); // skip space after quote
}
token = "\""; // add quote to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
} // if(valuetoo
mode = 40;
break;
case 40:
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
}
token = ","; // add comma to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(token);
}
count += strlen(token);
mode = 10;
break;
}
#ifdef DEBUG59
fprintf(stderr,"command:`%s`", p);
fprintf(stderr,", query:`%s`", query);
fprintf(stderr,", mode:%d", mode);
fprintf(stderr,"\n");
#endif
if(*p == '\0')
break;
if(prevp == p && prevq == q) {
fprintf(stderr,"%s: illegal character '", procname);
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", mode:%d", mode);
fprintf(stderr,"\n");
fflush(stderr);
if(++ exitcount == 10) {
break;
}
}
}
return(count);
}
Lisätty koodi, joka sivuttaa tulostetta sivuittain:
#include <termios.h>
struct termios old, new;
void startprompt()
{
setvbuf(stdout, NULL, _IONBF, 0);
tcgetattr(0, &old);
new = old;
new.c_lflag &= ~(ICANON | ECHO);
//new.c_lflag &= ~(ISIG | ICANON | ECHO);
new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 2;
tcsetattr(0, TCSANOW, &new);
}
void endprompt()
{
tcsetattr(0, TCSANOW, &old);
}
void util_backspacechars(int chars)
{
int c;
for(c = 0; c < chars; c++)
fprintf(stdout,"\b");
for(c = 0; c < chars; c++)
fprintf(stdout," ");
for(c = 0; c < chars; c++)
fprintf(stdout,"\b");
}
int screenlinesleft = 0, screenmaxchars, screenmaxlines;
int screenchars = 0;
int quitcmd = 0;
void more_wait()
{
int c;
unsigned char *moretext = "---more---";
startprompt();
fprintf(stdout,"%s", moretext);
// wait until something below is pressed
for(;;) {
c = getchar();
if(c == ' ') {
screenlinesleft = screenmaxlines; // full screen
break;
} else if(c == '\n') {
screenlinesleft = 1; // one line
break;
} else if(c == 'q') { // quit
quitcmd = 1;
break;
}
}
util_backspacechars(strlen(moretext));
endprompt();
}
#include <stdarg.h>
void more_printf(const char *format, ...)
{
int count;
va_list args;
unsigned char *p;
static char *printbuf=NULL;
static int printbuf_len=0;
va_start(args, format);
count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
va_end(args);
if(printbuf_len < count) {
printbuf_len = count;
printbuf=realloc(printbuf, printbuf_len);
va_start(args, format);
count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
va_end(args);
}
// print all characters from printbuf.
// prompt more for full screen pages.
p=printbuf;
while(*p!='\0') {
putchar(*p);
if(*p=='\n' || ++screenchars==screenmaxchars) {
screenchars=0;
if(--screenlinesleft==0) {
more_wait();
}
}
p++;
}
}
Lisätty koodi, jolla valitaan kyselyä vastaavat tietueet:
int db6_match(unsigned char *set, unsigned char *match)
{
int ok, ok2, first1, first2;
unsigned char *s, *m;
unsigned int namelen, valuelen;
unsigned char *name, *value;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG72
fprintf(stdout,"match:%s", match);
fprintf(stdout,", set:%s", set);
fprintf(stdout,"\n");
fflush(stdout);
#endif
m = match;
first2 = 1;
ok = 1;
while(*m != '\0') {
db5_skipwhite(&m);
if(!first2) {
if(*m == ',')
m++;
db5_skipwhite(&m);
}
first2 = 0;
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &m); // match
db5_skipwhite(&m);
#ifdef DEBUG72
fprintf(stdout,"db6_get_element2: ");
fprintf(stdout,"name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
fflush(stdout);
#endif
s = set;
first1 = 1;
ok2 = 0;
while(*s != '\0') {
db5_skipwhite(&s);
if(!first1) {
if(*s == ',')
s++;
db5_skipwhite(&s);
}
first1 = 0;
db5_get_element(&namelen, &name, &valuelen, &value, &s); // set
db5_skipwhite(&s);
#ifdef DEBUG72
fprintf(stdout,"db6_get_element: ");
fprintf(stdout,"name:%.*s(%d)", namelen, name, namelen);
fprintf(stdout,", value:%.*s(%d)", valuelen, value, valuelen);
fprintf(stdout,"\n");
fflush(stdout);
#endif
if((name2 != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value2 == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
ok2 = 1;
break;
}
}
if(ok2 == 0)
ok = 0;
}
#ifdef DEBUG72
fprintf(stdout,"db6_match done");
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
return(ok);
}
Lisätty koodi project, joka palauttaa rivistä vain kyselyn sisältämät sarakkeet:
void db6_project(unsigned int *projectlen, unsigned char **project, unsigned char *set, unsigned char *query)
{
unsigned char *q, *s;
unsigned int namelen, valuelen;
unsigned char *name, *value;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
if(db5_set != NULL) {
free(db5_set);
db5_set = NULL;
}
q = query;
while(*q != '\0') {
db5_skipwhite(&q);
db5_get_element(&namelen, &name, &valuelen, &value, &q);
db5_skipwhite(&q);
if(*q == ',') {
q++;
db5_skipwhite(&q);
}
s = set;
while(*s != '\0') {
db5_skipwhite(&s);
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &s);
db5_skipwhite(&s);
if(*s == ',') {
s++;
db5_skipwhite(&s);
}
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
unsigned char name3[64];
unsigned char value3[128];
memset(name3,0,sizeof(name3));
memset(value3,0,sizeof(value3));
strncpy(name3, name2, namelen2);
strncpy(value3, value2, valuelen2);
db5_put(name3, value3);
}
} // while(*s != '\0'
} // while(*q != '\0'
if(db5_set != NULL) {
if(*projectlen < strlen(db5_set) + 1) {
unsigned char *prevproject = *project;
*projectlen = strlen(db5_set) + 1;
*project = realloc(*project, *projectlen);
if(prevproject == NULL)
**project = '\0';
}
strcpy(*project, db5_set);
} else
*project = '\0';
}
Kirjoitettu rutiini, joka voi lukea tiedostosta merkkijonon, jonka pituutta ei tiedetä etukäteen. Ohjelma vain suurentaa muistipuskuria tarvittaessa:
unsigned char *util_fgets(int *commandlen, unsigned char **command, FILE *fp1)
{
int count, retval;
unsigned char buffer[64];
unsigned char *buf = *command;
count = 0;
if(buf != NULL)
buf[0] = '\0';
retval = 1;
for(;;) {
if(fgets(buffer, sizeof(buffer), fp1) == NULL) {
retval = 0;
break;
}
//fprintf(stderr," %s",buffer);
count = 0;
if(buf != NULL)
count += strlen(buf);
count += strlen(buffer);
if(*commandlen < count) {
unsigned char *prevbuf = buf;
*commandlen = count;
buf = realloc(buf, *commandlen);
if(prevbuf == NULL)
buf[0] = '\0';
}
strcat(buf, buffer);
if(buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
break;
}
}
*command = buf;
if(retval == 0)
return(NULL);
else
return(*command);
}
Seuraava pätkä tekee kyselyn, ja tulostaa vastauksen:
int util_doquery(unsigned char *query, unsigned char *filename)
{
FILE *fp1;
static unsigned char *line = NULL;
static unsigned int linelen = 0;
static unsigned char *project = NULL;
static unsigned int projectlen = 0;
if((fp1 = fopen(filename,"r"))== NULL) {
fprintf(stderr,"%s: cannot open file `%s`\n", procname, filename);
return(1);
}
db6_setheaderflags("project", 0); // standard: sorted, no duplicates
db6_setheaderquery("project", query);
db6_deletesets("project");
while(util_fgets(&linelen, &line, fp1) != NULL) {
if(quitcmd)
break;
if(line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
if(db6_match(line, query)) {
db6_project(&projectlen, &project, line, query);
db6_putset("project", project);
}
}
fclose(fp1);
int c = 0;
for(;;) {
unsigned char *set;
if(quitcmd)
break;
set = db6_getset("project", c);
if(set == NULL)
break;
more_printf("%d*`%s`\n", c, set);
c++;
}
}
Lisätty db6_putset koodi lajittelulle (ja tuplille):
void db6_putset(unsigned char *setname, unsigned char *set)
{
int add;
struct setheader *sh;
sh = db6_setheader(setname);
struct setline **ppsetline;
add = 1;
ppsetline = &sh->first;
while(*ppsetline != NULL) { // duplicates
if((sh->flags & DB6_DUP) == 0 &&
!strcmp(set, (*ppsetline)->set)) {
add = 0;
break;
}
if((sh->flags & DB6_NOSORT) == 0 && // sort
strcmp(set, (*ppsetline)->set) < 0) {
add = 1;
break;
}
ppsetline = &((*ppsetline)->next);
}
if(add) {
struct setline *nsl;
nsl = malloc(sizeof(struct setline));
nsl->set = db6_set(set);
#ifdef DEBUG66
more_printf("Adding chain `%s`, set `%s`\n", setname, nsl->set);
#endif
nsl->next = *ppsetline;
*ppsetline = nsl;
}
}
Seuraava kappale on pääohjelmassa (main) oleva rutiini, jolla voidaan tehdä testiaineistoa:
#define TEST_SETS 9
#define TEST_ITEMS 3
if(testflag) {
// 'a'='1', 'b'='1', 'c'='1'
// 'a'='2', 'b'='1', 'c'='1'
// 'a'='3', 'b'='2', 'c'='1'
// 'a'='4', 'b'='2', 'c'='2'
// 'a'='5', 'b'='3', 'c'='2'
// 'a'='6', 'b'='3', 'c'='2'
// 'a'='7', 'b'='4', 'c'='3'
// 'a'='8', 'b'='4', 'c'='3'
// 'a'='9', 'b'='5', 'c'='3'
for(c = 0; c < TEST_SETS; c++) {
first = 1;
for(d = 0; d < TEST_ITEMS ; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"'%c'", 'a' + d);
fprintf(stdout,"=");
fprintf(stdout,"'%d'", c / (d + 1) + 1);
first = 0;
}
fprintf(stdout,"\n");
}
}
Seuraava rutiini mahdollistaa lajittelun haussa. Lajittelu tehdään kenttien kyselyn järjestyksessä:
void db6_putset(unsigned char *setname, unsigned char *set)
{
int add;
struct setheader *sh;
sh = db6_setheader(setname);
struct setline **ppsetline;
add = 1;
ppsetline = &sh->first;
while(*ppsetline != NULL) { // duplicates
if((sh->flags & DB6_DUP) == 0 &&
!strcmp(set, (*ppsetline)->set)) {
add = 0;
break;
}
if((sh->flags & DB6_NOSORT) == 0 && // sort
strcmp(set, (*ppsetline)->set) < 0) {
add = 1;
break;
}
ppsetline = &((*ppsetline)->next);
}
if(add) {
struct setline *thissetline;
thissetline = malloc(sizeof(struct setline));
thissetline->set = db6_set(set);
sh->count++;
#ifdef DEBUG66
more_printf("Adding chain `%s`, set `%s`\n", setname, thissetline->set);
#endif
thissetline->next = *ppsetline;
*ppsetline = thissetline;
}
}
Seuraava rutiini siirtää käsiteltävän kyselyn tuloksen (setheader) aina listan alkuun: Näin usein käytettävät kyselyt löytyvät nopeammin.
static struct setheader *db6_setheader(unsigned char *setname)
{
struct setheader **ppsetheader, *thissetheader;
ppsetheader = &firstsetheader;
while(*ppsetheader != NULL) {
if(!strcmp(setname, (*ppsetheader)->setname))
break;
ppsetheader = &((*ppsetheader)->next);
}
if(*ppsetheader == NULL) { // does not exist, create
thissetheader = malloc(sizeof(struct setheader));
thissetheader->setname = malloc(strlen(setname) + 1);
strcpy(thissetheader->setname, setname);
thissetheader->flags = 0;
thissetheader->query = NULL;
thissetheader->count = 0;
thissetheader->first = NULL;
// put to first
thissetheader->next = firstsetheader;
firstsetheader = thissetheader;
#ifdef DEBUG66
fprintf(stdout,"added set `%s` as first set\n",setname);
#endif
} else {
// remove from list
thissetheader = *ppsetheader;
*ppsetheader = thissetheader->next;
// add back to 1st of list
thissetheader->next = firstsetheader;
firstsetheader = thissetheader;
#ifdef DEBUG66
fprintf(stdout,"added set `%s` as first set\n",setname);
#endif
}
return(thissetheader);
}
Seuraava rutiini poistaa kyselyn set:in. Samalla lasketaan viittauslaskuria (count), ja jos set:iin ei ole enää viittauksia, se poistetaan muistista:
void db6_deleteset(unsigned char *set)
{
int found;
struct set **ppset;
found = 0;
ppset = &firstset;
while(*ppset != NULL) {
if(!strcmp((*ppset)->set, set)) {
found = 1;
break;
}
ppset = &((*ppset)->next);
}
if(found) {
// set found
// decrement reference counter
(*ppset)->count--;
// if no references delete set
if((*ppset)->count == 0) {
struct set *prevppset;
prevppset = *ppset;
#ifdef DEBUG66
more_printf("Set `%s` deleted\n", (*ppset)->set);
#endif
(*ppset) = (*ppset)->next;
free(prevppset->set);
free(prevppset);
}
}
}
Seuraavassa on ohjelma kokonaisuudessaan:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname = NULL;
static unsigned char *programname = "Terttuutil1 version 0.17 ©";
static unsigned char *copyright = "Copyright (c) 1998-2023 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
int newressu_output = 0;
void ressu_dump(unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%-10s", header);
}
fprintf(stdout," %02x", buf[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
}
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
#ifdef DEBUG20
ressu_dump("cvar", cvarsize + 1, cvar, 32);
#endif
}
#define aCVARRANDOMSTART 2 // off by default
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
#ifdef CVARRANDOMSTART
ressu_genbytes(8, (unsigned char *)&cvar);
#endif
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE]; // orig 1024
static unsigned int gent_pos = 0;
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
static int streamt_pos = 0;
void stream_bytes(int size, unsigned char *buffer) // JariK 2023
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next random bytes
stream_internalbytes(stream_key); // change key
} // end of if(streamt_pos == 0
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
}
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
HashFinal(stream_key, &hash);
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#define DEBUG21 2
#ifdef DEBUG21
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," randomness from key, key=");
dumpbin(stderr, size, key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
}
void gent_clear()
{
memset(gent, 0, sizeof(gent));
}
int stream_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
#ifdef DEBUG23
ressu_dump("oldgent", 32, gent, 32); // first 32 bytes
#endif
gent_clear();
stream_bytes(sizeof(gent), gent);
#ifdef DEBUG23
ressu_dump("newgent", 32, gent, 32); // first 32 bytes
#endif
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
#ifdef DEBUG18
fprintf(stdout, "{%02x}", ch);
#endif
return(ch);
}
unsigned long stream_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) { // one byte
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) { // two bytes
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) { // three bytes
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) { // four bytes
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) { // five bytes
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) { // six bytes
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) { // seven bytes
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | stream_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
#include <termios.h>
struct termios old, new;
void startprompt()
{
setvbuf(stdout, NULL, _IONBF, 0);
tcgetattr(0, &old);
new = old;
new.c_lflag &= ~(ICANON | ECHO);
//new.c_lflag &= ~(ISIG | ICANON | ECHO);
new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 2;
tcsetattr(0, TCSANOW, &new);
}
void endprompt()
{
tcsetattr(0, TCSANOW, &old);
}
void util_backspacechars(int chars)
{
int c;
for(c = 0; c < chars; c++)
fprintf(stdout,"\b");
for(c = 0; c < chars; c++)
fprintf(stdout," ");
for(c = 0; c < chars; c++)
fprintf(stdout,"\b");
}
int screenlinesleft = 0, screenmaxchars, screenmaxlines;
int screenchars = 0;
int quitcmd = 0;
#include <sys/ioctl.h> // for TIOCGWINSZ
int more = 1;
void more_init()
{
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
screenmaxchars = w.ws_col;
screenmaxlines = w.ws_row-1;
screenlinesleft = screenmaxlines;
quitcmd = 0;
}
void more_wait()
{
int c;
unsigned char *moretext = "---more---";
startprompt();
fprintf(stderr,"%s", moretext);
// wait until something below is pressed
for(;;) {
c = getchar();
if(c == ' ') {
screenlinesleft = screenmaxlines; // full screen
break;
} else if(c == '\n') {
screenlinesleft = 1; // one line
break;
} else if(c == 'q') { // quit
quitcmd = 1;
break;
}
}
util_backspacechars(strlen(moretext));
endprompt();
}
#include <stdarg.h>
void more_printf(FILE *fp1, const char *format, ...)
{
int count;
va_list args;
unsigned char *p;
static char *printbuf=NULL;
static int printbuf_len=0;
va_start(args, format);
count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
va_end(args);
if(printbuf_len < count) {
printbuf_len = count;
printbuf=realloc(printbuf, printbuf_len);
va_start(args, format);
count=vsnprintf(printbuf, printbuf_len, format, args) + 1;
va_end(args);
}
// print all characters from printbuf.
// prompt more for full screen pages.
p=printbuf;
while(*p!='\0') {
fputc(*p, fp1);
if(*p=='\n' || ++screenchars==screenmaxchars) {
screenchars=0;
if(more && --screenlinesleft==0) {
more_wait();
}
}
p++;
}
}
unsigned char *db5_set = NULL;
unsigned char *db5_get_set()
{
return(db5_set);
}
void db5_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
#define aDEBUG8 2
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
void db5_get_element(unsigned int *namelen, unsigned char **name, unsigned int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db5_skipwhite(&p);
if(*p == '\'') { // name
p++;
*name = p;
*namelen = 0;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
} else
*name = NULL;
db5_skipwhite(&p);
if(*p == '=') {
p++;
}
db5_skipwhite(&p);
if(*p == '\"') { // value
p++;
*value = p;
*valuelen = 0;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
} else
*value = NULL;
db5_skipwhite(&p);
#ifdef DEBUG8
fprintf(stdout,"db5_get_element():");
fprintf(stdout," name:%.*s(%d)", *namelen, *name, *namelen);
fprintf(stdout,", value:%.*s(%d)", *valuelen, *value, *valuelen);
fprintf(stdout,", next:%s",p);
fprintf(stdout,"\n");
fflush(stdout);
#endif
*p2 = p;
}
int db5_get(unsigned char *name, int valuesize, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen = strlen(name);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** get\n");
#endif
value[0] = '\0';
if(db5_set != NULL) {
firstelement = 1;
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
#ifdef DEBUG9
fprintf(stdout,"get name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
db5_skipwhite(&p);
// we reached equal name
if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = strlen(value);
break;
}
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(db5_set != NULL)
return(retval);
}
#define aSORTED 2
void db5_put(unsigned char *name, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
unsigned int namelen = strlen(name);
unsigned int valuelen = strlen(value);
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG9
fprintf(stdout,"********** put\n");
#endif
firstelement = 1;
lastelement = 0;
if(db5_set != NULL) {
p = db5_set;
// read thru elements element by element
while(*p != '\0') {
db5_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db5_skipwhite(&p);
}
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &p);
db5_skipwhite(&p);
#ifdef DEBUG9
fprintf(stdout,"put name:%s", name);
fprintf(stdout,", name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
#endif
// we reached equal name
if(namelen == namelen2 &&
!strncmp(name, name2, namelen) ) {
found = 1;
thiselement = currentelement;
nextelement = p; // beginning of next element
break;
}
#ifdef SORTED
// we reached greater name
if(namelen == namelen2 &&
strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
thiselement = currentelement;
nextelement = currentelement;
break;
} else {
// common beginning of strings
int comblen = namelen;
if(comblen > namelen2)
comblen = namelen2;
int cmp = strncmp(name, name2, comblen);
if((cmp < 0) || // first characters less (aaaa, b)
(!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
thiselement = currentelement;
nextelement = currentelement;
break;
}
}
#endif
if(*p == '\0')
lastelement = 1;
firstelement = 0;
} // end of while(*p != '\0')
} else { // else of if(db5_set != NULL)
lastelement = 1;
firstelement = 1;
} // end of if(db5_set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%s' = \"%s\""; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%s' = \"%s\", "; // --> comma in the end (first new)
else
elementfmt = ", '%s' = \"%s\""; // ..> comma in the beginning (other)
// print element
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
if(elementsize < count) {
elementsize = count;
if((element = realloc(element, elementsize)) == NULL) {
fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
count = snprintf(element, elementsize, elementfmt, name, value) + 1;
}
// calculate change in length
long oldcount = 0;
count = 0;
if(db5_set != NULL) {
count += strlen(db5_set);
oldcount = count + 1; // + '\0'
}
if(found) // change in value only
count += valuelen - valuelen2; // no punctuation marks
else
count += strlen(element);
count++; // + '\0'
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout, "old length:%ld %s\n", oldcount, db5_set);
fflush(stdout);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempdb5_set = db5_set;
if((db5_set = realloc(db5_set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = db5_set + (thiselement - tempdb5_set);
if(nextelement != NULL)
nextelement = db5_set + (nextelement - tempdb5_set);
if(tempdb5_set == NULL)
db5_set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = db5_set + strlen(db5_set);
if(nextelement == NULL)
nextelement = db5_set + strlen(db5_set);
// move end of the set
memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too
// add new element
memmove(thiselement, element, strlen(element));
#ifdef DEBUG11
if(oldcount != count) {
fprintf(stdout,"new length:%ld %s\n", count, db5_set);
fflush(stdout);
}
#endif
#ifdef DEBUG10
fprintf(stdout,", set %s(%ld)", db5_set, strlen(db5_set));
fprintf(stdout,"\n");
fflush(stdout);
#endif
}
#define aDEBUG72 2
int db6_match(unsigned char *set, unsigned char *match)
{
int ok, ok2, first1, first2;
unsigned char *s, *m;
unsigned int namelen, valuelen;
unsigned char *name, *value;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
#ifdef DEBUG72
fprintf(stdout,"match:%s", match);
fprintf(stdout,", set:%s", set);
fprintf(stdout,"\n");
fflush(stdout);
#endif
m = match;
first2 = 1;
ok = 1;
while(*m != '\0') {
db5_skipwhite(&m);
if(!first2) {
if(*m == ',')
m++;
db5_skipwhite(&m);
}
first2 = 0;
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &m); // match
db5_skipwhite(&m);
#ifdef DEBUG72
fprintf(stdout,"db6_get_element2: ");
fprintf(stdout,"name2:%.*s(%d)", namelen2, name2, namelen2);
fprintf(stdout,", value2:%.*s(%d)", valuelen2, value2, valuelen2);
fprintf(stdout,"\n");
fflush(stdout);
#endif
s = set;
first1 = 1;
ok2 = 0;
while(*s != '\0') {
db5_skipwhite(&s);
if(!first1) {
if(*s == ',')
s++;
db5_skipwhite(&s);
}
first1 = 0;
db5_get_element(&namelen, &name, &valuelen, &value, &s); // set
db5_skipwhite(&s);
#ifdef DEBUG72
fprintf(stdout,"db6_get_element: ");
fprintf(stdout,"name:%.*s(%d)", namelen, name, namelen);
fprintf(stdout,", value:%.*s(%d)", valuelen, value, valuelen);
fprintf(stdout,"\n");
fflush(stdout);
#endif
if((name2 != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value2 == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
ok2 = 1;
break;
}
}
if(ok2 == 0)
ok = 0;
}
#ifdef DEBUG72
fprintf(stdout,"db6_match done");
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
return(ok);
}
#define aDEBUG50 2
#define aDEBUG51 2
void db6_project(unsigned int *projectlen, unsigned char **project, unsigned char *set, unsigned char *query)
{
unsigned char *q, *s;
unsigned int namelen, valuelen;
unsigned char *name, *value;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
if(db5_set != NULL) {
free(db5_set);
db5_set = NULL;
}
q = query;
while(*q != '\0') {
db5_skipwhite(&q);
db5_get_element(&namelen, &name, &valuelen, &value, &q);
db5_skipwhite(&q);
if(*q == ',') {
q++;
db5_skipwhite(&q);
}
s = set;
while(*s != '\0') {
db5_skipwhite(&s);
db5_get_element(&namelen2, &name2, &valuelen2, &value2, &s);
db5_skipwhite(&s);
if(*s == ',') {
s++;
db5_skipwhite(&s);
}
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
unsigned char name3[64];
unsigned char value3[128];
memset(name3,0,sizeof(name3));
memset(value3,0,sizeof(value3));
strncpy(name3, name2, namelen2);
strncpy(value3, value2, valuelen2);
db5_put(name3, value3);
}
} // while(*s != '\0'
} // while(*q != '\0'
if(db5_set != NULL) {
if(*projectlen < strlen(db5_set) + 1) {
unsigned char *prevproject = *project;
*projectlen = strlen(db5_set) + 1;
*project = realloc(*project, *projectlen);
if(prevproject == NULL)
**project = '\0';
}
strcpy(*project, db5_set);
} else
*project = '\0';
}
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
#define aDEBUG59 2
int db6_parsequery(int querylen, unsigned char *query, unsigned char *command)
{
unsigned char *token, *p, *q;
int mode = 0, copymode = 0, count, valuetoo, exitcount = 0;
p = command;
q = query;
mode = 20;
count = 0;
while(*p != '\0') {
unsigned char *prevp = NULL;
unsigned char *prevq = NULL;
prevp = p;
prevq = q;
if(count < querylen)
*q = '\0';
switch(mode) {
case 10:
token = " ";
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
mode = 20;
case 20:
token = "'";
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
copymode = 0; // 0 = isalpha, 1 = within quotes
db5_skipwhite(&p);
if(*p == '\'') { // skip possible first quote
copymode = 1;
p++;
//db5_skipwhite(&p);
}
token = " "; // placeholder for one character
while((copymode == 0 && *p != ' ' && *p != ',' && *p != '=' && *p != '\0') ||
(copymode == 1 && *p != '\'' && *p != '\0')) {
if(count + strlen(token) < querylen) {
*q++ = *p;
*q = '\0';
}
p++;
count++;
}
if(copymode) { // skip possible second quote
if(*p == '\'') {
p++;
}
db5_skipwhite(&p); // skip space after quote
}
token = "'"; // add single quote to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
if(*p == ',') // no value
mode = 40; // skip to comma
else
mode = 30; // go thru value
break;
case 30:
valuetoo = 0;
db5_skipwhite(&p);
if(*p == '=') { // skip possible equals sign
p++;
db5_skipwhite(&p);
valuetoo = 1;
}
if(*p == '"')
valuetoo = 1;
if(isalpha(*p) || isdigit(*p) || *p == '_')
valuetoo = 1;
if(valuetoo) {
token = " = \""; // add equals to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
copymode = 0; // 0 = isalpha, 1 = within quotes
db5_skipwhite(&p);
if(*p == '"') { // skip possible first quote
copymode = 1;
p++;
//db5_skipwhite(&p); // no skipwhite after first quote
}
token = " ";
while((copymode == 0 && *p != ' ' && *p != ',' && *p != '\0') ||
(copymode == 1 && *p != '"' && *p != '\0')) {
if(count + strlen(token) < querylen) {
*q++ = *p;
*q = '\0';
}
p++;
count++;
}
if(copymode) { // skip possible second quote
//db5_skipwhite(&p); // no skipwhite before second quote
if(*p == '\"')
p++;
db5_skipwhite(&p); // skip space after quote
}
token = "\""; // add quote to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(q);
}
count += strlen(token);
} // if(valuetoo
mode = 40;
break;
case 40:
db5_skipwhite(&p);
if(*p == ',') {
p++;
db5_skipwhite(&p);
}
token = ","; // add comma to set
if(count + strlen(token) < querylen) {
strcat (q, token);
q += strlen(token);
}
count += strlen(token);
mode = 10;
break;
}
#ifdef DEBUG59
fprintf(stderr,"command:`%s`", p);
fprintf(stderr,", query:`%s`", query);
fprintf(stderr,", mode:%d", mode);
fprintf(stderr,"\n");
#endif
if(*p == '\0')
break;
if(prevp == p && prevq == q) {
fprintf(stderr,"%s: illegal character '", procname);
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", mode:%d", mode);
fprintf(stderr,"\n");
fflush(stderr);
if(++ exitcount == 10) {
break;
}
}
}
return(count);
}
#define aDEBUG66 2
#define DB6_NOSORT 1
#define DB6_DUP 2
struct setheader {
unsigned char *setname;
int flags;
unsigned char *query;
int count;
struct setheader *next;
struct setline *first;
};
struct setheader *firstsetheader = NULL;
struct setline {
unsigned char *set;
struct setline *next;
};
struct set {
unsigned char *set;
int count;
struct set *next;
};
struct set *firstset = NULL;
static struct setheader *db6_setheader(unsigned char *setname)
{
struct setheader **ppsetheader, *thissetheader;
ppsetheader = &firstsetheader;
while(*ppsetheader != NULL) {
if(!strcmp(setname, (*ppsetheader)->setname))
break;
ppsetheader = &((*ppsetheader)->next);
}
if(*ppsetheader == firstsetheader) {
#ifdef DEBUG66
more_printf(stderr, "set `%s` is allready the first set\n",setname);
#endif
}
if(*ppsetheader == NULL) { // does not exist, create
thissetheader = malloc(sizeof(struct setheader));
thissetheader->setname = malloc(strlen(setname) + 1);
strcpy(thissetheader->setname, setname);
thissetheader->flags = 0;
thissetheader->query = NULL;
thissetheader->count = 0;
thissetheader->first = NULL;
// put to first
thissetheader->next = firstsetheader;
firstsetheader = thissetheader;
#ifdef DEBUG66
more_printf(stderr, "added set `%s` as first set\n",setname);
#endif
} else {
// remove from list
thissetheader = *ppsetheader;
*ppsetheader = thissetheader->next;
// add back to 1st of list
thissetheader->next = firstsetheader;
firstsetheader = thissetheader;
#ifdef DEBUG66
more_printf(stderr, "added set `%s` as first set\n",setname);
#endif
}
return(thissetheader);
}
static struct setheader *db6_setheaderflags(unsigned char *setname, int flags)
{
struct setheader *sh;
sh = db6_setheader(setname);
sh->flags = flags;
}
static struct setheader *db6_setheaderquery(unsigned char *setname, unsigned char *query)
{
struct setheader *sh;
sh = db6_setheader(setname);
if(sh->query != NULL)
free(sh->query);
sh->query = malloc(strlen(query) + 1);
strcpy(sh->query, query);
}
void db6_dumpsetheader(struct setheader *thissetheader)
{
more_printf(stderr, "setheader");
more_printf(stderr, " %p", thissetheader);
more_printf(stderr, " setname:`%s`", thissetheader->setname);
more_printf(stderr, ", flags:%02x", thissetheader->flags);
more_printf(stderr, ", query:`%s`", thissetheader->query);
more_printf(stderr, ", count:%d", thissetheader->count);
more_printf(stderr, ", next:%p", thissetheader->next);
more_printf(stderr, ", first:%p", thissetheader->first);
more_printf(stderr, "\n");
}
void db6_dumpsetheaders()
{
struct setheader *sh;
sh = firstsetheader;
while(sh != NULL) {
db6_dumpsetheader(sh);
sh=sh->next;
}
}
void db6_dumpsetline(struct setline *thissetline)
{
more_printf(stderr, "set");
more_printf(stderr, " %p", thissetline);
more_printf(stderr, " set:%s", thissetline->set);
more_printf(stderr, ", next:%p", thissetline->next);
more_printf(stderr, "\n");
}
unsigned char *db6_set(unsigned char *set)
{
int found;
struct set *s;
found = 0;
s = firstset;
while(s != NULL) {
if(!strcmp(s->set, set)) {
found = 1;
break;
}
s = s->next;
}
if(!found) {
struct set *thisset;
thisset = malloc(sizeof(struct set));
thisset->set = malloc(strlen(set) + 1);
strcpy(thisset->set, set);
thisset->count = 1;
//more_printf(stdout, "2:`%s`", set);
thisset->next = firstset;
firstset = thisset;
s = thisset;
} else {
s->count++;
}
return(s->set);
}
void db6_putset(unsigned char *setname, unsigned char *set)
{
int add;
struct setheader *sh;
sh = db6_setheader(setname);
struct setline **ppsetline;
add = 1;
ppsetline = &sh->first;
while(*ppsetline != NULL) { // duplicates
if((sh->flags & DB6_DUP) == 0 &&
!strcmp(set, (*ppsetline)->set)) {
add = 0;
break;
}
if((sh->flags & DB6_NOSORT) == 0 && // sort
strcmp(set, (*ppsetline)->set) < 0) {
add = 1;
break;
}
ppsetline = &((*ppsetline)->next);
}
if(add) {
struct setline *thissetline;
thissetline = malloc(sizeof(struct setline));
thissetline->set = db6_set(set);
sh->count++;
#ifdef DEBUG66
more_printf(stderr, "Adding chain `%s`, set `%s`\n", setname, thissetline->set);
#endif
thissetline->next = *ppsetline;
*ppsetline = thissetline;
}
}
void db6_dumpset(struct set *thisset)
{
more_printf(stderr, "set");
more_printf(stderr, " %p", thisset);
more_printf(stderr, " set:`%s`", thisset->set);
more_printf(stderr, " count:%d", thisset->count);
more_printf(stderr, ", next:%p", thisset->next);
more_printf(stderr, "\n");
}
void db6_dumpsets()
{
struct set *s;
s = firstset;
while(s != NULL) {
db6_dumpset(s);
s = s->next;
}
}
void db6_deleteset(unsigned char *set)
{
int found;
struct set **ppset;
found = 0;
ppset = &firstset;
while(*ppset != NULL) {
if(!strcmp((*ppset)->set, set)) {
found = 1;
break;
}
ppset = &((*ppset)->next);
}
if(found) {
// set found
// decrement reference counter
(*ppset)->count--;
// if no references delete set
if((*ppset)->count == 0) {
struct set *prevppset;
prevppset = *ppset;
#ifdef DEBUG66
more_printf(stderr, "Set `%s` deleted\n", (*ppset)->set);
#endif
(*ppset) = (*ppset)->next;
free(prevppset->set);
free(prevppset);
}
}
}
#ifdef OLD1
void db6_deleteset(unsigned char *set)
{
int found;
struct set *s;
found = 0;
s = firstset;
while(s != NULL) {
if(!strcmp(s->set, set)) {
found = 1;
break;
}
s = s->next;
}
if(found) {
s->count--;
}
}
#endif
void db6_deletesets(unsigned char *setname)
{
int c, found;
struct setheader *sh;
struct setline *sl, *sl2;
sh = db6_setheader(setname);
#ifdef DEBUG66
more_printf(stderr, "Deleting chain `%s`\n",setname);
#endif
sl = sh->first;
while(sl != NULL) {
#ifdef DEBUG66
more_printf(stderr, "Deleting:%s\n", sl->set);
#endif
db6_deleteset(sl->set);
sh->count--;
sl2 = sl;
sl = sl2->next;
free(sl2);
}
#ifdef DEBUG66
more_printf(stderr, "Chain `%s` deleted\n",setname);
#endif
sh->first = NULL;
}
unsigned char *db6_getset(unsigned char *setname, int lineno)
{
int c;
struct setheader *sh;
sh = db6_setheader(setname);
//db6_dumpsetheader(sh);
struct setline *sl;
sl = sh->first;
while(sl != NULL && lineno > 0) {
//db6_dumpsetline(sl);
sl = sl->next;
lineno--;
}
if(sl == NULL)
return(NULL);
else {
#ifdef DEBUG66
more_printf(stderr, "Restoring chain `%s`, set `%s`\n", setname, sl->set);
#endif
return(sl->set);
}
}
void util_parsequery(int *querylen, unsigned char **query, unsigned char *command)
{
int count;
count = db6_parsequery(*querylen, *query, command) + 1;
if(*querylen < count) {
*querylen = count;
*query = realloc(*query, *querylen);
count = db6_parsequery(*querylen, *query, command) + 1;
}
more_printf(stderr, "command:`%s`", command);
more_printf(stderr, ", query:`%s`", *query);
more_printf(stderr, "\n");
}
#define aDEBUG83 2
unsigned char *util_fgets(int *commandlen, unsigned char **command, FILE *fp1)
{
int count, retval;
unsigned char buffer[4];
unsigned char *buf = *command;
count = 0;
if(buf != NULL)
buf[0] = '\0';
retval = 1;
for(;;) {
if(fgets(buffer, sizeof(buffer), fp1) == NULL) {
retval = 0;
break;
}
#ifdef DEBUG83
more_printf(stderr, "/`%s`",buffer);
#endif
count = 0;
if(buf != NULL)
count += strlen(buf);
count += strlen(buffer) + 1;
if(*commandlen < count) {
unsigned char *prevbuf = buf;
*commandlen = count;
buf = realloc(buf, *commandlen);
if(prevbuf == NULL)
buf[0] = '\0';
}
strcat(buf, buffer);
if(buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
break;
}
}
*command = buf;
#ifdef DEBUG83
more_printf(stderr, "\n");
#endif
#ifdef DEBUG83
more_printf(stderr, "`%s`(%d)", buf, strlen(buf));
#endif
if(retval == 0)
return(NULL);
else
return(*command);
}
int util_doquery(unsigned char *query, unsigned char *filename)
{
FILE *fp1;
static unsigned char *line = NULL;
static unsigned int linelen = 0;
static unsigned char *project = NULL;
static unsigned int projectlen = 0;
if((fp1 = fopen(filename,"r"))== NULL) {
fprintf(stderr,"%s: cannot open file `%s`\n", procname, filename);
return(1);
}
//db6_setheaderflags("project", DB6_NOSORT | DB6_DUP);
//db6_setheaderflags("project", DB6_NOSORT);
//db6_setheaderflags("project", DB6_DUP);
db6_setheaderflags("project", 0);
//db6_setheaderflags("project", DB6_NOSORT | DB6_DUP);
db6_setheaderquery("project", query);
db6_deletesets("project");
while(util_fgets(&linelen, &line, fp1) != NULL) {
if(quitcmd)
break;
if(line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
if(db6_match(line, query)) {
db6_project(&projectlen, &project, line, query);
db6_putset("project", project);
}
}
fclose(fp1);
int c = 0;
for(;;) {
unsigned char *set;
if(quitcmd)
break;
set = db6_getset("project", c);
if(set == NULL)
break;
more_printf(stdout, "%d*`%s`\n", c, set);
c++;
}
}
void terttuutilversion()
{
fprintf(stdout,"%s\n", programname);
fprintf(stdout,"%s\n", copyright);
fflush(stdout);
}
#define aDEBUG96 2
int main(int argc, char *argv[])
{
int c, d, first, printcomma = 0, queryflag = 0, testflag = 0, test2flag = 0;
unsigned char command[4096], *p;
int commandlen = 4096;
#define aDEBUG98 2
more = 0;
if(isatty(STDOUT_FILENO))
more = 1;
#ifdef DEBUG98
db5_set = "'a' = \"1\", 'b' = \"2\", 'c' = \"3\"";
db6_match(db5_set, "'a' = \"1\"");
db6_match(db5_set, "'b' = \"2\"");
db6_match(db5_set, "'c' = \"3\"");
db6_match(db5_set, "'a'");
db6_match(db5_set, "'b'");
db6_match(db5_set, "'c'");
db6_match(db5_set, "'a' = \"a\"");
db6_match(db5_set, "'b' = \"b\"");
db6_match(db5_set, "'c' = \"c\"");
#endif
procname = argv[0];
first = 1;
command[0] = '\0';
int help = 0, stat = 1;
unsigned char filename[128] = "terttuutil1.3.skk";;
//
// look thru command line parameters
//
for(c = 1; c < argc; c++) {
if(!strncmp("-", argv[c], 1)) {
if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c])) {
help = 1;
} else if(!strncmp("--filename", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
strncpy(filename, argv[c] + 10, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
if(printcomma)
fprintf(stderr,", ");
else
printcomma = 0;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
terttuutilversion();
#ifdef SHA256
fprintf(stderr,"\nsha256(");
for(int c = 0; c < HashLen; c++) {
fprintf(stderr, "%02x", programfiledigest[c]);
}
fprintf(stderr, ")\n\n");
#endif
help = 0;
exit(1);
} else if(!strcmp("--stat", argv[c])) {
stat = !stat;
} else if(!strcmp("--query", argv[c])) {
queryflag = !queryflag;
} else if(!strcmp("--test", argv[c])) {
testflag = !testflag;
} else if(!strcmp("--test2", argv[c])) {
test2flag = !test2flag;
}
} else {
if(!first)
strcat(command, " ");
strcat(command, argv[c]);
first = 0;
}
}
db6_setheaderflags("headerfields", 0);
db6_setheaderflags("linesfields", 0);
db6_setheaderflags("header", 0);
db6_setheaderflags("lines", 0);
db6_setheaderflags("user", 0);
db6_setheaderflags("log", 0);
db6_setheaderflags("session", 0);
more_init();
#define TEST_SETS 8192
#define TEST_ITEMS 5
//#define TEST_SETS 9
//#define TEST_ITEMS 3
if(testflag) {
// 'a'='1', 'b'='1', 'c'='1'
// 'a'='2', 'b'='1', 'c'='1'
// 'a'='3', 'b'='2', 'c'='1'
// 'a'='4', 'b'='2', 'c'='2'
// 'a'='5', 'b'='3', 'c'='2'
// 'a'='6', 'b'='3', 'c'='2'
// 'a'='7', 'b'='4', 'c'='3'
// 'a'='8', 'b'='4', 'c'='3'
// 'a'='9', 'b'='5', 'c'='3'
for(c = 0; c < TEST_SETS; c++) {
first = 1;
for(d = 0; d < TEST_ITEMS ; d++) {
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"'%c'", 'a' + d);
fprintf(stdout," = ");
fprintf(stdout,"\"%d\"", c / (d + 1) + 1);
first = 0;
}
fprintf(stdout,"\n");
}
}
if(test2flag) {
#define SEQUENTIAL 1
#define RANDOM 2
struct field {
unsigned char *fieldname;
int fieldtype;
int lowlimit;
int highlimit;
unsigned char *valuestring;
} fields[] = {
{ "asno", SEQUENTIAL, 0, 0,"10%05d" },
{ "asnimi", SEQUENTIAL, 0,0, "nimi: %d" },
{ "asoso", SEQUENTIAL, 0, 0, "osoite: %d" },
{ "aspono", RANDOM, 0, 99999, "postinumero%d"},
{ "aspotmp", RANDOM, 0, 50, "postitmp %d"},
{ "asry", RANDOM, 0, 10, "1%d"},
{ "asmail", RANDOM, 0, 10, "mail: %d"},
};
stream_open(0, "kalakala");
for(c = 0; c < TEST_SETS; c++) {
if(quitcmd)
break;
first = 1;
for(d = 0; d < sizeof(fields) / sizeof(fields[0]); d++) {
if(!first)
more_printf(stdout,", ");
more_printf(stdout,"'%s'", fields[d].fieldname);
more_printf(stdout," = ");
more_printf(stdout,"\"");
if(fields[d].fieldtype = RANDOM && (fields[d].lowlimit != 0 || fields[d].highlimit != 0)) {
unsigned int e = stream_gen_limit(fields[d].highlimit - fields[d].lowlimit) + fields[d].lowlimit;
more_printf(stdout, fields[d].valuestring, e);
} else {
more_printf(stdout, fields[d].valuestring, c);
}
more_printf(stdout,"\"");
first = 0;
}
more_printf(stdout,"\n");
}
more_printf(stdout,"\n");
}
if(printcomma)
fprintf(stderr,", ");
else
printcomma = 0;
int count;
static unsigned char *query = NULL;
static int querylen = 0;
unsigned char *q;
//querylen = 1;
//query = realloc(query, querylen);;
querylen = 0;
query = NULL;
if(!queryflag && strlen(command) != 0) {
util_parsequery(&querylen, &query, command);
util_doquery(query, filename);
}
int quit = 0;
unsigned char *command2 = NULL;
int command2len = 0;
if(queryflag) {
while(!quit) {
more_init();
fprintf(stdout,"skk>");
util_fgets(&command2len, &command2, stdin);
if(command2[strlen(command) - 1] == '\n')
command2[strlen(command) - 1] = '\0';
if(strlen(command2)==0)
continue;
more_printf(stdout, "commandlen:%d\n", command2len);
if(!strcmp(command2,"quit"))
quit = 1;
else if(!strcmp(command2,"exit"))
quit = 1;
else if(!strcmp(command2,"dumpsh"))
db6_dumpsetheaders();
else if(!strcmp(command2,"dumps"))
db6_dumpsets();
else {
util_parsequery(&querylen, &query, command2);
util_doquery(query, filename);
}
}
}
}
Tässä vielä esimerkkejä terttuutil1:n ajosta: (ensimmäisessä ilman komentoriviparametreja ajettu ajo antaa tulokseksi koko testimateriaalin (poista , line: ja `:t datasta).
$ ./terttuutil1
stat, command:``, query: ``
, line: `'a' = "1", 'b' = "1", 'c' = "1"`
, line: `'a' = "2", 'b' = "1", 'c' = "1"`
, line: `'a' = "3", 'b' = "2", 'c' = "1"`
, line: `'a' = "4", 'b' = "2", 'c' = "1"`
, line: `'a' = "5", 'b' = "3", 'c' = "2"`
, line: `'a' = "6", 'b' = "3", 'c' = "2"`
, line: `'a' = "7", 'b' = "4", 'c' = "2"`
, line: `'a' = "8", 'b' = "4", 'c' = "2"`
$ ./terttuutil1 a=1
stat, command:`a=1`, added:, query: `'a' = "1"`
, line: `'a' = "1", 'b' = "1", 'c' = "1"`
$ ./terttuutil1 a=2
stat, command:`a=2`, added:, query: `'a' = "2"`
, line: `'a' = "2", 'b' = "1", 'c' = "1"`
$ ./terttuutil1 a=3
stat, command:`a=3`, added:, query: `'a' = "3"`
, line: `'a' = "3", 'b' = "2", 'c' = "1"`
$ ./terttuutil1 a=4
stat, command:`a=4`, added:, query: `'a' = "4"`
, line: `'a' = "4", 'b' = "2", 'c' = "1"`
$ ./terttuutil1 b=1
stat, command:`b=1`, added:, query: `'b' = "1"`
, line: `'a' = "1", 'b' = "1", 'c' = "1"`
, line: `'a' = "2", 'b' = "1", 'c' = "1"`
$ ./terttuutil1 b=2
stat, command:`b=2`, added:, query: `'b' = "2"`
, line: `'a' = "3", 'b' = "2", 'c' = "1"`
, line: `'a' = "4", 'b' = "2", 'c' = "1"`
$ ./terttuutil1 b=3
stat, command:`b=3`, added:, query: `'b' = "3"`
, line: `'a' = "5", 'b' = "3", 'c' = "2"`
, line: `'a' = "6", 'b' = "3", 'c' = "2"`
$ ./terttuutil1 b=4
stat, command:`b=4`, added:, query: `'b' = "4"`
, line: `'a' = "7", 'b' = "4", 'c' = "2"`
, line: `'a' = "8", 'b' = "4", 'c' = "2"`
$ ./terttuutil1 c=1
stat, command:`c=1`, added:, query: `'c' = "1"`
, line: `'a' = "1", 'b' = "1", 'c' = "1"`
, line: `'a' = "2", 'b' = "1", 'c' = "1"`
, line: `'a' = "3", 'b' = "2", 'c' = "1"`
, line: `'a' = "4", 'b' = "2", 'c' = "1"`
$ ./terttuutil1 c=2
stat, command:`c=2`, added:, query: `'c' = "2"`
, line: `'a' = "5", 'b' = "3", 'c' = "2"`
, line: `'a' = "6", 'b' = "3", 'c' = "2"`
, line: `'a' = "7", 'b' = "4", 'c' = "2"`
, line: `'a' = "8", 'b' = "4", 'c' = "2"`
$
Lisätty terttuutil1:een –query toiminto, joka on hieman interaktiivisempi versio siitä: tässä esimerkki ajosta.
$ ./terttuutil1 --query
command:``, query:`(null)`, command:``, count:0
**********querylen:0, count:1, query:`(null)`
, query:``, command:``, count:0
**********querylen:1, count:1, query:``
`'a' = "1", 'b' = "1", 'c' = "1"`
`'a' = "2", 'b' = "1", 'c' = "1"`
`'a' = "3", 'b' = "2", 'c' = "1"`
`'a' = "4", 'b' = "2", 'c' = "1"`
`'a' = "5", 'b' = "3", 'c' = "2"`
`'a' = "6", 'b' = "3", 'c' = "2"`
`'a' = "7", 'b' = "4", 'c' = "2"`
`'a' = "8", 'b' = "4", 'c' = "2"`
skk>a=1
`a=1`
, query:``, command:``, count:9
**********querylen:1, count:10, query:``
, query:`'a' = "1"`, command:``, count:9
**********querylen:10, count:10, query:`'a' = "1"`
`'a' = "1", 'b' = "1", 'c' = "1"`
skk>a=2
`a=2`
, query:`'a' = "2"`, command:``, count:9
**********querylen:10, count:10, query:`'a' = "2"`
`'a' = "2", 'b' = "1", 'c' = "1"`
skk>a=3
`a=3`
, query:`'a' = "3"`, command:``, count:9
**********querylen:10, count:10, query:`'a' = "3"`
`'a' = "3", 'b' = "2", 'c' = "1"`
skk>a=4
`a=4`
, query:`'a' = "4"`, command:``, count:9
**********querylen:10, count:10, query:`'a' = "4"`
`'a' = "4", 'b' = "2", 'c' = "1"`
skk>a=5
`a=5`
, query:`'a' = "5"`, command:``, count:9
**********querylen:10, count:10, query:`'a' = "5"`
`'a' = "5", 'b' = "3", 'c' = "2"`
skk>b=1
`b=1`
, query:`'b' = "1"`, command:``, count:9
**********querylen:10, count:10, query:`'b' = "1"`
`'a' = "1", 'b' = "1", 'c' = "1"`
`'a' = "2", 'b' = "1", 'c' = "1"`
skk>b=2
`b=2`
, query:`'b' = "2"`, command:``, count:9
**********querylen:10, count:10, query:`'b' = "2"`
`'a' = "3", 'b' = "2", 'c' = "1"`
`'a' = "4", 'b' = "2", 'c' = "1"`
skk>b=3
`b=3`
, query:`'b' = "3"`, command:``, count:9
**********querylen:10, count:10, query:`'b' = "3"`
`'a' = "5", 'b' = "3", 'c' = "2"`
`'a' = "6", 'b' = "3", 'c' = "2"`
skk>b=4
`b=4`
, query:`'b' = "4"`, command:``, count:9
**********querylen:10, count:10, query:`'b' = "4"`
`'a' = "7", 'b' = "4", 'c' = "2"`
`'a' = "8", 'b' = "4", 'c' = "2"`
skk>quit
`quit`
, query:`'quit'`, command:``, count:6
**********querylen:10, count:7, query:`'quit'`
$
Seuraavassa vielä uudemman terttuutil1:n tuloste, tällä kertaa DEBUG66:lla
$ ./terttuutil1 --query
added set `headerfields`
added set `linesfields`
added set `header`
added set `lines`
added set `user`
added set `log`
added set `session`
skk>a
commandlen:2
command:`a`, query:`'a'`
added set `project`
Deleting chain `project`
Chain `project` deleted
Adding chain `project`, set `'a' = "1"`
Adding chain `project`, set `'a' = "2"`
Adding chain `project`, set `'a' = "3"`
Adding chain `project`, set `'a' = "4"`
Adding chain `project`, set `'a' = "5"`
Adding chain `project`, set `'a' = "6"`
Adding chain `project`, set `'a' = "7"`
Adding chain `project`, set `'a' = "8"`
Restoring chain `project`, set `'a' = "8"`
0*`'a' = "8"`
Restoring chain `project`, set `'a' = "7"`
1*`'a' = "7"`
Restoring chain `project`, set `'a' = "6"`
2*`'a' = "6"`
Restoring chain `project`, set `'a' = "5"`
3*`'a' = "5"`
Restoring chain `project`, set `'a' = "4"`
4*`'a' = "4"`
Restoring chain `project`, set `'a' = "3"`
5*`'a' = "3"`
Restoring chain `project`, set `'a' = "2"`
6*`'a' = "2"`
Restoring chain `project`, set `'a' = "1"`
7*`'a' = "1"`
skk>b
commandlen:2
command:`b`, query:`'b'`
Deleting chain `project`
Deleting:'a' = "8"
Deleting:'a' = "7"
Deleting:'a' = "6"
Deleting:'a' = "5"
Deleting:'a' = "4"
Deleting:'a' = "3"
Deleting:'a' = "2"
Deleting:'a' = "1"
Chain `project` deleted
Adding chain `project`, set `'b' = "1"`
Adding chain `project`, set `'b' = "2"`
Adding chain `project`, set `'b' = "3"`
Adding chain `project`, set `'b' = "4"`
Restoring chain `project`, set `'b' = "4"`
0*`'b' = "4"`
Restoring chain `project`, set `'b' = "3"`
1*`'b' = "3"`
Restoring chain `project`, set `'b' = "2"`
2*`'b' = "2"`
Restoring chain `project`, set `'b' = "1"`
3*`'b' = "1"`
skk>c
commandlen:2
command:`c`, query:`'c'`
Deleting chain `project`
Deleting:'b' = "4"
Deleting:'b' = "3"
Deleting:'b' = "2"
Deleting:'b' = "1"
Chain `project` deleted
Adding chain `project`, set `'c' = "1"`
Adding chain `project`, set `'c' = "2"`
Restoring chain `project`, set `'c' = "2"`
0*`'c' = "2"`
Restoring chain `project`, set `'c' = "1"`
1*`'c' = "1"`
skk>
Ja vielä mallirivejä ilman DEBUG66:sta: Näistä huomaa helposti, että tuplatietueiden poisto toimii, mutta lajittelu (sort) ei vielä toimi.
$ ./terttuutil1 --query
skk>a
commandlen:2
command:`a`, query:`'a'`
0*`'a' = "8"`
1*`'a' = "7"`
2*`'a' = "6"`
3*`'a' = "5"`
4*`'a' = "4"`
5*`'a' = "3"`
6*`'a' = "2"`
7*`'a' = "1"`
skk>b
commandlen:2
command:`b`, query:`'b'`
0*`'b' = "4"`
1*`'b' = "3"`
2*`'b' = "2"`
3*`'b' = "1"`
skk>c
commandlen:2
command:`c`, query:`'c'`
0*`'c' = "2"`
1*`'c' = "1"`
skk>a=1
commandlen:4
command:`a=1`, query:`'a' = "1"`
0*`'a' = "1"`
skk>b=2
commandlen:4
command:`b=2`, query:`'b' = "2"`
0*`'b' = "2"`
skk>c=3
commandlen:4
command:`c=3`, query:`'c' = "3"`
skk>b=1
commandlen:4
command:`b=1`, query:`'b' = "1"`
0*`'b' = "1"`
skk>b=2
commandlen:4
command:`b=2`, query:`'b' = "2"`
0*`'b' = "2"`
skk>b=3
commandlen:4
command:`b=3`, query:`'b' = "3"`
0*`'b' = "3"`
skk>exit
Tässä vielä uudempi testimateriaalien hakuja sisältävä lista, jossa lajittelukin toimii:
$ ./terttuutil1 --query --filenameterttuutil1.skk
skk>a
commandlen:3
command:`a`, query:`'a'`
0*`'a' = "1"`
1*`'a' = "2"`
2*`'a' = "3"`
3*`'a' = "4"`
4*`'a' = "5"`
5*`'a' = "6"`
6*`'a' = "7"`
7*`'a' = "8"`
skk>b
commandlen:3
command:`b`, query:`'b'`
0*`'b' = "1"`
1*`'b' = "2"`
2*`'b' = "3"`
3*`'b' = "4"`
skk>c
commandlen:3
command:`c`, query:`'c'`
0*`'c' = "1"`
1*`'c' = "2"`
skk>exit
commandlen:6
$
Seuraavaksi jatkan satunnaisten lippujen arpomista. Käyn läpi newressu koodin lippujen osalta: Ensimmäisenä pätkä lippujen talletusrakenteesta. Seuraava kuva listaa maailman maiden liput, ja niiden erilaiset valintakriteerit. Jos esimerkiksi haluamme “arvontaan” suomen lipun voimme tehdä sen newressun komentorivioptioilla –fi, –fin, –finland, –Fi, –Fin, –Finland, –FI, –FIN, –FINLAND. Toivon että myös –🇫🇮 tulee olemaan mahdollinen. Huomaa että isolla kirjoitetut ovat suurempia ryhmiä, joihin kuuluu useampia maita, esimerkiksi suomen –FINLAND tapauksessa ryhmään kuuluu ahvenanmaa (åland). Muita muita ryhmiä, joihin suomi tässä yhteydessä kuuluu ovat –EU, –EUROPE ja –NORDIC. Jos halutaan kaikki ryhmään kuuluvat kirjoitetaan komentorivioptioksi ryhmän nimi. Tässä myös muita kuin standardia asciita sisältävät maat on kirjoitettu pelkällä asciilla, kuten åland = aland ja Curaçao = curacao.
Ensimmäinen kaksi merkkinen ascii “sana” (esimerkiksi suomen tapauksessa fi) on kaksi merkkinen isokoodi, ja kolmemerkkinen sana (suomen tapauksessa fin) on kolmemerkkinen isokoodi. Seuraavana iso-koodien jälkeen tuleva merkkijono on maan nimi ilman välilyöntejä (finland), ja loput isolla kirjoitetut ovat ryhmiä, joihin rivin maa kuuluu. Tässä lopun isoilla kirjoitetulla FINLAND sanalla suomi yhdistetään ahvenanmaahan. Lopussa on vielä ryhmät EU, EUROPE ja NORDIC.
struct idflags { // 202307 JariK
unsigned char *id;
unsigned char *flags;
} idsflags[] = {
{ "🇫🇮", "🇫🇮: fi, fin, finland, EU, EUROPE, NORDIC, FINLAND" },
{ "🇦🇽", "🇦🇽: ax, ala, åland, aland, EU, EUROPE, NORDIC, FINLAND" },
{ "🇸🇪", "🇸🇪: se, swe, sweden, EU, EUROPE, NORDIC" },
{ "🇳🇴", "🇳🇴: no, nor, norway, EU, EUROPE, NORDIC" },
{ "🇩🇰", "🇩🇰: dk, dnk, denmark, EU, EUROPE, NORDIC, DENMARK" },
{ "🇫🇴", "🇫🇴: fo, fro, FaroeIslands, EU, EUROPE, NORDIC, DENMARK" },
{ "🇮🇸", "🇮🇸: is, isl, iceland, EU, EUROPE, NORDIC" },
{ "🇪🇪", "🇪🇪: ee, est, estonia, EU, EUROPE, BALTIC" },
{ "🇱🇻", "🇱🇻: lv, lva, latvia, EU, EUROPE, BALTIC" },
{ "🇱🇹", "🇱🇹: lt, ltu, lithuania, EU, EUROPE, BALTIC" },
...
// you can find full structure in the
// beginning of this article or in the
// full source of newressu in the end
// of the article.
...
{ "🇨🇻", "🇨🇻: cv, cpv, CapeVerde, AFRICA" },
{ "🇪🇭", "🇪🇭: eh, esh, WesternSahara, AFRICA" },
{ "🇸🇹", "🇸🇹: st, stp, SãoToméandPríncipe, saotomeandprincipe, AFRICA" },
{ "🇸🇨", "🇸🇨: sc, syc, Seychelles, AFRICA" },
{ "🇦🇺", "🇦🇺: au, aus, Australia" },
};
Tässä esimerkiksi komento suomen ja ruotsin lippujen arpomiseksi: (komento ei vielä tätä kirjoittaessani arponut lippuja oikeasti, mutta nyt kun luet tätä olen varmasti koodannut arpomisen loppuun…)
$ ./newressu --fi --se --flags
00000 🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00001 🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪
00002 🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇸🇪
00003 🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇸🇪
00004 🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪
00005 🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪
00006 🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇸🇪
00007 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪🇸🇪
00008 🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪
00009 🇫🇮🇫🇮🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇸🇪🇸🇪🇫🇮🇫🇮🇫🇮🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪🇫🇮🇸🇪🇫🇮🇸🇪🇫🇮🇸🇪🇸🇪
$
Vielä pohjoismaiden (–NORDIC) maiden komentoesimerkki:
$ ./newressu --nordic --flags
00000 🇮🇸🇫🇴🇳🇴🇳🇴🇳🇴🇦🇽🇳🇴🇳🇴🇸🇪🇫🇴🇫🇴🇦🇽🇫🇴🇳🇴🇳🇴🇬🇱🇮🇸🇳🇴🇳🇴🇳🇴🇬🇱🇳🇴🇳🇴🇮🇸🇳🇴🇬🇱🇫🇮🇸🇪🇸🇪🇮🇸
00001 🇫🇮🇳🇴🇩🇰🇳🇴🇳🇴🇫🇮🇬🇱🇩🇰🇸🇪🇳🇴🇫🇮🇸🇪🇩🇰🇫🇮🇮🇸🇦🇽🇫🇴🇳🇴🇮🇸🇩🇰🇫🇴🇮🇸🇮🇸🇸🇪🇳🇴🇸🇪🇦🇽🇬🇱🇦🇽🇬🇱
00002 🇩🇰🇫🇮🇮🇸🇫🇮🇩🇰🇬🇱🇮🇸🇮🇸🇬🇱🇬🇱🇸🇪🇮🇸🇦🇽🇦🇽🇬🇱🇫🇴🇫🇴🇳🇴🇬🇱🇮🇸🇦🇽🇦🇽🇦🇽🇫🇴🇬🇱🇸🇪🇩🇰🇫🇮🇩🇰🇮🇸
00003 🇩🇰🇬🇱🇫🇮🇫🇴🇳🇴🇸🇪🇳🇴🇫🇴🇮🇸🇫🇴🇫🇮🇩🇰🇮🇸🇫🇮🇸🇪🇬🇱🇬🇱🇩🇰🇩🇰🇦🇽🇸🇪🇬🇱🇫🇴🇫🇴🇮🇸🇸🇪🇦🇽🇫🇴🇬🇱🇮🇸
00004 🇦🇽🇳🇴🇫🇴🇩🇰🇸🇪🇳🇴🇩🇰🇳🇴🇦🇽🇫🇴🇸🇪🇮🇸🇬🇱🇳🇴🇫🇴🇸🇪🇫🇴🇩🇰🇮🇸🇬🇱🇫🇴🇦🇽🇩🇰🇫🇮🇳🇴🇫🇮🇫🇴🇮🇸🇫🇴🇳🇴
00005 🇫🇴🇦🇽🇬🇱🇩🇰🇫🇴🇫🇮🇦🇽🇫🇮🇦🇽🇳🇴🇦🇽🇦🇽🇫🇴🇦🇽🇮🇸🇦🇽🇬🇱🇳🇴🇬🇱🇬🇱🇸🇪🇫🇴🇦🇽🇬🇱🇫🇴🇬🇱🇸🇪🇬🇱🇮🇸🇳🇴
00006 🇸🇪🇸🇪🇩🇰🇩🇰🇮🇸🇫🇮🇫🇮🇸🇪🇮🇸🇬🇱🇮🇸🇸🇪🇫🇴🇦🇽🇸🇪🇸🇪🇮🇸🇩🇰🇫🇴🇦🇽🇫🇮🇳🇴🇫🇮🇩🇰🇬🇱🇫🇮🇮🇸🇬🇱🇦🇽🇬🇱
00007 🇮🇸🇦🇽🇫🇮🇮🇸🇩🇰🇬🇱🇫🇴🇮🇸🇫🇮🇮🇸🇬🇱🇸🇪🇩🇰🇸🇪🇫🇴🇮🇸🇸🇪🇫🇴🇩🇰🇩🇰🇫🇮🇳🇴🇦🇽🇫🇴🇸🇪🇳🇴🇳🇴🇮🇸🇳🇴🇩🇰
00008 🇫🇴🇬🇱🇦🇽🇬🇱🇫🇴🇸🇪🇬🇱🇦🇽🇦🇽🇫🇴🇫🇴🇦🇽🇫🇮🇫🇮🇫🇴🇬🇱🇬🇱🇬🇱🇸🇪🇸🇪🇬🇱🇫🇮🇬🇱🇳🇴🇳🇴🇳🇴🇳🇴🇬🇱🇸🇪🇬🇱
00009 🇫🇮🇳🇴🇮🇸🇮🇸🇬🇱🇦🇽🇬🇱🇮🇸🇦🇽🇮🇸🇩🇰🇦🇽🇦🇽🇫🇴🇸🇪🇫🇮🇫🇮🇬🇱🇸🇪🇦🇽🇫🇴🇩🇰🇦🇽🇬🇱🇳🇴🇫🇴🇳🇴🇬🇱🇩🇰🇬🇱
$
Tässä vielä eu:n lippuesimerkki:
$ ./newressu --eu --flags
00000 🇱🇺🇦🇹🇵🇱🇪🇪🇸🇰🇩🇪🇸🇪🇧🇪🇮🇹🇧🇪🇧🇪🇵🇹🇨🇿🇵🇱🇩🇪🇷🇴🇫🇷🇱🇻🇲🇹🇪🇪🇳🇱🇲🇹🇬🇷🇪🇸🇵🇹🇫🇮🇲🇹🇵🇹🇸🇰🇳🇱
00001 🇭🇷🇧🇪🇸🇪🇨🇾🇵🇱🇩🇪🇮🇹🇸🇮🇭🇺🇩🇰🇫🇮🇬🇷🇲🇹🇧🇪🇮🇹🇫🇮🇮🇪🇮🇹🇫🇷🇳🇱🇸🇰🇩🇪🇫🇷🇧🇪🇬🇷🇵🇹🇸🇰🇭🇷🇧🇬🇫🇷
00002 🇸🇮🇸🇮🇫🇷🇸🇰🇱🇺🇵🇹🇬🇷🇸🇮🇸🇮🇵🇹🇲🇹🇷🇴🇱🇻🇮🇪🇧🇬🇪🇸🇨🇾🇮🇪🇱🇺🇱🇹🇲🇹🇸🇰🇫🇷🇭🇺🇩🇰🇭🇺🇱🇻🇱🇹🇩🇰🇮🇹
00003 🇫🇮🇸🇪🇵🇱🇸🇰🇮🇹🇫🇷🇳🇱🇸🇰🇭🇷🇭🇺🇸🇮🇩🇰🇮🇪🇧🇪🇫🇷🇨🇾🇲🇹🇭🇺🇩🇰🇮🇹🇭🇷🇫🇮🇧🇪🇮🇹🇧🇪🇷🇴🇱🇻🇫🇮🇧🇪🇪🇸
00004 🇬🇷🇸🇰🇱🇺🇧🇬🇮🇪🇩🇪🇫🇮🇸🇰🇷🇴🇮🇪🇨🇾🇬🇷🇭🇺🇸🇪🇨🇾🇩🇰🇵🇱🇱🇹🇮🇹🇱🇺🇭🇺🇸🇪🇪🇸🇪🇸🇪🇸🇵🇱🇱🇺🇬🇷🇸🇮🇷🇴
00005 🇩🇰🇭🇷🇸🇪🇸🇪🇸🇮🇪🇪🇮🇹🇨🇾🇳🇱🇵🇹🇫🇮🇮🇪🇪🇸🇸🇰🇨🇿🇪🇪🇫🇮🇳🇱🇮🇹🇲🇹🇪🇸🇫🇮🇫🇮🇧🇪🇩🇰🇸🇪🇧🇪🇪🇪🇱🇹🇨🇿
00006 🇵🇱🇨🇿🇸🇮🇮🇹🇨🇾🇫🇮🇩🇪🇪🇪🇳🇱🇪🇪🇭🇷🇷🇴🇱🇹🇩🇪🇸🇮🇱🇻🇱🇻🇱🇻🇭🇷🇵🇹🇨🇾🇭🇺🇵🇹🇬🇷🇪🇪🇪🇸🇩🇰🇱🇻🇦🇹🇭🇺
00007 🇪🇸🇸🇮🇮🇹🇫🇷🇨🇿🇧🇬🇧🇬🇬🇷🇸🇮🇭🇷🇬🇷🇪🇪🇮🇹🇷🇴🇸🇰🇸🇪🇨🇾🇳🇱🇦🇹🇸🇪🇬🇷🇸🇮🇪🇪🇪🇪🇦🇹🇪🇸🇪🇪🇭🇺🇪🇪🇲🇹
00008 🇷🇴🇲🇹🇸🇰🇸🇮🇪🇪🇮🇹🇪🇪🇵🇹🇩🇰🇸🇰🇨🇾🇱🇻🇬🇷🇳🇱🇫🇷🇪🇸🇵🇹🇩🇪🇨🇾🇸🇰🇮🇹🇭🇷🇸🇮🇮🇹🇦🇹🇭🇷🇨🇿🇦🇹🇸🇮🇫🇷
00009 🇸🇪🇦🇹🇳🇱🇸🇮🇪🇸🇸🇮🇩🇰🇫🇮🇸🇪🇱🇻🇫🇮🇦🇹🇩🇰🇱🇺🇫🇷🇵🇹🇳🇱🇲🇹🇸🇰🇵🇱🇨🇾🇭🇷🇫🇷🇸🇮🇪🇪🇳🇱🇪🇸🇮🇹🇨🇾🇷🇴
$
Ja vielä esimerkki lipun kuvalla:
$ ./newressu --🇫🇮 --flags
00000 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00001 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00002 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00003 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00004 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00005 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00006 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00007 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00008 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
00009 🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮🇫🇮
$
AFRICA:n lippuja: (nyt on ruotsin lippu alarivillä eksynyt. se oli itseasiassa komennossa…)
$ ./newressu --AFRICA --flags
00000 🇺🇬🇹🇬🇲🇿🇨🇮🇪🇹🇸🇱🇧🇮🇧🇮🇲🇿🇬🇳🇲🇺🇾🇹🇱🇷🇱🇾🇲🇿🇿🇦🇸🇱🇺🇬🇩🇿🇬🇲🇪🇹🇬🇼🇨🇩🇺🇬🇱🇸🇩🇿🇬🇦🇸🇱🇲🇺🇲🇷
00001 🇦🇴🇷🇼🇿🇼🇲🇺🇲🇼🇨🇩🇸🇳🇨🇻🇪🇹🇲🇷🇨🇩🇪🇹🇳🇪🇿🇦🇿🇲🇳🇪🇲🇺🇬🇦🇸🇳🇸🇳🇧🇮🇬🇳🇪🇷🇪🇬🇱🇸🇹🇿🇩🇯🇨🇻🇨🇮🇬🇭
00002 🇨🇩🇱🇾🇰🇲🇱🇷🇱🇾🇧🇯🇲🇷🇹🇬🇸🇩🇪🇭🇸🇸🇲🇺🇹🇩🇪🇷🇨🇮🇿🇲🇱🇸🇧🇯🇪🇷🇺🇬🇳🇦🇪🇬🇨🇩🇾🇹🇲🇿🇺🇬🇸🇳🇨🇻🇹🇩🇩🇿
00003 🇲🇺🇧🇯🇳🇦🇨🇮🇦🇴🇷🇪🇨🇩🇪🇹🇷🇼🇰🇪🇿🇦🇧🇯🇨🇲🇹🇬🇩🇯🇸🇱🇿🇲🇨🇩🇨🇮🇨🇩🇨🇲🇦🇴🇱🇾🇸🇸🇰🇪🇬🇭🇱🇸🇲🇺🇲🇱🇸🇸
00004 🇰🇲🇬🇭🇲🇿🇩🇯🇬🇭🇿🇲🇹🇬🇩🇿🇧🇼🇱🇷🇧🇮🇬🇦🇩🇿🇲🇿🇹🇿🇸🇨🇱🇷🇿🇼🇲🇱🇷🇪🇷🇪🇧🇫🇸🇱🇬🇳🇦🇴🇲🇺🇨🇻🇨🇲🇹🇿🇹🇳
00005 🇲🇿🇷🇪🇪🇬🇺🇬🇧🇯🇨🇻🇹🇩🇪🇷🇲🇿🇩🇯🇨🇩🇰🇪🇨🇩🇨🇬🇨🇩🇸🇩🇲🇺🇱🇾🇲🇺🇪🇷🇧🇼🇾🇹🇸🇸🇲🇺🇹🇳🇿🇲🇸🇩🇸🇨🇷🇪🇩🇿
00006 🇲🇺🇬🇼🇸🇸🇧🇮🇲🇺🇪🇷🇪🇹🇲🇷🇨🇬🇲🇺🇬🇳🇲🇦🇸🇩🇰🇪🇸🇳🇪🇬🇸🇿🇿🇼🇬🇼🇬🇭🇷🇼🇸🇴🇪🇷🇧🇯🇬🇲🇨🇲🇨🇮🇸🇨🇰🇪🇲🇷
00007 🇪🇬🇸🇳🇬🇦🇬🇭🇸🇿🇱🇾🇦🇴🇨🇮🇨🇩🇹🇳🇪🇬🇬🇲🇲🇿🇹🇬🇬🇲🇬🇲🇱🇸🇬🇳🇧🇫🇩🇿🇸🇱🇲🇬🇱🇾🇱🇷🇨🇩🇪🇷🇸🇳🇱🇷🇪🇹🇹🇬
00008 🇲🇼🇱🇾🇸🇴🇲🇿🇿🇼🇲🇬🇱🇸🇨🇻🇸🇸🇦🇴🇸🇸🇷🇼🇬🇦🇷🇪🇸🇸🇨🇬🇱🇾🇲🇦🇱🇾🇧🇼🇸🇱🇨🇲🇬🇼🇳🇪🇸🇨🇳🇪🇲🇱🇪🇷🇷🇪🇬🇳
00009 🇪🇷🇸🇸🇬🇭🇨🇩🇨🇻🇬🇲🇲🇷🇲🇺🇸🇨🇲🇷🇹🇩🇿🇦🇸🇱🇺🇬🇨🇲🇸🇸🇨🇮🇷🇪🇲🇺🇰🇲🇲🇷🇳🇪🇧🇯🇳🇪🇨🇲🇸🇸🇹🇩🇨🇻🇸🇸🇸🇸
$
Etelä afrikka: (SOUTHAFRICA)
$ ./newressu --SOUTHAFRICA --flags
00000 🇱🇸🇧🇼🇱🇸🇳🇦🇸🇿🇧🇼🇿🇦🇿🇦🇳🇦🇸🇿🇸🇿🇸🇿🇸🇿🇿🇦🇸🇿🇿🇦🇧🇼🇱🇸🇱🇸🇳🇦🇧🇼🇧🇼🇧🇼🇸🇿🇱🇸🇧🇼🇧🇼🇿🇦🇿🇦🇱🇸
00001 🇳🇦🇧🇼🇳🇦🇸🇿🇱🇸🇸🇿🇳🇦🇸🇿🇧🇼🇳🇦🇿🇦🇳🇦🇿🇦🇧🇼🇧🇼🇸🇿🇱🇸🇧🇼🇳🇦🇸🇿🇿🇦🇧🇼🇧🇼🇧🇼🇳🇦🇿🇦🇳🇦🇧🇼🇿🇦🇱🇸
00002 🇿🇦🇸🇿🇧🇼🇱🇸🇸🇿🇳🇦🇿🇦🇧🇼🇱🇸🇳🇦🇿🇦🇸🇿🇧🇼🇿🇦🇸🇿🇳🇦🇱🇸🇱🇸🇱🇸🇱🇸🇳🇦🇧🇼🇿🇦🇱🇸🇸🇿🇱🇸🇱🇸🇸🇿🇿🇦🇸🇿
00003 🇳🇦🇳🇦🇧🇼🇸🇿🇳🇦🇳🇦🇸🇿🇱🇸🇱🇸🇱🇸🇧🇼🇧🇼🇳🇦🇸🇿🇱🇸🇸🇿🇸🇿🇧🇼🇱🇸🇸🇿🇸🇿🇳🇦🇱🇸🇳🇦🇳🇦🇱🇸🇧🇼🇸🇿🇸🇿🇸🇿
00004 🇿🇦🇿🇦🇧🇼🇸🇿🇱🇸🇳🇦🇧🇼🇿🇦🇳🇦🇸🇿🇱🇸🇱🇸🇧🇼🇱🇸🇸🇿🇱🇸🇿🇦🇿🇦🇱🇸🇱🇸🇿🇦🇱🇸🇳🇦🇳🇦🇳🇦🇳🇦🇿🇦🇧🇼🇳🇦🇳🇦
00005 🇿🇦🇱🇸🇱🇸🇧🇼🇧🇼🇿🇦🇱🇸🇧🇼🇳🇦🇧🇼🇿🇦🇿🇦🇸🇿🇧🇼🇱🇸🇳🇦🇧🇼🇸🇿🇱🇸🇸🇿🇸🇿🇱🇸🇳🇦🇳🇦🇱🇸🇳🇦🇿🇦🇿🇦🇧🇼🇧🇼
00006 🇿🇦🇿🇦🇱🇸🇿🇦🇳🇦🇿🇦🇳🇦🇧🇼🇸🇿🇳🇦🇳🇦🇱🇸🇸🇿🇱🇸🇧🇼🇸🇿🇱🇸🇿🇦🇿🇦🇧🇼🇧🇼🇧🇼🇿🇦🇧🇼🇧🇼🇧🇼🇧🇼🇱🇸🇸🇿🇱🇸
00007 🇿🇦🇧🇼🇸🇿🇸🇿🇳🇦🇱🇸🇿🇦🇧🇼🇳🇦🇳🇦🇳🇦🇳🇦🇸🇿🇱🇸🇳🇦🇧🇼🇳🇦🇸🇿🇱🇸🇸🇿🇿🇦🇱🇸🇧🇼🇳🇦🇳🇦🇳🇦🇧🇼🇳🇦🇿🇦🇧🇼
00008 🇿🇦🇿🇦🇧🇼🇱🇸🇱🇸🇿🇦🇱🇸🇿🇦🇸🇿🇱🇸🇱🇸🇿🇦🇿🇦🇱🇸🇸🇿🇿🇦🇳🇦🇿🇦🇿🇦🇧🇼🇸🇿🇱🇸🇳🇦🇿🇦🇸🇿🇳🇦🇳🇦🇸🇿🇸🇿🇳🇦
00009 🇸🇿🇳🇦🇸🇿🇸🇿🇸🇿🇱🇸🇳🇦🇳🇦🇧🇼🇧🇼🇿🇦🇱🇸🇳🇦🇸🇿🇸🇿🇿🇦🇱🇸🇿🇦🇧🇼🇸🇿🇱🇸🇱🇸🇱🇸🇱🇸🇱🇸🇳🇦🇸🇿🇱🇸🇸🇿🇧🇼
$
Vielä lippuja –all optiolla: huomaa EquatorialGuinea:n lippu “cq”, joka tarkoittaa että isokoodilla cq ei löytynyt utf8 lippua. Lisätty muutamia puuttuvia maita.
$ ./newressu --all --flags
00000 🇯🇪🇨🇷🇲🇽🇨🇿🇰🇼🇨🇴🇵🇫🇸🇸🇬🇳🇹🇰🇻🇳🇰🇵🇧🇾🇱🇾🇺🇾🇰🇪🇪🇪🇵🇪🇦🇸🇵🇹🇬🇺🇸🇱🇬🇱🇰🇿🇲🇺🇫🇯🇬🇹🇷🇸🇹🇯🇨🇮
00001 🇫🇷🇻🇪🇰🇮🇩🇯🇬🇪🇪🇬🇸🇲🇴🇲🇰🇮🇰🇵🇸🇬🇵🇼🇸🇧🇻🇮🇩🇴🇨🇷🇵🇸🇱🇷🇩🇪🇧🇫🇾🇪🇬🇲🇪🇬🇨🇼🇬🇸🇪🇨🇫🇷🇰🇮🇾🇪🇨🇶
00002 🇹🇿🇦🇫🇵🇷🇨🇳🇲🇺🇲🇶🇸🇻🇾🇹🇵🇼🇳🇦🇯🇪🇹🇿🇧🇼🇳🇺🇭🇰🇹🇲🇲🇷🇵🇳🇨🇾🇾🇪🇧🇸🇰🇮🇲🇺🇧🇻🇷🇸🇸🇮🇾🇪🇰🇵🇨🇫🇮🇷
00003 🇮🇪🇬🇮🇰🇼🇵🇷🇸🇷🇬🇳🇫🇰🇸🇾🇩🇿🇧🇫🇻🇮🇿🇼🇫🇷🇭🇰🇱🇷🇦🇹🇹🇬🇸🇳🇳🇵🇧🇲🇹🇿🇧🇦🇦🇹🇱🇰🇷🇼🇹🇯🇳🇨🇧🇸🇧🇻🇨🇱
00004 🇰🇵🇮🇶🇰🇼🇰🇬🇸🇴🇨🇫🇵🇫🇫🇷🇸🇴🇪🇸🇱🇸🇪🇭🇨🇩🇦🇹🇶🇦🇩🇲🇬🇳🇲🇻🇨🇷🇪🇸🇰🇪🇰🇾🇱🇻🇮🇳🇬🇺🇨🇶🇧🇶🇰🇲🇳🇷🇹🇩
00005 🇺🇿🇩🇲🇵🇳🇨🇿🇧🇮🇧🇴🇪🇪🇲🇹🇬🇾🇸🇾🇸🇧🇵🇸🇱🇷🇨🇦🇬🇩🇻🇨🇮🇷🇲🇶🇵🇭🇸🇪🇵🇹🇸🇮🇬🇬🇱🇾🇲🇿🇵🇲🇺🇾🇼🇸🇸🇷🇬🇪
00006 🇱🇮🇫🇲🇾🇹🇪🇹🇨🇿🇻🇪🇮🇩🇵🇪🇲🇱🇨🇷🇵🇹🇱🇸🇲🇿🇨🇴🇨🇶🇳🇿🇦🇪🇬🇷🇪🇨🇸🇽🇸🇪🇨🇩🇪🇨🇼🇫🇮🇷🇱🇧🇩🇰🇮🇷🇻🇪🇧🇧
00007 🇵🇾🇨🇬🇺🇾🇲🇹🇸🇦🇨🇱🇨🇩🇹🇱🇵🇾🇳🇺🇬🇮🇸🇳🇫🇰🇿🇦🇦🇼🇲🇰🇪🇬🇦🇴🇧🇧🇹🇩🇯🇵🇺🇾🇸🇪🇹🇩🇬🇵🇮🇩🇸🇴🇪🇸🇺🇾🇨🇲
00008 🇬🇵🇲🇿🇹🇨🇹🇱🇹🇹🇧🇼🇾🇪🇮🇷🇲🇱🇰🇪🇹🇫🇬🇩🇱🇮🇰🇿🇾🇪🇨🇾🇨🇼🇬🇺🇳🇺🇦🇶🇹🇿🇲🇩🇲🇿🇲🇦🇸🇳🇸🇻🇫🇷🇲🇺🇹🇳🇩🇯
00009 🇲🇪🇲🇫🇳🇪🇭🇳🇫🇷🇵🇳🇲🇽🇷🇸🇨🇩🇲🇻🇧🇯🇰🇮🇰🇪🇵🇪🇸🇻🇵🇸🇱🇮🇫🇰🇲🇱🇯🇵🇵🇪🇸🇽🇷🇴🇮🇪🇸🇲🇲🇲🇮🇴🇾🇹🇨🇮🇺🇸
$
Seuraavassa rutiini, jolle kaikki komentoriviparametrit annetaan, ja funktio merkkaa ne id:t (tässä tapauksessa liput), jotka komentoriviparametri valitsee. Esimerkiksi ‘fi’ kääntää suomen kytkimen, samalla tavoin kun aiemminkin komentorivikytkimet ovat toimineet. Jos komentorivillä on useampia kytkimiä, jokaisella niistä kutsutaan tätä erikseen. Jos ensin ensimmäinen kytkin valitsee ‘finland’ lipun, se merkitään ensimmäisellä kutsulla, ja jos sen jälkeen valitaan ‘sweden’, se merkitään toisella kutsulla. Näin sekä finland ja sweden tulevat valituiksi. Jos komentoriviparametreissä on –all optio, se käynnistää “ALL” option joka kääntää kaikki “liput” vastakkaisiksi.
Rutiini tarkistaa myös että optio on kokonainen sana, eli että sanan jälkeen on välilyönti, pilkku, kaksoispiste (alun lipunkuva) tai merkkijonon loppu. Samoin merkkijoa pitää edeltää merkkijonon alku, välilyönti, pilkku tai kaksoispiste.
Varsinaiset objektikohtaiset liput ovat flagids kentässä. Siinä on tilaa jokaiselle lipulle (1 merkki/lippu, arvot 1/0, tulostetaan/ei tulosteta).
int newressu_toggleflag(unsigned char *flag)
{
int c, ok;
unsigned char *p, *q;
if(!strcmp(flag, "ALL")) {
idsall = !idsall;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
flagids[c] = idsall;
}
flagidflags = 1; // display flags
ok = 1; // one flag toggled
} else {
ok = 0;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
p = strstr(idsflags[c].flags, flag);
q = idsflags[c].flags;
int fl = strlen(flag);
if( p != NULL && // string found
(*(p + fl) == ' ' || *(p + fl) == ',' || *(p + fl) == ':' || *(p + fl) == '\0') && // character after string
( (p == q) || ( *(p - 1) == ' ' || *(p - 1) == ',' || *(p - 1) == ':' ) ) ) { // character before string
flagids[c] = !flagids[c];
//fprintf(stderr,"idsflags[%d].flags %s, toggled, value:%d\n", c, idsflags[c].flags, flagids[c]);
fflush(stderr);
flagidflags = 1; // display flags
ok = 1; // one flag toggled
}
}
//if(ok)
// fprintf(stdout,"\n");
}
return(ok);
}
int main(int argc, char *argv[])
{
....
//
// look thru command line parameters
//
for(c = 1; c < argc; c++) {
int ok = 1;
if(!strncmp("-", argv[c], 1)) {
....
} else if(!strcmp("--flags", argv[c])) { // not ready
// intentionally left empty
} else if(!strcmp("--all", argv[c])) { // not ready
if(flagsinit) {
idsall = 1;
newressu_toggleflag("ALL");
flagsinit = 0;
}
} else {
ok = 0;
}
unsigned char buffer[32];
int ok2 = 0;
if(!strncmp(argv[c], "--", 2)) {
if(flagsinit) {
idsall = 0;
newressu_toggleflag(buffer);
flagsinit = 0;
}
strcpy(buffer, argv[c] + 2); // as is
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
strtolower(buffer); // all letters lowercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
buffer[0] = toupper(buffer[0]); // first letter uppercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
strtoupper(buffer); // all letters uppercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
}
}
}
}
if( (!flagflags && ok == 0) ||
(flagflags && ok == 0 && ok2 == 0)) {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
} // if(!strncmp
} // for(c = 0
if(flagflags) {
int first = 1;
for(d = 0; d < sizeof(idsflags) / sizeof(idsflags[0]); d++) {
if(flagids[d] == 1) {
if(first) {
fprintf(stdout,"flags: ");
first = 0;
}
fprintf(stdout," %s",idsflags[d].id);
}
}
if(!first)
fprintf(stdout,"\n");
digits = "🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿";
//digits = "🇫🇮🇸🇪🇳🇴🇩🇰🇪🇪🇱🇻🇱🇹";
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
}
....
} // if(!strncmp
....
} // for(c = 0
....
}
Lisätty uusi debukki DEBUG77, joka tulostaa yhteenvedon eri alueiden lipuista: tässä listaus sen tulostamasta raportista:
area:FINLAND, finland, åland, count:2
area:DENMARK, denmark, FaroeIslands, greenland, count:3
area:NORDIC, finland, åland, sweden, norway, denmark, FaroeIslands, iceland, greenland, count:8
area:BALTIC, estonia, latvia, lithuania, count:3
area:EU, finland, sweden, denmark, estonia, latvia, lithuania, austria, belgium, bulgaria, croatia, cyprus, czechrepublic, france, germany, Greece, Hungary, Ireland, Italy, Luxembourg, Malta, Netherlands, Poland, Portugal, Romania, Slovakia, Slovenia, Spain, count:27
area:EUROPE, finland, sweden, norway, denmark, iceland, estonia, latvia, lithuania, ukraine, albania, albania, Armenia, austria, Azerbaijan, belarus, belgium, bulgaria, croatia, cyprus, czechrepublic, france, Georgia, germany, Greece, Hungary, Ireland, Italy, Vatican, Kazakhstan, Liechtenstein, Luxembourg, Malta, moldova, monaco, montenegro, Netherlands, Poland, Portugal, Romania, Russia, sanmarino, serbia, Slovakia, Slovenia, Turkey, Spain, UnitedKingdom, count:47
area:ASIA, Armenia, Azerbaijan, cyprus, Georgia, Kazakhstan, Russia, Turkey, UnitedArabEmirates, Afghanistan, Bangladesh, Bahrain, Brunei, Bhutan, China, HongKong, Indonesia, Israel, India, Iraq, Iran, Jordan, Japan, Kyrgyzstan, Cambodia, SouthKorea, Kuwait, Laos, Lebanon, SriLanka, Mongolia, Macao, Maldives, Myanmar, Malaysia, NorthKorea, Nepal, Oman, Philippines, Pakistan, Palestine, Qatar, SaudiArabia, Singapore, Syria, Thailand, Tajikistan, EastTimor, Turkmenistan, Taiwan, Uzbekistan, Vietnam, Yemen, Egypt, count:53
area:AFRICA, Nigeria, Ethiopia, Eritrea, Congo, DemocraticCongo, Tanzania, SouthAfrica, Kenya, Uganda, SouthSudan, sudan, Algeria, Egypt, Libya, Madeira, Morocco, Angola, Ghana, Mozambique, Madagascar, mayotte, IvoryCoast, Cameroon, Niger, BurkinaFaso, Mali, Malawi, Zambia, Chad, Somalia, Senegal, Zimbabwe, Guinea, Rwanda, Benin, Burundi, Tunisia, Togo, SierraLeone, Congo, Liberia, Mauritania, Eritrea, Gambia, Botswana, Namibia, Gabon, Lesotho, GuineaBissau, Mauritius, Mozambique, Eswatini, Djibouti, Comoros, CapeVerde, WesternSahara, Seychelles, Réunion, count:58
area:NORTHAFRICA, Algeria, Egypt, Libya, Madeira, Morocco, Tunisia, WesternSahara, count:7
area:EASTAFRICA, Ethiopia, Eritrea, Tanzania, Kenya, Uganda, SouthSudan, sudan, Madagascar, mayotte, Malawi, Zambia, Somalia, Zimbabwe, Rwanda, Burundi, Eritrea, Mauritius, Mozambique, Djibouti, Seychelles, Réunion, count:21
area:CENTRALAFRICA, Congo, DemocraticCongo, Angola, Cameroon, Chad, CentralAfrican, Gabon, EquatorialGuinea, SãoToméandPríncipe, count:9
area:SOUTHAFRICA, SouthAfrica, Botswana, Namibia, Lesotho, Eswatini, count:5
area:WESTAFRICA, Ghana, IvoryCoast, Niger, BurkinaFaso, Mali, Senegal, Guinea, Benin, Togo, SierraLeone, Liberia, Mauritania, Gambia, GuineaBissau, CapeVerde, count:15
area:SOUTHAMERICA, Argentina, Bolivia, Brazil, Chile, Colombia, Ecuador, FalklandIslands, FrenchGuiana, Guyana, Paraguay, Peru, Suriname, Uruguay, Venezuela, count:14
area:NORTHAMERICA, greenland, Anguilla, AntiguaAndBarbuda, Aruba, Bahamas, Barbados, Belize, Bermuda, Bonaire, BritishVirginIslands, Canada, CaymanIslands, ClippertonIsland, CostaRica, Cuba, Curaçao, Dominica, DominicanRepublic, ElSalvador, Greenland, Grenada, Guadeloupe, Guatemala, Haiti, Honduras, Jamaica, Martinique, Mexico, Montserrat, Nicaragua, Panama, PuertoRico, Saba, SaintBarthélemy, SaintKitts, SaintLucia, SaintMartin, SaintPierre, SaintVincent, TrinidadandTobago, VirginIslands, count:41
area:OCEANIA, kiribati, count:1
area:ALL, finland, åland, sweden, norway, denmark, FaroeIslands, iceland, greenland, estonia, latvia, lithuania, ukraine, albania, albania, Armenia, austria, Azerbaijan, belarus, belgium, bosniaandherzegovina, bulgaria, croatia, cyprus, czechrepublic, france, Georgia, germany, Greece, Hungary, Ireland, Italy, Vatican, Kazakhstan, Liechtenstein, Luxembourg, Malta, moldova, monaco, montenegro, Netherlands, northmacedonia, Poland, Portugal, Romania, Russia, sanmarino, serbia, Slovakia, Slovenia, Turkey, Spain, UnitedKingdom, England, Scotland, Wales, Anguilla, AntiguaAndBarbuda, Argentina, Aruba, Bahamas, Barbados, Belize, Bermuda, Bolivia, Bonaire, BouvetIsland, Brazil, BritishVirginIslands, Canada, CaymanIslands, Chile, ClippertonIsland, Colombia, CostaRica, Cuba, Curaçao, Dominica, DominicanRepublic, Ecuador, ElSalvador, FalklandIslands, FrenchGuiana, Greenland, Grenada, Guadeloupe, Guatemala, Guyana, Haiti, Honduras, Jamaica, Martinique, Mexico, Montserrat, Navassa, Nicaragua, Panama, Paraguay, Peru, PuertoRico, Saba, SaintBarthélemy, SaintKitts, SaintLucia, SaintMartin, SaintPierre, SaintVincent, SintMaarten, SouthGeorgia, Suriname, TrinidadandTobago, TurksandCaicos, UnitedStatesofAmerica, VirginIslands, Uruguay, Venezuela, UnitedArabEmirates, Afghanistan, Bangladesh, Bahrain, Brunei, Bhutan, China, HongKong, Indonesia, Israel, India, Iraq, Iran, Jordan, Japan, Kyrgyzstan, Cambodia, SouthKorea, Kuwait, Laos, Lebanon, SriLanka, Mongolia, Macao, Maldives, Myanmar, Malaysia, NorthKorea, Nepal, Oman, Philippines, Pakistan, Palestine, Qatar, SaudiArabia, Singapore, Syria, Thailand, Tajikistan, EastTimor, Turkmenistan, Taiwan, Uzbekistan, Vietnam, Yemen, Nigeria, Ethiopia, Eritrea, Congo, DemocraticCongo, Tanzania, SouthAfrica, Kenya, Uganda, SouthSudan, sudan, Algeria, Egypt, Libya, Madeira, Morocco, Angola, Ghana, Mozambique, Madagascar, mayotte, IvoryCoast, Cameroon, Niger, BurkinaFaso, Mali, Malawi, Zambia, Chad, Somalia, Senegal, Zimbabwe, Guinea, Rwanda, Benin, Burundi, Tunisia, Togo, SierraLeone, Congo, CentralAfrican, Liberia, Mauritania, Eritrea, Gambia, Botswana, Namibia, Gabon, Lesotho, GuineaBissau, EquatorialGuinea, Mauritius, Mozambique, Eswatini, Djibouti, Comoros, CapeVerde, WesternSahara, SãoToméandPríncipe, Seychelles, Australia, kiribati, antarctica, cookislands, newzealand, niue, tokelau, americansamoa, britishindianocean, christmasisland, cocosislands, fiji, frenchpolynesia, frenchsouthernandantarctic, gibraltar, guam, guernsey, heardandmacdonaldsislands, manisle, jersey, liechtenstein, marshallislands, micronesia, nauru, newcaledonia, norfolkisland, northernmariana, paiau, papuanewguinea, pitcairn, Réunion, tristandacunha, samoa, solomonislands, janmayen, tuvalu, usminoroutlyingislands, vanuatu, wallisandfutuna, count:259
00000 23933476602239466377815183666336410526913255853507880902531575913
00001 75892311131489151051584635035296694319912096485236112089206322461
00002 38592554073360093998514241158337970540330801205676600268884077746
00003 13319205731345237480638193592296597610207468715353376895830326942
00004 35590860392770168574790082985573286375551823885389108732528064216
00005 25219754152834136322488110178605362616714455236854036050793549832
00006 45176182884339628322847596264906590850829829071656985062184052439
00007 51278261352573525446779932273640595147314743083454039849513229535
00008 44658224189508110992349860032329909065106543682283883425608435040
00009 48669205961987714566615256512928279472410821451443832019885646062
Vielä 77-debukin koodi:
#define DEBUG77
#ifdef DEBUG77
unsigned char *areaflags = "FINLAND, DENMARK, NORDIC, BALTIC, EU, EUROPE, ASIA, AFRICA, SOUTHAMERICA, NORTHAMERICA, OCEANIA, ALL", *a;
unsigned char name[1024];
a = areaflags;
while(*a != '\0' && newressu_get_name(sizeof(name), name, &a)) {
fprintf(stdout,"area: %s",name);
count = 0;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
if(!strcmp(name, "ALL")) {
count++;
q = idsflags[c].flags;
unsigned char name2[1024];
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
fprintf(stdout,", %s",name2);
} else {
p = strstr(idsflags[c].flags, name);
q = idsflags[c].flags;
int fl = strlen(name);
if( p != NULL && // string found
( isblank(*(p + fl)) || ispunct(*(p + fl)) || *(p + fl) == '\0' ) && // character after string
( (p == q) || isblank(*(p - 1)) || ispunct(*(p - 1)) ) ) { // character before string
count++;
q = idsflags[c].flags;
unsigned char name2[1024];
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
newressu_get_name(sizeof(name2), name2, &q);
fprintf(stdout,", %s",name2);
}
}
}
fprintf(stdout,", count:%d",count);
fprintf(stdout,"\n");
}
#endif
Edellisen debukin käyttämä get_name rutiini:
int newressu_get_name(int length, unsigned char *name, unsigned char **p2)
{
int len, ok = 0;
unsigned char *n, *p;
p = *p2;
n = name;
len = 0;
while(ispunct(*p) || isblank(*p)) {
p++;
}
while(*p != '\0' && !ispunct(*p) && !isblank(*p)) {
if(len < length) {
*n++ = *p;
ok = 1;
}
p++;
len++;
}
*n = '\0';
*p2 = p;
return(ok);
}
Lisätty terttuutil1:een uusi tapa tuottaa testimateriaalia. Tässä testimateriaalia luodaan edeltä määritellyn rakenteen mukaisesti: rakenteessa luetellaan kentät, joita tarvitaan ja niiden arvojoukot ja tulostuksen formatointi.
struct field {
unsigned char *fieldname;
int fieldtype;
int lowlimit;
int highlimit;
unsigned char *valuestring;
} fields[] = {
{ "asno", SEQUENTIAL, 0, 0,"10%05d" },
{ "asnimi", SEQUENTIAL, 0,0, "nimi: %d" },
{ "asoso", SEQUENTIAL, 0, 0, "osoite: %d" },
{ "aspono", RANDOM, 0, 99999, "postinumero%d"},
{ "aspotmp", RANDOM, 0, 50, "postitmp %d"},
{ "asry", RANDOM, 0, 10, "1%d"},
{ "asmail", RANDOM, 0, 10, "mail: %d"},
};
Tässä pätkä edellisen mukaan luotua testimateriaalia: Tässä on testailun helpottamiseksi käytetty lyhyempiä kenttien nimiä.
'asno' = "1000000", 'asnimi' = "nimi: 0", 'asoso' = "osoite: 0", 'aspono' = "postinumero54863", 'aspotmp' = "postitmp 20", 'asry' = "10", 'asmail' = "mail: 7"
'asno' = "1000001", 'asnimi' = "nimi: 1", 'asoso' = "osoite: 1", 'aspono' = "postinumero58039", 'aspotmp' = "postitmp 25", 'asry' = "13", 'asmail' = "mail: 8"
'asno' = "1000002", 'asnimi' = "nimi: 2", 'asoso' = "osoite: 2", 'aspono' = "postinumero53052", 'aspotmp' = "postitmp 44", 'asry' = "15", 'asmail' = "mail: 2"
'asno' = "1000003", 'asnimi' = "nimi: 3", 'asoso' = "osoite: 3", 'aspono' = "postinumero49398", 'aspotmp' = "postitmp 22", 'asry' = "12", 'asmail' = "mail: 2"
'asno' = "1000004", 'asnimi' = "nimi: 4", 'asoso' = "osoite: 4", 'aspono' = "postinumero73740", 'aspotmp' = "postitmp 7", 'asry' = "17", 'asmail' = "mail: 3"
Ja koodi, jolla materiaali luodaan: Tässä on kenttien arvojen tekemiseen käytetty aiempaa stream_cipher rutiinia: stream_open() ja stream_bytes(). Näin on saatu data-arvot pysymään samoina, jos vain kenttien määrä ja kenttien arvot pysyvät samoina.
if(test2flag) {
#define SEQUENTIAL 1
#define RANDOM 2
struct field {
unsigned char *fieldname;
int fieldtype;
int lowlimit;
int highlimit;
unsigned char *valuestring;
} fields[] = {
{ "asno", SEQUENTIAL, 0, 0,"10%05d" },
{ "asnimi", SEQUENTIAL, 0,0, "nimi: %d" },
{ "asoso", SEQUENTIAL, 0, 0, "osoite: %d" },
{ "aspono", RANDOM, 0, 99999, "postinumero%d"},
{ "aspotmp", RANDOM, 0, 50, "postitmp %d"},
{ "asry", RANDOM, 0, 10, "1%d"},
{ "asmail", RANDOM, 0, 10, "mail: %d"},
};
stream_open(0, "kalakala");
for(c = 0; c < TEST_SETS; c++) {
if(quitcmd)
break;
first = 1;
for(d = 0; d < sizeof(fields) / sizeof(fields[0]); d++) {
if(!first)
more_printf(stdout,", ");
more_printf(stdout,"'%s'", fields[d].fieldname);
more_printf(stdout," = ");
more_printf(stdout,"\"");
if(fields[d].fieldtype = RANDOM && (fields[d].lowlimit != 0 || fields[d].highlimit != 0)) {
unsigned int e = stream_gen_limit(fields[d].highlimit - fields[d].lowlimit) + fields[d].lowlimit;
more_printf(stdout, fields[d].valuestring, e);
} else {
more_printf(stdout, fields[d].valuestring, c);
}
more_printf(stdout,"\"");
first = 0;
}
more_printf(stdout,"\n");
}
more_printf(stdout,"\n");
}
Vielä aiemmin käytetty stream_gen_limit() rutiini:
unsigned long stream_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) { // one byte
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) { // two bytes
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) { // three bytes
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) { // four bytes
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) { // five bytes
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) { // six bytes
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) { // seven bytes
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | stream_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
Ja -_limit rutiinissa käytetty stream_genbyte():
int stream_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
gent_clear();
stream_bytes(sizeof(gent), gent);
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
Ja kaikki stream cipher rutiinit:
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
static int streamt_pos = 0;
void stream_bytes(int size, unsigned char *buffer) // JariK 2023
{
int c;
static unsigned char streamt[HashLen]; // 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next random bytes
stream_internalbytes(stream_key); // change key
} // end of if(streamt_pos == 0
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++)
}
#define STREAM_KEY_ROUNDS 1024 // should be fast enough and slow enough, now 1024
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
HashFinal(stream_key, &hash);
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#define DEBUG21 2
#ifdef DEBUG21
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," randomness from key, key=");
dumpbin(stderr, size, key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
}
Ja vielä stream_cipher:in käyttämät cvar rutiinit:
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
#ifdef DEBUG20
ressu_dump("cvar", cvarsize + 1, cvar, 32);
#endif
}
#define aCVARRANDOMSTART 2 // off by default
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
#ifdef CVARRANDOMSTART
ressu_genbytes(8, (unsigned char *)&cvar);
#endif
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
Koko koodi terttuutil1:een oli aiemmin artikkelissa.
Aiemmin artikkelissa sanoin, että ressu on one time pad materiaalia, ja sillä perusteella kirjoitinkin ohjelman, jolla voi luoda uniikkia one time pad materiaalia, jos numeeristen tietokenttien pitää olla uniikkeja. Tässä pätkä mallitiedostosta: en kerro tässä miten materiaalia käytetään, mutta youtube:ssa on videoita aiheesta (hakusana one time pad).
$ ./newressuonetimepad
00000 22983 29088 27522 06071 83152 08423 04809 75707 72840 83759
00001 86262 02471 71623 56655 70705 45228 74332 59496 49090 79319
00002 87718 95655 33822 66347 41853 60517 65396 19485 13898 95025
00003 80611 58219 13708 85033 79649 76119 20896 26169 59084 38831
00004 18935 82852 05160 52485 01070 62471 51691 27036 56925 84451
00005 81595 77010 72735 56554 46639 59640 98532 50613 19521 75984
00006 58259 83748 30984 76252 81888 50448 59479 95014 43388 53501
00007 27187 69156 44641 13931 53178 46699 73574 26870 61794 93634
00008 45352 47203 46311 69134 03390 76745 88596 56731 59709 76978
00009 52048 41207 13038 04123 02288 20990 29157 44586 14704 11880
Ctrl-c
$
Ja pieni ohjelma:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
unsigned char *procname = NULL;
static unsigned char *programname = "newressuonetimepad version 0.02 ©";
static unsigned char *copyright = "Copyright (c) 2013-2024 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define GENT_SIZE 128
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
#define USE_PSEUDORESSU 2
void ressu_genbytes(int size, unsigned char *buffer);
#ifdef USE_PSEUDORESSU
void pseudoressu_bytes(int size, unsigned char *buffer);
void ressutwist_bytes(int size, unsigned char *buffer);
#endif
#define INPUT_RESSU 0
#define INPUT_RESSUTWIST 2
int input = INPUT_RESSU;
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
if(input == INPUT_RESSU)
ressu_genbytes(sizeof(gent), gent);
else if(input == INPUT_RESSUTWIST)
ressutwist_bytes(sizeof(gent), gent);
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
#define CODECHARS 5
#define CODES 100000
int main(int argc, char *argv[])
{
int c, d, e, f, help = 0, mode = 1;
int data[CODES];
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
} else if(!strcmp("--ressutwist", argv[c]) // JariK 2023
|| !strcmp("--ressuwtwist", argv[c])
|| !strcmp("--twist", argv[c]) ) {
input = INPUT_RESSUTWIST;
} else if(!strcmp("--mode1", argv[c])) {
mode = 1;
} else if(!strcmp("--mode2", argv[c])) {
mode = 2;
} else if(!strcmp("--mode3", argv[c])) {
mode = 3;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
} // end of for(c = 1; c < argc; c++)
// print help message if needed
if(help) {
fprintf(stderr,"%s: %s", procname, procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--mode1]");
fprintf(stderr," [--mode2]");
fprintf(stderr," [--mode3]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
fprintf(stdout,"mode:%d", mode);
fprintf(stdout,", input:%d", input);
fprintf(stdout,"\n");
if(mode == 1) { // simple, not unique. you can also use ./newressu --otp5n -w10
for(c = 0; c < CODES; c++) {
data[c] = newressu_gen_limit(CODES);
}
} else if(mode == 2) { // unique faster
for(c = 0; c < CODES; c++) {
data[c] = c;
}
for(c = 0; c < CODES; c++) {
e = newressu_gen_limit(CODES);
f = data[e];
data[e] = data[c];
data[c] = f;
}
} else if (mode == 3) { // unique slower
for(c = 0; c < CODES; c++) {
int ok = 0;
while(!ok) {
e = newressu_gen_limit(CODES);
ok = 1;
for(d = 0; d < c; d++) {
if(data[d] == e) {
ok = 0;
break;
}
}
}
data[c] = e;
}
}
int lineno = 0;
for(c = 0; c < CODES; c++) {
if(c % 10 == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05d ", lineno);
lineno++;
}
fprintf(stdout," %0*d", CODECHARS, data[c]);
}
fprintf(stdout,"\n");
exit(0);
}
Lisätty lippuihin australasia, melanesia, micronesia ja polynesia. Yksinkertaistettu lippufunktioita ja lisätty DEBUG77:an kaksimerkkinen iso koodi maan nimen perään: tässä DEBUG77 muutokset:
#define DEBUG77
#ifdef DEBUG77
unsigned char *areaflags = "FINLAND, DENMARK, NORDIC, BALTIC, EU, EUROPE, ASIA, AFRICA, NORTHAFRICA, EASTAFRICA, CENTRALAFRICA, SOUTHAFRICA, WESTAFRICA SOUTHAMERICA, NORTHAMERICA, OCEANIA, AUSTRALASIA, MELANESIA, MICRONESIA, POLYNESIA, ALL", *a;
unsigned char name[128];
a = areaflags;
while(*a != '\0' && newressu_getname(sizeof(name), name, &a)) {
fprintf(stdout,"area:%s",name);
int count = 0;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
if(!strcmp(name, "ALL")) {
count++;
unsigned char *q = idsflags[c].flags;
unsigned char name2[128], name3[128];
newressu_getname(sizeof(name2), name2, &q); // flag
newressu_getname(sizeof(name2), name2, &q); // 2 char isocode
newressu_getname(sizeof(name3), name3, &q); // 3 char isocode
newressu_getname(sizeof(name3), name3, &q); // name
fprintf(stdout,", %s(%s)",name3, name2); // name and isocode2 needed
} else {
if(newressu_strstr(idsflags[c].flags, name)!=NULL) {
count++;
unsigned char *q = idsflags[c].flags;
unsigned char name2[128], name3[128];
newressu_getname(sizeof(name2), name2, &q); // flag
newressu_getname(sizeof(name2), name2, &q); // 2 char isocode
newressu_getname(sizeof(name3), name3, &q); // 3 char isocode
newressu_getname(sizeof(name3), name3, &q); // name
fprintf(stdout,", %s(%s)", name3, name2); // name and isocode2 needed
}
}
}
fprintf(stdout,", count:%d",count);
fprintf(stdout,"\n");
}
#endif
Tässä getname funktio:
int newressu_getname(int length, unsigned char *name, unsigned char **p2)
{
int len, ok = 0;
unsigned char *n, *p;
p = *p2;
n = name;
len = 0;
while(ispunct(*p) || isblank(*p)) {
p++;
}
while(*p != '\0' && !ispunct(*p) && !isblank(*p)) {
if(len < length) {
*n++ = *p;
ok = 1;
}
p++;
len++;
}
*n = '\0';
*p2 = p;
return(ok);
}
Ja uusi newressu_strstr funktio: standardiin funktioon on lisätty se, että etsittävän merkkijonon pitää alkaa ja loppua sanarajalla.
unsigned char *newressu_strstr(unsigned char *haystack, unsigned char *needle)
{
int fl;
unsigned char *p = haystack;
while(*p != '\0') {
fl = strlen(needle);
if(!strncmp(p, needle, strlen(needle)) &&
( isblank(*(p + fl)) || ispunct(*(p + fl)) || *(p + fl) == '\0' ) && // character after string
( (p == haystack) || isblank(*(p - 1)) || ispunct(*(p - 1)) ) ) { // character before string
return(p);
}
p++;
}
return(NULL);
}
Olen aiemmin sanonut että satunnaislukujen luomiseen kannattaa käyttää useampia satunnaisbittigeneraattoreita summattuna. Tässä uusi satunnaislukulähde ressutwist (Ressu with twist), jossa ressuun lisätään pseudoressu. Molemmat vaikuttavat olevan hyviä generaattoreita, ja niiden yhdiste olisi tietenkin vaikeampi murtaa.
Seuraavassa twistin koodi: Aluksi koodi newressu_genbyte:stä:
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
#ifdef DEBUG23
ressu_dump("oldgent", 32, gent, 32); // first 32 bytes
#endif
gent_clear();
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(gent), gent);
#ifdef SHA256
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(gent), gent);
#endif
#ifdef SHA256
else if(input == INPUT_RESSUTWIST) {// ressu w twist
ressu_genbytes(sizeof(gent), gent);
pseudoressu_bytes(sizeof(gent), gent);
}
#endif
else if(input == INPUT_FASTRESSU) // ressu_fast
ressu_genbytes_fast(sizeof(gent), gent);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(gent), gent);
Koodi sample():sta:
//memset(buffer, 0, blocksize);
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(blocksize, buffer);
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(blocksize, buffer);
else if(input == INPUT_RESSUTWIST) { // ressu w twist
ressu_genbytes(blocksize, buffer);
pseudoressu_bytes(blocksize, buffer);
} else if(input == INPUT_FASTRESSU) // ressu fast
ressu_genbytes_fast(blocksize, buffer);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(blocksize, buffer);
Koodi komentoparametrien käsittelystä:
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
} else if(!strcmp("--pseudoressu", argv[c])) {
input = INPUT_PSEUDORESSU;
} else if(!strcmp("--ressutwist", argv[c]) // JariK 2023
|| !strcmp("--ressuwtwist", argv[c])
|| !strcmp("--twist", argv[c]) ) {
input = INPUT_RESSUTWIST;
} else if(!strcmp("--fast", argv[c])
|| !strcmp("--fastressu", argv[c]) ) {
input = INPUT_FASTRESSU;
} else if(!strcmp("--single", argv[c])
|| !strcmp("--singleressu", argv[c]) ) {
input = INPUT_SINGLERESSU;
Jos ajatteluni pitää paikkansa twist:in pitäisi myös olla one time pad kelpoinen. Siinä on siis ressu, joka on one time pad kelpoinen ja kun one time pad kelpoisiin bitteihin lisätään joku muu satunnaisgeneraattori (tässä pseudoressu), se on vieläkin one time pad kelpoinen.
Sitten ns “bad for randomness” -korjaus: Alkuperäinen eli viallinen koodi on merkitty #ifdef OLD1 iffeillä ja korjattu koodi on kaksi riviä ennen niitä. Alkuperäisenä ajatuksena oli satunnaistaa kehitetyn satunnaispuskurin merkkien järjestystä lisää, mutta se todellisuudessa vähentää sitä. Luulisin että ongelma johtuu siitä että todellisuudessa vanhoilla koodiriveillä samoista merkeistä kopioidaan vain osa ja niitäkin eri määrä. Yhtä merkkiä kopioidaan kolme kertaa, seuraavaa kaksi, seuraavaa yksi ja seuraavaa ei kopioida ollenkaan. Alkuperäinen idea vanhoilla riveillä oli, että kun valitaan seuraavista 256 merkistä satunnainen, niin se sisältää keskimäärin kaikki vaihtoehdot 0-255.
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
---
} // if(ressut_pos == 0)
buffer[c] ^= ressut[ressut_pos];
ressut_pos = (ressut_pos + 1) % ressut_bytes;
#ifdef OLD1
ressut_f = (ressut_f + ressut[ressut_pos] + 2) % ressut_bytes; // bad for randomness... JariK 2023
buffer[c] ^= ressut[ressut_f];
ressut_pos = (ressut_pos + 1) % ressut_bytes;
#endif
} // for(c = 0; c < size; c++)
...
}
“bad for randomness” bugin esittelyä varten tein sample() ajoista seuraavan kaltaisen, terttu tyylisen raportin: Raportilla satunnaisuuden lähde, tiedoston koko, tiedoston nimi, WEAK-rivit ja FAILED-rivit.
'input' = "pseudoressu", 'filesize' = "1080m", 'filename' = "newressusample801.rnd", 'weak' = "5", 'failed' = "3"
'input' = "pseudoressu", 'filesize' = "1g", 'filename' = "newressusample802.rnd", 'weak' = "1", 'failed' = "0"
'input' = "urandom", 'filesize' = "1g200m", 'filename' = "newressusample836.rnd", 'weak' = "4", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g200m", 'filename' = "newressusample837.rnd", 'weak' = "7", 'failed' = "0"
'input' = "twist", 'filesize' = "1g200m", 'filename' = "newressusample838.rnd", 'weak' = "1", 'failed' = "0"
'input' = "ressubfr1", 'filesize' = "10g", 'filename' = "newressusample897.rnd", 'weak' = "12", 'failed' = "31"
'input' = "ressubfr1", 'filesize' = "20g", 'filename' = "newressusample832.rnd", 'weak' = "8", 'failed' = "34"
'input' = "ressubfr1", 'filesize' = "30g", 'filename' = "newressusample860.rnd", 'weak' = "9", 'failed' = "33"
Raportin koodi:
void dump_sample() // & dieharder analysis
{
...
FILE *fp2;
if((fp2 = fopen("newressudieharder.skk", "a")) != NULL) { //
fprintf(fp2,"'input' = \"%s\"", input_str);
if(filesize_str != NULL)
fprintf(fp2,", 'filesize' = \"%s\"", filesize_str);
if(blocksize_str != NULL)
fprintf(fp2,", 'blocksize' = \"%s\"", blocksize_str);
if(blocks_str != NULL)
fprintf(fp2,"'blocks' = \"%s\"", blocks_str);
fprintf(fp2,", 'filename' = \"%s\"", filename);
fprintf(fp2,", 'weak' = \"%lld\"", weak);
fprintf(fp2,", 'failed' = \"%lld\"", failed);
fprintf(fp2,"\n");
fclose(fp2);
}
...
}
Ajoin –sample –dieharder rutiinia seuraavankaltaisilla shellscript:eillä:
$ cat newressidieharder7.sh
#!/bin/bash -x
./newressu --sample --dieharder --filesize 500m $@
./newressu --sample --dieharder --filesize 600m $@
./newressu --sample --dieharder --filesize 700m $@
./newressu --sample --dieharder --filesize 800m $@
./newressu --sample --dieharder --filesize 900m $@
./newressu --sample --dieharder --filesize 1g $@
./newressu --sample --dieharder --filesize 1g100m $@
./newressu --sample --dieharder --filesize 1g200m $@
./newressu --sample --dieharder --filesize 1g300m $@
./newressu --sample --dieharder --filesize 1g400m $@
./newressu --sample --dieharder --filesize 1g500m $@
./newressu --sample --dieharder --filesize 1g600m $@
./newressu --sample --dieharder --filesize 1g700m $@
./newressu --sample --dieharder --filesize 1g800m $@
./newressu --sample --dieharder --filesize 1g900m $@
./newressu --sample --dieharder --filesize 2g $@
./newressu --sample --dieharder --filesize 3g $@
./newressu --sample --dieharder --filesize 4g $@
./newressu --sample --dieharder --filesize 5g $@
./newressu --sample --dieharder --filesize 6g $@
$ chmod +x newressudieharder7.sh
$ ./newressudieharder7.sh --single
....
Single riveillä raportti näyttää hyvältä: failed rivejä on vain alle 1g tiedostoissa ja weak rivejä on vain muutamia tiedoston koosta huolimatta:
$ grep single newressudieharder7.sh
'input' = "single", 'filesize' = "1g", 'filename' = "newressusample913.rnd", 'weak' = "1", 'failed' = "0"
'input' = "single", 'filesize' = "1g100m", 'filename' = "newressusample1028.rnd", 'weak' = "5", 'failed' = "0"
'input' = "single", 'filesize' = "1g200m", 'filename' = "newressusample914.rnd", 'weak' = "1", 'failed' = "0"
'input' = "single", 'filesize' = "1g300m", 'filename' = "newressusample915.rnd", 'weak' = "1", 'failed' = "0"
'input' = "single", 'filesize' = "1g400m", 'filename' = "newressusample916.rnd", 'weak' = "3", 'failed' = "0"
'input' = "single", 'filesize' = "1g500m", 'filename' = "newressusample917.rnd", 'weak' = "2", 'failed' = "0"
'input' = "single", 'filesize' = "1g600m", 'filename' = "newressusample918.rnd", 'weak' = "3", 'failed' = "0"
'input' = "single", 'filesize' = "1g700m", 'filename' = "newressusample919.rnd", 'weak' = "6", 'failed' = "0"
'input' = "single", 'filesize' = "10g", 'filename' = "newressusample921.rnd", 'weak' = "0", 'failed' = "0"
'input' = "single", 'filesize' = "500m", 'filename' = "newressusample1022.rnd", 'weak' = "4", 'failed' = "1"
'input' = "single", 'filesize' = "600m", 'filename' = "newressusample1023.rnd", 'weak' = "7", 'failed' = "1"
'input' = "single", 'filesize' = "700m", 'filename' = "newressusample1024.rnd", 'weak' = "2", 'failed' = "0"
'input' = "single", 'filesize' = "800m", 'filename' = "newressusample1025.rnd", 'weak' = "6", 'failed' = "1"
'input' = "single", 'filesize' = "900m", 'filename' = "newressusample1026.rnd", 'weak' = "3", 'failed' = "3"
'input' = "single", 'filesize' = "1g800m", 'filename' = "newressusample1080.rnd", 'weak' = "4", 'failed' = "0"
'input' = "single", 'filesize' = "1g900m", 'filename' = "newressusample1081.rnd", 'weak' = "7", 'failed' = "0"
'input' = "single", 'filesize' = "2g", 'filename' = "newressusample1082.rnd", 'weak' = "2", 'failed' = "0"
'input' = "single", 'filesize' = "3g", 'filename' = "newressusample1083.rnd", 'weak' = "2", 'failed' = "0"
'input' = "single", 'filesize' = "4g", 'filename' = "newressusample1084.rnd", 'weak' = "2", 'failed' = "0"
'input' = "single", 'filesize' = "5g", 'filename' = "newressusample1085.rnd", 'weak' = "1", 'failed' = "0"
'input' = "single", 'filesize' = "6g", 'filename' = "newressusample1086.rnd", 'weak' = "2", 'failed' = "0"
$
Alkuperäisen “bad for randomness” koodin lista näyttää seuraavalta: (sekä weak että failed rivejä on paljon.
$ grep ressubfr1 newressudieharder.skk
'input' = "ressubfr1", 'filesize' = "10g", 'filename' = "newressusample897.rnd", 'weak' = "12", 'failed' = "31"
'input' = "ressubfr1", 'filesize' = "20g", 'filename' = "newressusample832.rnd", 'weak' = "8", 'failed' = "34"
'input' = "ressubfr1", 'filesize' = "30g", 'filename' = "newressusample860.rnd", 'weak' = "9", 'failed' = "33"
'input' = "ressubfr1", 'filesize' = "500m", 'filename' = "newressusample873.rnd", 'weak' = "11", 'failed' = "18"
'input' = "ressubfr1", 'filesize' = "600m", 'filename' = "newressusample874.rnd", 'weak' = "14", 'failed' = "18"
'input' = "ressubfr1", 'filesize' = "700m", 'filename' = "newressusample875.rnd", 'weak' = "12", 'failed' = "20"
'input' = "ressubfr1", 'filesize' = "800m", 'filename' = "newressusample876.rnd", 'weak' = "6", 'failed' = "21"
'input' = "ressubfr1", 'filesize' = "900m", 'filename' = "newressusample878.rnd", 'weak' = "15", 'failed' = "19"
'input' = "ressubfr1", 'filesize' = "1g", 'filename' = "newressusample880.rnd", 'weak' = "8", 'failed' = "18"
'input' = "ressubfr1", 'filesize' = "1g100m", 'filename' = "newressusample881.rnd", 'weak' = "9", 'failed' = "20"
'input' = "ressubfr1", 'filesize' = "1g200m", 'filename' = "newressusample882.rnd", 'weak' = "13", 'failed' = "31"
'input' = "ressubfr1", 'filesize' = "1g300m", 'filename' = "newressusample884.rnd", 'weak' = "14", 'failed' = "30"
'input' = "ressubfr1", 'filesize' = "1g400m", 'filename' = "newressusample885.rnd", 'weak' = "6", 'failed' = "32"
'input' = "ressubfr1", 'filesize' = "1g500m", 'filename' = "newressusample886.rnd", 'weak' = "9", 'failed' = "32"
'input' = "ressubfr1", 'filesize' = "1g600m", 'filename' = "newressusample889.rnd", 'weak' = "10", 'failed' = "19"
'input' = "ressubfr1", 'filesize' = "1g700m", 'filename' = "newressusample890.rnd", 'weak' = "7", 'failed' = "21"
'input' = "ressubfr1", 'filesize' = "1g800m", 'filename' = "newressusample891.rnd", 'weak' = "8", 'failed' = "20"
'input' = "ressubfr1", 'filesize' = "1g900m", 'filename' = "newressusample892.rnd", 'weak' = "8", 'failed' = "17"
'input' = "ressubfr1", 'filesize' = "2g", 'filename' = "newressusample899.rnd", 'weak' = "6", 'failed' = "21"
'input' = "ressubfr1", 'filesize' = "3g", 'filename' = "newressusample900.rnd", 'weak' = "9", 'failed' = "23"
'input' = "ressubfr1", 'filesize' = "4g", 'filename' = "newressusample901.rnd", 'weak' = "13", 'failed' = "17"
'input' = "ressubfr1", 'filesize' = "5g", 'filename' = "newressusample902.rnd", 'weak' = "9", 'failed' = "18"
'input' = "ressubfr1", 'filesize' = "6g", 'filename' = "newressusample903.rnd", 'weak' = "4", 'failed' = "18"
$
“bad for randomness” koodin +2 versio: tässäkin weak ja failed rivejä on paljon.
$ grep ressubfr2 newressudieharder.skk
'input' = "ressubfr2", 'filesize' = "1g200m", 'filename' = "newressusample932.rnd", 'weak' = "8", 'failed' = "22"
'input' = "ressubfr2", 'filesize' = "1g300m", 'filename' = "newressusample933.rnd", 'weak' = "6", 'failed' = "20"
'input' = "ressubfr2", 'filesize' = "1g400m", 'filename' = "newressusample934.rnd", 'weak' = "9", 'failed' = "17"
'input' = "ressubfr2", 'filesize' = "1g500m", 'filename' = "newressusample935.rnd", 'weak' = "5", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "1g600m", 'filename' = "newressusample936.rnd", 'weak' = "10", 'failed' = "20"
'input' = "ressubfr2", 'filesize' = "1g700m", 'filename' = "newressusample949.rnd", 'weak' = "13", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "10g", 'filename' = "newressusample950.rnd", 'weak' = "4", 'failed' = "22"
'input' = "ressubfr2", 'filesize' = "20g", 'filename' = "newressusample961.rnd", 'weak' = "9", 'failed' = "16"
'input' = "ressubfr2", 'filesize' = "30g", 'filename' = "newressusample962.rnd", 'weak' = "9", 'failed' = "17"
'input' = "ressubfr2", 'filesize' = "500m", 'filename' = "newressusample904.rnd", 'weak' = "12", 'failed' = "17"
'input' = "ressubfr2", 'filesize' = "600m", 'filename' = "newressusample980.rnd", 'weak' = "9", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "700m", 'filename' = "newressusample981.rnd", 'weak' = "14", 'failed' = "19"
'input' = "ressubfr2", 'filesize' = "800m", 'filename' = "newressusample982.rnd", 'weak' = "12", 'failed' = "21"
'input' = "ressubfr2", 'filesize' = "900m", 'filename' = "newressusample983.rnd", 'weak' = "13", 'failed' = "21"
'input' = "ressubfr2", 'filesize' = "1g", 'filename' = "newressusample984.rnd", 'weak' = "9", 'failed' = "20"
'input' = "ressubfr2", 'filesize' = "1g100m", 'filename' = "newressusample985.rnd", 'weak' = "12", 'failed' = "21"
'input' = "ressubfr2", 'filesize' = "1g600m", 'filename' = "newressusample986.rnd", 'weak' = "11", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "1g700m", 'filename' = "newressusample987.rnd", 'weak' = "9", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "1g800m", 'filename' = "newressusample988.rnd", 'weak' = "8", 'failed' = "20"
'input' = "ressubfr2", 'filesize' = "1g900m", 'filename' = "newressusample989.rnd", 'weak' = "11", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "2g", 'filename' = "newressusample990.rnd", 'weak' = "8", 'failed' = "18"
'input' = "ressubfr2", 'filesize' = "3g", 'filename' = "newressusample991.rnd", 'weak' = "8", 'failed' = "17"
'input' = "ressubfr2", 'filesize' = "4g", 'filename' = "newressusample992.rnd", 'weak' = "8", 'failed' = "21"
'input' = "ressubfr2", 'filesize' = "5g", 'filename' = "newressusample993.rnd", 'weak' = "8", 'failed' = "17"
$
Tämä lista on tehty korjatulla “bad for randomness” -rutiinilla: “Vihdoinkin” ressurivitkin näyttävät hyviltä, muutama weak ja ei failed rivejä suurissa tiedostoissa.
$ grep \"ressu\" newressudieharder.skk
'input' = "ressu", 'filesize' = "1g200m", 'filename' = "newressusample837.rnd", 'weak' = "7", 'failed' = "0"
'input' = "ressu", 'filesize' = "500m", 'filename' = "newressusample1042.rnd", 'weak' = "6", 'failed' = "1"
'input' = "ressu", 'filesize' = "600m", 'filename' = "newressusample1043.rnd", 'weak' = "6", 'failed' = "1"
'input' = "ressu", 'filesize' = "700m", 'filename' = "newressusample1044.rnd", 'weak' = "7", 'failed' = "1"
'input' = "ressu", 'filesize' = "800m", 'filename' = "newressusample1045.rnd", 'weak' = "4", 'failed' = "0"
'input' = "ressu", 'filesize' = "900m", 'filename' = "newressusample1046.rnd", 'weak' = "6", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g", 'filename' = "newressusample1047.rnd", 'weak' = "3", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g100m", 'filename' = "newressusample994.rnd", 'weak' = "5", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g300m", 'filename' = "newressusample1003.rnd", 'weak' = "4", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g400m", 'filename' = "newressusample1004.rnd", 'weak' = "2", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g500m", 'filename' = "newressusample1005.rnd", 'weak' = "2", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g600m", 'filename' = "newressusample1006.rnd", 'weak' = "2", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g700m", 'filename' = "newressusample1007.rnd", 'weak' = "3", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g800m", 'filename' = "newressusample1036.rnd", 'weak' = "6", 'failed' = "0"
'input' = "ressu", 'filesize' = "1g900m", 'filename' = "newressusample1037.rnd", 'weak' = "5", 'failed' = "0"
'input' = "ressu", 'filesize' = "2g", 'filename' = "newressusample1038.rnd", 'weak' = "3", 'failed' = "0"
$
Ressun fast version lista:
$ grep fast newressudieharder.skk
'input' = "fast", 'filesize' = "500m", 'filename' = "newressusample1078.rnd", 'weak' = "2", 'failed' = "2"
'input' = "fast", 'filesize' = "600m", 'filename' = "newressusample1079.rnd", 'weak' = "7", 'failed' = "2"
'input' = "fast", 'filesize' = "700m", 'filename' = "newressusample1103.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "800m", 'filename' = "newressusample1144.rnd", 'weak' = "7", 'failed' = "1"
'input' = "fast", 'filesize' = "900m", 'filename' = "newressusample1145.rnd", 'weak' = "3", 'failed' = "4"
'input' = "fast", 'filesize' = "1g", 'filename' = "newressusample1146.rnd", 'weak' = "4", 'failed' = "0"
'input' = "fast", 'filesize' = "1g100m", 'filename' = "newressusample1147.rnd", 'weak' = "2", 'failed' = "1"
'input' = "fast", 'filesize' = "1g200m", 'filename' = "newressusample1148.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "1g300m", 'filename' = "newressusample1149.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "1g400m", 'filename' = "newressusample1150.rnd", 'weak' = "4", 'failed' = "0"
'input' = "fast", 'filesize' = "1g500m", 'filename' = "newressusample1151.rnd", 'weak' = "5", 'failed' = "0"
'input' = "fast", 'filesize' = "1g600m", 'filename' = "newressusample1152.rnd", 'weak' = "5", 'failed' = "0"
'input' = "fast", 'filesize' = "1g700m", 'filename' = "newressusample1153.rnd", 'weak' = "2", 'failed' = "1"
'input' = "fast", 'filesize' = "1g800m", 'filename' = "newressusample1154.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "1g900m", 'filename' = "newressusample1155.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "2g", 'filename' = "newressusample1156.rnd", 'weak' = "2", 'failed' = "0"
'input' = "fast", 'filesize' = "3g", 'filename' = "newressusample1157.rnd", 'weak' = "3", 'failed' = "0"
'input' = "fast", 'filesize' = "4g", 'filename' = "newressusample1158.rnd", 'weak' = "0", 'failed' = "0"
'input' = "fast", 'filesize' = "5g", 'filename' = "newressusample1159.rnd", 'weak' = "5", 'failed' = "0"
'input' = "fast", 'filesize' = "6g", 'filename' = "newressusample1160.rnd", 'weak' = "5", 'failed' = "0"
$
Tässä vielä pseudoressu:sta samanlainen lista: Pseudoressulista näyttää kanssa hyvältä, se on avaimia lukuunottamatta SHA256:n tulos. Avaimethan tulevat ressusta.
$ grep \"pseudoressu\" newressudieharder.skk
'input' = "pseudoressu", 'filesize' = "1g", 'filename' = "newressusample802.rnd", 'weak' = "1", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "500m", 'filename' = "newressusample905.rnd", 'weak' = "7", 'failed' = "1"
'input' = "pseudoressu", 'filesize' = "600m", 'filename' = "newressusample906.rnd", 'weak' = "8", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "700m", 'filename' = "newressusample907.rnd", 'weak' = "11", 'failed' = "1"
'input' = "pseudoressu", 'filesize' = "800m", 'filename' = "newressusample908.rnd", 'weak' = "2", 'failed' = "1"
'input' = "pseudoressu", 'filesize' = "900m", 'filename' = "newressusample909.rnd", 'weak' = "5", 'failed' = "2"
'input' = "pseudoressu", 'filesize' = "1g", 'filename' = "newressusample910.rnd", 'weak' = "3", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g100m", 'filename' = "newressusample911.rnd", 'weak' = "4", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g200m", 'filename' = "newressusample912.rnd", 'weak' = "3", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g300m", 'filename' = "newressusample922.rnd", 'weak' = "2", 'failed' = "1"
'input' = "pseudoressu", 'filesize' = "1g400m", 'filename' = "newressusample824.rnd", 'weak' = "2", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g500m", 'filename' = "newressusample923.rnd", 'weak' = "1", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g600m", 'filename' = "newressusample924.rnd", 'weak' = "6", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g700m", 'filename' = "newressusample925.rnd", 'weak' = "4", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g800m", 'filename' = "newressusample926.rnd", 'weak' = "0", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "1g900m", 'filename' = "newressusample927.rnd", 'weak' = "4", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "2g", 'filename' = "newressusample928.rnd", 'weak' = "2", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "3g", 'filename' = "newressusample929.rnd", 'weak' = "2", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "4g", 'filename' = "newressusample930.rnd", 'weak' = "4", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "5g", 'filename' = "newressusample943.rnd", 'weak' = "1", 'failed' = "0"
'input' = "pseudoressu", 'filesize' = "6g", 'filename' = "newressusample944.rnd", 'weak' = "3", 'failed' = "0"
$
Stream lähteen tuloskin on hyvä lista: tässä listassa ei oikeasti ole mitään satunnaista, kaikki merkit tulevat avaimesta ‘kalakala’.
$ grep \"stream\" newressudieharder.skk
'input' = "stream", 'filesize' = "500m", 'filename' = "newressusample955.rnd", 'weak' = "2", 'failed' = "2"
'input' = "stream", 'filesize' = "600m", 'filename' = "newressusample956.rnd", 'weak' = "6", 'failed' = "0"
'input' = "stream", 'filesize' = "700m", 'filename' = "newressusample957.rnd", 'weak' = "4", 'failed' = "1"
'input' = "stream", 'filesize' = "800m", 'filename' = "newressusample958.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream", 'filesize' = "900m", 'filename' = "newressusample959.rnd", 'weak' = "8", 'failed' = "1"
'input' = "stream", 'filesize' = "1g", 'filename' = "newressusample960.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream", 'filesize' = "1g100m", 'filename' = "newressusample963.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream", 'filesize' = "1g200m", 'filename' = "newressusample964.rnd", 'weak' = "6", 'failed' = "0"
'input' = "stream", 'filesize' = "1g300m", 'filename' = "newressusample965.rnd", 'weak' = "3", 'failed' = "1"
'input' = "stream", 'filesize' = "1g500m", 'filename' = "newressusample966.rnd", 'weak' = "5", 'failed' = "1"
'input' = "stream", 'filesize' = "1g600m", 'filename' = "newressusample967.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream", 'filesize' = "1g700m", 'filename' = "newressusample968.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream", 'filesize' = "1g800m", 'filename' = "newressusample969.rnd", 'weak' = "3", 'failed' = "0"
'input' = "stream", 'filesize' = "1g900m", 'filename' = "newressusample970.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream", 'filesize' = "2g", 'filename' = "newressusample971.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream", 'filesize' = "3g", 'filename' = "newressusample972.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream", 'filesize' = "4g", 'filename' = "newressusample973.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream", 'filesize' = "5g", 'filename' = "newressusample974.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream", 'filesize' = "6g", 'filename' = "newressusample975.rnd", 'weak' = "3", 'failed' = "0"
$
Uusi ajo –stream optiolla: kuten odotin, lista näyttää samalta edellisen stream listan kanssa.
$ grep stream2 newressudieharder.skk
'input' = "stream2", 'filesize' = "500m", 'filename' = "newressusample1124.rnd", 'weak' = "2", 'failed' = "2"
'input' = "stream2", 'filesize' = "600m", 'filename' = "newressusample1125.rnd", 'weak' = "6", 'failed' = "0"
'input' = "stream2", 'filesize' = "700m", 'filename' = "newressusample1126.rnd", 'weak' = "4", 'failed' = "1"
'input' = "stream2", 'filesize' = "800m", 'filename' = "newressusample1127.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream2", 'filesize' = "900m", 'filename' = "newressusample1128.rnd", 'weak' = "8", 'failed' = "1"
'input' = "stream2", 'filesize' = "1g", 'filename' = "newressusample1129.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g100m", 'filename' = "newressusample1130.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g200m", 'filename' = "newressusample1131.rnd", 'weak' = "6", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g300m", 'filename' = "newressusample1132.rnd", 'weak' = "3", 'failed' = "1"
'input' = "stream2", 'filesize' = "1g400m", 'filename' = "newressusample1133.rnd", 'weak' = "3", 'failed' = "1"
'input' = "stream2", 'filesize' = "1g500m", 'filename' = "newressusample1134.rnd", 'weak' = "5", 'failed' = "1"
'input' = "stream2", 'filesize' = "1g600m", 'filename' = "newressusample1135.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g700m", 'filename' = "newressusample1136.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g800m", 'filename' = "newressusample1137.rnd", 'weak' = "3", 'failed' = "0"
'input' = "stream2", 'filesize' = "1g900m", 'filename' = "newressusample1138.rnd", 'weak' = "2", 'failed' = "0"
'input' = "stream2", 'filesize' = "2g", 'filename' = "newressusample1139.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream2", 'filesize' = "3g", 'filename' = "newressusample1140.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream2", 'filesize' = "4g", 'filename' = "newressusample1141.rnd", 'weak' = "7", 'failed' = "0"
'input' = "stream2", 'filesize' = "5g", 'filename' = "newressusample1142.rnd", 'weak' = "4", 'failed' = "0"
'input' = "stream2", 'filesize' = "6g", 'filename' = "newressusample1143.rnd", 'weak' = "3", 'failed' = "0"
$
Rdrand, eli intel prosessorin tarjoama satunnaisuus on kanssa –dieharder mielessä ok.
$ grep \"rdrand\" newressudieharder.skk
'input' = "rdrand", 'filesize' = "500m", 'filename' = "newressusample995.rnd", 'weak' = "5", 'failed' = "2"
'input' = "rdrand", 'filesize' = "600m", 'filename' = "newressusample996.rnd", 'weak' = "3", 'failed' = "4"
'input' = "rdrand", 'filesize' = "700m", 'filename' = "newressusample997.rnd", 'weak' = "3", 'failed' = "1"
'input' = "rdrand", 'filesize' = "800m", 'filename' = "newressusample998.rnd", 'weak' = "7", 'failed' = "0"
'input' = "rdrand", 'filesize' = "900m", 'filename' = "newressusample999.rnd", 'weak' = "4", 'failed' = "1"
'input' = "rdrand", 'filesize' = "1g", 'filename' = "newressusample1000.rnd", 'weak' = "5", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g100m", 'filename' = "newressusample1001.rnd", 'weak' = "5", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g200m", 'filename' = "newressusample827.rnd", 'weak' = "2", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g300m", 'filename' = "newressusample1039.rnd", 'weak' = "4", 'failed' = "1"
'input' = "rdrand", 'filesize' = "1g400m", 'filename' = "newressusample862.rnd", 'weak' = "2", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g500m", 'filename' = "newressusample1040.rnd", 'weak' = "5", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g600m", 'filename' = "newressusample1041.rnd", 'weak' = "5", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g700m", 'filename' = "newressusample1048.rnd", 'weak' = "4", 'failed' = "1"
'input' = "rdrand", 'filesize' = "1g800m", 'filename' = "newressusample1049.rnd", 'weak' = "1", 'failed' = "0"
'input' = "rdrand", 'filesize' = "1g900m", 'filename' = "newressusample1050.rnd", 'weak' = "0", 'failed' = "0"
'input' = "rdrand", 'filesize' = "2g", 'filename' = "newressusample1051.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdrand", 'filesize' = "3g", 'filename' = "newressusample1052.rnd", 'weak' = "3", 'failed' = "1"
'input' = "rdrand", 'filesize' = "4g", 'filename' = "newressusample1053.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdrand", 'filesize' = "5g", 'filename' = "newressusample1073.rnd", 'weak' = "2", 'failed' = "0"
'input' = "rdrand", 'filesize' = "6g", 'filename' = "newressusample1074.rnd", 'weak' = "2", 'failed' = "0"
$
Ja toinen intel tuote –rdseed: –dieharder ok. Näistä löydät keskustelua netistä. Ne ovat newressussa valinnaisia.
$ grep \"rdseed\" newressudieharder.skk
'input' = "rdseed", 'filesize' = "500m", 'filename' = "newressusample937.rnd", 'weak' = "7", 'failed' = "2"
'input' = "rdseed", 'filesize' = "600m", 'filename' = "newressusample938.rnd", 'weak' = "6", 'failed' = "0"
'input' = "rdseed", 'filesize' = "700m", 'filename' = "newressusample939.rnd", 'weak' = "12", 'failed' = "0"
'input' = "rdseed", 'filesize' = "800m", 'filename' = "newressusample940.rnd", 'weak' = "2", 'failed' = "0"
'input' = "rdseed", 'filesize' = "900m", 'filename' = "newressusample941.rnd", 'weak' = "9", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g", 'filename' = "newressusample942.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g100m", 'filename' = "newressusample1087.rnd", 'weak' = "6", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g200m", 'filename' = "newressusample835.rnd", 'weak' = "4", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g300m", 'filename' = "newressusample1088.rnd", 'weak' = "8", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g400m", 'filename' = "newressusample863.rnd", 'weak' = "4", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g500m", 'filename' = "newressusample1089.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g600m", 'filename' = "newressusample1090.rnd", 'weak' = "1", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g700m", 'filename' = "newressusample1091.rnd", 'weak' = "4", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g800m", 'filename' = "newressusample1092.rnd", 'weak' = "1", 'failed' = "0"
'input' = "rdseed", 'filesize' = "1g900m", 'filename' = "newressusample1093.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdseed", 'filesize' = "2g", 'filename' = "newressusample1094.rnd", 'weak' = "8", 'failed' = "0"
'input' = "rdseed", 'filesize' = "3g", 'filename' = "newressusample1095.rnd", 'weak' = "0", 'failed' = "0"
'input' = "rdseed", 'filesize' = "4g", 'filename' = "newressusample1096.rnd", 'weak' = "1", 'failed' = "0"
'input' = "rdseed", 'filesize' = "5g", 'filename' = "newressusample1097.rnd", 'weak' = "3", 'failed' = "0"
'input' = "rdseed", 'filesize' = "6g", 'filename' = "newressusample1098.rnd", 'weak' = "0", 'failed' = "0"
$
Edellinen lista edellisestä ressutwist generaattorista:
'input' = "ressutwist", 'filesize' = "500m", 'filename' = "newressusample1751.rnd", 'weak' = "5", 'failed' = "1"
'input' = "ressutwist", 'filesize' = "600m", 'filename' = "newressusample1752.rnd", 'weak' = "8", 'failed' = "1"
'input' = "ressutwist", 'filesize' = "700m", 'filename' = "newressusample1753.rnd", 'weak' = "6", 'failed' = "2"
'input' = "ressutwist", 'filesize' = "800m", 'filename' = "newressusample1754.rnd", 'weak' = "7", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "900m", 'filename' = "newressusample1755.rnd", 'weak' = "3", 'failed' = "2"
'input' = "ressutwist", 'filesize' = "1g", 'filename' = "newressusample1756.rnd", 'weak' = "2", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g100m", 'filename' = "newressusample1757.rnd", 'weak' = "3", 'failed' = "1"
'input' = "ressutwist", 'filesize' = "1g200m", 'filename' = "newressusample1758.rnd", 'weak' = "5", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g300m", 'filename' = "newressusample1759.rnd", 'weak' = "3", 'failed' = "1"
'input' = "ressutwist", 'filesize' = "1g400m", 'filename' = "newressusample1760.rnd", 'weak' = "4", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g500m", 'filename' = "newressusample1761.rnd", 'weak' = "5", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g600m", 'filename' = "newressusample1762.rnd", 'weak' = "7", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g700m", 'filename' = "newressusample1763.rnd", 'weak' = "1", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g800m", 'filename' = "newressusample1764.rnd", 'weak' = "6", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "1g900m", 'filename' = "newressusample1773.rnd", 'weak' = "4", 'failed' = "1"
'input' = "ressutwist", 'filesize' = "2g", 'filename' = "newressusample1774.rnd", 'weak' = "4", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "3g", 'filename' = "newressusample1775.rnd", 'weak' = "1", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "4g", 'filename' = "newressusample1776.rnd", 'weak' = "2", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "5g", 'filename' = "newressusample1777.rnd", 'weak' = "1", 'failed' = "0"
'input' = "ressutwist", 'filesize' = "6g", 'filename' = "newressusample1778.rnd", 'weak' = "3", 'failed' = "0"
Lisätty newressu:un test_bytes() -funktio, johon voit kirjoittaa oman satunnaisbittigeneraattorisi, ja ajaa sitä –test komentorivioptiolla. Tällöin kaikki newressu:un toiminnot ja newressutest? ohjelmat ovat käytössäsi generaattorin testaamiseen. Tällä hetkellä test_bytes() funktio palauttaa koko puskurin täynnä nollia. –dieharder ei jostain syystä toimi kunnolla jos satunnaismerkit ovat pelkkiä nollia.
Test koodi:
void test_bytes(int size, unsigned char *buffer) // JariK 2023
{
// insert your generator here, run it with --test command parameter
memset(buffer, 0, size);
}
int newressu_genbyte()
{
....
else if(input == INPUT_TEST) // test generator
test_bytes(sizeof(gent), gent);
----
}
void dump_sample() // & dieharder analysis
{
....
else if(input == INPUT_TEST) // test generator
test_bytes(blocksize, buffer);
....
}
int main(int argc, char *argv[])
{
....
} else if(!strcmp("--test", argv[c])) { // test generator
input = INPUT_TEST;
input_str = argv[c] + 2;
}
....
if(input == INPUT_TEST) {
fprintf(stderr,"%s: randomness from your generator (test_bytes)\n", procname);
}
....
}
Tässä vielä satunnaisuutta –test oletuskoodilla:
$ ./newressu --test
./newressu: randomness from your generator (test_bytes)
00000 00000000000000000000000000000000000000000000000000000000000000000
00001 00000000000000000000000000000000000000000000000000000000000000000
00002 00000000000000000000000000000000000000000000000000000000000000000
00003 00000000000000000000000000000000000000000000000000000000000000000
00004 00000000000000000000000000000000000000000000000000000000000000000
00005 00000000000000000000000000000000000000000000000000000000000000000
00006 00000000000000000000000000000000000000000000000000000000000000000
00007 00000000000000000000000000000000000000000000000000000000000000000
00008 00000000000000000000000000000000000000000000000000000000000000000
00009 00000000000000000000000000000000000000000000000000000000000000000
$
Lisätty test_bytes testirutiiniin ressun, pseudoressun ja /dev/urandom:in yhdistelmä:
void test_bytes(int size, unsigned char *buffer) // JariK 2023
{
// insert your generator here, run it with
// --test command line parameter (source for
// randomness)
ressutwist_bytes(size, buffer);
urandom_bytes(size, buffer);
//memset(buffer, 0, size);
//for(int c = 0; c < size; c++)
// buffer[c] = c & 0xff;
}
Ja ajettu edellinen testiscripti test generaattorilla: ressu-pseudoressu-urandom yhdistelmälläkin tulos on –dieharder kelpoinen.
'input' = "test", 'filesize' = "500m", 'filename' = "newressusample2665.rnd", 'weak' = "4", 'failed' = "0"
'input' = "test", 'filesize' = "600m", 'filename' = "newressusample2666.rnd", 'weak' = "6", 'failed' = "3"
'input' = "test", 'filesize' = "700m", 'filename' = "newressusample2667.rnd", 'weak' = "10", 'failed' = "1"
'input' = "test", 'filesize' = "800m", 'filename' = "newressusample2668.rnd", 'weak' = "3", 'failed' = "2"
'input' = "test", 'filesize' = "900m", 'filename' = "newressusample2669.rnd", 'weak' = "3", 'failed' = "1"
'input' = "test", 'filesize' = "1g", 'filename' = "newressusample2670.rnd", 'weak' = "3", 'failed' = "1"
'input' = "test", 'filesize' = "1g100m", 'filename' = "newressusample2671.rnd", 'weak' = "2", 'failed' = "0"
'input' = "test", 'filesize' = "1g200m", 'filename' = "newressusample2672.rnd", 'weak' = "4", 'failed' = "0"
'input' = "test", 'filesize' = "1g300m", 'filename' = "newressusample2673.rnd", 'weak' = "2", 'failed' = "1"
'input' = "test", 'filesize' = "1g400m", 'filename' = "newressusample2674.rnd", 'weak' = "2", 'failed' = "0"
'input' = "test", 'filesize' = "1g500m", 'filename' = "newressusample2675.rnd", 'weak' = "6", 'failed' = "0"
'input' = "test", 'filesize' = "1g600m", 'filename' = "newressusample2676.rnd", 'weak' = "5", 'failed' = "0"
'input' = "test", 'filesize' = "1g700m", 'filename' = "newressusample2677.rnd", 'weak' = "2", 'failed' = "0"
'input' = "test", 'filesize' = "1g800m", 'filename' = "newressusample2678.rnd", 'weak' = "6", 'failed' = "0"
'input' = "test", 'filesize' = "1g900m", 'filename' = "newressusample2679.rnd", 'weak' = "1", 'failed' = "0"
'input' = "test", 'filesize' = "2g", 'filename' = "newressusample2680.rnd", 'weak' = "4", 'failed' = "0"
'input' = "test", 'filesize' = "3g", 'filename' = "newressusample2681.rnd", 'weak' = "5", 'failed' = "0"
'input' = "test", 'filesize' = "4g", 'filename' = "newressusample2682.rnd", 'weak' = "4", 'failed' = "0"
'input' = "test", 'filesize' = "5g", 'filename' = "newressusample2683.rnd", 'weak' = "3", 'failed' = "0"
'input' = "test", 'filesize' = "6g", 'filename' = "newressusample2684.rnd", 'weak' = "4", 'failed' = "0"
Lisätty uusi komentoriviparametri –base, jolla voi tulostaa satunnaislukuja numerojärjestelmän kantaluvulla: esimerkiksi –base2 tulostaa binäärisiä lukuja:
$ ./newressu --base2 --space
00000 11000100 01111111 11001101 00011101 00010110 11100110 11010111
00001 01001011 10110000 10001001 00100010 00111100 00100010 00111001
00002 01001110 01110111 10001111 01111110 10000100 01100011 01000001
00003 01110111 11001010 00011001 11110001 01101000 11111000 00011000
00004 10000101 10001100 00010101 00010100 10100010 11111000 11111100
00005 11100110 10111110 01000000 01001011 01011000 01101000 10000111
00006 11000101 01100011 11000011 01010010 01100101 01101000 01110100
00007 10001001 10110101 01000100 10100010 10100101 00111101 01110010
00008 00101000 00011010 11000000 00011011 11101100 11110011 01110001
00009 00111100 11101110 01101100 00100011 10100010 10101011 01110010
$
–base8 Tulostaa oktaalisia lukuja:
$ ./newressu --base8 --space
00000 555 577 571 453 417 713 524 041 350 116 445 542 630 601 101 063
00001 110 137 621 616 464 522 350 133 141 516 440 030 276 666 025 041
00002 722 142 746 011 005 570 526 245 065 113 063 012 037 734 450 664
00003 055 652 736 117 031 130 673 271 700 500 573 752 344 545 137 664
00004 707 527 155 352 163 075 363 256 061 763 374 541 372 452 550 745
00005 350 435 256 756 356 763 454 472 170 523 442 513 662 022 002 442
00006 627 647 504 635 317 431 241 253 347 641 640 102 436 255 202 137
00007 450 066 722 262 331 446 336 750 607 650 143 172 522 105 424 207
00008 012 004 751 651 634 314 721 755 462 450 507 014 306 236 653 053
00009 211 057 450 474 524 047 017 346 211 071 235 501 626 474 715 175
$
–base10 tulostaa desimaalisia lukuja:
$ ./newressu --base10 --space
00000 95115 37937 89506 93199 97183 10901 23222 55074 57325 64779 14185
00001 51276 53941 32097 46818 39443 36891 04676 65278 82499 99531 14515
00002 83199 80506 17322 72150 41682 57004 48748 82340 77278 23999 48218
00003 60605 83877 91724 87016 18583 08774 07189 93432 28636 75338 33974
00004 30782 37979 14311 64447 42103 93364 15366 28464 50557 93526 37781
00005 48320 15913 14301 24410 93099 97241 65875 61581 43909 32427 94536
00006 96746 50411 50162 12843 31785 30160 37329 05794 66353 91398 38261
00007 75387 17734 87459 97700 02426 44844 07538 93280 86564 39398 35084
00008 92139 68175 16288 09362 65059 77951 77617 16583 71273 09692 13384
00009 06691 06553 33780 39081 64955 58401 92144 49439 40880 35723 89259
$
–base16 tulostaa heksadesimaalilukuja:
$ ./newressu --base16 --space
00000 4c37 8c70 bc04 6810 05b8 ed49 3177 19f7 17cc adb2 29d0 f020 621a
00001 b172 b32c 1ab5 a032 9d63 bc53 f412 0037 eefc d3d7 c8b1 978c 2099
00002 c22c fbed f611 32ad d5fe d4c4 3ba2 7e37 ab79 2342 5c69 aef0 7599
00003 29cc 01ec 005b 037f 53ab 8961 1140 35e3 3719 0580 ab56 fe80 2177
00004 d9df 80b6 3701 2682 d4e4 880c 030c f534 e84e 7017 379a f30e 0480
00005 371f 2b47 59cf 8ac2 4380 64d1 dd7b f1f7 a838 b2ad d3f9 8a03 0573
00006 3f1e 6f0c 0514 ef54 7312 a380 0d3c 6150 cdaa 15cd dace 4395 5d4b
00007 e898 84e8 c85f 39e7 5e50 013a da26 dc00 c447 7487 3b08 8dde c410
00008 f10a 14c7 128d fa4d 6732 f56e 5ea7 f77e 970f d164 daaf dc6b f255
00009 19f4 0c41 1ca1 ce7c 7466 0422 0943 af04 72c5 007a 480a 6dc6 7804
$
Edellä olivat perus numerojärjestelmät binääri, oktaali, desimaali ja heksadesimaali, mutta –base toimii myös muilla kantaluvuilla (2-64): esimerkiksi –base36 tulostaa 36 kantaisen numerojärjestelmän lukuja:
$ ./newressu --base36 --space
00000 vw6t4707 wmzejmor jnacj3wx pbytkend szssa2dt u29rofy4 7ddvaowo
00001 gxyyprag w2m2t8il h0rcz7zz 0a8j9z2p mrczccyl qj592k9w lj3obm93
00002 6oh3zd8d fpluix1l rcyjaeqt oynw60up 2763qwu1 891zbfls egwb6lvq
00003 x14rnc4f kuv2kz3p et1topzo 3imwi0li 7jzzf2w4 ks06zhuk 2xo1rog8
00004 d2gdqkfx v4bsh2w0 7uxk55wp ey2l6f7u ixcl2sab ue8tj2wy mxeuqsx0
00005 s51oe413 8zr2iifo xo93c33h 8iveqio1 zbmwvpnc clzy8vng 6bz994j4
00006 8b3z7870 7jzekf1v btzmmq4w 02v09ecd 2ic974kw 3w99jvxy 30z5z9yj
00007 p10k2f02 jqp7xc7f 0mjc41q5 molcvqmy goxbzcat p4e75z9h 16lm6mgr
00008 szn5d1v8 leepjby0 j08fhhf3 bn1hrd12 nji2qc6l 5oszvwxv uzufl14b
00009 rws9u11f x33fapt2 oub6phs2 91g8vl7p eas829wa b5q7z29s k724s4p9
$
36-kantaisessa numerojärjestelmässä on numerot ja kaikki pienet kirjaimet. ([0-9]+[a-z] = 10 + 26 = 36). Seuraavassa koodi:
static unsigned char *basedigits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
....
int main(int argc, char *argv[])
{
....
} else if(!strncmp("--base", argv[c], 6)) {
if(*(argv[c] + 6) != '\0') {
base = atoll(argv[c] + 6);
} else if(c + 1 < argc) {
base = atoll(argv[c + 1]);
c++;
}
if(base < 2 || base > 64)
base = -1;
} else if(!strncmp("--BASE", argv[c], 6)) {
if(*(argv[c] + 6) != '\0') {
base = atoll(argv[c] + 6);
uppercase = 1;
} else if(c + 1 < argc) {
base = atoll(argv[c + 1]);
uppercase = 1;
c++;
}
if(base < 2 || base > 64) {
base = -1;
uppercase = -1;
}
....'
} else if(!strcmp("-b", argv[c]) ||
!strcmp("--bin", argv[c]) ||
!strcmp("--1bit", argv[c]) ||
!strcmp("--1bits", argv[c])) {
base = 2;
} else if(!strcmp("--2bits", argv[c])) {
base = 4;
} else if(!strcmp("-o", argv[c]) ||
!strcmp("--oct", argv[c]) ||
!strcmp("--3bits", argv[c]) ) {
base = 8;
} else if(!strcmp("-d", argv[c]) ||
!strcmp("--dec", argv[c])) {
base = 10;
} else if(!strcmp("-x", argv[c]) ||
!strcmp("--hex", argv[c]) ||
!strcmp("--4bits", argv[c])) {
base = 16;
} else if(!strcmp("-X", argv[c]) ||
!strcmp("--HEX", argv[c]) ||
!strcmp("--4BITS", argv[c])) {
base = 16;
uppercase = 1;
} else if(!strcmp("-5", argv[c]) ||
!strcmp("--5bits", argv[c])) {
base = 32;
} else if(!strcmp("--5BITS", argv[c])) {
base = 32;
uppercase = 1;
} else if(!strcmp("-2", argv[c]) ||
!strcmp("--6bits", argv[c])) {
base = 64;
....
if(size == -1) {
if(base == 2)
size = 8;
else if(base == 8)
size = 3;
else if(base == 10)
size = 5;
else if(base == 16)
size = 4;
else
size = 8;
}
if(base == -1) {
base = 10;
} else {
digits = malloc(base + 1);
strncpy(digits, basedigits, base);
if(uppercase == 1 && base <= 36) { // if lowercase only ([0-9] + [a-z], 10 + 26
for(int c = 0; c < base; c++) { // to uppercase
if(digits[c] >= 'a' && digits[c] <= 'z')
digits[c] = digits[c] - 'a' + 'A';
else if(digits[c] >= 'A' && digits[c] <= 'Z')
digits[c] = digits[c] - 'A' + 'a';
}
}
digits[base] = '\0';
digitsext = digits;
charspaces = 0;
charwidth = 1;
}
....
}
Vielä –base toiminnon tarkistamiseen käytettyjä debukkeja:
#define aDEBUG67
#ifdef DEBUG67
unsigned long long big = 0xffffffffffffffff;
fprintf(stdout,"\n0x%llx\n", big);
fprintfbase(stdout, big, 2);
fprintf(stdout,"\n0o%llo\n", big);
fprintfbase(stdout, big, 8);
fprintf(stdout,"\n0d%llu\n", big);
fprintfbase(stdout, big, 10);
fprintf(stdout,"\n0x%llx\n", big);
fprintfbase(stdout, big, 16);
fprintf(stdout,"\n");
//for(unsigned long long ll = 4096; ll > 0; ll+=4096) {
for(unsigned long long ll = 0; ll < 1047576; ll++) {
//for(unsigned long long ll = 1; ll != 0; ll *= 2) {
fprintf(stdout,"%llu:", ll);
fflush(stdout);
for(int base = 2; base <= 64; base++) {
fprintf(stdout," ");
fprintfbase(stdout, ll, base);
fflush(stdout);
}
fprintf(stdout,"\n");
}
#endif
Edellinen debukki suoritetaan ennen newressu:n alkua main() rutiinissa. Se tulostaa seuraavanlaisen listan: Vasemmassa reunassa on desimaalijärjestelmän numero ja siitä oikealle on eri numerojärjestelmien numerot 2-järjestelmästä (binääri) 64 järjestelmään. Binääriluvut, oktaaliluvut desimaaliluvut ja heksadesimaaliluvut on aloitettu totutuilla prefix:eillä 0b, 0o, 0d ja 0x.
0: 0b0 0 0 0 0 0 0o0 0 0d0 0 0 0 0 0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1: 0b1 1 1 1 1 1 0o1 1 0d1 1 1 1 1 1 0x1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2: 0b10 2 2 2 2 2 0o2 2 0d2 2 2 2 2 2 0x2 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 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
3: 0b11 10 3 3 3 3 0o3 3 0d3 3 3 3 3 3 0x3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
4: 0b100 11 10 4 4 4 0o4 4 0d4 4 4 4 4 4 0x4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
5: 0b101 12 11 10 5 5 0o5 5 0d5 5 5 5 5 5 0x5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6: 0b110 20 12 11 10 6 0o6 6 0d6 6 6 6 6 6 0x6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
7: 0b111 21 13 12 11 10 0o7 7 0d7 7 7 7 7 7 0x7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
8: 0b1000 22 20 13 12 11 0o10 8 0d8 8 8 8 8 8 0x8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
9: 0b1001 100 21 14 13 12 0o11 10 0d9 9 9 9 9 9 0x9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
10: 0b1010 101 22 20 14 13 0o12 11 0d10 a a a a a 0xa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a
11: 0b1011 102 23 21 15 14 0o13 12 0d11 10 b b b b 0xb b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b
12: 0b1100 110 30 22 20 15 0o14 13 0d12 11 10 c c c 0xc c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
13: 0b1101 111 31 23 21 16 0o15 14 0d13 12 11 10 d d 0xd d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d
14: 0b1110 112 32 24 22 20 0o16 15 0d14 13 12 11 10 e 0xe e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e
15: 0b1111 120 33 30 23 21 0o17 16 0d15 14 13 12 11 10 0xf f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
16: 0b10000 121 100 31 24 22 0o20 17 0d16 15 14 13 12 11 0x10 g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g
17: 0b10001 122 101 32 25 23 0o21 18 0d17 16 15 14 13 12 0x11 10 h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h h
18: 0b10010 200 102 33 30 24 0o22 20 0d18 17 16 15 14 13 0x12 11 10 i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i
19: 0b10011 201 103 34 31 25 0o23 21 0d19 18 17 16 15 14 0x13 12 11 10 j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j
20: 0b10100 202 110 40 32 26 0o24 22 0d20 19 18 17 16 15 0x14 13 12 11 10 k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k
21: 0b10101 210 111 41 33 30 0o25 23 0d21 1a 19 18 17 16 0x15 14 13 12 11 10 l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l
22: 0b10110 211 112 42 34 31 0o26 24 0d22 20 1a 19 18 17 0x16 15 14 13 12 11 10 m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m
23: 0b10111 212 113 43 35 32 0o27 25 0d23 21 1b 1a 19 18 0x17 16 15 14 13 12 11 10 n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n
24: 0b11000 220 120 44 40 33 0o30 26 0d24 22 20 1b 1a 19 0x18 17 16 15 14 13 12 11 10 o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
25: 0b11001 221 121 100 41 34 0o31 27 0d25 23 21 1c 1b 1a 0x19 18 17 16 15 14 13 12 11 10 p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p
26: 0b11010 222 122 101 42 35 0o32 28 0d26 24 22 20 1c 1b 0x1a 19 18 17 16 15 14 13 12 11 10 q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q
27: 0b11011 1000 123 102 43 36 0o33 30 0d27 25 23 21 1d 1c 0x1b 1a 19 18 17 16 15 14 13 12 11 10 r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r r
28: 0b11100 1001 130 103 44 40 0o34 31 0d28 26 24 22 20 1d 0x1c 1b 1a 19 18 17 16 15 14 13 12 11 10 s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s
29: 0b11101 1002 131 104 45 41 0o35 32 0d29 27 25 23 21 1e 0x1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t
30: 0b11110 1010 132 110 50 42 0o36 33 0d30 28 26 24 22 20 0x1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u u
31: 0b11111 1011 133 111 51 43 0o37 34 0d31 29 27 25 23 21 0x1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v
32: 0b100000 1012 200 112 52 44 0o40 35 0d32 2a 28 26 24 22 0x20 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w
33: 0b100001 1020 201 113 53 45 0o41 36 0d33 30 29 27 25 23 0x21 1g 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
34: 0b100010 1021 202 114 54 46 0o42 37 0d34 31 2a 28 26 24 0x22 20 1g 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
35: 0b100011 1022 203 120 55 50 0o43 38 0d35 32 2b 29 27 25 0x23 21 1h 1g 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10 z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
Toinen debukki on jo vanha, mutta sitä on hiukan päivitetty: se on DEBUG24 seuraavassa gen_limit() rutiinissa:
#define DEBUG24 2
unsigned long newressu_gen_limit(unsigned long limit) // JariK 2022
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) { // one byte
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) { // two bytes
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) { // three bytes
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) { // four bytes
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) { // five bytes
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) { // six bytes
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) { // seven bytes
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
#ifdef DEBUG24
fprintf(stdout,"/");
fprintf(stdout,"%d bytes: ", bytes);
fprintf(stdout,"[");
if(base == -1)
fprintfbase(stdout, word, 16);
else
fprintfbase(stdout, word, base);
fprintf(stdout,"]");
fprintf(stdout,"/");
fflush(stdout);
#endif
return(word);
}
DEBUG24 tulostaa seuraavan listan: Listalla hakasulkeiden välissä on satunnaisluku halutussa numerojärjestelmässä ja kauttaviivojen välissä on newressu:n tulostama osa. Debukkailussa vertaillaan vaan näitä lukuja keskenään, jos ne poikkeavat, kysymys voi olla bugista.
$ ./newressu --base36
/6 bytes: [s8mgcnh3]/00000 s8mgcnh3/6 bytes: [9k2ib3e1]/9k2ib3e1/6 bytes: [9wp3bkxs]/9wp3bkxs/6 bytes: [518vdcat]/518vdcat/6 bytes: [ngdb4pp7]/ngdb4pp7/6 bytes: [rpttb929]/rpttb929/6 bytes: [lwo0fh64]/lwo0fh64/6 bytes: [hnb2u25m]/hnb2u25m
/6 bytes: [skbzruoy]/00001 skbzruoy/6 bytes: [sm3zjnoj]/sm3zjnoj/6 bytes: [8oypbwn7]/8oypbwn7/6 bytes: [41gq1eiw]/41gq1eiw/6 bytes: [z3o8q3sp]/z3o8q3sp/6 bytes: [tmtmov02]/tmtmov02/6 bytes: [9t0wdd6k]/9t0wdd6k/6 bytes: [4493jrr9]/4493jrr9
/6 bytes: [lfjc14j4]/00002 lfjc14j4/6 bytes: [q1eg504x]/q1eg504x/6 bytes: [l4pj6fo6]/l4pj6fo6/6 bytes: [mg5b9kwl]/mg5b9kwl/6 bytes: [zfk08not]/zfk08not/6 bytes: [srd8rz6v]/srd8rz6v/6 bytes: [m1zf881h]/m1zf881h/6 bytes: [51gvzg98]/51gvzg98
/6 bytes: [qdwjg75r]/00003 qdwjg75r/6 bytes: [6xgb7i7]/06xgb7i7/6 bytes: [jhqu1f3p]/jhqu1f3p/6 bytes: [fwyo6fal]/fwyo6fal/6 bytes: [n6dgl1wy]/n6dgl1wy/6 bytes: [mvco358n]/mvco358n/6 bytes: [siqxwadz]/siqxwadz/6 bytes: [bm64i7dy]/bm64i7dy
/6 bytes: [brgihpa2]/00004 brgihpa2/6 bytes: [ysj25oc3]/ysj25oc3/6 bytes: [9fls8bwv]/9fls8bwv/6 bytes: [zfjklzhm]/zfjklzhm/6 bytes: [exeky1m2]/exeky1m2/6 bytes: [mqi11o2o]/mqi11o2o/6 bytes: [b7hzs0ip]/b7hzs0ip/6 bytes: [2dt4wq9d]/2dt4wq9d
/6 bytes: [6sori6y4]/00005 6sori6y4/6 bytes: [l4iv2qgr]/l4iv2qgr/6 bytes: [9yc39f25]/9yc39f25/6 bytes: [ijtan82p]/ijtan82p/6 bytes: [u03ert1n]/u03ert1n/6 bytes: [hf2cy6qf]/hf2cy6qf/6 bytes: [o936snch]/o936snch/6 bytes: [6pyqcy9t]/6pyqcy9t
/6 bytes: [d17dc4fh]/00006 d17dc4fh/6 bytes: [1z2dtov8]/1z2dtov8/6 bytes: [ncw5v2ry]/ncw5v2ry/6 bytes: [lg90wern]/lg90wern/6 bytes: [v8k27knh]/v8k27knh/6 bytes: [i5gpv5rr]/i5gpv5rr/6 bytes: [a401wuzc]/a401wuzc/6 bytes: [qb872hiu]/qb872hiu
/6 bytes: [3e28gqkv]/00007 3e28gqkv/6 bytes: [90gvp2pb]/90gvp2pb/6 bytes: [wa449h7o]/wa449h7o/6 bytes: [r0yo8qnw]/r0yo8qnw/6 bytes: [ohettmrn]/ohettmrn/6 bytes: [zkznxobg]/zkznxobg/6 bytes: [o8tsp19w]/o8tsp19w/6 bytes: [adlj1ab0]/adlj1ab0
/6 bytes: [33fwjh4v]/00008 33fwjh4v/6 bytes: [m695umdx]/m695umdx/6 bytes: [50bi59u0]/50bi59u0/6 bytes: [cabcjlyh]/cabcjlyh/6 bytes: [ont9hx9s]/ont9hx9s/6 bytes: [m4olw55]/0m4olw55/6 bytes: [wmegho9f]/wmegho9f/6 bytes: [600aj7k5]/600aj7k5
/6 bytes: [d711s29h]/00009 d711s29h/6 bytes: [8vcucf6y]/8vcucf6y/6 bytes: [x2ekuqo8]/x2ekuqo8/6 bytes: [msmqzwue]/msmqzwue/6 bytes: [kgdm7xyw]/kgdm7xyw/6 bytes: [rmeff22k]/rmeff22k/6 bytes: [wa6xtfdw]/wa6xtfdw/6 bytes: [lmhmb5ti]/lmhmb5ti
$
Vielä debukkauksessa käytetty rutiini, joka tulostaa long long:in ll base lukujärjestelmässä:
void fprintfbase(FILE *fp1, unsigned long long ll2, int base) // JariK 2023
{
int count;
unsigned long long ll, divider;
if(base == 2)
fprintf(fp1,"0b");
else if(base == 8)
fprintf(fp1,"0o");
else if(base == 10)
fprintf(fp1,"0d");
else if(base == 16)
fprintf(fp1,"0x");
ll = ll2;
divider = 1;
count = 0;
for(;;) { // count digits
ll /= base;
count++;
if(ll == 0)
break;
divider *= base; // do not count last digit
}
while(count > 0) { // print digits
fprintf(fp1,"%c", basedigits[(ll2 / divider) % base]);
divider /= base;
count--;
}
}
Lisätty kenttiä ressu_nonrandom() rutiiniin. Näin pyritään varmistamaan, että eri prosessissa(getpid) ja eri kellonaikaan(tv.tc_sec ja tv.tv_usec) generoidut satunnaisluvut ovat varmasti erilaisia. Lisäksi on lisätty satunnaisuutta prosessin kuluttaman ajan lisäämisellä (clock).
Periaatteessa ressun pääluuppi riittää kelvollisiin satunnaislukuihin, mutta tapauksessa jossa koneen kellojono on liian säännöllinen tarvitaan copy-reverse:n tuomaa lisää. Se että kellonaika tuodaan mukaan copy-reverse:en siirtää satunnaisuuden generoinnin uudelle tielle siinä tapauksessa että kello on asetettu. Tapauksessa, jossa kellonaikaa ei ole jäädään kellojonon uniikkisuuden varaan. Jatkossa vielä yksi testiajo, jossa tutkitaan kellojonon uniikkisuutta (newressutest16).
Tähän nonrandom:iin voisi vielä lisätä prosessorin id:n yksilöimään konetta, mutta sellaista ei ole saatavilla (onneksi..). Toki sen voisi korvata prosessorin tekemällä satunnaisluvulla (intel:in tapauksessa rdrand), mutta sitä en kiistanalaisuuden vuoksi tehnyt.
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
rando = rando +
//genbytes +
//time(NULL) +
//ressu_useconds() +
//ressu_clock() +
//buf.tms_utime +
//buf.tms_stime +
getpid() +
clockbytes +
tv.tv_usec +
tv.tv_sec +
clock() / CLOCKS_PER_SEC +
clock() % CLOCKS_PER_SEC +
ch * ch;
#ifdef DEBUG04
count[rando % ressuct_bytes]++;
#endif
#ifdef DEBUG2C
fprintf(stderr," %u", rando % ressuct_bytes);
newressu_output = 1;
#endif
return(rando);
}
Jo edellisessä rutiinissa olevalla DEBUG04 osuudella on tarkoitus tarkastella nonrandom:in hajontaa puskurissa. Seuraavassa muut (ja edellinen) DEBUG04:n osat:
....
#define DEBUG04 2
#ifdef DEBUG04
unsigned long count[RESSUT_BYTES];
#endif
....
#ifdef DEBUG04
count[rando % ressuct_bytes]++;
#endif
....
#ifdef DEBUG04
for(int c = 0; c < RESSUT_BYTES; c++)
count[c] = 0;
#endif
....
#ifdef DEBUG04
int bufferlen = 0;
for(int c = 0; c < ressuct_bytes; c++) {
unsigned char buffer[16];
sprintf(buffer, "%lu", count[c]);
if(bufferlen < strlen(buffer))
bufferlen = strlen(buffer);
}
for(int c = 0; c < ressuct_bytes; c++) {
if(c % 16 == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05u ", c);
}
fprintf(stdout,"%*lu", bufferlen + 1, count[c]);
}
fprintf(stdout,"\n");
#endif
....
DEBUG04:n tulostaa seuraavan kaltaisen raportin: Tällä kertaa en tarkemmin tutkinut muuta kuin sen että kaikkia puskurin merkkejä käytetään tasaisesti.
$ ./newressu -l100000 --quiet
00000 1005 956 956 1011 967 987 975 1039 981 998 1047 1022 982 943 1009 952
00016 961 1061 1005 923 1014 1026 1020 1032 954 962 983 995 1000 1029 904 947
00032 967 950 1011 1017 1019 1022 922 1005 1026 1002 976 1002 987 984 1005 980
00048 1054 999 998 974 997 953 987 1028 977 947 1010 985 977 973 915 975
00064 944 1042 940 954 1019 915 1003 968 988 1018 994 942 1005 974 973 1011
00080 987 947 1009 937 987 973 956 940 1005 971 972 1004 988 921 1006 1040
00096 1016 964 1008 982 1003 989 1010 988 1021 1005 1019 955 972 963 965 979
00112 970 972 1039 1005 983 1008 1010 965 999 1044 969 939 994 961 986 1024
00128 941 943 1019 950 999 934 1021 945 1035 978 951 945 1009 967 1019 1022
00144 995 992 992 984 1025 989 1013 1037 970 989 986 997 993 994 930 980
00160 1012 981 977 1013 993 980 1009 929 1017 1037 977 922 956 1068 974 976
00176 1014 986 993 958 1010 975 989 970 933 985 980 1025 918 949 1034 923
00192 974 1015 957 990 985 985 991 998 1034 1029 949 971 1030 997 991 946
00208 961 988 986 960 950 985 980 950 969 1032 1011 982 940 965 989 1002
00224 1067 1026 973 965 1001 989 987 951 964 971 951 954 929 1066 999 975
00240 967 1025 928 989 1025 982 979 1002 943 1007 957 1010 965 990 950 1001
00256 996 1019 1004 976 1062 953 1023 1043 956 991 966 997 963 1036 947 974
00272 980 931 945 935 1013 1020 944 967 987 1018 977 1010 967 951 990 922
00288 1015 976 1008 992 985 930 998 994 970 995 1067 994 949 997 987 1008
00304 1030 1095 1034 997 1014 1064 1024 1029 988 948 988 970 1056 1035 983 1002
00320 989 994 989 1007 995 1047 964 988 1014 975 1062 1016 992 1009 981 957
00336 1000 960 992 963 951 1004 964 999 1000 1023 971 956 986 961 1015 980
00352 989 982 971 959 968 980 923 974 994 1011 1006 994 1002 1008 954 974
00368 1038 950 980 999 957 999 972 921 1012 1015 1042 984 988 970 960 989
00384 987 958 978 956 1042 1051 967 1004 963 987 968 987 1001 1011 1013 1018
00400 961 1023 1027 976 965 969 891 1010 941 1005 954 1046 1035 995 1003 961
00416 995 1003 1017 1012 1028 970 980 973 1019 986 979 1006 976 998 994 952
00432 1024 981 931 972 974 977 971 1008 1028 973 1011 977 977 1009 907 963
00448 1017 1008 936 984 959 986 1036 1055 998 1087 1014 975 989 932 935 1063
00464 1028 1021 1026 1006 988 961 1028 956 980 999 986 992 984 1003 1016 977
00480 968 982 1034 981 1019 982 946 982 987 993 999 978 987 1034 1020 1052
00496 969 989 1042 988 994 1022 991 926 967 963 942 994 1012 1010 948 967
00512 1045 1029 1016 995 963 968 1001 1013 986 1008 977 1034 968 1010 1028 982
00528 965 1036 984 1011 974 1013 1021 971 1015 1045 973 984 960 927 1045 994
00544 946 961 974 1012 1018 1025 960 996 969 989 1019 1009 998 1008 944 1014
00560 963 979 1015 981 1021 968 986 986 978 1000 1050 948 961 993 982 960
00576 1025 1018 1008 1048 944 975 1013 936 1009 972 1007 960 1020 1017 997 1035
00592 968 1000 1009 975 1006 1026 980 1018 1021 967 933 933 978 985 1008 985
00608 991 940 942 945 995 1011 991 974 1016 1004 960 945 1005 953 999 1016
00624 1050 996 984 1035 995 961 1011 1021 1001 984 981 1022 988 939 962 1003
00640 1023 953 927 974 996 977 965 1009 964 1028 975 1059 1020 996 1017 965
00656 1021 1001 939 988 982 999 1001 1005 959 961 953 1030 948 949 991 981
00672 971 947 961 983 1030 951 962 968 968 1009 968 937 915 967 1009 1014
00688 979 1000 921 1040 967 1039 989 951 957 1004 981 989 992 1013 891 946
00704 956 995 1035 970 1000 992 962 999 1004 999 980 1060 994 1018 989 1007
00720 971 983 991 977 942 1016 1011 918 1020 973 957 983 973 1022 1006 969
00736 1004 994 983 930 975 1011 993 974 986 990 1027 996 998 1005 987 1006
00752 1054 954 985 977 954 1027 1001 1026 1002 1011 1003 996 943 993 992 941
00768 1036 954 1012 954 1001 1066 987 1006 1026 988 986 1055 937 1005 995 1000
00784 993 952 962 983 975 937 977 989 1011 1006 1012 992 1024 933 980 1013
00800 960 991 969 961 1017 1007 943 979 920 1055 973 962 1012 952 915 1008
00816 1027 985 1022 989 950 977 974 987 973 1003 981 992 929 1015 965 971
00832 994 983 1020 955 1024 1035 956 1055 990 957 932 1015 1013 996 1028 1002
00848 953 1008 978 986 997 970 985 1014 979 957 1002 1011 1011 993 994 970
00864 987 991 1035 1066 996 973 989 975 998 981 1052 983 934 960 1012 968
00880 976 955 976 1032 969 920 959 929 987 969 1000 979 974 986 984 982
00896 1026 910 1010 1054 1014 910 1009 967 1027 997 994 953 947 1035 984 959
00912 1026 976 1000 1002 1008 975 1015 952 979 1008 957 944 1032 1040 1014 957
00928 1045 999 1000 1004 963 960 979 957 992 953 991 1025 970 920 980 961
00944 983 930 943 898 1000 1075 1049 960 1014 1051 1027 937 1018 975 977 964
00960 1009 993 1019 986 1007 997 981 992 967 1000 1022 964 995 949 918 950
00976 1017 1017 957 973 981 896 979 975 1002 998 970 990 1044 1002 1018 970
00992 969 1003 980 970 1002 982 1012 1045 985 996 991 1026 998 1046 924 992
01008 1026 1009 976 936 987 1008 977 985 1021 999 1017 985 1075 1041 953 978
01024 947 1011 955 978 954 947 947 985 1020 1007 1005 983 1002 975 954 922
01040 1034 995 1017 950 1030 989 974 945 932 992 969 1005 993 932 940 985
01056 1009 989 957 934 1019 1043 991 980 938 993 1004 1003 962 955 1000 949
01072 946 947 1005 979 1019 1008 1039 985 1031 971 973 943 929 957 950 1041
01088 964 973 1025 994 952 929 967 1040 1019 1015 1052 959 1018 1021 943 1013
01104 911 1020 999 998 947 1004 964 952 956 998 1012 997 964 984 1013 984
01120 930 1003 973 946 977 1007 940 1062 928 1012 1009 995 1000 1007 999 983
01136 952 1017 961 954 937 1013 983 993 956 931 1063 944 974 1066 1015 1003
01152 990 973 1009 965 960 1020 978 986 1039 971 970 983 1004 989 958 940
01168 994 1009 948 974 995 911 1013 1021 973 1037 994 1021 998 968 997 964
01184 1018 1010 1025 964 1013 957 970 1028 994 1012 1014 937 983 1016 1006 1015
01200 977 961 971 1034 954 976 1034 994 990 963 947 1024 996 1044 935 965
01216 1013 984 971 997 1023 1032 1023 949 962 1050 997 992 958 982 948 1011
01232 1008 973 973 997 893 1003 997 1010 931 979 950 979 964 957 953 970
01248 959 980 922 980 996 965 963 948 945 1014 1054 1034 971 948 1002 964
01264 1077 1038 989 966 952 951 1027 947 1032 980 993 1034 979 953 1026 988
01280 1022 975 1004 1003 1016 964 985 986 1009 1008 1018 990 1058 936 1000 994
01296 1038 1014 941 927 1046 963 1055 954 950 1042 991 1014 956 1012 1006 1038
01312 965 992 1041 998 1022 965 905 944 950 1003 973 973 1053 964 1018 988
01328 990 1000 985 982 972 974 1015 1007 964 963 967 989 950 994 985 974
01344 1027 1026 950 1018 1017 991 963 961 1027 970 938 998 925 1024 973 1004
01360 996 955 1018 972 991 971 1016 993 962 998 1044 991 990 1008 987 947
01376 1002 1028 942 983 982 961 1003 1039 978 1007 1032 961 981 966 987 1050
01392 930 966 967 1006 1040 1000 990 978 946 931 1000 960 977 1019 960 980
01408 937 1023 1027 1051 1015 983 1008 949 951 956 961 977 993 986 951 930
01424 1024 999 979 1046 952 943 973 1054 987 995 1009 985 1028 945 992 963
01440 1031 967 999 989 1020 966 937 959 1034 952 1010 1023 961 1015 963 1011
01456 1026 1035 1051 963 937 924 973 959 1028 997 1048 1053 987 913 926 1026
01472 953 964 975 986 919 962 1012 995 952 1056 970 1002 1032 994 889 960
01488 948 910 992 1017 955 988 1002 1020 891 1027 1000 962 989 1017 1010 1045
01504 1033 1021 960 1014 973 988 1038 990 1023 986 987 961 936 1003 952 1001
01520 999 908 1026 976 989 971 964 986 1008 1040 957 971 954 991 968 979
01536 1001 948 1005 976 975 999 1017 930 999 1006 1028 982 994 986 949 1028
01552 1022 1000 923 956 1014 934 1068 1013 985 963 959 1014 927 984 1064 1074
01568 952 1010 1035 1033 995 929 976 985 984 983 984 951 992 994 994 1003
01584 946 1024 978 1059 962 1008 1023 943 982 984 978 1028 1025 978 960 929
01600 999 1030 1023 992 1006 1024 979 965 1028 958 1037 997 972 972 1056 929
01616 1025 995 1006 1004 993 991 953 970 985 955 1020 1024 972 949 968 972
01632 978 983 1026 1041 1000 1021 1013 985 1009 937 980 902 997 940 988 988
01648 991 974 1037 974 982 966 983 963 976 987 953 1015 990 992 964 1045
01664 954 960 941 1004 1034 995 1010 952 1015 955 985 1000 1012 1019 949 1045
01680 971 998 1016 1008 969 965 951 916 958 996 954 1035 968 955 955 970
01696 1023 982 1004 986 993 964 1000 966 1024 959 939 954 976 948 1011 1020
01712 964 972 1000 954 1002 971 963 997 964 1012 959 1008 963 991 1005 957
01728 1015 955 998 932 1044 948 975 1006 1000 1032 964 972 950 948 960 1045
01744 1022 990 957 970 991 985 954 1016 919 939 1014 957 933 971 1039 982
01760 989 991 910 997 1033 1036 969 1016 951 1016 981 967 982 942 960 959
01776 1015 1026 1007 995 1006 957 1023 968 1068 990 972 978 908 979 982 944
01792 1038 1036 984 990 974 987 968 970 974 1038 979 936 930 957 962 1014
01808 1011 968 992 1039 959 1042 933 987 1046 1008 1009 1017 988 1040 941 1023
01824 979 982 970 1019 959 945 976 1019 1045 1041 956 953 1029 986 930 981
01840 982 959 991 979 952 1015 963 993 1014 1015 989 966 1037 975 1003 1005
01856 994 997 969 953 962 999 923 989 970 903 983 1053 907 972 1047 1013
01872 987 1041 968 963 979 1019 1002 1061 1008 1015 989 1027 1042 910 954 971
01888 941 979 995 1059 1036 993 967 1000 937 967 945 1035 1011 904 923 960
01904 1007 1016 983 1035 977 959 982 941 930 942 1000 921 947 1026 958 1016
01920 966 996 1082 931 990 933 1016 1037 979 967 1042 1009 952 980 1015 1002
01936 963 962 966 1014 947 976 1003 965 1005 1046 974 973 1078 924 983 1027
01952 991 971 968 1015 916 1032 994 990 1021 1001 972 1033 987 1040 1015 987
01968 932 1061 979 948 1016 978 947 892 1019 1015 1026 997 994 968 958 990
01984 928 962 1011 1043 966 1023 978 1058 943 1007 1009 1019 974 995 969 974
02000 935 1023 1028 998 985 993 1032 958 1006 1017 950 986 992 983 1000 910
02016 1038 1025 1008 971 900 926 983 1001 943 954 974 1002 997 1051 976 1002
02032 1010 989 950 991 1022 985 957 1008 972 955 930 1004 994 981 946 958
Seuraavassa vielä kellojonon uniikkiuden tarkasteluun pieni ohjelma. Ohjelma pakkaa kellojonon siten että yhdestä ketjusta tulostetaan aina peräkkäin arvo ja pituus. Seuraavassa esimerkkitietue: raportin luvut ovat kaksimerkkisiä heksalukuja. Ensimmäinen merkki on nolla ja niitä on $5 kappaletta, seuraava merkki on $1 ja niitä on $1 kappale, jne…
$ ./newressutest16 --filesize1600 -
string:'1600', base:10(10B), multiplier:1(1B), prevll:1600(~1K), ll:1600(~1K), totll:1600(~1K)
clockstream, lines:1(1B), clocksize:1600(~1K), linesize:1601(~1K), filesize:1601(~1K)
filename:-
00050101020103080411051106130714081309110a140b140c130d140e130f141014110f121113131414151416141714181419121a131b141c141d141e141f1420142112221423142414251426142714281429122a142b132c142d142e142f1430143113321333133414351436143714381439123a133b143c143d133e143f1440144111421443144413451446144714481349124a134b144c144d144e144f1350145113521453145413551456145714581359135a135b145c135d145e145f1360146111621363146413651466136714681469126a136b136c146d146e136f1470147112721473137414751376147714781379127a137b137c147d137e147f1380138113821283138413851486138714881389128a138b138c148d108e148f1390149112921393149413951496139714981399129a139b139c149d139e139f14a013a111a212a313a413a513a614a713a813a912aa12ab14ac13ad13ae13af14b013b112b214b313b413b513b613b714b813b911ba13bb13bc13bd14be13bf13c013c112c213c312c413c513c613c713c813c912ca12cb13cc13cd13ce13cf13d013d111d213d313d413d513d614d713d813d911da12db13dc13dd13de13df13e013e111e213e313e413e513e613e713e813e911ea12eb13ec12ed13ee14ef12f013f113f212f313f413f512f614f712f813f911fa13fb13fc13fd13fe13ff130013010c020f03110411051206130712081209100a120b120c120d120e130f1210121111121313131412151316131712181319101a111b121c121d131e131f1320132110221223122412251326132713281329102a112b112c122d132e132f1230133111321233133413351336123713381339103a133b113c133d123e133f1240134111421143124412451346134713481249104a124b134c124d134e134f1350125111521353135412551356125713581259115a125b135c125d135e135f126013610f620e63126411651266126713681269116a116b126c126d136e126f1370127112721273137412751376127713781279107a117b137c127d127e137f1280138110821183118412851286128713881289118a118b128c138d128e128f13
./newressutest16: hashed file, sha256:661922921ecb992b816a89aa619fbb639b215104b51a4b3f3531ca7cb45362a3
jarik@jarik-HP14dv2002:~/f/ressurngd$
Seuraavassa ohjelmaa on ajettu siten, että sen tuloste lajitellaan ja vertaillaan 1500 ensimmäistä merkkiä lajitellun tiedoston peräkkäisistä riveistä. Jos ne ovat samat, se on ongelma ja tietueet tulostetaan. Jos ne poikkeavat, ne ovat molemmat uniikkeja, eikä mitään tulosteta: Eli kaikki on kunnossa, jos ohjelma ei tulosta mitään.
$ ./newressutest16 --filesize100g --stdout | sort | uniq -D --check-chars=1500
string:'100g', base:10(10B), multiplier:1073741824(1G), prevll:100(100B), ll:107374182400(100G), totll:107374182400(100G)
clockstream, lines:67066948(~63M), clocksize:1600(~1K), linesize:1601(~1K), filesize:107374183748(~100G)
filename:-
Done:100.0%
./newressutest16: hashed file, sha256:485573cfe61b732c01722be1cddfd12adf769055e0395f89baad0ad6aa62857a
$
Ja varsinainen ohjelma:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include "sha256.h"
unsigned char *procname;
static unsigned char *programname = "newressutest16 version 0.2 ©";
static unsigned char *copyright = "Copyright (c) 2024 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FILESIZE 16010
#define CLOCKSIZE 1600 // bytes per line
#define LINESIZE 1601 // CLOCKSIZE + 1
#define LINES 10
#define BLOCKSIZE 1024
#define GENT_SIZE 128
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
#include <sys/time.h>
unsigned long long useconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec + 1000000 * tv.tv_sec);
}
#include <string.h>
#include <stdlib.h>
//#define KILO 1000
#define KILO 1024
int stat = 0;
void fprintfcharacter(FILE *fp1, unsigned char *p)
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p) // JariK 2023
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
void readablelonglong(FILE *fp1, unsigned long long ll2)
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
#define DEBUG45 2
unsigned long long getlonglong(unsigned char *p2) // JariK 2023
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb)
p++;
totll += ll;
#ifdef DEBUG45
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value:%d", digit);
fprintf(stderr,", base:%u(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
return(totll);
}
#define FILE_HASH 2 // on by default
#ifdef FILE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x", final[c]);
}
}
#endif
#define DEBUG79 2
int main(int argc, char *argv[])
{
int c, d, percentageline = 1, prevpros, pros, quiet = 0, help = 0;
int filesize_set = 0, clocksize_set = 0, linesize_set = 0, lines_set = 0;
unsigned long long filesize = FILESIZE, lines = LINES;
unsigned int clocksize = CLOCKSIZE, linesize = LINESIZE;
int stdoutflag = 0;
unsigned long long plines = 0;
unsigned char *buffer, filename[128] = "";
FILE *fp1;
procname = argv[0];
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(c == argc - 1 && !strcmp(argv[c], "-")) { // last option hyphen
stdoutflag = 1; // output to stdout
continue;
}
if(strncmp("-", argv[c], 1)) { // filename not expected
fprintf(stderr,"%s: filename not expected", procname);
fprintf(stderr,", parameter:%s", argv[c]);
fprintf(stderr,"\n");
exit(1);
}
if(!strncmp("-", argv[c], 1)) { // option starting with hyphen
if(!strncmp("-o", argv[c], 2)) { // output filename
if(*(argv[c] + 2) != '\0') {
strncpy(filename, argv[c] + 2, sizeof(filename));
} else if(c + 1 < argc) {
strncpy(filename, argv[c + 1], sizeof(filename));
c++;
}
stdoutflag = 0;
} else if(!strcmp("--stdout", argv[c])) { // output stdout
stdoutflag = 1; // output to stdout
filename[0] = '\0';
} else if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c]) ) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--quiet", argv[c])) {
quiet = !quiet;
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
filesize = getlonglong(argv[c + 1]);
c++;
}
filesize_set = 1;
} else if(!strncmp("--linesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
linesize = getlonglong(argv[c] + 10);
} else if(c + 1 < argc) {
linesize = getlonglong(argv[c + 1]);
c++;
}
linesize_set = 1;
} else if(!strncmp("--lines", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
lines = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
lines = getlonglong(argv[c + 1]);
c++;
}
lines_set = 1;
} else if(!strncmp("--clocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
clocksize = getlonglong(argv[c] + 11);
} else if(c + 1 < argc) {
clocksize = getlonglong(argv[c + 1]);
c++;
}
clocksize_set = 1;
} else if(!strcmp("--stat", argv[c])) {
stat = !stat;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
}
if(!linesize_set)
linesize = clocksize + 1;
else if(!clocksize_set)
clocksize = linesize - 1;
if(!filesize_set)
filesize = lines * linesize;
else if(!lines_set) {
lines = (filesize + linesize - 1) / linesize; // round up
filesize = lines * linesize;
} else if(!linesize_set) {
linesize = (filesize + lines - 1) / lines; // round up
clocksize = (linesize - 1);
filesize = lines * linesize;
}
if(linesize != clocksize + 1 ||
linesize < 5 || clocksize < 4) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", clocksize:%u(", clocksize);
readablelonglong(stderr, clocksize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize != lines * linesize ||
lines < 1 || linesize < 5) {
fflush(stdout);
fprintf(stderr,"%s: mismatched parameters", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / lines != linesize) { // test overflow too
fflush(stdout);
fprintf(stderr,"%s: parameter overflow", procname);
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
// print help message if needed
if(help) {
fprintf(stderr,"%s", procname);
fprintf(stderr,"\n\t[-o filename]");
//fprintf(stderr," [--stdout]");
fprintf(stderr,"\n\t[--filesize base-number-multiplier]");
fprintf(stderr,"\n\t[--lines base-number-multiplier]");
fprintf(stderr," [--linesize base-number-multiplier]");
fprintf(stderr,"\n\t[--clocksize base-number-multiplier]");
fprintf(stderr,"\n\t[--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--stat]");
fprintf(stderr," [--verbose]");
fprintf(stderr," [--quiet]");
fprintf(stderr,"\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr,"\t$ %s --single --filesize1g\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --lines1m\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --linesize25\n", procname);
fprintf(stderr,"\t$ %s --single --filesize1g --clocksize12\n", procname);
exit(1);
} // end of if(help)
#ifdef DEBUG79
// print filesize parameters
fprintf(stderr,"clockstream");
fprintf(stderr,", lines:%llu(", lines);
readablelonglong(stderr, lines);
fprintf(stderr,")");
fprintf(stderr,", clocksize:%u(", clocksize);
readablelonglong(stderr, clocksize);
fprintf(stderr,")");
fprintf(stderr,", linesize:%u(", linesize);
readablelonglong(stderr, linesize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
#endif
if(!stdoutflag && filename[0] == '\0') {
// find first available filename,
// or empty "slot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, "newressutest16.%d.rnd", c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef FILE_HASH
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
}
if(stdoutflag) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
percentageline = 0;
}
}
if(stdoutflag)
fprintf(stderr,"filename:-\n");
else
fprintf(stderr,"filename:%s\n", filename);
if(stdoutflag == 1) {
fp1 = stdout;
} else if((fp1 = fopen(filename, "w")) == NULL) {
fprintf(stderr,"%s: cannot open file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,"\n");
exit(1);
}
#ifdef FILE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // initialize hash
#endif
if((buffer = malloc(linesize + 1)) == NULL) { // space for '\0' too
fprintf(stderr,"%s: cannot allocate memory (buffer)\n", procname);
exit(1);
}
memset(buffer, 0, linesize + 1);
prevpros = -1;
int count, prevusec = -1, usec;
unsigned long long diff0;
for(;;) {
#define DEBUG87
#ifdef DEBUG87
prevusec = useconds();
while((usec = useconds()) == prevusec);
diff0 = usec;
#else
diff0 = 0;
#endif
*buffer = '\0';
count = 0;
prevusec = -1;
for(;;) {
usec = (useconds() - diff0) & 0xff;
if(prevusec == -1)
prevusec = usec;
else if(usec != prevusec) {
unsigned char buffer10[10];
sprintf(buffer10,"%02x%02x", prevusec, count);
if(strlen(buffer) + strlen(buffer10) < linesize)
strcat(buffer, buffer10);
else
break;
prevusec = usec;
count = 0;
}
count++;
}
strcat(buffer, "\n");
#ifdef FILE_HASH
HashUpdate(&hash, buffer, strlen(buffer)); // calculate hash
#endif
if(fwrite(buffer, 1, strlen(buffer), fp1) < strlen(buffer)) {
fprintf(stderr,"%s:", procname);
fprintf(stderr," cannot write file");
fprintf(stderr,"\n");
exit(1);
}
plines++;
if(plines >= lines)
break;
}
#ifdef FILE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
if(!stdoutflag)
fclose(fp1);
#ifdef FILE_HASH
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
fprintf(stderr,"%s: hashed file", procname);
if(filename[0] != '\0') {
fprintf(stderr,", filename:%s", filename);
unsigned char filename2[138];
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,", hashfilename:%s", filename2);
if((fp1 = fopen(filename2, "w")) != NULL) {
fprintf(fp1,"%s\n", hashstring);
fclose(fp1);
}
} // end of if(filename[0] != '\0'
fprintf(stderr,", sha256:%s\n", hashstring);
if(!stdoutflag) {
fprintf(stderr,"%s: checking sha256", procname);
fprintf(stderr,", filename:%s\n", filename);
unsigned char command[1024];
sprintf(command,"sha256sum %s", filename);
system(command);
}
#endif
free(buffer);
return(0);
}
Copy-reverse on uudelleenkirjoitettu siten, että kellojonoon lisätään aikaista enemmän satunnaisuutta: Uudessa versiossa on neljä (DEPTH) tasoa, joissa kussakin on oma lohkoihin jako. Näin ennen copy reverse käsitteli kellojonon vain yhtenä copy reverse puskurina ja nyt niitä on neljä.
#define DEPTH 4
unsigned int copyreverse = 1;
unsigned long cblocks = 0;
unsigned char lens = 4;
static unsigned char ressu_copyreverse(int depth)
{
static int reverse[DEPTH] = {0}; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned int len[DEPTH] = {0};
static unsigned int count[DEPTH] = {0};
static unsigned int low[DEPTH] = {0};
static unsigned int high[DEPTH] = {0};
static unsigned char bytes[DEPTH][257] = {0};
if(depth == 0) {
#ifdef DEBUG2D
int c = ressu_clock();
fprintf(stdout,", ch2:%02x",c);
return(c);
#else
return(ressu_clock());
#endif
}
depth--;
// dividing clock stream into blocks
// and reversing every other block
// copy next block to bytes
if(count[depth] == 0) { // previous block ended
reverse[depth] = !reverse[depth];
len[depth] = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
//len[depth] = (ressuct[ressu_nonrandom() % ressuct_bytes] & 3 ) + 2; // block size
//len[depth] = --lens + 2; // block size
//len[depth] = lens++ + 2; // block size
count[depth] = len[depth];
low[depth] = 0;
high[depth] = len[depth];
rndbits2 += 2;
#ifdef DEBUG2A
fprintf(stdout,"\nblk:");
fprintf(stdout," depth:%d", depth);
fprintf(stdout,", reverse:%d", reverse[depth]);
fprintf(stdout,", len:%d", len[depth]);
fprintf(stdout,", count:%d", count[depth]);
fprintf(stdout,", low:%d", low[depth]);
fprintf(stdout,", high:%d", high[depth]);
fflush(stdout);
#endif
for(int c = 0; c < len[depth]; c++) {
bytes[depth][c] = ressu_copyreverse(depth); // block bytes
#ifdef DEBUG2A
fprintf(stdout,", b%d:%02x", depth, bytes[depth][c]);
newressu_output = 1;
#endif
}
}
if(reverse[depth]) { // reverse
// get reversed byte to return
ch = bytes[depth][--high[depth]]; // reverse
#ifdef DEBUG2E
fprintf(stdout,", rev%d:%02x", depth, ch);
fflush(stdout);
#endif
--count[depth];
} else { // copy
// get copied byte to return
ch = bytes[depth][low[depth]++];
#ifdef DEBUG2E
fprintf(stdout,", copy%d:%02x", depth, ch);
fflush(stdout);
#endif
--count[depth];
}
return(ch);
}
Seuraava rutiini kutsuu edellistä:
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
if(copyreverse) {
ch = ressu_copyreverse(DEPTH);
} else {
ch = ressu_clock();
} // end of if(copyreverse)
#ifdef DEBUG2F
static unsigned int cols = 0;
if(cols % 32 == 0) {
if(cols > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05u ",cols);
}
if(cols % 4 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x",ch);
cols++;
#endif
// statistics for theoretical
// random bits calculation (rndbits?)
static int prevbyte = -1, clockcount = 0;
if(prevbyte == -1)
prevbyte = ch;
if(prevbyte != ch) {
periods[clockcount]++;
clockbytes += clockcount;
#ifdef DEBUG2B
fprintf(stdout," %d", clockcount);
newressu_output = 1;
#endif
clockcount = 0;
prevbyte = ch;
}
clockcount++;
return(ch);
}
Lisätty heprean (hebrew, –heb) merkistö:
} else if(!strcmp("--heb", argv[c])) { // hebrew
// ֑֖֚֒֓֔֕֗֘֙־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתׯװױײ׳״
digits = "אבגדהוזחטיךכלםמןנסעףפץצקרשת";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
}
Seuraavassa satunnaisbittejä heprean merkistöllä:
$ ./newressu --heb
00000 ץמחבסץדרעפירקכאטילטתפוגגיתחסנסעיסגתזצוסלפסלנפיץמקילדץקעסמזאפסץרת
00001 ףתחטייעיםתתאמכזצםפםטטםץעקרגטזפחשאצנמעבוחנץוטאףץפרקבעטשתטונרהףזסל
00002 זלעטףלףבכגיפםקצךטשסחתנזכסהפפוצקדקיזפחהפףתמטךצפיזאקצתדמבדצפמןזץחד
00003 נמוחאלשקבךכזדצחקקףבערסתעקץסנכפלףתץךהןכהפגעפץפףתאנועתביבםוהעשפלפש
00004 אאנךחעחלףסכפדגזשצדטצעחףץךלעגםלשדסגסבףקישקדערץנץזעטידפןיהןבםדבךטצ
00005 יץןףפרנכלמישלדתכשךוקץזשטןךאךדכחמאןמכדכתפץכףייךזןצהצפבצותגרחצףקטז
00006 ןנתתדבצדדלםןגרככממזאויגחידפזעשלסלאתוזוןתתףיצסדץעסבסםףםסחקםצפעןקר
00007 רוןזםץנחםסמםטמדתנץהפפיסשתיתחמגפמגאוץתףחאהעףדחןדצתפכךצנףמחגשקנמפכ
00008 טטפזצנתרמבתרנןףסגןהפאזפתרתשחצחבאפדןנכטשפעןוקאחוןנצכחדפהגזנעךבגרנ
00009 ךכדחעגקףתצפךטקפשכהםדףתשחןטלוףקכזיךפשאץשןתלןץקיבסומכץוחךםהסבזמגצן
$
Lisätty satunnaisbitit foinikialaisen (phoenician, –pho) merkistön mukaan.
$ ./newressu --pho
00000 𐤙𐤍𐤐𐤓𐤄𐤀𐤑𐤏𐤆𐤚𐤑𐤍𐤍𐤎𐤇𐤑𐤚𐤛𐤅𐤑𐤆𐤛𐤋𐤀𐤃𐤛𐤓𐤍𐤒𐤍𐤆𐤐𐤕𐤓𐤄𐤚𐤙𐤓𐤁𐤏𐤑𐤉𐤃𐤉𐤆𐤙𐤋𐤎𐤐𐤇𐤐𐤁𐤇𐤃𐤎𐤌𐤊𐤃𐤘𐤓𐤍𐤛𐤖𐤂
00001 𐤐𐤒𐤂𐤈𐤂𐤙𐤚𐤅𐤆𐤆𐤋𐤁𐤉𐤁𐤙𐤒𐤄𐤀𐤁𐤂𐤄𐤊𐤉𐤉𐤚𐤒𐤊𐤒𐤉𐤍𐤆𐤀𐤔𐤈𐤃𐤚𐤅𐤅𐤂𐤕𐤘𐤈𐤁𐤘𐤀𐤉𐤑𐤄𐤑𐤆𐤀𐤅𐤐𐤖𐤅𐤓𐤈𐤄𐤛𐤐𐤃𐤘𐤚𐤖
00002 𐤘𐤃𐤁𐤒𐤓𐤖𐤛𐤓𐤚𐤌𐤀𐤘𐤏𐤅𐤅𐤀𐤕𐤚𐤆𐤁𐤌𐤓𐤉𐤚𐤁𐤃𐤁𐤅𐤅𐤀𐤗𐤈𐤗𐤉𐤁𐤈𐤓𐤒𐤘𐤕𐤅𐤊𐤙𐤏𐤂𐤇𐤉𐤉𐤆𐤒𐤉𐤆𐤊𐤔𐤄𐤔𐤚𐤙𐤃𐤖𐤄𐤆𐤃𐤗
00003 𐤏𐤛𐤃𐤈𐤗𐤘𐤓𐤂𐤕𐤙𐤖𐤄𐤆𐤌𐤛𐤖𐤛𐤌𐤔𐤀𐤓𐤀𐤂𐤏𐤏𐤓𐤉𐤘𐤗𐤑𐤃𐤕𐤉𐤗𐤕𐤖𐤍𐤋𐤀𐤗𐤂𐤌𐤆𐤗𐤓𐤄𐤚𐤎𐤑𐤁𐤅𐤍𐤍𐤒𐤛𐤘𐤋𐤌𐤓𐤔𐤄𐤄𐤁𐤃
00004 𐤗𐤀𐤓𐤈𐤏𐤒𐤗𐤇𐤖𐤅𐤏𐤛𐤌𐤎𐤚𐤄𐤐𐤄𐤄𐤚𐤄𐤒𐤆𐤋𐤑𐤋𐤙𐤁𐤏𐤍𐤀𐤁𐤄𐤊𐤍𐤃𐤚𐤇𐤙𐤊𐤑𐤊𐤆𐤈𐤔𐤋𐤓𐤚𐤗𐤐𐤍𐤑𐤚𐤏𐤛𐤇𐤎𐤔𐤃𐤇𐤄𐤙𐤇𐤀
00005 𐤓𐤔𐤅𐤊𐤈𐤆𐤈𐤁𐤅𐤄𐤌𐤀𐤐𐤏𐤑𐤁𐤛𐤛𐤃𐤏𐤎𐤚𐤕𐤀𐤋𐤓𐤙𐤂𐤇𐤛𐤄𐤐𐤃𐤑𐤈𐤌𐤎𐤐𐤈𐤇𐤃𐤒𐤆𐤓𐤍𐤓𐤋𐤈𐤂𐤗𐤈𐤉𐤕𐤗𐤓𐤍𐤐𐤗𐤉𐤑𐤄𐤇𐤖𐤖
00006 𐤌𐤈𐤊𐤌𐤔𐤏𐤋𐤙𐤗𐤓𐤇𐤑𐤍𐤆𐤄𐤊𐤉𐤛𐤖𐤈𐤍𐤑𐤖𐤁𐤀𐤁𐤍𐤇𐤉𐤈𐤂𐤋𐤕𐤃𐤐𐤂𐤁𐤅𐤓𐤘𐤖𐤃𐤘𐤋𐤎𐤈𐤆𐤙𐤖𐤀𐤕𐤔𐤘𐤃𐤊𐤎𐤑𐤁𐤎𐤘𐤇𐤔𐤒𐤅
00007 𐤐𐤑𐤋𐤍𐤚𐤅𐤍𐤖𐤃𐤋𐤌𐤈𐤁𐤁𐤏𐤖𐤑𐤀𐤊𐤅𐤌𐤑𐤀𐤋𐤏𐤆𐤕𐤐𐤁𐤄𐤅𐤐𐤐𐤚𐤒𐤕𐤅𐤌𐤚𐤆𐤍𐤒𐤚𐤅𐤆𐤈𐤑𐤕𐤀𐤈𐤔𐤊𐤗𐤃𐤖𐤔𐤎𐤂𐤚𐤈𐤙𐤐𐤎𐤕
00008 𐤙𐤓𐤛𐤘𐤐𐤒𐤇𐤌𐤊𐤎𐤁𐤎𐤐𐤒𐤊𐤄𐤃𐤓𐤄𐤗𐤀𐤔𐤂𐤖𐤗𐤖𐤛𐤔𐤀𐤉𐤒𐤎𐤙𐤊𐤓𐤌𐤆𐤍𐤈𐤈𐤖𐤀𐤌𐤆𐤓𐤃𐤅𐤑𐤄𐤘𐤖𐤌𐤓𐤔𐤒𐤆𐤔𐤄𐤁𐤍𐤒𐤇𐤊𐤒
00009 𐤕𐤕𐤌𐤆𐤌𐤐𐤂𐤎𐤒𐤖𐤓𐤄𐤎𐤊𐤈𐤉𐤊𐤈𐤒𐤂𐤔𐤄𐤔𐤆𐤄𐤀𐤁𐤃𐤑𐤅𐤂𐤉𐤊𐤔𐤓𐤔𐤗𐤉𐤙𐤖𐤔𐤙𐤀𐤓𐤊𐤌𐤑𐤐𐤐𐤓𐤉𐤁𐤉𐤙𐤛𐤉𐤌𐤚𐤗𐤕𐤐𐤚𐤌𐤉
$
Ja edellisten koodi:
} else if(!strcmp("--pho", argv[c])) { // phoenician alphabet, (fi "foinikialaiset aakkoset")
//phoenician: 𐤀𐤁𐤂𐤃𐤄𐤅𐤆𐤇𐤈𐤉𐤊𐤋𐤌𐤍𐤎𐤏𐤐𐤑𐤒𐤓𐤔𐤕𐤖𐤗𐤘𐤙𐤚𐤛𐤟𐤠𐤡𐤢𐤣𐤤𐤥𐤦𐤧𐤨𐤩𐤪𐤫𐤬𐤭𐤮𐤯
digits = "𐤀𐤁𐤂𐤃𐤄𐤅𐤆𐤇𐤈𐤉𐤊𐤋𐤌𐤍𐤎𐤏𐤐𐤑𐤒𐤓𐤔𐤕𐤖𐤗𐤘𐤙𐤚𐤛";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--som", argv[c]) ||
Lisätty –depth kytkin, jolla voi määritellä copy reversen syvyyden. Lisäsin kytkimen, jotta voidaan kokeilla uuden copy-reverse funktion toimintaa. Tämän testailun mahdollistamiseksi on lisätty myös debukki DEBUG2F
Seuraavassa DEBUG2F:n tulostamaa listaa –depth0 kytkimellä: –depth0 vastaa tilannetta, jossa ei käytetä copy-reverseä. Tässä debukissa kello kiertää koko ajan väliä 0-255 koko ajan.
101728 70707070 70707071 71717171 71717171 71727272 72727272 72727373 73737373
101760 73737374 74747474 74747474 75757575 75757575 75767676 76767676 76767677
101792 77777777 77777778 78787878 78787878 78797979 79797979 79797a7a 7a7a7a7a
101824 7a7a7b7b 7b7b7b7b 7b7b7b7b 7c7c7c7c 7c7c7c7c 7c7d7d7d 7d7d7d7d 7d7d7e7e
101856 7e7e7e7e 7e7e7e7f 7f7f7f7f 7f7f7f7f 80808080 80808080 80818181 81818181
101888 81818282 82828282 82828283 83838383 83838383 83848484 84848484 84848585
101920 85858585 85858586 86868686 86868686 87878787 87878787 87878888 88888888
101952 88888989 89898989 89898989 8a8a8a8a 8a8a8a8a 8a8b8b8b 8b8b8b8b 8b8b8b8c
101984 8c8c8c8c 8c8c8c8d 8d8d8d8d 8d8d8d8d 8d8e8e8e 8e8e8e8e 8e8e8f8f 8f8f8f8f
102016 8f8f8f90 90909090 90909090 91919191 91919191 91919292 92929292 92929293
102048 93939393 93939393 94949494 94949494 94959595 95959595 95959696 96969696
102080 96969697 97979797 97979797 97989898 98989898 98989999 99999999 99999999
102112 9a9a9a9a 9a9a9a9a 9b9b9b9b 9b9b9b9b 9b9c9c9c 9c9c9c9c 9c9c9c9d 9d9d9d9d
102144 9d9d9d9d 9e9e9e9e 9e9e9e9e 9e9f9f9f 9f9f9f9f 9f9fa0a0 a0a0a0a0 a0a0a0a0
102176 a1a1a1a1 a1a1a1a1 a2a2a2a2 a2a2a2a2 a2a2a3a3 a3a3a3a3 a3a3a3a4 a4a4a4a4
102208 a4a4a4a4 a5a5a5a5 a5a5a5a5 a5a6a6a6 a6a6a6a6 a6a6a7a7 a7a7a7a7 a7a7a7a7
102240 a8a8a8a8 a8a8a8a8 a8a9a9a9 a9a9a9a9 a9a9aaaa aaaaaaaa aaaaaaaa abababab
102272 abababab acacacac acacacac acacadad adadadad adadadae aeaeaeae aeaeaeae
102304 aeafafaf afafafaf afb0b0b0 b0b0b0b0 b0b0b0b1 b1b1b1b1 b1b1b1b1 b2b2b2b2
102336 b2b2b2b2 b2b3b3b3 b3b3b3b3 b3b3b3b4 b4b4b4b4 b4b4b4b4 b5b5b5b5 b5b5b5b5
102368 b5b6b6b6 b6b6b6b6 b6b6b7b7 b7b7b7b7 b7b7b7b7 b8b8b8b8 b8b8b8b8 b8b9b9b9
102400 c7c7c8c8 c8c8c8c8 c8c8c8c9 c9c9c9c9 c9c9c9c9 c9cacaca cacacaca cacacbcb
102432 cbcbcbcb cbcbcbcc cccccccc cccccccc cdcdcdcd cdcdcdcd cdcdcece cececece
102464 cececfcf cfcfcfcf cfcfcfcf d0d0d0d0 d0d0d0d0 d0d1d1d1 d1d1d1d1 d1d1d1d2
102496 d2d2d2d2 d2d2d2d3 d3d3d3d3 d3d3d3d3 d3d4d4d4 d4d4d4d4 d4d4d5d5 d5d5d5d5
102528 d5d5d5d6 d6d6d6d6 d6d6d6d6 d7d7d7d7 d7d7d7d7 d7d7d8d8 d8d8d8d8 d8d8d8d9
102560 d9d9d9d9 d9d9d9d9 dadadada dadadada dadbdbdb dbdbdbdb dbdbdbdc dcdcdcdc
102592 dcdcdcdd dddddddd dddddddd dddedede dededede dededfdf dfdfdfdf dfdfdfdf
–depth1 vastaa edellistä versiota copy-reversestä, siinä copy ja reverse lohkot seuraavat toisiaan, ensin kellojonon luvut kasvavat lohkon ja seuraavaksi ne vähenevät lohkon:
26144 4e4e4e4e 4e4e4e4e 4e4e4e4e 4e4e4e4e 4e4e4f4f 4f4f4f4f 4f4f4f4f 4f4f4f4f
26176 4f4f4f4f 4f4f6968 68686868 68686868 68686868 68686868 68686868 68686868
26208 68686868 68676767 67676767 67676767 67676767 67676767 67676767 67676f6f
26240 6f6f6f6f 6f6f6f6f 6f6f6f6f 6f6f6f6f 6f6f6f6f 6f6f7070 70707070 70707070
26272 70707070 70707070 70707070 70707070 70707071 71717171 71717171 71717171
26304 71717171 71717171 71717171 71717171 71727272 72727272 72727272 72727272
26336 72727272 72727272 72727272 72727273 73737373 73737373 73737373 73737373
26368 73737373 73737373 73888888 88888888 88888888 88888888 88888888 88888888
26400 88888888 88888887 87878787 87878787 87878787 87878787 87878787 87878787
26432 87878787 86868686 86868686 86868686 86868686 86868686 86868686 86868686
26464 86868585 85858585 85858585 85858585 85858585 85858585 85858585 85858585
26496 84848484 84848484 84848484 84848484 84848484 84848484 84848484 84838383
26528 83838383 83838383 83838383 83838383 83838383 83838383 83838382 82828282
26560 82828282 82828282 82828282 82828282 82828282 8282a1a1 a1a1a1a1 a1a1a1a1
26592 a1a1a1a1 a1a1a1a1 a1a1a1a1 a1a1a1a1 a1a2a2a2 a2a2a2a2 a2a2a2a2 a2a2a2a2
26624 a2a2a2a2 a2a2a2a2 a2a2a2a2 a2a2a2a3 a3a3a3a3 a3a3a3a3 a3a3a3a3 a3a3a3a3
26656 a3a3a3a3 a3a3a3a3 a3a3a3a3 a3a4a4a4 a4a4a4a4 a4a4a4a4 a4a4a4a4 a4a4a4a4
26688 a4a4a4a4 a4a4a4a4 a4a4a5a5 a5a5a5a5 a5a5a5a5 a5a5a5a5 a5a5a5a5 a5a5a5a5
26720 a5a5a5a5 a5a5a5a5 a6a6a6a6 a6a6a6a6 a6a6a6a6 a6a6a6a6 a6a6a6a6 a6d4d4d4
26752 d3d3d3d3 d3d3d3d3 d3d3d3d3 d3d3d3d3 d3d3d3d3 d3d3d3d3 d3d3d3d3 d3d2d2d2
26784 d2d2d2d2 d2d2d2d2 d2d2d2d2 d2d2d2d2 d2d2d2d2 d2d2d2d2 d2d2d2d1 d1d1d1d1
26816 d1d1d1d1 d1d1d1d1 d1d1d1d1 d1d1d1d1 d1d1d1d1 d1d1d1d1 d1d0d0d0 d0d0d0d0
26848 d0d0d0d0 d0d0d0d0 d0d0d0d0 d0d0d0d0 d0d0d0d0 d0d0cfe0 e0e0e0e0 e0e0e1e1
26880 e1e1e1e1 e1e1e1e1 e1e1e1e1 e1e1e1e1 e1e1e1e1 e1e1e1e1 e1e1e1e1 e2e2e2e2
26912 e2e2e2e2 e2e2e2e2 e2e2e2e2 e2e2e2e2 e2e2e2e2 e2e2e2e2 e2e3e3e3 e3e3e3e3
26944 e3e3e3e3 e3e3e3e3 e3e3e3e3 e3e3e3e3 e3e3e3e3 e3e3e3e4 e4e4e4e4 e4e4e4e4
26976 e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e4e4e4 e4e5e5e5 e5f7f7f7 f7f7f7f7
27008 f7f7f7f7 f7f7f7f7 f7f7f7f7 f6f6f6f6 f6f6f6f6 f6f6f6f6 f6f6f6f6 f6f6f6f6
27040 f6f6f6f6 f6f6f6f6 f6f6f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5
27072 f5f5f5f5 f5f5f5f4 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f4f4f4
27104 f4f4f4f4 f4f3f3f3 f3f3f3f3 f3f3f3f3 f3f3f3f3 f3f3f3f3 f3f3f3f3 f3f3f3f3
27136 f3f3f3f2 f2f2f2f2 f2f2f2f2 f2f2f2f2 f2f2f207 07070707 07070707 07070707
27168 07070707 07070708 08080808 08080808 08080808 08080808 08080808 08080808
27200 08080808 08090909 09090909 09090909 09090909 09090909 09090909 09090909
27232 0909090a 0a141414 14141515 15151515 15151515 15151616 16161616 16161616
Vielä copy-reverse debukkilista –depth4 kytkimellä: tämä versio on “voimassa” oletuksena, ja se monimutkaistaa eri copy-reverse lohkojen järjestystä entisestään:
12096 e1e1e1e1 e1e1e1e1 e0e0dfdf dfdfdfdf dfdfdfdf dfdfdfdf dfdfdfdf dfdfdfdf
12128 dfdfdfdf dfdfdfdf dfdedede dededede dededede dededede dededede dededede
12160 dededede dedede92 92929292 92919191 91919191 91919191 91919191 91919191
12192 91919191 91919191 91919191 90909090 90909090 909090b7 b7b7b7b7 b7b7b7b7
12224 b7b7b7b7 b7b7b7b7 b7b7b7b7 b7b7b7b7 b7b7b7b7 b7b6b6b6 b6e2e2e2 e2e3e3e3
12256 e3e3e3e3 e3e3e3e3 e3e3e3e3 e3e3e3e3 e3e3fcfc fcfcfbfb fbfbfbfb fbfbfbfb
12288 fbfbfbfb fbfbfbfb fbfbfbfb fbfbfbfb fbfbfbfb fbf6f6f6 f6f6f6f6 f6f6f6f6
12320 f6f6f6f6 f6f6f6f6 f6f5f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5 f5f5f5f5
12352 f5f5f5f5 f5f5f5f5 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f4f4f4 f4f41818
12384 19191919 19191919 19191919 19191919 19191919 19191919 19191919 1919191a
12416 1a1a1a1a 1a1a1a1a f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f9fa fafafafa fafafafa
12448 fafafafa fafafafa 1c1c1c1c 1c1c1b1b 1b1b1b1b 1b1b1b1b 1b1b1b1b 1b1b1b1b
12480 1b1b1b1b 1b1b1b1b 1b1b1b1b 1b1a1a1a 1a1a1a1a 1a1a1a1a 1a1a1a1a 1a1a1a1a
12512 1a1a1af9 f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f9f8 f8f8f8f8 f8f8f8f8 f8f8f8f8
12544 f8f8f8f8 f8f8f8f8 f8f8f8f8 f8f8f8f8 f8f8f7f7 f7f7f7f7 f7f7f7f7 f7f7f7f7
12576 f7f7f7f7 f7f7f7f7 f7f7f7f7 f7f7f7f7 f7f6f6f6 f6f6f6f6 f6f6f6f6 fafafafa
12608 fafafafa fafafafa fafa1c1c 1c1c1c1c 1c1c1c1c 1c1c1c1f 1f1f1f1f 1f1f1f1f
12640 1f1f1f1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e 1e1e1e1e
12672 1e1e1d1d 1d1d1d1d 1d1d1d1d 1d1d1d1d 1d1d1d1d 1d1d1d1d 1d1d1d1d 1d1d1d1d
12704 1c1c1c1c 1c1c1c1c 1c1c1c1c 1f1f1f1f 1f1f1f4a 4a4a4a4a 4a4a4a4a 4a4a4a4a
12736 4a4a4a4a 4a4a4a4a 49494949 49494949 49494949 49494949 49494949 49494949
12768 49636363 63636363 63646464 64646464 64646464 64646464 64646464 64646464
12800 64646464 64646464 65656565 65656565 65656565 65656565 656b6b49 49496363
12832 63636363 63636363 63636363 63636363 63636363 63626262 62626262 62626262
12864 62626262 62626262 62626262 62626262 62626262 48484848 48494949 6b6b6a6a
12896 6a6a6a6a 6a6a6a6a 6a6a6a6a 6a6a6a6a 6a6a6a6a 6a6a6a6a 6a6a6a6a 6a696969
12928 70707070 70707070 70707070 70707070 70707070 70707070 70707171 71717171
12960 71717171 71717171 71717171 71717171 71717171 71717171 71727272 72727272
12992 72727272 72727272 72727272 72727272 72727272 72727272 73737373 6f6f6f6f
13024 6f6f6f6f 6f6f6f6f 6f6f6f6f 6f6f6f6e 6e6e6e67 67676767 67676767 67676767
13056 6767676e 67676767 67676768 68686868 68686868 68686868 68686868 68686868
13088 68686868 68686868 68686969 69696969 69696969 69696969 69696969 69696969
13120 69696969 69697070 7070706f 6f6f6f6f 6f6f6f6f 6f6f6f73 73737373 73737373
13152 73737373 73737373 73737373 73737373 73737474 74747474 74747474 74747474
13184 7474b0b0 b0b0b0b0 b0b0b0b0 b0b0b0b0 b0b0b0b0 b0afafaf afafafaf afafafaf
13216 afafafaf afafafaf afafafac acacacac acacacac acacacac acacacac acacacac
13248 acacacac acacacac acacabab abababb4 b4b4b4b4 b4b4b4b4 b4b4b4b4 b4b4b4b4
13280 b4b4b4b4 b5afafaf afafafaf afafadad adadadad adadadad adadadad adadadad
13312 adadadad adadadad adadadad adaeaeae aededede dededede dededede dededede
13344 dedededf dfdfdfdf dfdfdfdf b8b8b8b8 b8b8b8b8 b8b8b8b8 b8b8b8b8 b8b8b8b8
13376 b8b8b8b8 b8b8b8b8 b8b8b8b7 b7b7b7b7 b7b7b7b7 b7b7b7b7 b7b7b7b7 b7b7b7b7
13408 b7b7b7b7 b7b7b7b7 b7b7b6b6 b6b6b6b6 b6b6b6b6 b6b6b6b6 b6b6b6b6 b6b6b6b6
13440 b6b6b6b6 b6b6b6b6 b6b5b5b5 b5b5b5b5 b5b5b5b5 b5b5b5b5 b5b5b5b5 b5b5b5b5
13472 b5b5b5b5 b5b5f9f9 02020202 02020202 02020202 020202fa fafafafa fafafafa
13504 f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f9f9 f9f9f902 02020202
13536 02020202 02020202 01010101 01010101 01010101 01010101 010101dd dddddddd
Vielä uudestaan copy-reverse:n koodi:
#define MAX_DEPTH 4 // now 4
int depth = 4; // now 4
unsigned int copyreverse = 1;
unsigned long cblocks = 0;
unsigned char lens = 4;
static unsigned char ressu_copyreverse(int pdepth) // 2024 JariK
{
static int reverse[MAX_DEPTH] = {0}; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned int len[MAX_DEPTH] = {0};
static unsigned int count[MAX_DEPTH] = {0};
static unsigned int low[MAX_DEPTH] = {0};
static unsigned int high[MAX_DEPTH] = {0};
static unsigned char bytes[MAX_DEPTH][257] = {0};
if(pdepth == 0) {
#ifdef DEBUG2D
int c = ressu_clock();
//fprintf(stdout,", ch2:%02x",c);
return(c);
#else
return(ressu_clock());
#endif
}
pdepth--;
// dividing clock stream into blocks
// and reversing every other block
// copy next block to bytes
if(count[pdepth] == 0) { // previous block ended
reverse[pdepth] = !reverse[pdepth];
len[pdepth] = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
//len[pdepth] = (ressuct[ressu_nonrandom() % ressuct_bytes] & 3 ) + 2; // block size
//len[pdepth] = --lens + 2; // block size
//len[pdepth] = lens++ + 2; // block size
count[pdepth] = len[pdepth];
low[pdepth] = 0;
high[pdepth] = len[pdepth];
rndbits2 += 2;
#ifdef DEBUG2A
fprintf(stdout,"\nblk:");
fprintf(stdout," depth:%d", pdepth);
fprintf(stdout,", reverse:%d", reverse[pdepth]);
fprintf(stdout,", len:%d", len[pdepth]);
fprintf(stdout,", count:%d", count[pdepth]);
fprintf(stdout,", low:%d", low[pdepth]);
fprintf(stdout,", high:%d", high[pdepth]);
fflush(stdout);
#endif
for(int c = 0; c < len[pdepth]; c++) {
bytes[pdepth][c] = ressu_copyreverse(pdepth); // block bytes
#ifdef DEBUG2A
fprintf(stdout,", b%d:%02x", pdepth, bytes[pdepth][c]);
newressu_output = 1;
#endif
}
}
if(reverse[pdepth]) { // reverse
// get reversed byte to return
ch = bytes[pdepth][--high[pdepth]]; // reverse
#ifdef DEBUG2E
fprintf(stdout,", rev%d:%02x", pdepth, ch);
fflush(stdout);
#endif
--count[pdepth];
} else { // copy
// get copied byte to return
ch = bytes[pdepth][low[pdepth]++]; // copy
#ifdef DEBUG2E
fprintf(stdout,", copy%d:%02x", pdepth, ch);
fflush(stdout);
#endif
--count[pdepth];
}
return(ch);
}
....
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
if(copyreverse) {
ch = ressu_copyreverse(depth);
} else {
ch = ressu_clock();
} // end of if(copyreverse)
#ifdef DEBUG2F
static unsigned int cols = 0;
if(cols % 32 == 0) {
if(cols > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05u ",cols);
newressu_output = 1;
}
if(cols % 4 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x",ch);
newressu_output = 1;
cols++;
#endif
// statistics for theoretical
// random bits calculation (rndbits?)
static int prevbyte = -1, clockcount = 0;
if(prevbyte == -1)
prevbyte = ch;
if(prevbyte != ch) {
periods[clockcount]++;
clockbytes += clockcount;
#ifdef DEBUG2B
fprintf(stdout," %d", clockcount);
newressu_output = 1;
#endif
if((ch & 1) != (prevbyte & 1))
rndbits20++;
if((ch & 2) != (prevbyte & 2))
rndbits21++;
if((ch & 4) != (prevbyte & 4))
rndbits22++;
clockcount = 0;
prevbyte = ch;
}
clockcount++;
return(ch);
}
....
} else if(!strncmp("--depth", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
depth = atoi(argv[c] + 7);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
depth = atoi(argv[c + 1]);
c++;
} else {
depth = MAX_DEPTH;
}
if(depth < 0 || depth > MAX_DEPTH) {
fprintf(stderr,"%s: --depth must be between 0 and %d(MAX_DEPTH)\n",
procname, MAX_DEPTH);
exit(2);
}
fprintf(stderr,"depth:%d\n", depth);
} else if(!strcmp("--copyreverse", argv[c])) {
....
Vielä loppukevennykseksi uusi ressun satunnaisuutta käyttävä ohjelma, joka etsii sudokuja (newressusudoku).
Seuraavassa haetaan yksi sudoku:
$ ./newressusudoku
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 | |
B | 4 | 6 | 5 |
C | 9 | 5 | |
+-----------+-----------+-----------+
D | 9 8 | | 1 2 |
E | 7 5 | 1 2 8 | |
F | 3 | 4 | |
+-----------+-----------+-----------+
G | 5 | 2 | 7 9 |
H | 6 | 8 | 5 4 |
I | | 6 | 8 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:4 digits:27
$
Sudokuja on niin paljon erilaisia, että kaikkien tulostettujen sudokujen pitäisi olla ainutlaatuisia. Ohjelman ei pitäisi tulostaa samaa sudokua kahta kertaa. Tätä on omalta osaltaan takaamassa pseudoressu, jolta newressusudoku hakee satunnaisbittinsä (sudoku_make()).
Sudokun ulkomuotoon voi vaikuttaa –board -kytkimellä. –board:iin voi lisätä numeron, jolla valitaan miltä sudoku näyttää. Ensimmäisenä –board1, joka on oletusarvo: Tämä on sopiva muoto sudokun tulostukseen paperille ja ratkaistavaksi kynällä. Voit muotoilla sudokut tekstinkäsittelyllä esimerkiksi neljään sarakkeeseen, joissa on kolme sudokua, tai muuhun muotoon. Eniten merkintöjä paperille mahtuu kun tulostat nämä 1 sudoku / a4 lomake. Seuraavassa erilaiset –board kytkimet ja niiden tulosteet: –board0 kytkimellä voit jättää tehtäväruudukon tulostamatta. Ilman –board:in jälkeistä numeroa kytkin vaihdetaan vastakkaiseksi (0=false, 1/muu=true).
Ratkaisun tulostusmuotoon voi vaikuttaa –solution -kytkimellä, joka toimii samalla tavoin kun –board kytkin.
$ ./newressusudoku --board1
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 5 | 8 | 2 |
B | 7 | 1 | 3 |
C | 9 4 | | |
+-----------+-----------+-----------+
D | 3 | 2 | |
E | | 9 6 | 1 4 |
F | 8 | 1 | 9 |
+-----------+-----------+-----------+
G | 6 | 5 | 8 2 |
H | 7 | | 5 |
I | 1 | 6 | 9 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:4 digits:27
$
–board2 tulostaa seuraavanlaisen listan nämä pienemmät peliruudukot ovat hyviä ratkaisun tulostukseen:
$ ./newressusudoku --board2
ABC DEF GHI
+---+---+---+
A|2 |3 |9 8|
B| 5| | 2|
C| |7 | |
+---+---+---+
D| |9 4| 5 |
E|6 | | 8 |
F|5 | 31| 64|
+---+---+---+
G|36 | 5 | 2 |
H|45 | 7|8 |
I|12 | | |
+---+---+---+
s:0 steps:0 rounds:5 digits:27
$
Jatkossa loput –board tulosteet
$ ./newressusudoku --board3
ABCDEFGHI
+---------+
A| 3 9 2|
B|769 23 |
C| 71 9|
D|4 1 8 |
E| 8 4 |
F|1 7 |
G| 25 8 1|
H| 136 |
I| 5 6 |
+---------+
s:0 steps:0 rounds:4 digits:27
$
$ ./newressusudoku --board4
ABCDEFGHI
+---------
A| 7 3
B| 6 47
C|4 12
D|3 4 7
E|8 59 1 6
F|5 8
G|9 8 2
H|12 7 4
I| 51
s:0 steps:0 rounds:3 digits:27
$ ./newressusudoku --board5
ABCDEFGHI
A 1 43
B3 6 5918
C95 7
D6 8 7
E 8 3
F4 8 2
G23 9
H
I7 2 6 1
s:0 steps:0 rounds:6 digits:27
$ ./newressusudoku --board6
1
38
4 5 3
72 1
9 6 58
76 4 2
39
7 3 81
3 2 64
s:0 steps:0 rounds:5 digits:27
$
$ ./newressusudoku --board10
AA8 AB1456 AC4569 AD7 AE369 AF36 AG2 AH56 AI3456
BA24569 BB4567 BC245679 BD249 BE2369 BF8 BG1 BH56 BI3456
CA246 CB3 CC246 CD1 CE26 CF5 CG468 CH7 CI9
DA26 DB9 DC2678 DD28 DE5 DF4 DG678 DH3 DI12678
EA23456 EB4567 EC245678 ED289 EE1 EF2367 EG46789 EH2689 EI24678
FA2346 FB467 FC1 FD289 FE236789 FF2367 FG5 FH2689 FI24678
GA7 GB1456 GC4569 GD258 GE28 GF12 GG3 GH125689 GI12568
HA159 HB2 HC3 HD6 HE78 HF17 HG789 HH4 HI1578
IA156 IB8 IC56 ID3 IE4 IF9 IG67 IH1256 II12567
s:0 steps:0 rounds:5 digits:27
$ ./newressusudoku --board11
392 8 29 5 1 85 27 5 1 9 62 814 1 7 3 76 8 7
s:0 steps:0 rounds:4 digits:27
$ ./newressusudoku --board20
'AC' = "6", 'AD' = "8", 'AE' = "2", 'AH' = "5", 'BB' = "5", 'BG' = "8", 'BH' = "9", 'CD' = "1", 'CG' = "3", 'CH' = "7", 'DC' = "5", 'DE' = "6", 'DI' = "9", 'EB' = "8", 'EC' = "3", 'EF' = "1", 'FA' = "2", 'FC' = "4", 'FI' = "3", 'GB' = "6", 'GD' = "3", 'GI' = "7", 'HA' = "1", 'HC' = "2", 'HG' = "5", 'IA' = "9", 'IH' = "2"
s:0 steps:0 rounds:3 digits:27
$ ./newressusudoku --board21
'AA' = "4589", 'AB' = "6", 'AC' = "28", 'AD' = "2489", 'AE' = "48", 'AF' = "1", 'AG' = "47", 'AH' = "2347", 'AI' = "2457", 'BA' = "7", 'BB' = "128", 'BC' = "3", 'BD' = "248", 'BE' = "5", 'BF' = "2468", 'BG' = "146", 'BH' = "9", 'BI' = "1246", 'CA' = "1459", 'CB' = "1259", 'CC' = "12", 'CD' = "3", 'CE' = "46", 'CF' = "7", 'CG' = "146", 'CH' = "8", 'CI' = "12456", 'DA' = "189", 'DB' = "1789", 'DC' = "4", 'DD' = "1578", 'DE' = "2", 'DF' = "58", 'DG' = "1789", 'DH' = "6", 'DI' = "3", 'EA' = "2", 'EB' = "1378", 'EC' = "18", 'ED' = "6", 'EE' = "9", 'EF' = "348", 'EG' = "5", 'EH' = "147", 'EI' = "1478", 'FA' = "6", 'FB' = "13789", 'FC' = "5", 'FD' = "1478", 'FE' = "1348", 'FF' = "348", 'FG' = "2", 'FH' = "147", 'FI' = "14789", 'GA' = "1358", 'GB' = "12358", 'GC' = "1268", 'GD' = "12458", 'GE' = "7", 'GF' = "9", 'GG' = "1468", 'GH' = "124", 'GI' = "12468", 'HA' = "1358", 'HB' = "12358", 'HC' = "9", 'HD' = "12458", 'HE' = "13468", 'HF' = "234568", 'HG' = "14678", 'HH' = "1247", 'HI' = "124678", 'IA' = "18", 'IB' = "4", 'IC' = "7", 'ID' = "128", 'IE' = "168", 'IF' = "268", 'IG' = "3", 'IH' = "5", 'II' = "12689"
s:0 steps:0 rounds:5 digits:27
$
–board20 ja –board21 ovat terttu muodossa, että sitäkin tulee ajateltua.
Jos haluat ratkaisun tulosteen käytä –solution -kytkintä:
$ ./newressusudoku --solution
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 9 | 5 2 | |
B | | 8 | |
C | 2 4 | | 6 |
+-----------+-----------+-----------+
D | 5 | 1 | |
E | 1 | | 3 |
F | | 5 4 7 | 8 2 |
+-----------+-----------+-----------+
G | | 7 9 | 3 |
H | 7 | 4 3 | 5 |
I | 8 | 2 | 7 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:5 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 3 9 | 6 5 2 | 1 7 4 |
B | 6 1 7 | 3 8 4 | 2 5 9 |
C | 2 5 4 | 7 9 1 | 3 6 8 |
+-----------+-----------+-----------+
D | 4 2 5 | 1 3 8 | 7 9 6 |
E | 1 7 8 | 9 2 6 | 4 3 5 |
F | 9 6 3 | 5 4 7 | 8 1 2 |
+-----------+-----------+-----------+
G | 5 4 1 | 8 7 9 | 6 2 3 |
H | 7 9 2 | 4 6 3 | 5 8 1 |
I | 3 8 6 | 2 1 5 | 9 4 7 |
+-----------+-----------+-----------+
s:0
$
Seuraavassa neljä aloittelijalle sopivaa sudokua:
$ ./newressusudoku --easy45 --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 8 3 | 2 7 |
B | 9 2 | 4 | 1 |
C | 8 3 5 | 7 2 1 | 4 6 9 |
+-----------+-----------+-----------+
D | 4 7 | 5 9 | 1 |
E | 8 | 6 | 5 |
F | 1 6 | 7 | |
+-----------+-----------+-----------+
G | 8 | | 1 9 5 |
H | 6 | 8 5 | 3 7 |
I | 5 3 | 7 9 | 6 8 2 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:2 digits:45
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 7 | 3 9 | 4 |
B | 6 | 1 | 9 2 5 |
C | | 5 | 3 |
+-----------+-----------+-----------+
D | 8 | 6 | 5 1 2 |
E | 7 | 9 | 8 |
F | 4 2 1 | | 7 6 |
+-----------+-----------+-----------+
G | | 1 4 5 | 7 9 |
H | 6 | 8 9 3 | 2 5 1 |
I | 9 5 | 2 6 7 | 3 4 8 |
+-----------+-----------+-----------+
s:1 steps:0 rounds:3 digits:45
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 7 | 4 |
B | 3 1 7 | 2 5 4 | 8 9 |
C | 5 6 | 9 | 3 7 |
+-----------+-----------+-----------+
D | 7 3 | 1 6 | 9 |
E | 1 9 | 8 3 | 7 4 6 |
F | | 2 | 8 1 |
+-----------+-----------+-----------+
G | 9 | | 6 3 |
H | 2 | 3 5 | 7 |
I | 4 3 5 | 6 9 | 1 8 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:2 digits:45
A B C D E F G H I
+-----------+-----------+-----------+
A | | 8 7 | 6 2 |
B | 5 7 | 1 6 | 8 |
C | 2 8 6 | 4 9 | 3 |
+-----------+-----------+-----------+
D | | 3 | 6 |
E | 9 7 | | 1 8 |
F | 2 1 | 5 | 9 3 4 |
+-----------+-----------+-----------+
G | 3 6 5 | 8 4 | 7 2 1 |
H | 7 9 4 | 5 1 | 6 |
I | 8 2 | 6 | 9 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:2 digits:45
$
Hiukan vaikeampia 33:n vihjeen sudokuja:
$ ./newressusudoku --digits33 --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | 1 9 | 4 |
B | 2 6 | 5 | |
C | | 7 | 8 6 |
+-----------+-----------+-----------+
D | 1 | 5 | 2 |
E | 3 | | |
F | 8 | 4 | 6 5 |
+-----------+-----------+-----------+
G | 8 | 5 7 | 9 |
H | 7 9 2 | 3 4 | 5 8 |
I | 4 5 | 8 | 1 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:3 digits:33
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | 3 | 9 1 2 |
B | | 1 9 | 6 |
C | 1 | 6 | 8 7 |
+-----------+-----------+-----------+
D | 4 | 6 9 5 | |
E | 9 8 2 | 1 3 | |
F | | 8 | |
+-----------+-----------+-----------+
G | 7 | 2 | 1 |
H | 3 | 6 1 | 8 5 |
I | 6 | 7 5 | |
+-----------+-----------+-----------+
s:1 steps:0 rounds:4 digits:33
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 5 2 | 7 8 | |
B | | 2 | |
C | | 4 3 | 5 |
+-----------+-----------+-----------+
D | 6 7 | 9 | 8 |
E | 1 9 | 3 | 4 6 |
F | 3 4 | 6 | |
+-----------+-----------+-----------+
G | 5 | 8 | 3 |
H | 9 | 3 7 | 5 1 |
I | 8 3 | | 9 2 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:3 digits:33
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 | | 4 1 |
B | 1 3 | 4 2 | 9 8 |
C | 8 | 6 9 | 5 |
+-----------+-----------+-----------+
D | 8 | 2 | |
E | 4 | 5 9 3 | 2 8 |
F | 3 | | 6 |
+-----------+-----------+-----------+
G | | | 7 |
H | 1 | 9 | 5 4 |
I | 2 | 8 3 4 | 9 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:3 digits:33
$
27 vihjeisiä helppoja sudokuja:
A B C D E F G H I
+-----------+-----------+-----------+
A | | | 5 9 |
B | 7 | | 3 |
C | 4 | 9 8 | 2 |
+-----------+-----------+-----------+
D | | 1 2 | 7 3 5 |
E | 3 | | 2 4 |
F | 6 | 4 3 | |
+-----------+-----------+-----------+
G | | | 1 |
H | 5 8 | 7 | |
I | 4 | 5 | 2 3 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:4 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | 9 | 6 4 |
B | 2 6 | 3 7 | 1 |
C | 7 5 | | |
+-----------+-----------+-----------+
D | 6 | 3 | 8 9 |
E | | | |
F | 7 | 8 | 2 5 |
+-----------+-----------+-----------+
G | | 4 | 2 |
H | | 8 5 | 4 |
I | 8 | 1 7 | |
+-----------+-----------+-----------+
s:1 steps:0 rounds:6 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 6 | 2 |
B | 5 4 | 1 | 6 |
C | 1 | 2 | 5 |
+-----------+-----------+-----------+
D | | 3 7 5 | |
E | | | |
F | 7 4 | 9 2 | |
+-----------+-----------+-----------+
G | 6 | | 5 4 3 |
H | | 7 | 8 9 |
I | 3 | 6 8 | |
+-----------+-----------+-----------+
s:2 steps:0 rounds:4 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | | |
B | 7 | 1 | 5 |
C | 4 | 8 6 | 1 3 |
+-----------+-----------+-----------+
D | 6 | 9 | 2 |
E | 9 8 | | |
F | 4 5 | 3 | 8 |
+-----------+-----------+-----------+
G | | 8 2 | 3 |
H | 3 4 | 5 | 9 8 |
I | | | 7 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:5 digits:27
$
Ja tässä 23 vihjeisiä helppoja sudokuja:
$ ./newressusudoku --digits23 --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 6 8 | |
B | | 4 | 9 3 5 |
C | 9 | 2 | |
+-----------+-----------+-----------+
D | 1 | | 3 |
E | 6 | 9 | 5 2 |
F | | 7 | |
+-----------+-----------+-----------+
G | | | 6 |
H | 4 | | 7 5 |
I | 2 | | 8 9 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:7 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | | 7 |
B | | 2 | 8 |
C | 3 | 4 9 | |
+-----------+-----------+-----------+
D | 4 | 9 3 | |
E | 6 | | 1 4 |
F | 8 | 5 | |
+-----------+-----------+-----------+
G | | 6 4 | 9 5 |
H | 9 | 7 | |
I | 3 | | 6 |
+-----------+-----------+-----------+
s:1 steps:0 rounds:4 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 2 | |
B | 1 | 6 | 2 |
C | 5 | | 1 |
+-----------+-----------+-----------+
D | 3 | 1 | |
E | 4 | 2 | 7 |
F | 9 | 3 8 | |
+-----------+-----------+-----------+
G | 2 | 8 | 4 |
H | 8 5 | 7 | 9 |
I | | | 5 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:6 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | | |
B | 9 | 7 6 | 3 |
C | | 3 | 6 |
+-----------+-----------+-----------+
D | 4 1 | 2 8 | |
E | 6 | | 9 |
F | 2 | | 5 |
+-----------+-----------+-----------+
G | | 1 | 8 |
H | | 5 | 7 1 2 |
I | 5 | 3 | |
+-----------+-----------+-----------+
s:3 steps:0 rounds:6 digits:23
$
Jos haluat näitä kauttaviiva (slashes) sudokuja:
$ ./newressusudoku --slashes --digits27
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 | 1 | 8 |
B | 9 | 4 | 3 |
C | 1 | 7 | 5 |
+-----------+-----------+-----------+
D | 1 | 8 | 4 |
E | 6 | 2 | 7 |
F | 7 | 3 | 6 |
+-----------+-----------+-----------+
G | 3 | 7 | 5 |
H | 8 | 5 | 9 |
I | 9 | 8 | 3 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:5 digits:27
$
Kauttaviivasudokut voidaan sekoittaa (mix()) siten että kuitenkin rivit sarakkeet ja blokit säilyvät samanlaisina:
$ ./newressusudoku --slashes --mix --digits27
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | 1 | 5 |
B | 5 | 6 | 2 |
C | 7 | 5 | 1 |
+-----------+-----------+-----------+
D | 7 | 5 | 9 |
E | 5 | 4 | 8 |
F | 2 | 8 | 1 |
+-----------+-----------+-----------+
G | 8 | 7 | 4 |
H | 9 | 6 | 2 |
I | 3 | 4 | 7 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:4 digits:27
$
Seuraavassa kauttaviivasudoku ja sen sekoitettu versio, joista huomataan että rivit, sarakkeet ja laatikot pysyvät samoina:
$ ./newressusudoku --slashes --mix --verbose --digits27
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 6 | 4 |
B | 8 | 2 | 3 |
C | 7 | 8 | 5 |
+-----------+-----------+-----------+
D | 1 | 5 | 8 |
E | 4 | 8 | 7 |
F | 6 | 3 | 2 |
+-----------+-----------+-----------+
G | 9 | 4 | 3 |
H | 3 | 7 | 2 |
I | 8 | 5 | 4 |
+-----------+-----------+-----------+
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 4 | 6 |
B | 8 | 3 | 2 |
C | 7 | 5 | 8 |
+-----------+-----------+-----------+
D | 8 | 4 | 5 |
E | 9 | 3 | 4 |
F | 3 | 2 | 7 |
+-----------+-----------+-----------+
G | 6 | 2 | 3 |
H | 4 | 7 | 8 |
I | 1 | 8 | 5 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:5 digits:27
$
27 vihjeisiä slashes sudokuja:
$ ./newressusudoku --digits27 --slashes --mix --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 | 8 | 1 |
B | 2 | 3 | 6 |
C | 5 | 2 | 4 |
+-----------+-----------+-----------+
D | 4 | 9 | 7 |
E | 1 | 2 | 4 |
F | 9 | 7 | 6 |
+-----------+-----------+-----------+
G | 8 | 6 | 2 |
H | 4 | 9 | 7 |
I | 7 | 3 | 5 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:5 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | 8 | 6 |
B | 7 | 6 | 9 |
C | 8 | 7 | 1 |
+-----------+-----------+-----------+
D | 8 | 3 | 5 |
E | 2 | 5 | 9 |
F | 1 | 9 | 8 |
+-----------+-----------+-----------+
G | 1 | 3 | 8 |
H | 2 | 1 | 7 |
I | 8 | 4 | 6 |
+-----------+-----------+-----------+
s:1 steps:0 rounds:5 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | 9 | 1 |
B | 2 | 6 | 9 |
C | 3 | 8 | 2 |
+-----------+-----------+-----------+
D | 4 | 3 | 7 |
E | 5 | 7 | 3 |
F | 9 | 5 | 6 |
+-----------+-----------+-----------+
G | 5 | 8 | 2 |
H | 7 | 2 | 4 |
I | 8 | 9 | 3 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:5 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 3 | 7 |
B | 5 | 9 | 4 |
C | 2 | 1 | 9 |
+-----------+-----------+-----------+
D | 7 | 2 | 5 |
E | 1 | 9 | 4 |
F | 5 | 4 | 7 |
+-----------+-----------+-----------+
G | 7 | 5 | 9 |
H | 8 | 6 | 1 |
I | 3 | 9 | 4 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:8 digits:27
$
26 vihjeisiä helppoja slashes sudokuja:
$ ./newressusudoku --digits26 --slashes --mix --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 8 | 3 |
B | 7 | 2 | 1 |
C | 3 | 9 | 5 |
+-----------+-----------+-----------+
D | 9 | 1 | 2 |
E | 5 | 3 | 8 |
F | 4 | 5 | 1 |
+-----------+-----------+-----------+
G | 5 | | 8 |
H | 1 | 7 | 9 |
I | 7 | 6 | 5 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:4 digits:26
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 7 | 2 |
B | 5 | 4 | 8 |
C | 7 | 8 | 6 |
+-----------+-----------+-----------+
D | 9 | 2 | 3 |
E | 1 | 8 | 7 |
F | 3 | 4 | 9 |
+-----------+-----------+-----------+
G | 1 | 6 | 7 |
H | 2 | 3 | 1 |
I | 3 | 1 | |
+-----------+-----------+-----------+
s:1 steps:0 rounds:6 digits:26
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 4 | 1 |
B | 3 | 7 | 5 |
C | 5 | 9 | 8 |
+-----------+-----------+-----------+
D | 6 | 3 | 2 |
E | 9 | 1 | 6 |
F | 5 | 8 | 3 |
+-----------+-----------+-----------+
G | 7 | 8 | 2 |
H | 9 | | 4 |
I | 4 | 2 | 9 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:4 digits:26
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 8 | 1 |
B | 4 | 9 | 2 |
C | 1 | 7 | 9 |
+-----------+-----------+-----------+
D | 5 | 4 | 8 |
E | 8 | 6 | 4 |
F | 3 | 2 | 6 |
+-----------+-----------+-----------+
G | 6 | 4 | 5 |
H | 5 | | 7 |
I | 2 | 1 | 6 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:5 digits:26
$
23 vihjeisiä helppoja slashes sudokuja:
$ ./newressusudoku --digits23 --slashes --mix --sudokues4
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | | 1 |
B | 9 | 8 | 3 |
C | 6 | 4 | 5 |
+-----------+-----------+-----------+
D | 4 | 3 | 6 |
E | 9 | 2 | |
F | 8 | 6 | 2 |
+-----------+-----------+-----------+
G | | 4 | 8 |
H | 5 | | 2 |
I | 7 | 3 | 5 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:6 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 5 | 6 |
B | 1 | | 3 |
C | 4 | 2 | 9 |
+-----------+-----------+-----------+
D | 7 | 6 | 8 |
E | 3 | 1 | 4 |
F | | 3 | 7 |
+-----------+-----------+-----------+
G | 3 | | 9 |
H | 9 | 4 | 5 |
I | 1 | 7 | |
+-----------+-----------+-----------+
s:1 steps:0 rounds:5 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 9 | 2 |
B | 7 | 5 | 6 |
C | 9 | 6 | 5 |
+-----------+-----------+-----------+
D | | 5 | 3 |
E | 8 | 1 | |
F | | | 5 |
+-----------+-----------+-----------+
G | 5 | 4 | 8 |
H | 9 | 2 | 6 |
I | 4 | 7 | 9 |
+-----------+-----------+-----------+
s:2 steps:0 rounds:7 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 3 | 4 |
B | 4 | 2 | 1 |
C | 1 | 6 | 2 |
+-----------+-----------+-----------+
D | | 4 | 7 |
E | 4 | | |
F | 2 | 5 | 6 |
+-----------+-----------+-----------+
G | 6 | 5 | 8 |
H | 9 | 7 | 3 |
I | 5 | | 9 |
+-----------+-----------+-----------+
s:3 steps:0 rounds:5 digits:23
$
Edellä haetut olivat ns helppoja sudokuja, jotka ratkeavat varmasti päättelemällä ruutu ruudulta, teknisesti ne ratkeavat aina simplesolve() menetelmällä. Seuraavassa hakuun käytetään solve() menettelyä: Alarivin muuttujat kertovat taustatietoa sudokusta. S: kenttä kertoo sudokun numeron tässä haussa, rounds: kertoo kuinka monta simple() menetelmän kierrosta tarvitaan sudokun ratkaisussa. steps: kertoo kuinka monta solve():n askelta tarvitaan sudokun raatkaisussa koneellisesti. Edellisesiä voi käyttää sudokun vaikeuden arvioinnissa. Seuraava sudoku on helppo, koska sekä steps ja rounds ovat nollia.
$ ./newressusudoku --solve
A B C D E F G H I
+-----------+-----------+-----------+
A | | 1 6 | 7 5 |
B | | 8 | |
C | 8 9 | 7 | 1 3 |
+-----------+-----------+-----------+
D | | | |
E | 7 | 5 | 2 6 |
F | 8 | 7 | 4 |
+-----------+-----------+-----------+
G | 1 | 8 2 | 7 |
H | 2 | 7 | |
I | 3 | 5 | 9 2 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:0 digits:27
$
Oletan että ohjelman steps arvolla voidaan arvioida sudokun vaikeutta, ja olenkin etsinyt malliksi mielestäni todella vaikeita sudokuja:
A B C D E F G H I
+-----------+-----------+-----------+
A | | | 3 |
B | 1 | 8 | 6 7 |
C | | 5 | |
+-----------+-----------+-----------+
D | 3 9 | 8 | 1 2 |
E | | 5 | 4 |
F | | 6 | |
+-----------+-----------+-----------+
G | 4 | 3 2 | 7 1 |
H | 2 | 1 | 8 |
I | 9 1 | 5 8 | |
+-----------+-----------+-----------+
s:0 steps:638 rounds:0 digits:26
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 2 | 9 | 4 |
B | 4 | 8 | 7 |
C | 8 3 | 2 | |
+-----------+-----------+-----------+
D | 6 | 2 | |
E | 2 | 1 6 | 4 3 5 |
F | | | 7 |
+-----------+-----------+-----------+
G | | 8 | 2 4 |
H | | | 5 3 |
I | | 4 | |
+-----------+-----------+-----------+
s:0 steps:512 rounds:0 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 3 | 5 |
B | 1 | 9 | |
C | 3 9 | 6 | |
+-----------+-----------+-----------+
D | 7 | | 3 |
E | 8 | 7 | 2 |
F | | 1 | 7 6 |
+-----------+-----------+-----------+
G | 3 | 6 | 2 |
H | 6 9 | 3 5 | 8 |
I | | | |
+-----------+-----------+-----------+
s:0 steps:489 rounds:0 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 5 8 | 2 9 |
B | 8 | 2 1 | 6 |
C | 2 | 7 3 | |
+-----------+-----------+-----------+
D | | | |
E | | 4 | 5 |
F | 6 | 2 9 | |
+-----------+-----------+-----------+
G | 2 1 | 3 9 7 | 8 |
H | 7 4 | | 9 |
I | 3 | | 7 |
+-----------+-----------+-----------+
s:0 steps:309 rounds:0 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 | 9 2 | 6 |
B | | 7 | 5 |
C | 6 | 5 | |
+-----------+-----------+-----------+
D | 7 1 | 9 3 | 6 |
E | 4 2 | 6 7 | 3 8 |
F | 6 | 5 | 7 |
+-----------+-----------+-----------+
G | 1 8 | 9 | 2 |
H | 7 | 5 | |
I | | | 9 7 |
+-----------+-----------+-----------+
s:0 steps:178 rounds:0 digits:30
Tässä mielestäni vaikeita slashes sudokuja:
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 6 | 5 |
B | 9 | 2 | |
C | | 5 | 4 |
+-----------+-----------+-----------+
D | 9 | 8 | 1 |
E | 3 | 9 | 4 |
F | | 6 | 9 |
+-----------+-----------+-----------+
G | 1 | 5 | 8 |
H | 8 | 1 | 2 |
I | | 4 | 3 |
+-----------+-----------+-----------+
s:0 steps:413 rounds:0 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | | 8 | |
B | | 1 | 7 |
C | 9 | 7 | 6 |
+-----------+-----------+-----------+
D | 8 | 1 | 3 |
E | 1 | 4 | 2 |
F | 6 | 2 | 1 |
+-----------+-----------+-----------+
G | 3 | 7 | 8 |
H | 6 | 2 | 9 |
I | 2 | 4 | 5 |
+-----------+-----------+-----------+
s:0 steps:553 rounds:0 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 | 5 |
B | 4 | 1 | 2 |
C | 2 | 9 | 4 |
+-----------+-----------+-----------+
D | 5 | 1 | 3 |
E | 8 | 3 | 7 |
F | | 9 | 1 |
+-----------+-----------+-----------+
G | 4 | 5 | 2 |
H | 3 | 4 | 6 |
I | 6 | 8 | 4 |
+-----------+-----------+-----------+
s:0 steps:371 rounds:0 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 1 | 9 |
B | 1 | 9 | 3 |
C | 9 | 4 | 1 |
+-----------+-----------+-----------+
D | 8 | 5 | 6 |
E | 7 | 1 | |
F | 9 | 8 | 2 |
+-----------+-----------+-----------+
G | 6 | 2 | 1 |
H | 4 | 1 | 3 |
I | 9 | 5 | 8 |
+-----------+-----------+-----------+
s:0 steps:197 rounds:0 digits:26
Oikeasti vaikeita sudokuja (muutettu steps: koodia), näissä on 24 vihjettä:
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 5 | 9 1 4 |
B | | | 3 |
C | 2 3 | 1 | |
+-----------+-----------+-----------+
D | 7 | | 3 9 |
E | | 4 | 1 |
F | 5 | 6 | |
+-----------+-----------+-----------+
G | 9 | 3 8 | 5 |
H | | | 7 |
I | 3 | 7 2 | |
+-----------+-----------+-----------+
s:0 steps:1 rounds:4 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 7 | 3 |
B | 8 | 2 3 | 9 1 |
C | | 5 | 6 2 |
+-----------+-----------+-----------+
D | 4 | 1 | 8 7 |
E | | | 9 2 |
F | | | 1 5 |
+-----------+-----------+-----------+
G | 9 | | 3 |
H | 1 | 7 | |
I | 6 | 9 | |
+-----------+-----------+-----------+
s:1 steps:2 rounds:6 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | | 6 3 |
B | | 7 | 4 |
C | 9 | 4 | 2 |
+-----------+-----------+-----------+
D | | 8 | |
E | 3 1 | 6 | 5 |
F | 5 | | 8 |
+-----------+-----------+-----------+
G | 4 | 1 3 | 6 |
H | 6 8 | | |
I | 3 | 5 | 7 |
+-----------+-----------+-----------+
s:2 steps:3 rounds:3 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | 1 7 | |
B | 7 | 4 | 9 5 |
C | | | |
+-----------+-----------+-----------+
D | | 8 6 | 3 |
E | 7 | 2 | |
F | 4 | 5 | 1 |
+-----------+-----------+-----------+
G | 8 1 | 6 | 7 |
H | | 9 | 6 |
I | 4 | 8 | 2 |
+-----------+-----------+-----------+
s:3 steps:4 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | 7 | 9 |
B | | | 8 |
C | 4 | 1 | 3 |
+-----------+-----------+-----------+
D | 8 | 6 | 4 |
E | 9 | 5 4 | |
F | 3 | 2 | |
+-----------+-----------+-----------+
G | 2 | 3 | 6 |
H | | 1 2 | 3 |
I | 1 4 | 6 | |
+-----------+-----------+-----------+
s:4 steps:5 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 5 | 9 7 |
B | 2 4 | 9 | 8 |
C | | | |
+-----------+-----------+-----------+
D | 6 | 3 1 | |
E | 5 | 2 | 6 9 |
F | 4 | | 7 |
+-----------+-----------+-----------+
G | 2 | 1 | 3 |
H | 9 | 5 | 6 |
I | 3 | | 5 |
+-----------+-----------+-----------+
s:5 steps:6 rounds:3 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | | 4 5 |
B | 7 | 3 | |
C | 9 | 8 | |
+-----------+-----------+-----------+
D | | 5 | 9 2 |
E | 8 | | 6 |
F | | 1 7 | 3 4 |
+-----------+-----------+-----------+
G | 2 | 3 6 | 8 7 |
H | 9 | | 5 |
I | 1 | 8 | |
+-----------+-----------+-----------+
s:1 steps:7 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | | 1 7 |
B | 6 | 1 8 | |
C | | | 4 |
+-----------+-----------+-----------+
D | | | 1 |
E | 9 | 4 | |
F | 6 | 7 9 | 5 |
+-----------+-----------+-----------+
G | 2 4 | 3 | |
H | 7 | 6 | 2 8 |
I | 9 5 | 1 | 3 |
+-----------+-----------+-----------+
s:7 steps:8 rounds:2 digits:24
Lisää oikeasti vaikeita sudokuja, näissä on 24 vihjettä ja ne ovat miksattuja (–mix) kauttaviivoja (–slashes):
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 9 | 6 |
B | 9 | 4 | 1 |
C | 3 | 2 | 7 |
+-----------+-----------+-----------+
D | | 1 | 9 |
E | 2 | 3 | 6 |
F | 3 | 2 | 4 |
+-----------+-----------+-----------+
G | 5 | 8 | 3 |
H | | 5 | 2 |
I | 7 | | 1 |
+-----------+-----------+-----------+
s:0 steps:1 rounds:5 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 7 | 3 |
B | 3 | 5 | 1 |
C | 1 | 9 | 8 |
+-----------+-----------+-----------+
D | 6 | 1 | 4 |
E | | 4 | 3 |
F | | 6 | 9 |
+-----------+-----------+-----------+
G | | 6 | 2 |
H | 4 | 3 | 5 |
I | 9 | 8 | 7 |
+-----------+-----------+-----------+
s:1 steps:2 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 7 | 2 |
B | 6 | 5 | 1 |
C | 4 | 6 | 8 |
+-----------+-----------+-----------+
D | 8 | 2 | 9 |
E | | 1 | 3 |
F | 3 | | 4 |
+-----------+-----------+-----------+
G | 6 | 2 | 7 |
H | 9 | 6 | 5 |
I | 7 | 9 | |
+-----------+-----------+-----------+
s:2 steps:3 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 | 3 | 8 |
B | 1 | 5 | 9 |
C | 9 | 7 | 6 |
+-----------+-----------+-----------+
D | 6 | 4 | 1 |
E | 3 | 5 | 2 |
F | | 6 | |
+-----------+-----------+-----------+
G | 8 | 1 | 4 |
H | 3 | | 7 |
I | 6 | 2 | 9 |
+-----------+-----------+-----------+
s:3 steps:4 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 7 | 6 |
B | 4 | 1 | 9 |
C | 8 | 5 | 3 |
+-----------+-----------+-----------+
D | | 9 | 5 |
E | 5 | 3 | 8 |
F | 9 | 7 | 2 |
+-----------+-----------+-----------+
G | 1 | 7 | 6 |
H | 6 | 5 | 4 |
I | 3 | 6 | |
+-----------+-----------+-----------+
s:4 steps:5 rounds:3 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 7 | 2 |
B | 5 | 6 | |
C | 8 | 3 | 9 |
+-----------+-----------+-----------+
D | 5 | 6 | 1 |
E | 2 | 4 | 8 |
F | 1 | 8 | 6 |
+-----------+-----------+-----------+
G | 9 | | 4 |
H | 3 | 9 | 7 |
I | 2 | 8 | |
+-----------+-----------+-----------+
s:5 steps:6 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 2 | 9 | 7 |
B | 8 | 2 | 4 |
C | 5 | 6 | 8 |
+-----------+-----------+-----------+
D | | 7 | 8 |
E | 5 | 4 | 9 |
F | | | 6 |
+-----------+-----------+-----------+
G | 9 | 1 | 7 |
H | 2 | 9 | 3 |
I | 3 | 8 | 1 |
+-----------+-----------+-----------+
s:6 steps:7 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 5 | 8 |
B | 9 | 2 | |
C | | 7 | 2 |
+-----------+-----------+-----------+
D | 3 | 1 | 4 |
E | 2 | | 3 |
F | 5 | 8 | 6 |
+-----------+-----------+-----------+
G | 6 | 3 | 2 |
H | 4 | 6 | 1 |
I | 7 | 8 | 6 |
+-----------+-----------+-----------+
s:7 steps:8 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 | 7 |
B | 2 | 5 | 3 |
C | 4 | 7 | 6 |
+-----------+-----------+-----------+
D | 1 | | 7 |
E | 3 | 6 | 2 |
F | 5 | 8 | 9 |
+-----------+-----------+-----------+
G | 1 | 6 | 4 |
H | 6 | 8 | 1 |
I | 5 | 2 | |
+-----------+-----------+-----------+
s:8 steps:9 rounds:2 digits:24
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 5 | 6 |
B | | 4 | 2 |
C | 5 | 2 | 7 |
+-----------+-----------+-----------+
D | | 9 | 1 |
E | 1 | 7 | 8 |
F | 4 | 6 | 9 |
+-----------+-----------+-----------+
G | 6 | 1 | 3 |
H | 8 | 5 | 6 |
I | | 9 | 4 |
+-----------+-----------+-----------+
s:9 steps:10 rounds:2 digits:24
Vielä oikeasti vaikeita sudokuja (25 vihjettä)
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 | 1 | 7 3 |
B | | 5 2 | 8 |
C | 8 | 3 | |
+-----------+-----------+-----------+
D | 6 | 7 | 5 |
E | | 1 | |
F | 1 | 4 | 8 |
+-----------+-----------+-----------+
G | 5 | 7 | |
H | 7 | 2 | 6 |
I | 4 | 8 9 | 2 |
+-----------+-----------+-----------+
s:0 steps:1 rounds:3 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 2 | | |
B | 5 | 4 | 9 |
C | 8 1 | 6 | 3 |
+-----------+-----------+-----------+
D | 6 | 7 | |
E | 7 4 | | 9 |
F | 3 | 8 | 5 |
+-----------+-----------+-----------+
G | 2 | 6 9 | |
H | | 1 | 8 7 |
I | | 4 | 2 |
+-----------+-----------+-----------+
s:1 steps:2 rounds:4 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | | | 3 |
B | | 3 | 8 2 |
C | 4 8 | | 5 1 |
+-----------+-----------+-----------+
D | 5 | 4 1 | 6 |
E | 7 | 9 | |
F | | | 3 |
+-----------+-----------+-----------+
G | | 6 8 | 3 |
H | 5 8 2 | | |
I | 9 | 4 7 | 8 |
+-----------+-----------+-----------+
s:2 steps:3 rounds:3 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 | | |
B | 1 2 | 5 | 9 4 |
C | 4 | 7 | |
+-----------+-----------+-----------+
D | | 1 | 8 |
E | 1 | 7 | 6 |
F | 3 | 4 | 2 |
+-----------+-----------+-----------+
G | 3 | 9 | 2 |
H | 9 | 2 4 | 5 3 |
I | | 3 | |
+-----------+-----------+-----------+
s:3 steps:4 rounds:2 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 | 2 | |
B | 1 6 | 8 9 4 | |
C | 3 | 1 | |
+-----------+-----------+-----------+
D | 8 | 9 5 | 3 |
E | 5 | 7 4 | |
F | | | 9 2 |
+-----------+-----------+-----------+
G | 9 2 | 8 | |
H | 6 | | |
I | | 7 | 2 5 |
+-----------+-----------+-----------+
s:4 steps:5 rounds:3 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 | |
B | 9 | 2 6 | |
C | 5 | 1 9 | 8 |
+-----------+-----------+-----------+
D | 2 | 4 | |
E | 8 5 | 7 | 4 6 |
F | | | 2 8 |
+-----------+-----------+-----------+
G | 4 | | 1 7 |
H | 8 | | |
I | 6 1 | 7 | 2 |
+-----------+-----------+-----------+
s:5 steps:6 rounds:4 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 9 | 2 1 |
B | | 8 | 4 |
C | 7 | | 3 |
+-----------+-----------+-----------+
D | 4 1 | 5 | 8 |
E | 2 3 | 7 | |
F | 9 | | |
+-----------+-----------+-----------+
G | | | 7 2 |
H | 8 5 | | 1 |
I | 2 | 1 | 5 4 |
+-----------+-----------+-----------+
s:6 steps:7 rounds:2 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 2 | 1 | 9 |
B | | 4 | 6 |
C | 8 | 2 6 | |
+-----------+-----------+-----------+
D | | 3 | |
E | 5 7 | 1 | 8 |
F | | | 2 6 |
+-----------+-----------+-----------+
G | 5 | 9 6 | 3 |
H | 3 | | 9 7 |
I | | 7 | 4 |
+-----------+-----------+-----------+
s:7 steps:8 rounds:3 digits:25
A B C D E F G H I
+-----------+-----------+-----------+
A | | 9 | 6 |
B | 3 4 | | 5 |
C | 7 6 | 8 | |
+-----------+-----------+-----------+
D | 5 | 2 4 | |
E | | 6 | |
F | 7 | | 6 4 |
+-----------+-----------+-----------+
G | 1 | | 7 3 |
H | 4 | 3 1 | 2 |
I | | 5 | 9 1 |
+-----------+-----------+-----------+
Myös simplesolven rounds: yrittää kuvata sudokun vaikeutta, mutta siitä huolimatta nämä ratkeavat yksinkertaisilla menetelmillä (katso simplesolve): seuraavassa muutamia:
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 9 | 5 2 |
B | 8 | 5 1 | |
C | | | 1 |
+-----------+-----------+-----------+
D | | | 3 7 |
E | 2 | 8 | |
F | 4 | | 9 |
+-----------+-----------+-----------+
G | | 7 | 6 |
H | 9 5 | 3 | 8 |
I | 8 | 4 | 1 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:12 digits:23
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 9 5 | |
B | | 8 1 | |
C | | 4 6 | 9 7 |
+-----------+-----------+-----------+
D | 8 | | 6 |
E | 6 | | 7 3 |
F | | 6 8 | 9 4 |
+-----------+-----------+-----------+
G | 1 | 3 | 4 |
H | 6 3 | 2 9 | |
I | 2 | | 5 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:12 digits:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 | 6 | 5 |
B | | 1 | 6 |
C | 3 6 | 7 | 8 |
+-----------+-----------+-----------+
D | 4 | 6 8 | 7 |
E | 7 5 | 2 1 4 | 3 6 |
F | 8 | | 1 |
+-----------+-----------+-----------+
G | 4 | 3 2 | |
H | | | 3 9 |
I | | 6 | 2 |
+-----------+-----------+-----------+
s:0 steps:0 rounds:12 digits:29
Seuraavassa ohjelman osien läpikäyminen, ensimmäisenä rutiinit,joilla sudokuetsin hakee satunnaisbitit: ensimmäinen palauttaa yhden merkin satunnaismerkin, ja jos sisäisen puskurin (gent) merkit loppuvat, hakee seuraavan puskurillisen pseudoressu_bytes() rutiinilla. Toinen rutiini palauttaa satunnaisen kokonaisluvun nollan ja halutun kokonaisluvun välillä. Funktion parametrinä oleva yläraja ei kuulu joukkoon, vaan maksimissaan palautetaan yhtä pienempi arvo.
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
pseudoressu_bytes(sizeof(gent), gent);
} // if(gent_pos == 0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
ylärajak } else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
Seuraava rutiini palauttaa tämän sudokun (b) solun (cell) mahdolliset vaihtoehdot (choices2)
void sudoku_get_choices(unsigned char b[82], int cell, char choices2[10])
{
int c, d, lin, col, box;
char choices[10], digit[2], digits[]="123456789";
lin = cell / 9;
col = cell % 9;
box = lin / 3 * 27 + col / 3 * 3;
choices[0] = '\0';
for(c = 0; c < 9; c++) {
if(b[lin * 9 + c] != ' ' && strchr(choices, b[lin * 9 + c]) == NULL) {
digit[0] = b[lin * 9 + c];
digit[1] = '\0';
strcat(choices, digit);
}
}
for(c = 0; c < 9; c++) {
if(b[c * 9 + col] != ' ' && strchr(choices, b[c * 9 + col]) == NULL) {
digit[0] = b[c * 9 + col];
digit[1] = '\0';
strcat(choices, digit);
}
}
for(c = 0; c < 3; c++) {
for(d = 0; d < 3; d++) {
if(b[box + c * 9 + d] != ' ' && strchr(choices, b[box + c * 9 + d]) == NULL) {
digit[0] = b[box + c * 9 + d];
digit[1] = '\0';
strcat(choices, digit);
}
}
}
choices2[0] = '\0';
for(c = 0; c < 9; c++) {
if(strchr(choices, digits[c]) == NULL) {
digit[0] = digits[c];
digit[1] = '\0';
strcat(choices2, digit);
}
}
}
Seuraavilla sudoku_boardx() rutiineilla tulostetaan sudokuruudukot eri muodoissaan: seuraavana sudoku_board, joka tulostaa oletusmuotoilun mukaisen ruudukon (–board1).
void sudoku_board(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " A B C D E F G H I \n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"|\n");
}
if(c % 27 == 0)
strcat(s," +-----------+-----------+-----------+\n");
if(c % 9 == 0) {
sprintf(line,"%c ",'A' + c / 9);
strcat(s, line);
}
if(c % 3 == 0) {
strcat(s, "|");
} else strcat(s, " ");
if(b[c] != ' ' && b[c] != '0')
sprintf(line," %c ", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "|\n +-----------+-----------+-----------+");
strcat(s, "\n");
}
Seuraavana sudoku ruudukon tulostava rutiini, joka tulostaa halutun muotoisen sudokun:
void sudoku_print(unsigned char *b, int board)
{
unsigned char string[2048];
string[0] = '\0';
/* zero -> no board */
if(board == 1)
sudoku_board(string, b);
else if(board == 2)
sudoku_board2(string, b);
else if(board == 3)
sudoku_board3(string, b);
else if(board == 4)
sudoku_board4(string, b);
else if(board == 5)
sudoku_board5(string, b);
else if(board == 6)
sudoku_board6(string, b);
else if(board == 10)
sudoku_board10(string, b);
else if(board == 11)
sudoku_board11(string, b);
else if(board == 20)
sudoku_board20(string, b);
else if(board == 21)
sudoku_board21(string, b);
fprintf(stdout,"%s", string);
}
Seuraavassa pienet rutiinit, joilla voidaan tarkastaa onko sudoku täynnä (valmis), tai tyhjentää sudoku:
int sudoku_full(unsigned char b[82])
{
for(int c = 0; c < 81; c++) {
if(b[c] == ' ')
return(0);
}
return(1);
}
void sudoku_clear(unsigned char b[82])
{
int c;
for(c = 0; c < 81; c++) {
b[c] = ' ';
}
b[c] = '\0';
}
Seuraavaksi solve() rutiinin aliohjelma, jolla voidaan tarkastaa onko sudokuruudun (r) tietylle riville (i) ja tiettyyn sarakkeeseen (j) tietty numero mahdollinen.
int sudoku_isallowed(unsigned char b[82], int i, int j, int e)
{
int k, l, base;
for(k = 0; k < 9; k++) {
if(b[i * 9 + k] == e)
return(0);
}
for(k = 0; k < 9; k++) {
if(b[9 * k + j] == e)
return(0);
}
base = i / 3 * 27 + j / 3 * 3;
for(k = 0; k < 3; k++) {
for(l = 0; l < 3; l++) {
if(b[base + k * 9 + l] == e)
return(0);
}
}
return(1);
}
Seuraavalla rutiinilla solve() hakee seuraavan solun, johon tarvitaan numero: eli palautetaan ensimmäisen tyhjän ruudun rivi ja sarake.
int sudoku_getnextemptycell(char *b, int *i, int *j)
{
int i2, j2;
for(i2 = 0; i2 < 9; i2++) {
for(j2 = 0; j2 < 9; j2++) {
if(*(b + i2 * 9 + j2) == ' ') {
*i = i2;
*j = j2;
return(1);
}
}
}
*i = -1;
*j = -1;
return(0);
}
Seuraavassa solve() rutiini. Solve2() on sen alirutiini, joka tekee varsinaisen rekursiivisen taulukon ratkaisun:
int sudoku_solve2(unsigned char *sudoku, unsigned char *solution, long long *solutions)
{
int c, i, j;
if(sudoku_getnextemptycell(sudoku, &i, &j) == 0) {
(*solutions)++;
if(solve_verbose) {
if(*solutions % 1000000000 == 0)
fprintf(stdout,"%lld: %s\n", *solutions, sudoku);
}
if(*solutions == 1)
strcpy(solution, sudoku);
#ifdef SOLVE_QUICK_EXIT
if(solve_quick_exit && *solutions > 1) // quick exit && multiple solutions, fail
return(1);
else
#endif
return(0);
}
for(c = '1'; c <= '9'; c++) {
if(sudoku_isallowed(sudoku, i, j, c) == 1) {
#ifdef SOLVE_USESIMPLE
char savesudoku[82];
if(solve_usesimple)
strcpy(savesudoku, sudoku);
#endif
*(sudoku + i * 9 + j) = c;
if(solve_verbose)
fprintf(stdout,"%s\n", sudoku);
#ifdef SOLVE_USESIMPLE
if(solve_usesimple)
sudoku_simplesolve(sudoku);
#endif
solve_steps++;
#ifdef DEBUG57
if(solve_verbose)
fprintf(stdout,"%s\n", sudoku);
#endif
if(sudoku_solve2(sudoku, solution, solutions) == 1)
return(1);
#ifdef SOLVE_USESIMPLE
if(solve_usesimple)
strcpy(sudoku, savesudoku);
#endif
*(sudoku + i * 9 + j) = ' ';
}
}
return(0);
}
int sudoku_solve(unsigned char *sudoku)
{
unsigned char tsudoku[82], solution[82];
solve_steps = 0;
solutions = 0;
memcpy(tsudoku, sudoku, sizeof(tsudoku));
sudoku_simplesolve(tsudoku);
sudoku_solve2(tsudoku, solution, &solutions);
if(solutions == 1) { // single solution
memcpy(sudoku, solution, sizeof(solution));
if(solve_verbose) {
fprintf(stdout,"%s\n", sudoku);
}
return(1);
} else {
return(0);
}
}
Seuraavassa simplesolven eri versiot: simplesolve1 ratkaisee tapaukset, joissa sudokuruudulla on vain yksi mahdollinen vaihtoehto:
int sudoku_simplesolve1(unsigned char b[82])
{
int c, changes = 0;
unsigned char choices[10];
for(c = 0; c < 81; c++) {
if(newb[c] == ' ') { // empty cell
choices[0] = '\0';
sudoku_get_choices(newb, c, choices);
int lenchoices = strlen(choices);
if(lenchoices == 0) {
break;
} else if(lenchoices == 1) {
if(simple_verbose) {
#ifdef DEBUG32
fprintf(stdout,"simplesolve1");
#endif
fprintf(stdout," %c%c%c", c / 9 + 'A', c % 9 + 'A', *choices);
#ifdef DEBUG32
fprintf(stdout,"\n");
sudoku_print(newb, 1);
#endif
}
newb[c] = *choices;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG32
if(simple_verbose) {
fprintf(stdout,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
} // end of if(strlen(choices)
} // end of if(b[c] == ' ') { // empty cell
} // end of for(c
return(changes);
}
Simplesolve2 ratkaisee tapaukset, joissa rivillä numero sopii vain yhteen soluun:
int sudoku_simplesolve2(unsigned char b[82]) {
int c, h, i, j, count, cell, base, changes = 0;
char choices[81][10];
for(c = '1'; c <= '9'; c++) { // digits
for(i = 0; i < 9; i++) { // rows
count = 0;
cell = -1;
for(j = 0; j < 9; j++) { // columns
if(newb[i * 9 + j] == ' ' && sudoku_isallowed(newb, i, j, c) == 1) {
count++;
cell = i * 9 + j;
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG34
fprintf(stdout,"simplesolve2: rows");
#endif
fprintf(stdout," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
#ifdef DEBUG34
fprintf(stdout,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG34
if(simple_verbose) {
fprintf(stdout,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
}
}
}
return(changes);
}
Simplesolve3 ratkaisee tapaukset, joissa sarakkeessa on vain yksi paikka, johon voi laittaa tietyn numeron:
int sudoku_simplesolve3(unsigned char b[82]) {
int c, h, i, j, count, cell, base, changes = 0;
char choices[81][10];
sudoku_get_all_choices(b, choices);
for(c = '1'; c <= '9'; c++) { // digits
for(j = 0; j < 9; j++) { // columns
count = 0;
cell = -1;
for(i = 0; i < 9; i++) { // rows
if(newb[i * 9 + j] == ' ' && sudoku_isallowed(newb, i, j, c) == 1) {
count++;
cell = i * 9 + j;
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG36
fprintf(stdout,"simplesolve3: columns");
#endif
fprintf(stdout," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
simple_output = 1;
#ifdef DEBUG36
fprintf(stdout,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
simple_count++;
#ifdef DEBUG36
if(simple_verbose) {
fprintf(stdout,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
}
}
}
return(changes);
}
Simplesolve4 ratkaisee tapaukset joissa numero voidaan laittaa vain yhteen laatikon soluun:
int sudoku_simplesolve4(unsigned char b[82]) {
int c, h, i, j, basei, basej, count, cell, changes = 0;
char choices[81][10];
for(basei = 0; basei < 9; basei += 3) {
for(basej = 0; basej < 9; basej += 3) {
for(c = '1'; c <= '9'; c++) { // digits
count = 0;
cell = -1;
for(i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
#ifdef KOK
fprintf(stdout,"basei:%d", basei);
fprintf(stdout," basej:%d", basej);
fprintf(stdout," i:%d", i);
fprintf(stdout," j:%d", j);
fprintf(stdout," basei+i:%d", basei + i);
fprintf(stdout," basej+j:%d", basej + j);
fprintf(stdout," c:%d", c);
fprintf(stdout," cell:%d", cell);
fprintf(stdout,"\n");
#endif
if(newb[(basei + i) * 9 + basej + j] == ' ' && sudoku_isallowed(newb, basei + i, basej + j, c) == 1) {
cell = (basei + i) * 9 + j + basej;
count++;
}
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG38
fprintf(stdout,"simplesolve4: boxes");
#endif
fprintf(stdout," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
#ifdef DEBUG38
fprintf(stdout,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG38
if(simple_verbose) {
fprintf(stdout,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
} // end of if(count
} // end of for(c
} // end of for(basej
} // end of for(basei
return(changes);
}
Lisätty ohjelmaan ensimmäinen kaavailu DB8 liittymästä.
....
#define aOUTPUTDB 2
#define OUTPUTFILE 2
#ifdef OUTPUTDB
#include "db8.h"
#endif
....
#ifdef OUTPUTDB
unsigned char temp[16];
db8_set_filename(sudokuesdb);
db8_put_element("sudoku", 0, "board", 0, b);
db8_put_element("sudoku", 0, "solution", 0, s);
db8_put_element("sudoku", 0, "cboard", 0, cboard);
sprintf(temp,"%d",digits);
db8_put_element("sudoku", 0, "digits", 0, temp);
sprintf(temp,"%d",empty);
db8_put_element("sudoku", 0, "empty", 0, temp);
if(gmode == 0) {
sprintf(temp,"%d", digitsa);
db8_put_element("sudoku", 0, "digitsa", 0, temp);
sprintf(temp,"%d", digitsb);
db8_put_element("sudoku", 0, "digitsb", 0, temp);
} else {
sprintf(temp,"%d", digitsa);
db8_put_element("sudoku", 0, "digitsa", 0, temp);
}
sprintf(temp,"%d", mode);
db8_put_element("sudoku", 0, "mode", 0, temp);
sprintf(temp,"%d", gmode);
db8_put_element("sudoku", 0, "gmode", 0, temp);
db8_save("sudoku");
db8_clear("sudoku");
#endif
....
Vielä newressusudoku ohjelman kokonainen sorsa: ($ cc -DSHA256 newressusudoku.c newressu.c sha256.c -o newressusudoku -lm)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
unsigned char *procname;
static unsigned char *programname = "newressusudoku version 0.5 ©";
static unsigned char *copyright = "Copyright (c) 1998-2024 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
int sudoku_output = 0;
void pseudoressu_bytes(int size, unsigned char *buffer);
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
pseudoressu_bytes(sizeof(gent), gent);
} // if(gent_pos == 0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
#define aDEBUG4 2
#ifdef DEBUG4
fprintf(stdout,"limit:%lu", limit);
fprintf(stdout,", highlimit:%lu", highlimit);
fprintf(stdout,", bytes:%d", bytes);
fprintf(stdout,", word:%lu", word);
fprintf(stdout,", word%%limit:%lu\n", (unsigned long) word % limit);
#endif
word %= limit;
return(word);
}
int digitsa = -1;
int digitsb = -1;
unsigned char *cross =
"111222111"
"111222111"
"111222111"
"222111222"
"222111222"
"222111222"
"111222111"
"111222111"
"111222111";
unsigned char *plus =
"222111222"
"222111222"
"222111222"
"111111111"
"111111111"
"111111111"
"222111222"
"222111222"
"222111222";
unsigned char *slashes =
"001001001"
"010010010"
"100100100"
"001001001"
"010010010"
"100100100"
"001001001"
"010010010"
"100100100";
unsigned char *full =
"111111111"
"111111111"
"111111111"
"111111111"
"111111111"
"111111111"
"111111111"
"111111111"
"111111111";
unsigned char *sudoku_grid1 = NULL;
void sudoku_get_choices(unsigned char b[82], int cell, char choices2[10])
{
int c, d, lin, col, box;
char choices[10], digit[2], digits[]="123456789";
lin = cell / 9;
col = cell % 9;
box = lin / 3 * 27 + col / 3 * 3;
choices[0] = '\0';
for(c = 0; c < 9; c++) {
if(b[lin * 9 + c] != ' ' && strchr(choices, b[lin * 9 + c]) == NULL) {
digit[0] = b[lin * 9 + c];
digit[1] = '\0';
strcat(choices, digit);
}
}
for(c = 0; c < 9; c++) {
if(b[c * 9 + col] != ' ' && strchr(choices, b[c * 9 + col]) == NULL) {
digit[0] = b[c * 9 + col];
digit[1] = '\0';
strcat(choices, digit);
}
}
for(c = 0; c < 3; c++) {
for(d = 0; d < 3; d++) {
if(b[box + c * 9 + d] != ' ' && strchr(choices, b[box + c * 9 + d]) == NULL) {
digit[0] = b[box + c * 9 + d];
digit[1] = '\0';
strcat(choices, digit);
}
}
}
choices2[0] = '\0';
for(c = 0; c < 9; c++) {
if(strchr(choices, digits[c]) == NULL) {
digit[0] = digits[c];
digit[1] = '\0';
strcat(choices2, digit);
}
}
}
/*
A B C D E F G H I
+-----------+-----------+-----------+
A | | 2 | 7 |
B | | 6 | |
C | 5 3 | 8 4 7 | 2 |
+-----------+-----------+-----------+
D | 2 | 8 | 1 9 |
E | | | |
F | 1 8 | 9 | 7 6 3 |
+-----------+-----------+-----------+
G | 9 | 7 | |
H | | 9 1 | 5 |
I | 4 | 6 | 9 |
+-----------+-----------+-----------+
steps:209
*/
void sudoku_board(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " A B C D E F G H I \n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"|\n");
}
if(c % 27 == 0)
strcat(s," +-----------+-----------+-----------+\n");
if(c % 9 == 0) {
sprintf(line,"%c ",'A' + c / 9);
strcat(s, line);
}
if(c % 3 == 0) {
strcat(s, "|");
} else strcat(s, " ");
if(b[c] != ' ' && b[c] != '0')
sprintf(line," %c ", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "|\n +-----------+-----------+-----------+");
strcat(s, "\n");
}
/*
ABC DEF GHI
+---+---+---+
A| | | |
B| | 26| |
C|8 7|13 |6 2|
+---+---+---+
D|7 | 3|1 |
E| 52|6 7|9 |
F| | | |
+---+---+---+
G|3 |7 8|49 |
H|4 9| | 7|
I| | 1| 36|
+---+---+---+
*/
void sudoku_board2(char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " ABC DEF GHI \n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"|\n");
}
if(c % 27 == 0)
strcat(s, " +---+---+---+\n");
if(c % 9 == 0) {
sprintf(line,"%c",'A' + c / 9);
strcat(s, line);
}
if(c % 3 == 0) {
strcat(s, "|");
}
if(b[c] != ' ' && b[c] != '0')
sprintf(line,"%c", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "|\n +---+---+---+");
strcat(s, "\n");
}
/*
ABCDEFGHI
+---------+
A|573842619|
B|219675348|
C|684319275|
D|821453967|
E|937168524|
F|456297831|
G|145936782|
H|392781456|
I|768524193|
+---------+
*/
void sudoku_board3(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " ABCDEFGHI \n");
strcat(s," +---------+\n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"|\n");
}
if(c % 9 == 0) {
sprintf(line,"%c",'A' + c / 9);
strcat(s, line);
}
if(c % 9 == 0) {
strcat(s, "|");
}
if(b[c] != ' ' && b[c] != '0')
sprintf(line,"%c", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "|\n +---------+");
strcat(s, "\n");
}
/*
ABCDEFGHI
+---------
A|695217483
B|138564792
C|724893156
D|572946318
E|463185279
F|981732645
G|357429861
H|846351927
I|219678534
*/
void sudoku_board4(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " ABCDEFGHI\n");
strcat(s," +---------\n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0)
strcat(s,"\n");
if(c % 9 == 0) {
sprintf(line,"%c",'A' + c / 9);
strcat(s, line);
}
if(c % 9 == 0)
strcat(s, "|");
if(b[c] != ' ' && b[c] != '0')
sprintf(line,"%c", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "\n");
}
/*
ABCDEFGHI
A287935641
B615482379
C943761258
D324519867
E596874123
F178623495
G432197586
H761258934
I859346712
*/
void sudoku_board5(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
strcat(s, " ABCDEFGHI \n");
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0)
strcat(s,"\n");
if(c % 9 == 0) {
sprintf(line,"%c",'A' + c / 9);
strcat(s, line);
}
if(b[c] != ' ' && b[c] != '0')
sprintf(line,"%c", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "\n");
}
/*
435189627
691275384
872436591
349852176
168947235
257613849
914368752
723591468
586724913
*/
void sudoku_board6(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char line[128];
*s='\0';
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"\n");
}
if(b[c] != ' ' && b[c] != '0')
sprintf(line,"%c", b[c]);
else
sprintf(line," ");
strcat(s, line);
}
strcat(s, "\n");
}
/*
AA5 AB28 AC3 AD1 AE9 AF278 AG4 AH367 AI678
BA6 BB248 BC7 BD23 BE23 BF28 BG389 BH1 BI589
CA138 CB9 CC13 CD367 CE4 CF5 CG2 CH367 CI678
DA13479 DB14567 DC2 DD69 DE16 DF149 DG369 DH8 DI4679
EA1479 EB1467 EC1469 ED269 EE8 EF3 EG5 EH2679 EI24679
FA3489 FB468 FC3469 FD5 FE7 FF249 FG369 FH2369 FI1
GA12479 GB12457 GC1459 GD8 GE1235 GF6 GG19 GH259 GI259
HA1279 HB3 HC1569 HD279 HE125 HF1279 HG1689 HH4 HI25689
IA129 IB1256 IC8 ID4 IE125 IF129 IG7 IH2569 II3
*/
void sudoku_board10(unsigned char *s, unsigned char b[82])
{
int c, first;
unsigned char choices[10], line[128];
*s='\0';
first = 1;
for(c = 0; c < 81; c++) {
if(c > 0 && c % 9 == 0) {
strcat(s,"\n");
first = 1;
}
if(!first)
strcat(s, " ");
sprintf(line,"%c%c",'A' + c / 9, 'A' + c % 9);
strcat(s, line);
if(b[c] >= '1' && b[c] <= '9') {
unsigned char digit[3];
digit[0] = b[c];
digit[1] = '\0';
strcat(s, digit);
} else {
sudoku_get_choices(b, c, choices);
strcat(s, choices);
}
first = 0;
}
strcat(s, "\n");
}
/*
7 37 1 88 95 78 1 4 21 595 6 3 4 23 6 7 1 5 9
*/
void sudoku_board11(unsigned char *s, unsigned char b[82])
{
int c;
unsigned char digit[3];
*s='\0';
for(c = 0; c < 81; c++) {
if(b[c] >= '1' && b[c] <= '9') {
digit[0] = b[c];
digit[1] = '\0';
strcat(s, digit);
} else
strcat(s, " ");
}
strcat(s, "\n");
}
/*
'AA' = "4", 'AB' = "9", 'AE' = "7", 'BA' = "5", 'CB' = "8", 'CE' = "2", 'CF' = "4", 'CG' = "3", 'DC' = "9", 'DE' = "4", 'DH' = "6", 'EB' = "6", 'EE' = "5", 'FD' = "8", 'FF' = "3", 'FH' = "1", 'GA' = "3", 'GC' = "4", 'GE' = "9", 'GI' = "2", 'HC' = "6", 'HG' = "8", 'IA' = "9", 'IB' = "5", 'ID' = "2", 'IF' = "6", 'II' = "3"
*/
void sudoku_board20(unsigned char *s, unsigned char b[82])
{
int c, first = 1;
unsigned char column[128], digit[3];
*s='\0';
for(c = 0; c < 81; c++) {
if(b[c] >= '1' && b[c] <= '9') {
column[0] = '\0';
if(!first)
strcat(column, ", ");
sprintf(column + strlen(column), "'%c%c'",'A' + c / 9, 'A' + c % 9);
digit[0] = b[c];
digit[1] = '\0';
strcat(column, " = \"");
strcat(column, digit);
strcat(column, "\"");
first = 0;
strcat(s, column);
}
}
strcat(s, "\n");
}
/*
'AA' = "278", 'AB' = "1", 'AC' = "2358", 'AD' = "29", 'AE' = "278", 'AF' = "4", 'AG' = "237", 'AH' = "2357", 'AI' = "6", 'BA' = "24678", 'BB' = "245678", 'BC' = "2458", 'BD' = "26", 'BE' = "2678", 'BF' = "3", 'BG' = "247", 'BH' = "1", 'BI' = "9", 'CA' = "9", 'CB' = "23467", 'CC' = "234", 'CD' = "126", 'CE' = "5", 'CF' = "267", 'CG' = "2347", 'CH' = "8", 'CI' = "37", 'DA' = "28", 'DB' = "289", 'DC' = "7", 'DD' = "23569", 'DE' = "1", 'DF' = "2569", 'DG' = "2389", 'DH' = "4", 'DI' = "35", 'EA' = "5", 'EB' = "2489", 'EC' = "6", 'ED' = "239", 'EE' = "237", 'EF' = "279", 'EG' = "123789", 'EH' = "2379", 'EI' = "137", 'FA' = "3", 'FB' = "29", 'FC' = "129", 'FD' = "259", 'FE' = "4", 'FF' = "8", 'FG' = "6", 'FH' = "2579", 'FI' = "157", 'GA' = "478", 'GB' = "345789", 'GC' = "34589", 'GD' = "345", 'GE' = "3", 'GF' = "1", 'GG' = "379", 'GH' = "6", 'GI' = "2", 'HA' = "1267", 'HB' = "235679", 'HC' = "12359", 'HD' = "8", 'HE' = "236", 'HF' = "256", 'HG' = "1379", 'HH' = "379", 'HI' = "4", 'IA' = "1246", 'IB' = "2346", 'IC' = "1234", 'ID' = "7", 'IE' = "9", 'IF' = "26", 'IG' = "5", 'IH' = "3", 'II' = "8"
*/
void sudoku_board21(unsigned char *s, unsigned char b[82])
{
int c, first = 1;
unsigned char column[128], digit[3], choices[10];
*s='\0';
for(c = 0; c < 81; c++) {
column[0] = '\0';
if(!first)
strcat(column, ", ");
sprintf(column + strlen(column), "'%c%c' = ", 'A' + c / 9, 'A' + c % 9);
if(b[c] >= '1' && b[c] <= '9') {
digit[0] = b[c];
digit[1] = '\0';
strcat(column, "\"");
strcat(column, digit);
strcat(column, "\"");
} else {
sudoku_get_choices(b, c, choices);
strcat(column, "\"");
strcat(column, choices);
strcat(column, "\"");
}
first = 0;
strcat(s, column);
}
strcat(s, "\n");
}
void sudoku_print(unsigned char *b, int board)
{
unsigned char string[2048];
string[0] = '\0';
/* zero -> no board */
if(board == 1)
sudoku_board(string, b);
else if(board == 2)
sudoku_board2(string, b);
else if(board == 3)
sudoku_board3(string, b);
else if(board == 4)
sudoku_board4(string, b);
else if(board == 5)
sudoku_board5(string, b);
else if(board == 6)
sudoku_board6(string, b);
else if(board == 10)
sudoku_board10(string, b);
else if(board == 11)
sudoku_board11(string, b);
else if(board == 20)
sudoku_board20(string, b);
else if(board == 21)
sudoku_board21(string, b);
fprintf(stdout,"%s", string);
}
void sudoku_get_all_choices(unsigned char *b, char choices[81][10]) {
int c;
for(c = 0; c < 81; c++) {
choices[c][0] = '\0';
if(*(b + c) == ' ') {
sudoku_get_choices(b, c, choices[c]);
} else {
choices[c][0] = *(b + c);
choices[c][1] = '\0';
}
}
}
int sudoku_full(unsigned char b[82])
{
for(int c = 0; c < 81; c++) {
if(b[c] == ' ')
return(0);
}
return(1);
}
void sudoku_clear(unsigned char b[82])
{
int c;
for(c = 0; c < 81; c++) {
b[c] = ' ';
}
b[c] = '\0';
}
void sudoku_cleargrid(unsigned char b[82], unsigned char grid[82], char choice)
{
int c;
for(c = 0; c < 81; c++) {
if(grid[c] == choice)
b[c] = ' ';
}
}
int sudoku_isallowed(unsigned char b[82], int i, int j, int e)
{
int k, l, base;
for(k = 0; k < 9; k++) {
if(b[i * 9 + k] == e)
return(0);
}
for(k = 0; k < 9; k++) {
if(b[9 * k + j] == e)
return(0);
}
base = i / 3 * 27 + j / 3 * 3;
for(k = 0; k < 3; k++) {
for(l = 0; l < 3; l++) {
if(b[base + k * 9 + l] == e)
return(0);
}
}
return(1);
}
int sudoku_verbose = 0;
int simple_verbose = 0, simple_output = 0, simple_count = 0;
int solve_verbose = 0;
int simple_rounds = 0, save_rounds = 0, save_steps = 0;
int simple_errors = 0;
unsigned char newb[82];
#define aDEBUG32 2
int sudoku_simplesolve1(unsigned char b[82])
{
int c, changes = 0;
unsigned char choices[10];
for(c = 0; c < 81; c++) {
if(newb[c] == ' ') { // empty cell
choices[0] = '\0';
sudoku_get_choices(newb, c, choices);
int lenchoices = strlen(choices);
if(lenchoices == 0) {
break;
} else if(lenchoices == 1) {
if(simple_verbose) {
#ifdef DEBUG32
fprintf(stderr,"simplesolve1");
#endif
fprintf(stderr," %c%c%c", c / 9 + 'A', c % 9 + 'A', *choices);
#ifdef DEBUG32
fprintf(stderr,"\n");
sudoku_print(newb, 1);
#endif
}
newb[c] = *choices;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG32
if(simple_verbose) {
fprintf(stderr,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
} // end of if(strlen(choices)
} // end of if(b[c] == ' ') { // empty cell
} // end of for(c
return(changes);
}
#define aDEBUG34 2
int sudoku_simplesolve2(unsigned char b[82]) {
int c, i, j, count, cell, changes = 0;
for(c = '1'; c <= '9'; c++) { // digits
for(i = 0; i < 9; i++) { // rows
count = 0;
cell = -1;
for(j = 0; j < 9; j++) { // columns
if(newb[i * 9 + j] == ' ' && sudoku_isallowed(newb, i, j, c) == 1) {
count++;
cell = i * 9 + j;
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG34
fprintf(stderr,"simplesolve2: rows");
#endif
fprintf(stderr," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
#ifdef DEBUG34
fprintf(stderr,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG34
if(simple_verbose) {
fprintf(stderr,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
}
}
}
return(changes);
}
#define aDEBUG36 2
int sudoku_simplesolve3(unsigned char b[82]) {
int c, i, j, count, cell, changes = 0;
char choices[81][10];
sudoku_get_all_choices(b, choices);
for(c = '1'; c <= '9'; c++) { // digits
for(j = 0; j < 9; j++) { // columns
count = 0;
cell = -1;
for(i = 0; i < 9; i++) { // rows
if(newb[i * 9 + j] == ' ' && sudoku_isallowed(newb, i, j, c) == 1) {
count++;
cell = i * 9 + j;
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG36
fprintf(stderr,"simplesolve3: columns");
#endif
fprintf(stderr," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
simple_output = 1;
#ifdef DEBUG36
fprintf(stderr,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
simple_count++;
#ifdef DEBUG36
if(simple_verbose) {
fprintf(stderr,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
}
}
}
return(changes);
}
#define aDEBUG38 2
int sudoku_simplesolve4(unsigned char b[82]) {
int c, i, j, basei, basej, count, cell, changes = 0;
for(basei = 0; basei < 9; basei += 3) {
for(basej = 0; basej < 9; basej += 3) {
for(c = '1'; c <= '9'; c++) { // digits
count = 0;
cell = -1;
for(i = 0; i < 3; i++) {
for(j = 0; j < 3; j++) {
#ifdef KOK
fprintf(stderr,"basei:%d", basei);
fprintf(stderr," basej:%d", basej);
fprintf(stderr," i:%d", i);
fprintf(stderr," j:%d", j);
fprintf(stderr," basei+i:%d", basei + i);
fprintf(stderr," basej+j:%d", basej + j);
fprintf(stderr," c:%d", c);
fprintf(stderr," cell:%d", cell);
fprintf(stderr,"\n");
#endif
if(newb[(basei + i) * 9 + basej + j] == ' ' && sudoku_isallowed(newb, basei + i, basej + j, c) == 1) {
cell = (basei + i) * 9 + j + basej;
count++;
}
}
}
if(count == 1 && cell != -1 && newb[cell] == ' ') {
if(simple_verbose) {
#ifdef DEBUG38
fprintf(stderr,"simplesolve4: boxes");
#endif
fprintf(stderr," %c%c%c", cell / 9 + 'A', cell % 9 + 'A', c);
#ifdef DEBUG38
fprintf(stderr,"\n");
sudoku_print(newb, 1);
#endif
}
newb[cell] = c;
if(simple_verbose) {
simple_count++;
simple_output = 1;
}
#ifdef DEBUG38
if(simple_verbose) {
fprintf(stderr,"\n");
sudoku_print(newb, 1);
}
#endif
changes++;
//sudoku_get_all_choices(b, choices);
} // end of if(count
} // end of for(c
} // end of for(basej
} // end of for(basei
return(changes);
}
int simple1 = 1, simple2 = 1, simple3 = 1, simple4 = 1;
int sudoku_simplesolve(unsigned char *b)
{
int changes, changes2 = 0;
simple_count = 0;
simple_rounds = 0;
simple_errors = 0;
changes = 1;
while(simple_errors == 0 && changes) {
memcpy(newb, b, sizeof(newb));
changes = 0;
if(simple1)
changes += sudoku_simplesolve1(b);
if(simple2)
changes += sudoku_simplesolve2(b);
if(simple3)
changes += sudoku_simplesolve3(b);
if(simple4)
changes += sudoku_simplesolve4(b);
changes2 += changes;
simple_rounds++;
memcpy(b, newb, sizeof(newb));
}
if(simple_verbose && simple_output) {
fprintf(stderr,", moves:%d\n", simple_count);
simple_output = 0;
}
return(changes2);
}
int sudoku_getnextemptycell(char *b, int *i, int *j)
{
int i2, j2;
for(i2 = 0; i2 < 9; i2++) {
for(j2 = 0; j2 < 9; j2++) {
if(*(b + i2 * 9 + j2) == ' ') {
*i = i2;
*j = j2;
return(1);
}
}
}
*i = -1;
*j = -1;
return(0);
}
int sudoku_boardsmatch(unsigned char *board, unsigned char *board2)
{
int c, ok;
ok = 1;
for(c = 0;c < 81; c++) {
if(*(board + c) != ' ' &&
*(board2 + c) != ' ' &&
*(board + c) != *(board2 + c)) {
ok = 0;
break;
}
}
return(ok);
}
int solve_steps = 0, solve_exact = -1, solve_greater = -1;
int rounds_greater = -1;
int solve_usesimple = 1;
#define SOLVE_QUICK_EXIT 2 // on for now
#define aDEBUG57 2
int solve_quick_exit = 1;
int solve_calculate_steps = 0;
unsigned long long solutions;
unsigned char prevsolution[82];
int sudoku_solve2(unsigned char *sudoku, unsigned char *solution, unsigned long long *solutions)
{
int c, i, j;
if(sudoku_getnextemptycell(sudoku, &i, &j) == 0) {
(*solutions)++;
if(solve_verbose) {
if(*solutions % 1000000 == 0) {
FILE *fp1;
if((fp1 = fopen("newressusudokusolutions.txt", "a")) != NULL) {
fprintf(fp1,"%llu: %s\n", *solutions, sudoku);
fclose(fp1);
}
}
}
if(*solutions == 1)
strcpy(solution, sudoku);
#ifdef SOLVE_QUICK_EXIT
if(solve_quick_exit && *solutions > 1) // quick exit && multiple solutions, fail
return(1);
else
#endif
return(0);
}
for(c = '1'; c <= '9'; c++) {
if(sudoku_isallowed(sudoku, i, j, c) == 1) {
char savesudoku[82];
if(solve_usesimple)
strcpy(savesudoku, sudoku);
*(sudoku + i * 9 + j) = c;
#ifdef DEBUG57
if(solve_verbose)
fprintf(stderr,"%s\n", sudoku);
#endif
if(solve_usesimple)
sudoku_simplesolve(sudoku);
#ifdef OLD1
solve_steps++;
#endif
if(solve_verbose)
fprintf(stderr,"%s",sudoku);
if(solve_calculate_steps && sudoku_boardsmatch(sudoku, prevsolution)) {
solve_steps++;
if(solve_verbose)
fprintf(stderr,"*****");
}
if(solve_verbose)
fprintf(stderr,"\n");
#ifdef DEBUG57
if(solve_verbose)
fprintf(stderr,"%s\n", sudoku);
#endif
if(sudoku_solve2(sudoku, solution, solutions) == 1)
return(1);
if(solve_usesimple)
strcpy(sudoku, savesudoku);
*(sudoku + i * 9 + j) = ' ';
}
}
return(0);
}
int sudoku_solve(unsigned char *sudoku)
{
unsigned char tsudoku[82], solution[82];
solve_steps = 0;
solutions = 0;
if(solve_verbose)
fprintf(stderr,"%s\n",prevsolution);
memcpy(tsudoku, sudoku, sizeof(tsudoku));
sudoku_simplesolve(tsudoku);
sudoku_solve2(tsudoku, solution, &solutions);
if(solutions == 1) { // single solution
memcpy(sudoku, solution, sizeof(solution));
if(solve_verbose) {
fprintf(stderr,"%s\n", sudoku);
}
return(1);
}
return(0);
}
unsigned char items[6][3] = {
{ 0,1,2 },
{ 0,2,1 },
{ 1,0,2 },
{ 1,2,0 },
{ 2,0,1 },
{ 2,1,0 }
};
void sudoku_mix(unsigned char *sudoku)
{
int c, d, e, f, g, h, temp;
for(c = 0; c < 3; c++) { // from stacks (bands) 0 - 3
d = newressu_gen_limit(3); // to stack (band)) 0 - 3
e = newressu_gen_limit(6); // order of columns (rows) in stack (band)
for(f = 0; f < 3; f++) { // order of columns (rows) in from stack (band)
g = items[e][f]; // order of columns (rows) in stack (band)
for(h = 0; h < 9; h++) { // swap columns in stack
temp = *(sudoku + c * 3 + f + h * 9);
*(sudoku + c * 3 + f + h * 9) = *(sudoku + d * 3 + g + h * 9);
*(sudoku + d * 3 + g + h * 9) = temp;
}
for(h = 0; h < 9; h++) { // swap rows in band
temp = *(sudoku + c * 27 + f * 9 + h);
*(sudoku + c * 27 + f * 9 + h) = *(sudoku + d * 27 + g * 9 + h);
*(sudoku + d * 27 + g * 9 + h) = temp;
}
}
}
}
int sudoku_makegrid(unsigned char *b, unsigned char *grid, char choice, unsigned int count)
{
int c, cell, digit;
unsigned char choices[10];
for(c = 0; c < count; c++) {
for(;;) {
// get cell number from pseudoressutwist
cell = newressu_gen_limit(81);
if(*(grid + cell) != choice)
continue;
if(*(b + cell) != ' ') // filled cell
continue;
sudoku_get_choices(b, cell, choices);
int choiceslen = strlen(choices);
if(choiceslen == 0)
return(1); // no choices, fail
else if(choiceslen == 1)
digit = choices[0]; // one choice only, use it
else
digit = choices[newressu_gen_limit(choiceslen)]; // multiple choices, get digit choise from pseudoressu
*(b + cell) = digit;
break;
} // end of for(;;)
} // end of for(c = 0; c
return(0); // ok
}
#define SUDOKU_PHASE2_ROUNDS 30 // avgtries 2156
#define aOUTPUTDB 2
#define OUTPUTFILE 2
#ifdef OUTPUTDB
#include "db8.h"
#endif
long long sumtries = 0, counttries = 0;
int mode = 0, gmode = 1;
int mix = 0;
unsigned char *sudokuesfile = "newressusudoku.skk";
unsigned char *sudokuesdb = "newressusudoku.skk.db";
unsigned char sudokuaietana[82] = "1 7 9 3 2 8 96 5 53 9 1 8 26 4 3 1 4 7 7 3 ";
unsigned char sudokuhard[82] = " 2 7 6 2 9 3 6 7 3 8 3 6 58 1 4 4 7 2 3 5 8 9 1";
int sudoku_make(unsigned char *b, unsigned char *s, unsigned char *m)
{
int tries = 0, changes = 0, ok;
unsigned char board[82], solution[82];
for(;;) {
prevsolution[0] = 0;
solve_quick_exit = 1;
solutions = 0;
save_rounds = 0;
save_steps = 0;
#define aDEBUG63 2
#ifdef DEBUG63
fprintf(stderr,".");
sudoku_output = 1;
fflush(stderr);
#endif
sudoku_clear(board);
tries++;
if(gmode == 0) {
if(tries % SUDOKU_PHASE2_ROUNDS == 0) {
ok = 0;
while(!ok) {
ok = 1;
sudoku_clear(board);
if(sudoku_makegrid(board, sudoku_grid1, '1', digitsa) == 1)
ok = 0;
}
}
if(sudoku_makegrid(board, sudoku_grid1, '2', digitsb) == 1) {
sudoku_cleargrid(board, sudoku_grid1, '2');
continue;
}
} else if(gmode == 1) {
ok = 0;
while(!ok) {
ok = 1;
sudoku_clear(board);
if(sudoku_makegrid(board, sudoku_grid1, '1', digitsa) == 1)
ok = 0;
}
}
//memcpy(board, sudokuhard, sizeof(sudokuhard));
*m = '\0';
if(mix) {
strcpy(m, board);
sudoku_mix(board);
}
memcpy(b, board, sizeof(board));
if(mode == 0) { // easy
sudoku_simplesolve(b);
save_rounds = simple_rounds;
} else if(mode == 1) { // hard
changes = sudoku_simplesolve(b);
save_rounds = simple_rounds;
if(changes > 1 && changes < 10 && !sudoku_full(b))
sudoku_solve(b);
else
continue;
} else if(mode == 2) { // harder
changes = sudoku_simplesolve(b);
save_rounds = simple_rounds;
if(changes == 1 && !sudoku_full(b))
sudoku_solve(b);
else
continue;
} else if(mode == 3) { // hardest
if((changes = sudoku_simplesolve(b)) == 0 &&
!sudoku_full(b)) {
save_rounds = simple_rounds;
sudoku_solve(b);
} else
continue;
} else if(mode == 10) { // solve only
solve_quick_exit = 1;
sudoku_solve(b);
memcpy(prevsolution, b, sizeof(prevsolution));
}
if(solutions > 1)
continue;
if(!sudoku_full(b))
continue;
if(rounds_greater != -1 &&
save_rounds <= rounds_greater)
continue;
if(solve_exact != -1 ||
solve_greater != -1) {
// calculate solve steps using full
// solve
solve_calculate_steps = 1;
solve_quick_exit = 0;
memcpy(b, board, sizeof(board));
sudoku_solve(b);
save_steps = solve_steps;
if((solve_exact != -1 &&
solve_exact != solve_steps) ||
(solve_greater != -1 &&
save_steps <= solve_greater) )
continue;
}
memcpy(solution, b, sizeof(solution));
break;
}
sumtries += tries;
counttries++;
memcpy(b, board, sizeof(board));
memcpy(s, solution, sizeof(solution));
int digits = 0;
unsigned char cboard[82], *p;
p = cboard;
for(int c = 0; c < sizeof(board); c++) {
if(board[c] >= '1' && board[c] <= '9') {
*p++ = board[c];
digits++;
}
}
*p = '\0';
int empty = 81 - digits;
#ifdef OUTPUTDB
unsigned char temp[16];
static int row = 0;
db8_set_filename(sudokuesdb);
db8_put_element("sudoku", row, 0, "board", 0, b);
db8_put_element("sudoku", row, 0, "solution", 0, s);
db8_put_element("sudoku", row, 0, "cboard", 0, cboard);
sprintf(temp,"%d",digits);
db8_put_element("sudoku", row, 0, "digits", 0, temp);
sprintf(temp,"%d",empty);
db8_put_element("sudoku", row, 0, "empty", 0, temp);
if(gmode == 0) {
sprintf(temp,"%d", digitsa);
db8_put_element("sudoku", row, 0, "digitsa", 0, temp);
sprintf(temp,"%d", digitsb);
db8_put_element("sudoku", row, 0, "digitsb", 0, temp);
} else {
sprintf(temp,"%d", digitsa);
db8_put_element("sudoku", row, 0, "digitsa", 0, temp);
}
sprintf(temp,"%d", mode);
db8_put_element("sudoku", row, 0, "mode", 0, temp);
sprintf(temp,"%d", gmode);
db8_put_element("sudoku", row, 0, "gmode", 0, temp);
db8_save("sudoku");
db8_clear("sudoku");
row++;
#endif
#ifdef OUTPUTFILE
FILE *fp1;
if((fp1 = fopen(sudokuesfile, "a"))!=NULL) {
*p = '\0';
fprintf(fp1,"'board' = \"%s\"", b);
fprintf(fp1,", 'solution' = \"%s\"", s);
fprintf(fp1,", 'cboard' = \"%s\"", cboard);
fprintf(fp1,", 'digits' = \"%d\"", digits);
fprintf(fp1,", 'empty' = \"%d\"", empty);
if(gmode == 0) {
fprintf(fp1,", 'digitsa' = \"%d\"", digitsa);
fprintf(fp1,", 'digitsb' = \"%d\"", digitsb);
} else if(gmode == 1) {
fprintf(fp1,", 'digitsa' = \"%d\"", digitsa);
}
fprintf(fp1,", 'mode' = \"%d\"", mode);
fprintf(fp1,", 'gmode' = \"%d\"", gmode);
fprintf(fp1,"\n");
fclose(fp1);
}
#endif
return(0);
}
unsigned char *sudoku_fgets(int *linelen, unsigned char **line, FILE *fp1)
{
int count, retval;
unsigned char buffer[128];
unsigned char *buf = *line;
count = 0;
if(buf != NULL)
buf[0] = '\0';
retval = 1;
for(;;) {
if(fgets(buffer, sizeof(buffer), fp1) == NULL) {
retval = 0;
break;
}
count = 0;
if(buf != NULL)
count += strlen(buf);
count += strlen(buffer) + 1;
if(*linelen < count) {
unsigned char *prevbuf = buf;
*linelen = count;
buf = realloc(buf, *linelen);
if(prevbuf == NULL)
buf[0] = '\0';
}
strcat(buf, buffer);
if(buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
break;
}
}
*line = buf;
if(retval == 0)
return(NULL);
else
return(*line);
}
int help = 0, quiet = 0, psolution = 0, pboard = 1, avgtries = 0, sudokues = 1;
int history = 0;
unsigned char *match = NULL;
int main(int argc, char *argv[])
{
int c;
unsigned char board[82], sboard[82], tboard[82], mixboard[82];
procname = argv[0];
sudoku_grid1 = full;
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strncmp("-",argv[c], 1)) {
if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strcmp("--avgtries", argv[c])) {
avgtries = !avgtries;
} else if(!strncmp("--sudokues", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
sudokues = atoi(argv[c] + 10);
} else if(c + 1 < argc) {
sudokues = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--solution", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
psolution = atoi(argv[c] + 10);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
psolution = atoi(argv[c + 1]);
c++;
} else
psolution = !psolution;
} else if(!strncmp("--board", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
pboard = atoi(argv[c] + 7);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
pboard = atoi(argv[c + 1]);
c++;
} else
pboard = !pboard;
} else if(!strncmp("--history", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
history = atoi(argv[c] + 9);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
history = atoi(argv[c + 1]);
c++;
} else
history = !history;
} else if(!strncmp("--match", argv[c], 7)) {
if(*(argv[c] + 7) != '\0') {
match = argv[c] + 7;
} else if(c + 1 < argc) {
match = argv[c + 1];
c++;
}
} else if(!strcmp("--verbose", argv[c])) {
sudoku_verbose = !sudoku_verbose;
} else if(!strcmp("--mix", argv[c])) {
mix = !mix;
} else if(!strcmp("--simple1", argv[c])) {
simple1 = !simple1;
} else if(!strcmp("--simple2", argv[c])) {
simple2 = !simple2;
} else if(!strcmp("--simple3", argv[c])) {
simple3 = !simple3;
} else if(!strcmp("--simple4", argv[c])) {
simple4 = !simple4;
} else if(!strncmp("--digits", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
digitsa = atoi(argv[c] + 8);
} else if(c + 1 < argc) {
digitsa = atoi(argv[c + 1]);
c++;
}
digitsb = 0;
} else if(!strncmp("--digitsa", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
digitsa = atoi(argv[c] + 9);
} else if(c + 1 < argc) {
digitsa = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--digitsb", argv[c], 9)) {
if(*(argv[c] + 9) != '\0') {
digitsb = atoi(argv[c] + 9);
} else if(c + 1 < argc) {
digitsb = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--stepsexact", argv[c], 12)) {
if(*(argv[c] + 12) != '\0') {
solve_exact = atoi(argv[c] + 12);
} else if(c + 1 < argc) {
solve_exact = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--stepsgreater", argv[c], 14)) {
if(*(argv[c] + 14) != '\0') {
solve_greater = atoi(argv[c] + 14);
} else if(c + 1 < argc) {
solve_greater = atoi(argv[c + 1]);
c++;
}
fprintf(stderr,"solve_greater:%d\n",solve_greater);
} else if(!strncmp("--roundsgreater", argv[c], 15)) {
if(*(argv[c] + 15) != '\0') {
rounds_greater = atoi(argv[c] + 15);
} else if(c + 1 < argc) {
rounds_greater = atoi(argv[c + 1]);
c++;
}
} else if(!strcmp("--gmode1", argv[c]) ) {
gmode = 1;
} else if(!strcmp("--gmode0", argv[c]) ) {
gmode = 0;
} else if(!strcmp("--mode0", argv[c]) ) {
mode = 0;
} else if(!strcmp("--mode1", argv[c]) ) {
mode = 1;
} else if(!strcmp("--mode2", argv[c]) ) {
mode = 2;
} else if(!strcmp("--mode3", argv[c]) ) {
mode = 3;
} else if(!strcmp("--mode10", argv[c]) ) {
mode = 10;
} else if(!strcmp("--full", argv[c])) {
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy", argv[c])) {
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy38", argv[c])) {
digitsa = 38;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy1", argv[c])) {
digitsa = 25;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy2", argv[c])) {
digitsa = 27;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy3", argv[c])) {
digitsa = 29;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy4", argv[c])) {
digitsa = 31;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy38", argv[c])) {
digitsa = 38;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy41", argv[c])) {
digitsa = 41;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--easy45", argv[c])) {
digitsa = 45;
sudoku_grid1 = full;
gmode = 1;
mode = 0; // easy
} else if(!strcmp("--hard", argv[c])) {
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--hard1", argv[c])) {
digitsa = 23;
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--hard24", argv[c])) {
digitsa = 24;
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--hard2", argv[c])) {
digitsa = 26;
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--hard3", argv[c])) {
digitsa = 29;
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--hard4", argv[c])) {
digitsa = 33;
sudoku_grid1 = full;
gmode = 1;
mode = 1; // hard
} else if(!strcmp("--harder", argv[c])) {
sudoku_grid1 = full;
gmode = 1;
mode = 2; // harder
} else if(!strcmp("--harder1", argv[c])) {
digitsa = 23;
sudoku_grid1 = full;
gmode = 1;
mode = 2; // harder
} else if(!strcmp("--harder5", argv[c])) {
digitsa = 34;
sudoku_grid1 = full;
gmode = 1;
mode = 2; // harder
} else if(!strcmp("--hardest", argv[c])) {
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--hardest1", argv[c])) {
digitsa = 23;
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--hardest2", argv[c])) {
digitsa = 27;
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--hardest3", argv[c])) {
digitsa = 31;
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--hardest4", argv[c])) {
digitsa = 31;
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--hardest5", argv[c])) {
digitsa = 33;
sudoku_grid1 = full;
gmode = 1;
mode = 3; // hardest
} else if(!strcmp("--solve", argv[c])) {
sudoku_grid1 = full;
gmode = 1;
mode = 10; // solve
} else if(!strcmp("--cross1", argv[c])) {
digitsa = 25;
digitsb = 0;
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--cross2", argv[c])) {
digitsa = 30;
digitsb = 0;
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--cross3", argv[c])) {
digitsa = 35;
digitsb = 0;
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--cross4", argv[c])) {
digitsa = 40;
digitsb = 0;
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--cross5", argv[c])) {
digitsa = 45;
digitsb = 0;
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--cross", argv[c])) {
sudoku_grid1 = cross;
gmode = 0;
} else if(!strcmp("--plus1", argv[c])) {
digitsa = 25;
digitsb = 10;
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--plus2", argv[c])) {
digitsa = 30;
digitsb = 10;
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--plus3", argv[c])) {
digitsa = 35;
digitsb = 10;
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--plus4", argv[c])) {
digitsa = 40;
digitsb = 10;
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--plus5", argv[c])) {
digitsa = 45;
digitsb = 10;
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--plus", argv[c])) {
sudoku_grid1 = plus;
gmode = 0;
} else if(!strcmp("--slashes", argv[c])) {
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--slashes1", argv[c])) {
digitsa = 23;
digitsb = 0;
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--slashes2", argv[c])) {
digitsa = 24;
digitsb = 0;
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--slashes3", argv[c])) {
digitsa = 25;
digitsb = 0;
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--slashes4", argv[c])) {
digitsa = 26;
digitsb = 0;
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--slashes5", argv[c])) {
digitsa = 27;
digitsb = 0;
sudoku_grid1 = slashes;
gmode = 0;
} else if(!strcmp("--test3", argv[c])) {
simple1 = 1;
simple2 = 1;
digitsa = 9;
digitsb = 25;
} else {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
}
} // end of for(c = 1; c < argc; c++)
if(help) {
fprintf(stderr,"%s: %s", procname, procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--board[n]]");
fprintf(stderr," [--solution[n]]");
fprintf(stderr," [--history");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
if(digitsa == -1)
digitsa = 27;
if(digitsb == -1)
digitsb = 10;
solve_quick_exit = 1;
#define aDEBUG90 2
#ifdef DEBUG90
unsigned char *empty_sudoku =
" "
" "
" "
" "
" "
" "
" "
" "
" ";
#ifdef KOK
"123456789"
"789123456"
"456789123"
"214365897"
"365897214"
"897214365"
"531642978"
"648971532"
"972538641";
#endif
fprintf(stderr,"Counting all solutions...\n");
fflush(stderr);
simple_verbose = 0;
solve_quick_exit = 0;
solve_verbose = sudoku_verbose;
memcpy(tboard, empty_sudoku, sizeof(tboard));
sudoku_solve(tboard);
fprintf(stderr,", solutions:%lld", solutions);
sudoku_grid1 = full;
simple_verbose = 0;
solve_verbose = 0;
fprintf(stderr,", Done\n");
fflush(stderr);
#endif
#ifdef OUTPUTDB
if(history) {
int row, col, first, ok;
int namesize, valuesize, namelen, valuelen;
unsigned char name[128], value[128];
namesize = sizeof(name);
valuesize = sizeof(value);
db8_set_filename(sudokuesdb);
if(match != NULL)
db8_set_match("sudokues", match);
if(history == 1) {
db8_verbose = 0;
row = 0;
for(;;) {
ok = 0;
if(db8_get_element("sudokues", row, 0, "board", valuesize, &valuelen, value)) {
fprintf(stderr,"board:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "solution", valuesize, &valuelen, value)) {
fprintf(stderr,", solution:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "cboard", valuesize, &valuelen, value)) {
fprintf(stderr,", cboard:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "digits", valuesize, &valuelen, value)) {
fprintf(stderr,", digits:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "empty", valuesize, &valuelen, value)) {
fprintf(stderr,", empty:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "digitsa", valuesize, &valuelen, value)) {
fprintf(stderr,", digitsa:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "mode", valuesize, &valuelen, value)) {
fprintf(stderr,", mode:\"%s\"",value);
ok = 1;
}
if(db8_get_element("sudokues", row, 0, "gmode", valuesize, &valuelen, value)) {
fprintf(stderr,", gmode:\"%s\"",value);
ok = 1;
}
fprintf(stderr,"\n");
if(!ok)
break;
row++;
}
} else if(history == 2) {
db8_verbose = 0;
row = 0;
for(;;) {
first = 1;
col = 0;
ok = 0;
for(;;) {
if(db8_get_element_num("sudokues", row, col, namesize, &namelen, name, valuesize, &valuelen, value))
ok = 1;
else
break;
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"'%s':\"%s\"", name, value);
col++;
first = 0;
}
fprintf(stdout,"\n");
fflush(stdout);
if(!ok)
break;
row++;
}
} else if(history == 3) {
db8_verbose = 1;
db8_set_query("sudokues", "'board', 'solution'");
fprintf(stderr,"****\n");
row = 0;
for(;;) {
first = 1;
col = 0;
ok = 0;
for(;;) {
fprintf(stdout,"row:%d, col:%d, ", row, col);
if(db8_get_element_num("sudokues", row, col, namesize, &namelen, name, valuesize, &valuelen, value))
ok = 1;
else
break;
if(!first)
fprintf(stdout,", ");
fprintf(stdout,"**'%s':\"%s\"",name, value);
col++;
first = 0;
}
fprintf(stdout,"\n");
fflush(stdout);
if(!ok)
break;
row++;
}
}
db8_verbose = 0;
//db8_dump("sudokues");
//db8_clear("sudoku");
exit(0);
} // end of if(history
#endif
#define aDEBUG94 2
#ifdef DEBUG94
/*
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 2 | 9 | 4 |
B | 4 | 8 | 7 |
C | 8 3 | 2 | |
+-----------+-----------+-----------+
D | 6 | 2 | |
E | 2 | 1 6 | 4 3 5 |
F | | | 7 |
+-----------+-----------+-----------+
G | | 8 | 2 4 |
H | | | 5 3 |
I | | 4 | |
+-----------+-----------+-----------+
s:0 steps:512 rounds:0 digits:25
*/
unsigned char hard1[82] =
"12 9 4"
"4 8 7 "
"83 2 "
"6 2 "
"2 16 435"
" 7 "
" 8 24 "
" 5 3"
" 4 ";
unsigned char solution[82];
sudoku_clear(solution);
memcpy(board, sudokuaietana, sizeof(sudokuaietana));
sudoku_print(board, pboard);
simple_verbose = 1;
memcpy(tboard, board, sizeof(board));
sudoku_simplesolve(tboard);
sudoku_print(tboard, pboard);
simple_verbose = 0;
solve_verbose = 1;
memcpy(tboard, board, sizeof(board));
solve_quick_exit = 0;
solve_usesimple = 1;
sudoku_solve(tboard);
if(solutions > 1)
fprintf(stderr,"multiple solutions\n");
fprintf(stderr,"solvesteps:%d\n", solve_steps);
sudoku_print(tboard, 1);
fprintf(stderr,"**********\n");
#endif
unsigned char simplesolution[82], solvesolution[82];
unsigned char solvesolutions[82];
int id = 0;
for(int boards = 0; boards < sudokues; boards++) {
solve_usesimple = 1;
solve_quick_exit = 1;
simple_verbose = 0;
solve_verbose = 0;
sudoku_clear(board);
sudoku_clear(sboard);
sudoku_make(board, sboard, mixboard);
if(sudoku_output) {
fprintf(stdout,"\n");
fflush(stdout);
sudoku_output = 0;
}
// simplesolve for verbose
memcpy(tboard, board, sizeof(board));
simple_verbose = sudoku_verbose;
sudoku_simplesolve(tboard);
memcpy(simplesolution, tboard, sizeof(simplesolution));
save_rounds = simple_rounds;
simple_verbose = 1; // *****
// solve for verbose
memcpy(tboard, board, sizeof(board));
solve_verbose = sudoku_verbose;
solve_usesimple = 1;
solve_quick_exit = 0;
simple_verbose = 0;
sudoku_solve(tboard);
memcpy(solvesolution, tboard, sizeof(solvesolution));
save_steps = solve_steps;
solve_verbose = sudoku_verbose;
// solve without usesimple
solve_usesimple = 0;
simple_verbose = 0;
sudoku_solve(tboard);
memcpy(solvesolutions, tboard, sizeof(solvesolution));
if(mix && sudoku_verbose)
sudoku_print(mixboard, pboard);
sudoku_print(board, pboard);
int digits = 0;
for(c = 0;c < sizeof(board); c++)
if(board[c] >= '0' && board[c] <= '9')
digits++;
fprintf(stdout," s:%d", id);
#ifdef SOLVE_QUICK_EXIT
fprintf(stdout," steps:%d", save_steps);
#endif
fprintf(stdout," rounds:%d", save_rounds);
fprintf(stdout," digits:%d", digits);
fprintf(stdout,"\n");
if(psolution) {;
sudoku_print(solvesolution, psolution);
fprintf(stdout," s:%d", id);
fprintf(stdout,"\n");
}
id++;
//if(sudoku_verbose) {
solve_verbose = sudoku_verbose;
if(sudoku_boardsmatch(board, simplesolution) &&
sudoku_boardsmatch(board, solvesolution) &&
sudoku_boardsmatch(board, solvesolutions) &&
sudoku_boardsmatch(simplesolution, solvesolution) &&
sudoku_full(solvesolution)) {
} else {
fprintf(stderr,"board: %s\n", board);
fprintf(stderr,"simple: %s\n", simplesolution);
fprintf(stderr,"solvewsi: %s\n", solvesolutions);
fprintf(stderr,"solve: %s\n", solvesolution);
fprintf(stderr,"board and solutions differ\n");
}
if(sudoku_verbose)
fprintf(stderr,"solvesteps:%d\n", save_steps);
fflush(stdout);
}
if(avgtries)
fprintf(stderr,"avgtries:%f\n",(double) sumtries / counttries);
return(0);
}
Suurin osa tästä postista on ollut exfat debukkailua ja satunnaisuus testiajoja, mutta taas kerran tuntuu siltä että “pasianssi” menee läpi. Eli että nuo db_get ja db_put rutiinit toimivat tosiaan sovelluksen koodauksessa. Tällä hetkellä mielessäni on idea että sovellukseen tarvittavat kyselyt ja rivit nimetään sovelluksen “sisäisillä” nimillä (header, lines, headerfields, linesfields, session, log jne…) ja niille lisätään järjestysnumero. Järjestysnumerolla voidaan lukea useampirivisen kyselyn halutun rivin kenttä. Esimerkiksi tilausrivit, taulukon sarakkeiden nimet, otsakkeen kenttien nimet. Onkohan jo aika 🍾&🥂, aika näyttää…
Olen miettinyt, että tästä saattaisi olla mahdollista tehdä vielä yksi uusi ammatti (/ansaintatapa), ja kyselenkin, koetteko saavanne näiden artikkeleiden lukemisesta niin paljon arvoa että voitte tukea niitä. Lahjoituksen suomessa voi tehdä, mutta ei voi sitä pyytää. Yritän keksiä lahjoitukselle jonkin vastalahjan. Tällä hetkellä ajattelen muistitikkua tai dvd-levyä, jolla on lähdekoodeja. Lahjoitus kattaa tämän ja edellisten artikkeleiden viihdearvon. Arvon, jota ajattelen raporttien voivan antaa ovat tietysti henkilökohtaisia. Päällisimpänä ajattelen viihdearvoa, seuraavina uutuusarvo, käyttöarvo, julkistusarvo jne… Toisaalta joku voi ajatella tämän arvoa hyvänä hack:inä (vanha merkitys, nykyinen termi ~eettinen hack). Lahjoitussumman ajattelin korvaavan levyjen valmistuksen kopiointikulut, hintaa en voi vielä miettiä hmmm? (Haaga-Helia Laiho, n.1997-1998). Toinen vaihtoehto on tietysti miettiä summaa, joka mahdollistaisi koodaamisen ja ei veisi koodaamiselta liiaksi aikaa. Toisaalta vastalahjalla pitäisi olla muutakin arvoa kun ohjelmistot, ehkäpä joku “laatutikku”, tai toisaalta mahdollinen dvd-levyn “taiteellinen” etiketti. Lahjoitus voisi voisi olla 1000€. Ensimmäisen valmistuksessa aina tietenkin kestää… Toisaalta voisin jatkaa yliopistolla ja tehdä lopputyön näistä.
Vastalahja tikku on edistynyt sen verran että sisältö on vaatimaton edistymisraportti, joka sisältää artikkelin lähdekoodeja ja niiden varmuuskopioita artikkelin kirjoituksen ajalta. Hakusessa on vielä saisiko artikkelin pdf:n mukaan tikulle.
Vielä joukko entistäkin parempia satunnaislukuja newressulla (+ 2 korjaus, copy/reverse muutos ja “bad for randomness” -korjaus):
$ ./newressu
00000 77458582497443145904566934443436246480701130620326935991456610973
00001 94507419393879258178180749627076833108928192114356128593175144808
00002 69955332005176379096756541035011728926172026506046261674970499492
00003 10041144250791764746028281923017387934850354308811311475334133566
00004 35481673992214936870774513280004290499190496268994268401165338970
00005 82463289343086188404499348759211815912057510425970342155995679459
00006 57920773023068190680028846995762779195455248238525716464305873857
00007 86630133084381732337741142532649045059766988279545483298107240233
00008 01015986958233860186920327673324049941187364720513073490914507087
00009 28508727880161886875910325608456711423282083816715925889000039535
$
Vielä ressun ja pseudoressu:n yhdistelmä ressutwist: tämän pitäisi olla kestävämpi kun pelkkä ressu.
$ ./newressu --ressutwist
00000 38169523754911197205187055060318737263295581333071814524589708402
00001 72357785313131012189080233848055894425568528104200838183302063376
00002 46313582383678766598338369217460575659675989837848215915983938840
00003 42087445607719393940612257351025832890546631293746186346013303374
00004 12111436258786575204528802582398706615613192232411446341863086139
00005 72046192140160144744229764463489240213143808100563106362594903710
00006 69877913434074772919675327159017485427086810711562559812792448662
00007 32295749372024209206376009222244012624606168682788316244901158666
00008 63384464324225511781931177910571924012544413758040773312731575605
00009 58904257885745995006916810801142432472067950180960633658250684053
$
Ja vielä satunnaisbittejä copy-reversen uusimmalla versiolla:
$ ./newressu
00000 07335951055253046500024163620453813836373328157321739152165317232
00001 40437299179549477553339146701997626827264050286975274380764359537
00002 75949993077782013732124213539976675604773074469960950132152302275
00003 05898243685309528542470891406823291120178413018559965061316979463
00004 48592522524365791666828231469872960396694950351782368719254710405
00005 44605804163182092800496364780633986485900223135483144357756924456
00006 49967812285265296249341492424239573141753602165258479636833398129
00007 63349903954970474474841131104375788104580100307465955328736696190
00008 00759242770205026105719795721070351377102239463323928394740626089
00009 53518248667093503967427116311430118211771697290836792208148299677
$
Sitten newressu sorsa kokonaisuudessaan, ensin Makefile:
CC = cc
CFLAGS = -g -Wall -Wno-pointer-sign
newressuobjs = newressu.mfs.o fort.o sha256.o intelrandom.o webrandom.o commandrandom.o
sha256objs = sha256.m.o
all: newressu sha256
newressu: $(newressuobjs)
cc $(CFLAGS) $(newressuobjs) -o newressu -lssl -lcrypto -lm
sha256: $(sha256objs)
cc $(CFLAGS) $(sha256objs) -o sha256
%.mfs.o: %.c
$(CC) $(CFLAGS) -DMAIN -DFORT -DSHA256 -c -o $@ $<
%.fs.o: %.c
$(CC) $(CFLAGS) -DFORT -DSHA256 -c -o $@ $<
%.m.o: %.c
$(CC) $(CFLAGS) -DMAIN -c -o $@ $<
%.p.o: %.c
$(CC) $(CFLAGS) -DPSEUDORESSU -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *~ \#*\# *.o
newressu.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/time.h>
#include <math.h>
#include <sys/types.h>
//#define SHA256 2 // in Makefile
#include "sha256.h"
//#define MAIN 2 // in Makefile
extern unsigned char *procname;
static unsigned char *programname = "Newressu version 4.09 ©";
static unsigned char *copyright = "Copyright (c) 1998-2024 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
int newressu_output = 0;
void ressu_dump(unsigned char *header, int len, unsigned char *buf, int linelen)
{
int c;
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
for(c = 0; c < len; c++) {
if(c % linelen == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%-10s", header);
}
fprintf(stdout," %02x", buf[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
}
static unsigned long periods[1024];
static unsigned long genbytes = 0;
static unsigned long clockbytes = 0;
int verbose = 0;
int size = -1, type = 10;
#define USE_RANDOM 2
#define ALL_SLICE 16 // 16 // orig 64
#define RESSUT_SLICES 128 // 128 // orig 32
#define RESSUT_BYTES (RESSUT_SLICES * ALL_SLICE) // 2048 16 * 128 // (32 * 64)
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16 * 1024
#define GENT_SLICES 128 // 32 // orig 16
#define GENT_SIZE (GENT_SLICES * ALL_SLICE) // 1024 (16 * 64)
static int ressut_bytes = (RESSUT_SLICES * ALL_SLICE); // orig 2048
static int ressut_bits1_needed = RESSUT_SLICES * 2; // orig 256
static int ressut_bits2_needed = RESSUT_SLICES * 8; // orig 1024
static int ressut_bits3_needed = RESSUT_SLICES * 16; // orig 2048
static int ressut_bits4_needed = RESSUT_SLICES * 16; // orig 2048
static int ressut_bits5_needed = RESSUT_SLICES * 16; // orig 2048
static int ressut_bits6_needed = RESSUT_SLICES * 32; // orig 2048 * 2
static int ressut_bits7_needed = RESSUT_SLICES * 128; // orig 2048 * 8
static int ressut_bits20_needed = RESSUT_SLICES * 32; // orig 2048 * 2
static int ressut_bits21_needed = RESSUT_SLICES * 16; // orig 2048
int rndbits1 = 0,
rndbits2 = 0,
rndbits3 = 0,
rndbits4 = 0,
rndbits5 = 0,
rndbits6 = 0,
rndbits7 = 0,
rndbits20 = 0,
rndbits21 = 0,
rndbits22 = 0;
static int stats = 0;
#define DEBUG_SORTED 2
unsigned long long ressu_useconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec + 1000000 * tv.tv_sec);
}
static unsigned char ressu_lowusec() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
#define FIXEDCLOCKCHAINLENGTH 50 // orig 50
unsigned int fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
int fixedclock = 0; // 0 = normal, 1 = fixed
static unsigned char ressu_clock()
{
static unsigned int clockbyte = 0, counter = 0;
if(!fixedclock)
return ressu_lowusec();
else {
if(counter == 0) {
clockbyte++;
counter += fixedclockchainlength;
}
counter--;
return(clockbyte & 0xff);
}
}
#include <sys/types.h>
#include <unistd.h>
#define aDEBUG2A 2
#define aDEBUG2B 2
#define aDEBUG2C 2
#define aDEBUG2D 2
#define aDEBUG2E 2
#define aDEBUG2F 2
#define aDEBUG2G 2
#define aDEBUG2H 2
static unsigned char *ressuct; // ressu random buffer lookup
static unsigned int ressuct_bytes;
static unsigned char ch;
#ifdef DEBUG2H
unsigned long count[RESSUT_BYTES];
#endif
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
struct timeval tv;
int pid = getpid();
int clock2 = clock();
gettimeofday(&tv, NULL);
#ifdef DEBUG2G
static int rowid = 0;
if(rowid == 0) {
fprintf(stdout,"%6s","rowid");
fprintf(stdout,"%6s","rando");
fprintf(stdout,"%6s","pid");
fprintf(stdout,"%6s","clk");
fprintf(stdout,"%6s","dtime");
fprintf(stdout,"%6s","+usec");
fprintf(stdout,"%6s","ptime");
fprintf(stdout,"%6s","+usec");
fprintf(stdout,"%6s","ch*ch");
fprintf(stdout,"%6s","newra");
fprintf(stdout,"\n");
}
fprintf(stdout,"%6d", rowid++);
fprintf(stdout,"%6d", rando % RESSUT_BYTES);
#endif
rando = rando +
//genbytes +
//time(NULL) +
//ressu_useconds() +
//ressu_clock() +
//buf.tms_utime +
//buf.tms_stime +
pid +
clockbytes +
tv.tv_sec +
tv.tv_usec +
clock2 / CLOCKS_PER_SEC +
clock2 % CLOCKS_PER_SEC +
ch * ch;
#ifdef DEBUG2G
fprintf(stdout,"%6d", pid % RESSUT_BYTES);
fprintf(stdout,"%6d", (int) clockbytes %RESSUT_BYTES);
fprintf(stdout,"%6d", (int) tv.tv_sec % RESSUT_BYTES);
fprintf(stdout,"%6d", (int) tv.tv_usec % RESSUT_BYTES);
fprintf(stdout,"%6d", (int) (clock2 / CLOCKS_PER_SEC) % RESSUT_BYTES);
fprintf(stdout,"%6d", (int) (clock2 % CLOCKS_PER_SEC) % RESSUT_BYTES);
fprintf(stdout,"%6d", (int) (ch * ch) % RESSUT_BYTES);
fprintf(stdout,"%6d", rando % RESSUT_BYTES);
fprintf(stdout,"\n");
#endif
#ifdef DEBUG2H
count[rando % ressuct_bytes]++;
#endif
#if defined DEBUG2C && !defined DEBUG2G
static unsigned int itemnum = 0;
if(itemnum % 16 == 0) {
if(itemnum > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05d ", itemnum);
}
fprintf(stdout," %4u", rando % ressuct_bytes);
itemnum++;
newressu_output = 1;
#endif
return(rando);
}
#define MAX_DEPTH 8 // now 4
int depth = 4; // now 4
unsigned int copyreverse = 1;
unsigned long cblocks = 0;
unsigned char lens = 4;
static unsigned char ressu_copyreverse(int pdepth) // 2024 JariK
{
static int reverse[MAX_DEPTH] = {0}; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned int len[MAX_DEPTH] = {0};
static unsigned int count[MAX_DEPTH] = {0};
static unsigned int low[MAX_DEPTH] = {0};
static unsigned int high[MAX_DEPTH] = {0};
static unsigned char bytes[MAX_DEPTH][257] = {0};
if(pdepth == 0) {
#ifdef DEBUG2D
int c = ressu_clock();
//fprintf(stdout,", ch2:%02x",c);
return(c);
#else
return(ressu_clock());
#endif
}
pdepth--;
// dividing clock stream into blocks
// and reversing every other block
// copy next block to bytes
if(count[pdepth] == 0) { // previous block ended
reverse[pdepth] = !reverse[pdepth];
len[pdepth] = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
//len[pdepth] = (ressuct[ressu_nonrandom() % ressuct_bytes] & 3 ) + 2; // block size
//len[pdepth] = --lens + 2; // block size
//len[pdepth] = lens++ + 2; // block size
count[pdepth] = len[pdepth];
low[pdepth] = 0;
high[pdepth] = len[pdepth];
rndbits2 += 2;
#ifdef DEBUG2A
fprintf(stdout,"\nblk:");
fprintf(stdout," depth:%d", pdepth);
fprintf(stdout,", reverse:%d", reverse[pdepth]);
fprintf(stdout,", len:%d", len[pdepth]);
fprintf(stdout,", count:%d", count[pdepth]);
fprintf(stdout,", low:%d", low[pdepth]);
fprintf(stdout,", high:%d", high[pdepth]);
fflush(stdout);
#endif
for(int c = 0; c < len[pdepth]; c++) {
bytes[pdepth][c] = ressu_copyreverse(pdepth); // block bytes
#ifdef DEBUG2A
fprintf(stdout,", b%d:%02x", pdepth, bytes[pdepth][c]);
newressu_output = 1;
#endif
}
}
if(reverse[pdepth]) { // reverse
// get reversed byte to return
ch = bytes[pdepth][--high[pdepth]]; // reverse
#ifdef DEBUG2E
fprintf(stdout,", rev%d:%02x", pdepth, ch);
fflush(stdout);
#endif
--count[pdepth];
} else { // copy
// get copied byte to return
ch = bytes[pdepth][low[pdepth]++]; // copy
#ifdef DEBUG2E
fprintf(stdout,", copy%d:%02x", pdepth, ch);
fflush(stdout);
#endif
--count[pdepth];
}
return(ch);
}
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
if(copyreverse) {
ch = ressu_copyreverse(depth);
} else {
ch = ressu_clock();
} // end of if(copyreverse)
#ifdef DEBUG2F
static unsigned int cols = 0;
if(cols % 32 == 0) {
if(cols > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05u ",cols);
newressu_output = 1;
}
if(cols % 4 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x",ch);
newressu_output = 1;
cols++;
#endif
// statistics for theoretical
// random bits calculation (rndbits?)
static int prevbyte = -1, clockcount = 0;
if(prevbyte == -1)
prevbyte = ch;
if(prevbyte != ch) {
periods[clockcount]++;
clockbytes += clockcount;
#ifdef DEBUG2B
fprintf(stdout," %d", clockcount);
newressu_output = 1;
#endif
if((ch & 1) != (prevbyte & 1))
rndbits20++;
if((ch & 2) != (prevbyte & 2))
rndbits21++;
if((ch & 4) != (prevbyte & 4))
rndbits22++;
clockcount = 0;
prevbyte = ch;
}
clockcount++;
return(ch);
}
#define RR8(byte, bits) ( ((byte) >> (bits)) | ((byte) << (8 - (bits))) )
#define RL8(byte, bits) ( ((byte) >> (8 - (bits))) | ((byte) << (bits)) )
#define aDEBUG5A 2
#define aDEBUG5B 2
#define aDEBUG5C 2
#define aLOWCLOCKBITONLY 2 // off by default
void ressu_genbytes_single_do(int size, unsigned char *buffer) // JariK 2013
{
int c, d;
unsigned char e;
static int f = 0;
for(c = 0; c < 8; c++) {
for(d = 0; d < size; d++) { // shift and xor
e = buffer[d];
e = RL8(e, 1); // rotate byte left 1 bits
//e = RL8(e, 3); // rotate byte left 3 bits
//e = RR8(e, 1); // rotate byte right 1 bits
#ifdef LOWCLOCKBITONLY
buffer[d] = e ^ (ressu_clockbyte() & 1);
#else
buffer[d] = e ^ ressu_clockbyte();
#endif
}
#ifdef DEBUG5A
if(newressu_output)
fprintf(stdout, "\n");
ressu_dump("ressu 1", 32, buffer, 32); // first 32 bytes
fflush(stdout);
#endif
for(d = 0; d < size; d++) { // swap
#ifdef DEBUG5B
fprintf(stdout,"d:%d", d);
fprintf(stdout,", f:%d", f);
fprintf(stdout,", bufferd:%d", buffer[d]);
fprintf(stdout,", bufferf:%d", buffer[f]);
fprintf(stdout,"\n");
#endif
f = (f + buffer[d] + 2) % size; // + 2 JariK 2022
e = buffer[d];
buffer[d] = buffer[f];
buffer[f] = e;
}
#ifdef DEBUG5A
if(newressu_output)
fprintf(stdout,"\n");
ressu_dump("ressu 2", 32, buffer, 32); // first 32 bytes
fflush(stdout);
#endif
#ifdef DEBUG5C
fprintf(stdout,"\n");
ressu_dump("ressu 3", size, buffer, 32); // whole buffer
fflush(stdout);
#endif
}
}
void ressu_genbytes_single(int size, unsigned char *buffer)
{
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
cblocks = 0;
ressu_genbytes_single_do(size, buffer);
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:1");
long chains = 0;
for(int e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
#ifdef DEBUG7
ressu_dump("single", size, buffer, 32);
#endif
genbytes += size;
}
void ressu_genbytes_fast(int size, unsigned char *buffer)
{
int d, e, f;
ressuct = buffer; // ressu random buffer lookup
ressuct_bytes = size;
rndbits2 = 0;
clockbytes = 0;
cblocks = 0;
for(d = 0; d < RESSU_MIN_ROUNDS ||
(copyreverse == 1 && depth > 0 && rndbits2 < ressut_bits2_needed) ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
ressu_genbytes_single_do(size, buffer);
}
//
// display statistics
//
if(stats) {
if(newressu_output == 1)
fprintf(stdout, "\n");
newressu_output = 0;
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
#ifdef DEBUG_SORTED
fprintf(stderr, ", sorted:");
int g = 0;
for(;;) {
f = -1;
for(e = 0; e < 1024; e++) {
if( (f == -1 && periods[e] > g) ||
(periods[e] > g && f > periods[e]) )
f = periods[e];
}
if(f == -1)
break;
g = f;
fprintf(stderr," %d", g);
}
#endif
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, "\n");
fflush(stderr);
}
#ifdef DEBUG7
ressu_dump("fast", size, buffer, 32);
#endif
genbytes += size;
}
#define aDEBUG3B 2
void ressu_genbytes(int size, unsigned char *buffer) // 6.5.2021 JariK
{
int c, d, e, f;
static unsigned char ressut[RESSUT_BYTES];
static int ressut_first = 1,
ressut_pos = 0;
unsigned long prevperiods[1024];
ressuct = ressut; // ressu random buffer lookup
ressuct_bytes = ressut_bytes; // table used in ressu_genbytes_single_do
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;
}
rndbits1 = 0;
rndbits2 = 0;
rndbits3 = 0;
rndbits4 = 0;
rndbits5 = 0;
rndbits6 = 0;
rndbits7 = 0;
rndbits20 = 0;
rndbits21 = 0;
rndbits22 = 0;
cblocks = 0;
int lim, lim1 = 0, lim2 = 0;
int lim1a, lim1b;
int high1, high2;
int rndbits3high;
int rndbits4highdigits;
int rndbits6high;
int rndbits6pos;
int rndbits7high;
for(d = 0;
rndbits1 < ressut_bits1_needed ||
(copyreverse == 1 && depth > 0 && rndbits2 < ressut_bits2_needed) ||
rndbits3 < ressut_bits3_needed ||
rndbits4 < ressut_bits4_needed ||
rndbits5 < ressut_bits5_needed ||
rndbits6 < ressut_bits6_needed ||
rndbits7 < ressut_bits7_needed ||
rndbits20 < ressut_bits20_needed ||
rndbits21 < ressut_bits21_needed ||
d < RESSU_MIN_ROUNDS ||
clockbytes < RESSU_MIN_CLOCKBYTES; d++) {
#define aDEBUG6 2
//
// calculate rndbits1
//
// save previous round
for(e = 0; e < 1024; e++) {
prevperiods[e] = periods[e];
}
ressu_genbytes_single_do(ressut_bytes, ressut);
// find new lim1
lim = lim1;
f = -1;
for(e = 0; e < 1024; e++) {
if(prevperiods[e] > 0 && prevperiods[e] == lim) {
if(f == -1 || (periods[e]>0 && f<periods[e])) {
f = periods[e];
}
}
}
if(f != -1)
lim = f;
lim1a = lim;
// find highest amount of chains
high1 = -1;
for(e = 0; e < 1024; e++) {
if(high1 == -1 || high1 < periods[e]) {
high1 = periods[e];
}
}
// and second highest
high2 = -1;
for(e = 0; e < 1024; e++) {
if( (high2 == -1 && periods[e] < high1) ||
(high2 < periods[e] && periods[e] < high1) ) {
high2 = periods[e];
}
}
// and average
int psum = 0;
int pcnt = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
psum += periods[e];
pcnt++;
}
}
lim1b = (int)((double)psum / pcnt);
// find next smaller than average
f = -1;
for(e = 0; e < 1024; e++) {
if( (f == -1 && periods[e] < lim1b) ||
(f < periods[e] && periods[e] < lim1b) ) {
f = periods[e];
}
}
if(f != -1)
lim1b = f;
if(lim == 0 || lim > lim1b)
lim = lim1b;
// if lim greater that second highest,
// set to second highest
if(lim > high2) {
lim = high2;
}
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;
// calculate rndbits1
#define aDEBUG14A 2
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
}
}
//
// calculate rndbits3
//
#define aDEBUG14C 2
rndbits3high = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high < periods[e])
rndbits3high = periods[e];
}
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e]) {
rndbits3 += periods[e];
}
}
//
// calculate rndbits4
//
#define aDEBUG14D 2
rndbits4highdigits = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits < (int)log10((double)periods[e]) + 1) {
rndbits4highdigits = (int)log10((double)periods[e]) + 1;
}
}
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1) {
rndbits4 += periods[e];
}
}
//
// calculate rndbits5
//
#define aDEBUG14E 2
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
rndbits5 += periods[e];
}
//
// calculate rndbits6
//
#define aDEBUG14F 2
rndbits6high = 0;
rndbits6pos = 0;
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high < periods[e]) {
rndbits6high = periods[e];
rndbits6pos = e;
}
}
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] && periods[e] > 0) {
if(rndbits6pos > e)
rndbits6 += log2((double)rndbits6pos - e) * periods[e];
else
rndbits6 += log2((double)e - rndbits6pos) * periods[e];
}
}
//
// calculate rndbits7
//
#define aDEBUG14G 2
rndbits7high = 0;
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high < periods[e])
rndbits7high = periods[e];
}
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] && periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
}
}
} // for(d = 0;
//
// debug display for rndbits1
//
#ifdef DEBUG14A
rndbits1 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0 && periods[e] < lim) {
rndbits1 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits1+prev:%d", rndbits1);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits3
//
#ifdef DEBUG14C
rndbits3 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits3high > periods[e] &&
periods[e] > 0) {
rndbits3 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits3+prev:%d", rndbits3);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits4
//
#ifdef DEBUG14D
rndbits4 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits4highdigits > (int)log10((double)periods[e]) + 1 &&
periods[e] > 0) {
rndbits4 += periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", rndbits4+prev:%d", rndbits4);
fprintf(stderr,"\n");
}
}
#endif
//
// debug display for rndbits5
//
#ifdef DEBUG14E
rndbits5 = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
rndbits5 += periods[e];
fprintf(stderr,", rndbits5+prev:%d", rndbits5);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits6
//
#ifdef DEBUG14F
rndbits6 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits6high > periods[e] &&
periods[e] > 0) {
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%lu", periods[e]);
double l2;
if(rndbits6pos > e) {
fprintf(stderr,", pos-e:%d", rndbits6pos - e);
l2 = log2((double)rndbits6pos - e);
} else {
fprintf(stderr,", e-pos:%d", e - rndbits6pos);
l2 = log2((double)e - rndbits6pos);
}
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
rndbits6 += l2 * periods[e];
fprintf(stderr,", rndbits6+prev:%d", rndbits6);
fprintf(stderr,"\n");
}
}
#endif
//
// debug diplay for rndbits7
//
#ifdef DEBUG14G
rndbits7 = 0;
for(e = 0; e < 1024; e++) {
if(rndbits7high > periods[e] &&
periods[e] > 0) {
rndbits7 += log2((double)rndbits7high - periods[e]) * periods[e];
fprintf(stderr,"e:%d", e);
fprintf(stderr,", periods:%ld", periods[e]);
fprintf(stderr,", high-prev:%ld", rndbits7high-periods[e]);
double l2=log2((double)rndbits7high-periods[e]);
fprintf(stderr,", log2(prev):%f", l2);
fprintf(stderr,", periods*prev:%ld", (long int) ((double)periods[e] * l2));
fprintf(stderr,", rndbits7+prev:%d", rndbits7);
fprintf(stderr,"\n");
}
}
#endif
if(stats) {
if(newressu_output == 1)
fprintf(stderr,"\n");
newressu_output = 0;
//
// display statistics
//
fprintf(stderr, "rounds:%d", d);
long chains = 0;
for(e = 0; e < 1024; e++) {
if(periods[e] > 0) {
fprintf(stderr, " %d:%lu", e, periods[e]);
chains += periods[e];
}
}
fprintf(stderr, ", chains:%ld", chains);
fprintf(stderr, ", blocks:%ld", cblocks);
#ifdef DEBUG_SORTED
fprintf(stderr, ", sorted:");
int g = 0;
for(;;) {
f = -1;
for(e = 0; e < 1024; e++) {
if( (f == -1 && periods[e] > g) ||
(periods[e] > g && f > periods[e]) )
f = periods[e];
}
if(f == -1)
break;
g = f;
fprintf(stderr," %d", g);
}
#endif
fprintf(stderr, ", ressut size:%d", ressut_bytes);
fprintf(stderr, ", high1:%d", high1);
fprintf(stderr, ", high2:%d", high2);
fprintf(stderr, ", lim1a:%d", lim1a);
fprintf(stderr, ", lim1b:%d", lim1b);
fprintf(stderr, ", lim1:%d", lim1);
fprintf(stderr, ", lim2:%d", lim2);
fprintf(stderr, ", div:%f", (double)lim2 / lim1);
fprintf(stderr, ", clockbytes:%ld", clockbytes);
fprintf(stderr, ", rndbits1:%d", rndbits1);
fprintf(stderr, ", rndbits2:%d", rndbits2);
fprintf(stderr, ", rndbits3high:%d", rndbits3high);
fprintf(stderr, ", rndbits3:%d", rndbits3);
fprintf(stderr, ", rndbits4highdigits:%d", rndbits4highdigits);
fprintf(stderr, ", rndbits4:%d", rndbits4);
fprintf(stderr, ", rndbits5:%d", rndbits5);
fprintf(stderr, ", rndbits6high:%d", rndbits6high);
fprintf(stderr, ", rndbits6:%d", rndbits6);
fprintf(stderr, ", rndbits7high:%d", rndbits7high);
fprintf(stderr, ", rndbits7:%d", rndbits7);
fprintf(stderr, ", rndbits20:%d", rndbits20);
fprintf(stderr, ", rndbits21:%d", rndbits21);
fprintf(stderr, ", rndbits22:%d", rndbits22);
fprintf(stderr, ", 20-21:%d", rndbits20 - rndbits21);
fprintf(stderr, ", 21-22:%d", rndbits21 - rndbits22);
fprintf(stderr, "\n");
fflush(stderr);
} // if(stats
} // if(ressut_pos == 0)
buffer[c] ^= ressut[ressut_pos];
ressut_pos = (ressut_pos + 1) % ressut_bytes;
#ifdef OLD1
ressut_f = (ressut_f + ressut[ressut_pos] + 2) % ressut_bytes; // bad for randomness... JariK 2023
buffer[c] ^= ressut[ressut_f];
ressut_pos = (ressut_pos + 1) % ressut_bytes;
#endif
} // for(c = 0; c < size; c++)
if(verbose) {
fprintf(stdout,"ressu ");
for(c = 0; c < size; c++) {
if(c > 0 && c % 32 == 0)
fprintf(stdout," ");
fprintf(stdout,"%02x", buffer[c]);
newressu_output = 1;
}
fprintf(stdout,"\n");
}
#ifdef DEBUG7
ressu_dump("genbytes", size, buffer, 32);
#endif
genbytes += size;
}
#define aDEBUG20 2
unsigned char cvar[16];
int cvarsize = 0;
void inccvar()
{
int c;
/* 16 bytes, LSB first */
for(c = 0; ++cvar[c] == 0 && c < sizeof(cvar) - 1; c++);
if(cvarsize < c)
cvarsize = c;
#ifdef DEBUG20
ressu_dump("cvar", cvarsize + 1, cvar, 32);
#endif
}
#define aCVARRANDOMSTART 2 // off by default
void clearcvar()
{
int c;
cvarsize = 0;
for(c = 0; c < sizeof(cvar); c++)
cvar[c] = 0;
#ifdef CVARRANDOMSTART
ressu_genbytes(8, (unsigned char *)&cvar);
#endif
for(c = 0; c < sizeof(cvar); c++)
if(cvar[c] != 0)
cvarsize = c;
}
#ifdef SHA256
#define PSEUDORESSU_LIMIT 1048576 // limit between rekeys
#define TOPUP_BYTES 32*1024 // bytes between topups
#define TOPUP_SIZE 32 // topup size in bytes (32 bytes, 256 bits)
#define aTOPUP_TWICE 2 // off by default
unsigned long topup_bytes = TOPUP_BYTES;
static unsigned char pseudoressu_key[HashLen]; // 32 bytes, 256 bits
static void pseudoressu_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
static void pseudoressu_addrandomness(int size, unsigned char *buffer)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, pseudoressu_key, sizeof(pseudoressu_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashUpdate(&hash, buffer, size);
HashFinal(pseudoressu_key, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
#define aDEBUG23 2
static void pseudoressu_topup()
{
unsigned char topup[TOPUP_SIZE]; // 32 bytes, 256 bits
ressu_genbytes(sizeof(topup), topup);
#ifdef DEBUG23
ressu_dump("topup", sizeof(topup), topup, 32);
#endif
pseudoressu_addrandomness(sizeof(topup), topup);
memset(&topup, 0, sizeof(topup)); // forget topup
}
void pseudoressu_bytes(int size, unsigned char *buffer) // JariK 2022
{
unsigned int n, blockbytes = 0;
unsigned char digest[HashLen]; // 32 bytes, 256 bits
static unsigned int initneeded = 1, topup_counter = 0;
if(verbose)
fprintf(stdout,"pseudoressu");
while(size > 0) {
if(topup_counter == 0) {
if(initneeded) {
ressu_genbytes(sizeof(pseudoressu_key), pseudoressu_key); // set first key
#ifdef DEBUG23
ressu_dump("first key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
initneeded = 0;
}
pseudoressu_topup(); // add randomness to key
#ifdef TOPUP_TWICE
pseudoressu_topup(); // add randomness to key
#endif
topup_counter = topup_bytes;
blockbytes = 0;
} // end of if(topup_counter <= 0
pseudoressu_internalbytes(digest); // get random bits using the key
// n = smallest from size, digest and topup_counter
n = (size < sizeof(digest) ? size : sizeof(digest));
n = (topup_counter < n ? topup_counter : n);
//fprintf(stderr,", n:%d",n);
for(int c = 0; c < n; c++)
buffer[c] ^= digest[c];
#ifdef DEBUG23
ressu_dump("newdata", n, buffer, 32);
#endif
if(verbose) {
fprintf(stdout," ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
newressu_output = 1;
}
buffer += n;
size -= n;
topup_counter -= n;
blockbytes += n;
if(blockbytes >= PSEUDORESSU_LIMIT && size > 0) {
pseudoressu_internalbytes(pseudoressu_key); // replace key with new random one
#ifdef DEBUG23
ressu_dump("rekey", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
blockbytes = 0;
}
} // end of while(size > 0
pseudoressu_internalbytes(pseudoressu_key); // replace key with new random one
#ifdef DEBUG23
ressu_dump("new key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
}
void ressutwist_bytes(int size, unsigned char *buffer) // JariK 2023
{
ressu_genbytes(size, buffer);
pseudoressu_bytes(size, buffer);
}
#endif // end of #ifdef SHA256
#ifdef SHA256
void dumpbin(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
if(isprint(buf[c]) && buf[c]!= ' ')
fputc(buf[c], stderr);
else
fprintf(stderr,"\\%02x", buf[c]);
}
void dumpline(FILE *fp1, int len, unsigned char *buf)
{
int c;
for(c = 0; c < len; c++)
fprintf(fp1,"%02x", buf[c]);
}
static unsigned char stream_key[HashLen]; // 32 bytes, 256 bits
static void stream_internalbytes(unsigned char *digest)
{
HashCtx hash;
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
HashFinal(digest, &hash);
memset(&hash, 0, sizeof(hash)); // forget hash
}
static int streamt_pos = 0;
void stream_bytes(int size, unsigned char *buffer) // JariK 2023
{
int c;
static unsigned char streamt[HashLen]; // 32 bytes, 256 bits
for(c = 0; c < size; c++) {
if(streamt_pos == 0) {
stream_internalbytes(streamt); // read next random bytes
stream_internalbytes(stream_key); // change key
} // end of if(streamt_pos == 0
buffer[c] = streamt[streamt_pos];
streamt_pos = (streamt_pos + 1) % sizeof(streamt);
} // end of for(c = 0; c < size; c++
}
#define STREAM_KEY_ROUNDS 4096 // should be fast enough and slow enough, now 4096
void stream_open(int size, unsigned char *key) // size = 0 --> zero terminated string
{
int c;
HashCtx hash;
clearcvar();
streamt_pos = 0;
if(size == 0)
size = strlen(key);
HashInit(&hash);
HashUpdate(&hash, key, size);
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
for(c = 0; c < STREAM_KEY_ROUNDS; c++) {
HashFinal(stream_key, &hash);
HashInit(&hash);
HashUpdate(&hash, stream_key, sizeof(stream_key));
HashUpdate(&hash, (unsigned char *) &cvar, cvarsize + 1);
inccvar();
}
HashFinal(stream_key, &hash);
#define DEBUG21 2
#ifdef DEBUG21
fflush(stdout);
fprintf(stderr,"%s: stream_open():", procname);
fprintf(stderr," randomness from key, key=");
dumpbin(stderr, size, key);
fprintf(stderr,"\n");
fflush(stderr);
#endif
memset(&hash, 0, sizeof(hash)); // forget hash
}
#endif // end of #ifdef SHA256
void readfile_xor(int size,
unsigned char *buffer,
unsigned char *filename)
{
int c, n;
unsigned char temp[64];
FILE *fp1;
if((fp1 = fopen(filename, "rb")) == NULL) {
fprintf(stderr,"%s: fopen(): cannot open file %s\n",
procname, filename);
exit(1);
}
while(size > 0) {
n = (size < sizeof(temp)) ? size : sizeof(temp);
if(fread(temp, 1, n, fp1) < n) {
fprintf(stderr,"%s: fread(): cannot read file %s\n",
procname, filename);
exit(1);
}
for(c = 0; c < n; c++)
buffer[c] ^= temp[c];
size -= n;
buffer += n;
}
fclose(fp1);
memset(temp, 0, sizeof(temp)); // forget temp
}
static unsigned char urandomfilename[128] = "/dev/urandom";
void urandom_bytes(int size, unsigned char *buffer)
{
readfile_xor(size, buffer, urandomfilename);
}
#ifdef USE_RANDOM
static unsigned char randomfilename[128] = "/dev/random";
void random_bytes(int size, unsigned char *buffer)
{
readfile_xor(size, buffer, randomfilename);
}
#endif
void test_bytes(int size, unsigned char *buffer) // JariK 2023
{
// insert your generator here, run it with
// --test command line parameter (source for
// randomness)
ressutwist_bytes(size, buffer);
urandom_bytes(size, buffer);
//memset(buffer, 0, size);
//for(int c = 0; c < size; c++)
// buffer[c] = c & 0xff;
}
void newressu_version()
{
fprintf(stderr, "%s", programname); // touch these outside #ifdef MAIN
fprintf(stderr, ", %s", copyright);
}
#ifdef MAIN
#include <unistd.h>
#include <ctype.h>
#include <malloc.h>
#include "newressu.h"
#define SAMPLE_WRITE 2 // on by default
#define SAMPLE_HASH 2 // on by default (for now)
#define SAMPLE_SYNC 2 // on by default (for now (exfat))
#define USE_TIMER 2
#define aUSE_DUMMY 2
void command_readline(unsigned char *command, int linelen, unsigned char *line)
{
FILE *fp1;
line[0] = '\0';
if((fp1 = popen(command, "r")) == NULL) {
fprintf(stdout,"%s: popen(): cannot open process '%s'\n",
procname, command);
} else {
fgets(line, linelen, fp1);
if(line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
}
}
long long command_countlines(unsigned char *command)
{
unsigned char buffer[1024];
long long ll = 0;
FILE *fp1;
if((fp1 = popen(command, "r")) == NULL) {
fprintf(stdout,"%s: popen(): cannot open process '%s'\n",
procname, command);
} else {
while(fgets(buffer, sizeof(buffer), fp1) != NULL)
ll++;
}
return(ll);
}
#define aDEBUG25 // off by default
#define aDEBUG19 // off by default
#ifdef DEBUG19
void save_path(int path_length, unsigned char *path)
{
if((getcwd(path, path_length)) == NULL) {
fprintf(stdout,"%s: save_path(): cannot get working directory (getcwd())\n",
procname);
}
#ifdef DEBUG25
fprintf(stderr,"%s: save_path(): saved current path (getcwd()), path = %s\n",
procname, path);
#endif
}
int exists_path(unsigned char *path)
{
FILE *fp1;
if((fp1 = fopen(path, "r")) != NULL) {
fclose(fp1);
//fprintf(stderr,"path %s ok\n", path);
return(1);
} else
return(0);
}
void set_path(unsigned char *path)
{
if(chdir(path) != 0) {
fprintf(stdout,"%s: set_path(): cannot change directory (chdir())\n",
procname);
}
#ifdef DEBUG25
fprintf(stderr,"%s: set_path(): set path (chdir()), path = %s\n",
procname, path);
#endif
}
#endif // end of #ifdef DEBUG19
unsigned char *newressu_strstr(unsigned char *haystack, unsigned char *needle)
{
int nlen = strlen(needle);;
unsigned char *p = haystack;
while(*p != '\0') {
if(!strncmp(p, needle, nlen) &&
( isblank(*(p + nlen)) || ispunct(*(p + nlen)) || *(p + nlen) == '\0' ) && // character after string
( (p == haystack) || isblank(*(p - 1)) || ispunct(*(p - 1)) ) ) // character before string
return(p);
p++;
}
return(NULL);
}
#ifdef OLD1
unsigned char *newressu_strstr(unsigned char *haystack, unsigned char *needle)
{
int fl;
unsigned char *p = haystack;
while(*p != '\0') {
fl = strlen(needle);
if(!strncmp(p, needle, strlen(needle)) &&
( isblank(*(p + fl)) || ispunct(*(p + fl)) || *(p + fl) == '\0' ) && // character after string
( (p == haystack) || isblank(*(p - 1)) || ispunct(*(p - 1)) ) ) { // character before string
return(p);
}
p++;
}
return(NULL);
}
#endif
/*
* code for flags functions
*/
/*
🇦
🇧
🇨
🇩
🇪
🇫
🇬
🇭
🇮
🇯
🇰
🇱
🇲
🇳
🇴
🇵
🇶
🇷
🇸
🇹
🇺
🇻
🇼
🇽
🇾
🇿
*/
/*
🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿
*/
struct idflags { // 202307 JariK
unsigned char *id;
unsigned char *flags;
} idsflags[] = {
{ "🇫🇮", "🇫🇮: fi, fin, Finland, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC, FINLAND" },
{ "🇦🇽", "🇦🇽: ax, ala, Åland, aland, NORDIC, FINLAND" },
{ "🇸🇪", "🇸🇪: se, swe, Sweden, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇳🇴", "🇳🇴: no, nor, Norway, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇩🇰", "🇩🇰: dk, dnk, Denmark, EU, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC, DENMARK" },
{ "🇫🇴", "🇫🇴: fo, fro, FaroeIslands, NORDIC, DENMARK" },
{ "🇮🇸", "🇮🇸: is, isl, Iceland, NORTHERNEUROPE, EUROPE, EURASIA, NORDIC" },
{ "🇬🇱", "🇬🇱: gl, grl, Greenland, NORTHAMERICA, NORDIC, DENMARK" },
{ "🇪🇪", "🇪🇪: ee, est, Estonia, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇱🇻", "🇱🇻: lv, lva, Latvia, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇱🇹", "🇱🇹: lt, ltu, Lithuania, EU, NORTHERNEUROPE, EUROPE, EURASIA, BALTIC" },
{ "🇺🇦", "🇺🇦: ua, ukr, Ukraine, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇱", "🇦🇱: al, alb, Albania, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇩", "🇦🇩: ad, and, Andorra, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇲", "🇦🇲: am, arm, Armenia, EASTERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇦🇹", "🇦🇹: at, aut, Austria, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇦🇿", "🇦🇿: az, aze, Azerbaijan, EASTERNEUROPE, EUROPE, WESTASIA, ASIA, EURASIA" },
{ "🇧🇾", "🇧🇾: by, blr, Belarus, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇧🇪", "🇧🇪: be, bel, Belgium, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇧🇦", "🇧🇦: ba, bih, BosniaandHerzegovina, EASTERNEUROPE, EUROPE" }, // Bosnia and Herzegovina
{ "🇧🇬", "🇧🇬: bg, bgr, Bulgaria, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇭🇷", "🇭🇷: hr, hrv, Croatia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇨🇾", "🇨🇾: cy, cyp, Cyprus, EU, SOUTHERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇨🇿", "🇨🇿: cz, cze, CzechRepublic, EU, EASTERNEUROPE, EUROPE, EURASIA" }, // Czech Republic Czechia
{ "🇫🇷", "🇫🇷: fr, fra, France, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇬🇪", "🇬🇪: ge, geo, Georgia, EASTERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇩🇪", "🇩🇪: de, deu, Germany, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇬🇷", "🇬🇷: gr, grc, Greece, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇭🇺", "🇭🇺: hu, hun, Hungary, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇪", "🇮🇪: ie, irl, Ireland, UK, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇹", "🇮🇹: it, ita, Italy, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇻🇦", "🇻🇦: va, vat, Vatican, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇰🇿", "🇰🇿: kz, kaz, Kazakhstan, EUROPE, EURASIA, CENTRALASIA, ASIA" },
{ "🇱🇮", "🇱🇮: li, lie, Liechtenstein, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇱🇺", "🇱🇺: lu, lux, Luxembourg, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇹", "🇲🇹: mt, mlt, Malta, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇩", "🇲🇩: md, mda, Moldova, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇪", "🇲🇪: me, mne, Montenegro, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇨", "🇲🇨: mc, mco, Monaco, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇪", "🇲🇪: me, mne, Montenegro, EUROPE, EURASIA" },
{ "🇳🇱", "🇳🇱: nl, nld, Netherlands, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇲🇰", "🇲🇰: mk, mkd, Northmacedonia, EASTERNEUROPE, EUROPE, EURASIA" }, // North Macedonia
{ "🇵🇱", "🇵🇱: pl, pol, Poland, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇵🇹", "🇵🇹: pt, prt, Portugal, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇷🇴", "🇷🇴: ro, rou, Romania, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇷🇺", "🇷🇺: ru, rus, Russia, EASTERNEUROPE, EUROPE, EURASIA, NORTHASIA, ASIA, BRICS" },
{ "🇸🇲", "🇸🇲: sm, smr, SanMarino, SOUTHERNEUROPE, EUROPE, EURASIA" }, // San Marino
{ "🇷🇸", "🇷🇸: rs, srb, Serbia, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇸🇰", "🇸🇰: sk, svk, Slovakia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇸🇮", "🇸🇮: si, svn, Slovenia, EU, EASTERNEUROPE, EUROPE, EURASIA" },
{ "🇪🇸", "🇪🇸: es, esp, Spain, EU, SOUTHERNEUROPE, EUROPE, EURASIA" },
{ "🇨🇭", "🇨🇭: ch, che, Switzerland, EU, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇹🇷", "🇹🇷: tr, tur, Turkey, SOUTHERNEUROPE, EUROPE, EURASIA, WESTASIA, ASIA" },
{ "🇬🇧", "🇬🇧: gb, gbr, UnitedKingdom, UK, WESTERNEUROPE, EUROPE, EURASIA" },
{ "🇮🇪", "🇮🇪: gb, gbr, England, UK" },
{ "🇮🇪", "🇮🇪: gb, gbr, Scotland, UK" },
{ "🇮🇪", "🇮🇪: gb, gbr, Wales, UK" },
{ "🇬🇮", "🇬🇮: gi, gib, Gibraltar, UK" },
{ "🇸🇯", "🇸🇯: sj, sjm, JanMayen, NORWAY" }, // Jan Mayen
{ "🇦🇮", "🇦🇮: ai, aia, Anguilla, NORTHAMERICA, UK" },
{ "🇦🇬", "🇦🇬: ag, atg, AntiguaAndBarbuda, NORTHAMERICA" }, // Antigua and Barbuda
{ "🇦🇼", "🇦🇼: aw, sbw, Aruba, NORTHAMERICA" },
{ "🇧🇸", "🇧🇸: bs, bhs, Bahamas, NORTHAMERICA" },
{ "🇧🇧", "🇧🇧: bb, brb, Barbados, NORTHAMERICA" },
{ "🇧🇿", "🇧🇿: bz, blz, Belize, NORTHAMERICA" },
{ "🇧🇲", "🇧🇲: bm, bmu, Bermuda, UK, NORTHAMERICA" },
{ "🇧🇶", "🇧🇶: bq, bes, Bonaire, NETHERLANDS, NORTHAMERICA" },
{ "🇻🇬", "🇻🇬: vg, vgb, BritishVirginIslands, UK, NORTHAMERICA" }, // British Virgin Islands
{ "🇨🇦", "🇨🇦: ca, can, Canada, NORTHAMERICA" },
{ "🇰🇾", "🇰🇾: ky, cym, CaymanIslands, UK, NORTHAMERICA" },
{ "🇫🇷", "🇫🇷: fr, fra, ClippertonIsland, FRANCE, NORTHAMERICA" },
{ "🇨🇷", "🇨🇷: cr, cri, CostaRica, NORTHAMERICA" },
{ "🇨🇺", "🇨🇺: cu, cub, Cuba, NORTHAMERICA" },
{ "🇨🇼", "🇨🇼: cw, cuw, Curaçao, curacao, NORTHAMERICA" },
{ "🇩🇲", "🇩🇲: dm, dma, Dominica, NORTHAMERICA" },
{ "🇩🇴", "🇩🇴: do, dom, DominicanRepublic, NORTHAMERICA" }, // Dominican Republic
{ "🇸🇻", "🇸🇻: sv, slv, ElSalvador, NORTHAMERICA" },
{ "🇬🇱", "🇬🇱: gl, grl, Greenland, DENMARK, NORTHAMERICA" },
{ "🇬🇩", "🇬🇩: gd, grd, Grenada, NORTHAMERICA" },
{ "🇬🇵", "🇬🇵: gp, glp, Guadeloupe, FRANCE, NORTHAMERICA" },
{ "🇬🇹", "🇬🇹: gt, gtm, Guatemala, NORTHAMERICA" },
{ "🇭🇹", "🇭🇹: ht, hti, Haiti, NORTHAMERICA" },
{ "🇭🇳", "🇭🇳: hn, hnd, Honduras, NORTHAMERICA" },
{ "🇯🇲", "🇯🇲: jm, jam, Jamaica, NORTHAMERICA" },
{ "🇲🇶", "🇲🇶: mq, mtq, Martinique, FRANCE, NORTHAMERICA" },
{ "🇲🇽", "🇲🇽: mx, mex, Mexico, NORTHAMERICA" },
{ "🇲🇸", "🇲🇸: ms, msr, Montserrat, UK, NORTHAMERICA" },
{ "🇳🇮", "🇳🇮: ni, nic, Nicaragua, NORTHAMERICA" },
{ "🇵🇦", "🇵🇦: pa, pan, Panama, NORTHAMERICA" },
{ "🇵🇷", "🇵🇷: pr, pri, PuertoRico, NORTHAMERICA" },
{ "🇧🇶", "🇧🇶: bq, bes, Saba, NORTHAMERICA" },
{ "🇧🇱", "🇧🇱: bl, blm, SaintBarthélemy, saintbarthelemy, NORTHAMERICA" }, // Saint Barthélemy
{ "🇰🇳", "🇰🇳: kn, kna, SaintKitts, NORTHAMERICA" }, // Saint Kitts and Nevis
{ "🇱🇨", "🇱🇨: lc, lca, SaintLucia, NORTHAMERICA" }, // Saint Lucia
{ "🇲🇫", "🇲🇫: mf, maf, SaintMartin, NORTHAMERICA" }, // Collectivity of Saint Martin
{ "🇸🇽", "🇸🇽: sx, sxm, SintMaarten, NORTHAMERICA" }, // Sint Maarten
{ "🇹🇹", "🇹🇹: tt, tto, TrinidadandTobago, NORTHAMERICA" }, // Trinidad and Tobago
{ "🇹🇨", "🇹🇨: tc, tca, TurksandCaicos, UK, NORTHAMERICA" }, // Turks and Caicos Islands
{ "🇵🇲", "🇵🇲: pm, spm, SaintPierre, NORTHAMERICA" }, // Saint Pierre and Miquelon
{ "🇻🇨", "🇻🇨: vc, vct, SaintVincent, NORTHAMERICA" }, // Saint Vincent and the Grenadines
{ "🇺🇸", "🇺🇸: us, usa, UnitedStatesofAmerica, USA, NORTHAMERICA" }, // United States of America
{ "🇻🇮", "🇻🇮: vi, vir, VirginIslands, USA, NORTHAMERICA" }, // United States Virgin Islands
{ "🇧🇻", "🇧🇻: bv, bvt, BouvetIsland" }, // Bouvet Island
{ "🇺🇲", "🇺🇲: um, umi, Navassa" },
{ "🇸🇭", "🇸🇭: sh, shn, SaintHelena" }, // Saint Helena
{ "🇦🇷", "🇦🇷: ar, arg, Argentina, SOUTHAMERICA" },
{ "🇧🇴", "🇧🇴: bo, bol, Bolivia, SOUTHAMERICA" },
{ "🇧🇷", "🇧🇷: br, bra, Brazil, SOUTHAMERICA, BRICS" },
{ "🇨🇱", "🇨🇱: cl, chl, Chile, SOUTHAMERICA" },
{ "🇨🇴", "🇨🇴: co, col, Colombia, SOUTHAMERICA" },
{ "🇪🇨", "🇪🇨: ec, ecu, Ecuador, SOUTHAMERICA" },
{ "🇫🇰", "🇫🇰: fk, flk, FalklandIslands, UK, SOUTHAMERICA" }, // Falkland Islands
{ "🇬🇫", "🇬🇫: gf, guf, FrenchGuiana, SOUTHAMERICA, FRANCE" }, // French Guiana
{ "🇬🇾", "🇬🇾: gy, guy, Guyana, SOUTHAMERICA" },
{ "🇵🇾", "🇵🇾: py, pry, Paraguay, SOUTHAMERICA" },
{ "🇵🇪", "🇵🇪: pe, per, Peru, SOUTHAMERICA" },
{ "🇬🇸", "🇬🇸: gs, sgs, SouthGeorgia, SOUTHAMERICA" }, // South Georgia and the South Sandwich Islands
{ "🇸🇷", "🇸🇷: sr, sur, Suriname, SOUTHAMERICA" },
{ "🇺🇾", "🇺🇾: uy, ury, Uruguay, SOUTHAMERICA" },
{ "🇻🇪", "🇻🇪: ve, ven, Venezuela, SOUTHAMERICA" },
{ "🇦🇪", "🇦🇪: ae, are, UnitedArabEmirates, WESTASIA, ASIA, EURASIA" }, // United Arab Emirates
{ "🇦🇫", "🇦🇫: af, afg, Afghanistan, SOUTHASIA, ASIA, EURASIA" },
{ "🇧🇩", "🇧🇩: bd, bgd, Bangladesh, SOUTHASIA, ASIA, EURASIA" },
{ "🇧🇭", "🇧🇭: bh, bhr, Bahrain, EASTASIA, ASIA, EURASIA" },
{ "🇧🇳", "🇧🇳: bn, brn, Brunei, ASIA, EURASIA" },
{ "🇧🇹", "🇧🇹: bt, btn, Bhutan, SOUTHASIA, ASIA, EURASIA" },
{ "🇨🇳", "🇨🇳: cn, chn, China, EASTASIA, ASIA, EURASIA, BRICS" },
{ "🇭🇰", "🇭🇰: hk, hkg, HongKong, EASTASIA, ASIA, EURASIA" },
{ "🇮🇩", "🇮🇩: id, idn, Indonesia, ASIA, EURASIA" },
{ "🇮🇱", "🇮🇱: il, isr, Israel, WESTASIA, ASIA, EURASIA" },
{ "🇮🇳", "🇮🇳: in, ind, India, SOUTHASIA, ASIA, EURASIA, BRICS" },
{ "🇮🇶", "🇮🇶: iq, irq, Iraq, WESTASIA, ASIA, EURASIA" },
{ "🇮🇷", "🇮🇷: ir, irn, Iran, WESTASIA, ASIA, EURASIA" },
{ "🇯🇴", "🇯🇴: jo, jor, Jordan, WESTASIA, ASIA, EURASIA" },
{ "🇯🇵", "🇯🇵: jp, jpn, Japan, EASTASIA, ASIA, EURASIA" },
{ "🇰🇬", "🇰🇬: kg, kgz, Kyrgyzstan, CENTRALASIA, ASIA, EURASIA" },
{ "🇰🇭", "🇰🇭: kh, khm, Cambodia, ASIA, EURASIA" },
{ "🇰🇷", "🇰🇷: kr, kor, SouthKorea, EASTASIA, ASIA, EURASIA" },
{ "🇰🇼", "🇰🇼: kw, kwt, Kuwait, WESTASIA, ASIA, EURASIA" },
{ "🇱🇦", "🇱🇦: la, lao, Laos, ASIA, EURASIA" },
{ "🇱🇧", "🇱🇧: lb, lbn, Lebanon, WESTASIA, ASIA, EURASIA" },
{ "🇱🇰", "🇱🇰: lk, lka, SriLanka, SOUTHASIA, ASIA, EURASIA" },
{ "🇲🇳", "🇲🇳: mn, mng, Mongolia, EASTASIA, ASIA, EURASIA" },
{ "🇲🇴", "🇲🇴: mo, mac, Macao, EASTASIA, ASIA, EURASIA" },
{ "🇲🇻", "🇲🇻: mv, mdv, Maldives, SOUTHASIA, ASIA, EURASIA" },
{ "🇲🇲", "🇲🇲: mm, mmr, Myanmar, ASIA, EURASIA" },
{ "🇲🇾", "🇲🇾: my, mys, Malaysia, ASIA, EURASIA" },
{ "🇰🇵", "🇰🇵: kp, prk, NorthKorea, EASTASIA, ASIA, EURASIA" },
{ "🇳🇵", "🇳🇵: np, npl, Nepal, SOUTHASIA, ASIA, EURASIA" },
{ "🇴🇲", "🇴🇲: om, omn, Oman, WESTASIA, ASIA, EURASIA" },
{ "🇵🇭", "🇵🇭: ph, phl, Philippines, ASIA, EURASIA" },
{ "🇵🇰", "🇵🇰: pk, pak, Pakistan, SOUTHASIA, ASIA, EURASIA" },
{ "🇵🇸", "🇵🇸: ps, pse, Palestine, WESTASIA, ASIA, EURASIA" },
{ "🇶🇦", "🇶🇦: qa, qat, Qatar, WESTASIA, ASIA, EURASIA" },
{ "🇸🇦", "🇸🇦: sa, sau, SaudiArabia, WESTASIA, ASIA, EURASIA" },
{ "🇸🇬", "🇸🇬: sg, sgb, Singapore, ASIA, EURASIA" },
{ "🇸🇾", "🇸🇾: sy, syr, Syria, WESTASIA, ASIA, EURASIA" },
{ "🇹🇭", "🇹🇭: th, tha, Thailand, ASIA, EURASIA" },
{ "🇹🇯", "🇹🇯: tj, tjk, Tajikistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇹🇱", "🇹🇱: tl, tls, EastTimor, ASIA, EURASIA" },
{ "🇹🇲", "🇹🇲: tm, tkm, Turkmenistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇹🇼", "🇹🇼: tw, twn, Taiwan, EASTASIA, ASIA, EURASIA" },
{ "🇺🇿", "🇺🇿: uz, uzb, Uzbekistan, CENTRALASIA, ASIA, EURASIA" },
{ "🇻🇳", "🇻🇳: vn, vnm, Vietnam, ASIA, EURASIA" },
{ "🇾🇪", "🇾🇪: ye, yem, Yemen, WESTASIA, ASIA, EURASIA" },
{ "🇳🇪", "🇳🇪: ne, ner, Nigeria, AFRICA, WESTAFRICA" },
{ "🇪🇹", "🇪🇹: et, eth, Ethiopia, AFRICA, AFRICA, EASTAFRICA" },
{ "🇪🇷", "🇪🇷: er, eri, Eritrea, AFRICA, EASTAFRICA" },
{ "🇨🇬", "🇨🇬: cg, cog, Congo, AFRICA, CENTRALAFRICA" }, // Rebublic of the Congo
{ "🇨🇩", "🇨🇩: cd, cod, DemocraticCongo, AFRICA, CENTRALAFRICA" }, // Democratic Rebublic of the Congo
{ "🇹🇿", "🇹🇿: tz, tza, Tanzania, AFRICA, EASTAFRICA" },
{ "🇿🇦", "🇿🇦: za, zaf, SouthAfrica, AFRICA, SOUTHAFRICA, BRICS" },
{ "🇰🇪", "🇰🇪: ke, ken, Kenya, AFRICA, EASTAFRICA" },
{ "🇺🇬", "🇺🇬: ug, uga, Uganda, AFRICA, EASTAFRICA" },
{ "🇸🇸", "🇸🇸: ss, ssd, SouthSudan, AFRICA, EASTAFRICA" },
{ "🇸🇩", "🇸🇩: sd, sdn, Sudan, AFRICA, EASTAFRICA" },
{ "🇩🇿", "🇩🇿: dz, dza, Algeria, AFRICA, NORTHAFRICA" },
{ "🇪🇬", "🇪🇬: eg, egy, Egypt, AFRICA, NORTHAFRICA, WESTASIA, ASIA, EURASIA" },
{ "🇱🇾", "🇱🇾: ly, lby, Libya, AFRICA, NORTHAFRICA" },
{ "🇱🇾", "🇱🇾: ly, lby, Madeira, AFRICA, NORTHAFRICA" },
{ "🇲🇦", "🇲🇦: ma, mar, Morocco, AFRICA, NORTHAFRICA" },
{ "🇦🇴", "🇦🇴: ao, ago, Angola, AFRICA, CENTRALAFRICA" },
{ "🇬🇭", "🇬🇭: gh, gha, Ghana, AFRICA, WESTAFRICA" },
{ "🇲🇿", "🇲🇿: mz, moz, Mozambique, AFRICA" },
{ "🇲🇬", "🇲🇬: mg, mdg, Madagascar, AFRICA, EASTAFRICA" },
{ "🇾🇹", "🇾🇹: yt, myt, Mayotte, FRANCE, AFRICA, EASTAFRICA" },
{ "🇨🇮", "🇨🇮: ci, civ, IvoryCoast, AFRICA, WESTAFRICA" },
{ "🇨🇲", "🇨🇲: cm, cmr, Cameroon, AFRICA, CENTRALAFRICA" },
{ "🇳🇪", "🇳🇪: ne, ner, Niger, AFRICA, WESTAFRICA" },
{ "🇧🇫", "🇧🇫: bf, bfa, BurkinaFaso, AFRICA, WESTAFRICA" }, // Burkina Faso
{ "🇲🇱", "🇲🇱: ml, mli, Mali, AFRICA, WESTAFRICA" },
{ "🇲🇼", "🇲🇼: mw, mwi, Malawi, AFRICA, EASTAFRICA" },
{ "🇿🇲", "🇿🇲: zm, zmb, Zambia, AFRICA, EASTAFRICA" },
{ "🇹🇩", "🇹🇩: td, tcd, Chad, AFRICA, CENTRALAFRICA" },
{ "🇸🇴", "🇸🇴: so, som, Somalia, AFRICA, EASTAFRICA" },
{ "🇸🇳", "🇸🇳: sn, sen, Senegal, AFRICA, WESTAFRICA" },
{ "🇿🇼", "🇿🇼: zw, zwe, Zimbabwe, AFRICA, EASTAFRICA" },
{ "🇬🇳", "🇬🇳: gn, gin, Guinea, AFRICA, WESTAFRICA" },
{ "🇷🇪", "🇷🇪: re, reu, Réunion, reunion, FRANCE, AFRICA, EASTAFRICA" }, // Réunion
{ "🇷🇼", "🇷🇼: rw, rwa, Rwanda, AFRICA, EASTAFRICA" },
{ "🇧🇯", "🇧🇯: bj, ben, Benin, AFRICA, WESTAFRICA" },
{ "🇧🇮", "🇧🇮: bi, bdi, Burundi, AFRICA, EASTAFRICA" },
{ "🇹🇳", "🇹🇳: tn, tun, Tunisia, AFRICA, NORTHAFRICA" },
{ "🇹🇬", "🇹🇬: tg, tgo, Togo, AFRICA, WESTAFRICA" },
{ "🇸🇱", "🇸🇱: sl, sle, SierraLeone, AFRICA, WESTAFRICA" }, // Sierra Leone
{ "🇨🇩", "🇨🇩: cd, cod, Congo, AFRICA, CENTRALAFRICA" },
{ "🇨🇫", "🇨🇫: cf, caf, CentralAfrican, CENTRALAFRICA" }, // Central African Republic
{ "🇱🇷", "🇱🇷: lr, lbr, Liberia, AFRICA, WESTAFRICA" },
{ "🇲🇷", "🇲🇷: mr, mrt, Mauritania, AFRICA, WESTAFRICA" },
{ "🇪🇷", "🇪🇷: er, eri, Eritrea, AFRICA, EASTAFRICA" },
{ "🇬🇲", "🇬🇲: gm, gmb, Gambia, AFRICA, WESTAFRICA" },
{ "🇧🇼", "🇧🇼: bw, bwa, Botswana, AFRICA, SOUTHAFRICA" },
{ "🇳🇦", "🇳🇦: na, nam, Namibia, AFRICA, SOUTHAFRICA" },
{ "🇬🇦", "🇬🇦: ga, gab, Gabon, AFRICA, CENTRALAFRICA" },
{ "🇱🇸", "🇱🇸: ls, lso, Lesotho, AFRICA, SOUTHAFRICA" },
{ "🇬🇼", "🇬🇼: gw, gnb, GuineaBissau, AFRICA, WESTAFRICA" }, // Guinea-Bissau
{ "🇬🇶", "🇬🇶: gq, gnq, EquatorialGuinea, CENTRALAFRICA" }, // Equatorial Guinea
{ "🇲🇺", "🇲🇺: mu, mus, Mauritius, AFRICA, EASTAFRICA" },
{ "🇲🇺", "🇲🇺: mz, moz, Mozambique, AFRICA, EASTAFRICA" },
{ "🇸🇿", "🇸🇿: sz, swz, Eswatini, AFRICA, SOUTHAFRICA" },
{ "🇩🇯", "🇩🇯: dj, dji, Djibouti, AFRICA, EASTAFRICA" },
{ "🇰🇲", "🇰🇲: km, com, Comoros, AFRICA" },
{ "🇨🇻", "🇨🇻: cv, cpv, CapeVerde, AFRICA, WESTAFRICA" },
{ "🇪🇭", "🇪🇭: eh, esh, WesternSahara, SPAIN, AFRICA, NORTHAFRICA" }, // Western Sahara
{ "🇸🇹", "🇸🇹: st, stp, SãoToméandPríncipe, saotomeandprincipe, CENTRALAFRICA" }, // São Tomé and Príncipe
{ "🇸🇨", "🇸🇨: sc, syc, Seychelles, AFRICA, EASTAFRICA" },
{ "🇸🇭", "🇸🇭: sh, shn, TristandaCunha, UK" }, // Tristan da Cunha
{ "🇦🇺", "🇦🇺: au, aus, Australia, AUSTRALASIA, OCEANIA" },
{ "🇨🇽", "🇨🇽: cx, cxr, Christmasisland, AUSTRALIA" }, // Christmas Island
{ "🇨🇨", "🇨🇨: cc, cck, CocosIslands, AUSTRALIA" }, // Cocos (Keeling) Islands
{ "🇮🇲", "🇮🇲: im, imn, ManIsle, UK" }, // Isle of Man
{ "🇰🇮", "🇰🇮: ki, kir, Kiribati, MICRONESIA, OCEANIA" },
{ "🇳🇷", "🇳🇷: nr, nru, Nauru, MICRONESIA, OCEANIA" },
{ "🇳🇨", "🇳🇨: nc, ncl, NewCaledonia, FRANCE, OCEANIA" }, // New Caledonia
{ "🇫🇯", "🇫🇯: fj, fji, Fiji, MELANESIA, OCEANIA" },
{ "🇫🇲", "🇫🇲: fm, fsm, Micronesia, MICRONESIA, OCEANIA" },
{ "🇵🇬", "🇵🇬: pg, png, PapuanewGuinea, MELANESIA, OCEANIA" }, // Papua New Guinea
{ "🇻🇺", "🇻🇺: vu, vut, Vanuatu, MELANESIA, OCEANIA" },
{ "🇸🇧", "🇸🇧: sb, slb, SolomonIslands, MELANESIA, OCEANIA" }, // Solomon Islands
{ "🇬🇺", "🇬🇺: gu, gum, Guam, USA, MICRONESIA, OCEANIA" },
{ "🇲🇭", "🇲🇭: mh, mhl, MarshallIslands, MICRONESIA, OCEANIA" }, // Marshall Islands
{ "🇲🇵", "🇲🇵: mp, mnp, NorthernMariana, MICRONESIA, OCEANIA" }, // Northern Mariana Islands
{ "🇵🇫", "🇵🇫: pf, pyf, FrenchPolynesia, FRANCE, POLYNESIA, OCEANIA" }, // French Polynesia
{ "🇼🇸", "🇼🇸: ws, wsm, Samoa, POLYNESIA, OCEANIA" },
{ "🇼🇫", "🇼🇫: wf, wlf, WallisandFutuna, FRANCE, OCEANIA" }, // Wallis and Futuna
{ "🇹🇻", "🇹🇻: tv, tuv, Tuvalu, OCEANIA" },
{ "🇦🇸", "🇦🇸: as, asm, Americansamoa, USA, POLYNESIA, OCEANIA" }, // American Samoa
{ "🇵🇳", "🇵🇳: pn, pcn, Pitcairn, UK, POLYNESIA, OCEANIA" }, // Pitcairn Islands
{ "🇵🇼", "🇵🇼: pw, plw, Palau, MICRONESIA, OCEANIA" },
{ "🇯🇪", "🇯🇪: je, jey, Jersey, FRANCE" },
{ "🇦🇶", "🇦🇶: aq, ata, Antarctica, ANTARCTICA" },
{ "🇳🇫", "🇳🇫: nf, nfk, NorFolkIsland, AUSTRALASIA, POLYNESIA, OCEANIA" }, // Norfolk Island
{ "🇨🇰", "🇨🇰: ck, cok, Cookisland, NEWZEALAND, POLYNESIA, OCEANIA" }, // Cook Islands
{ "🇳🇿", "🇳🇿: nz, nzl, NewZealand, NEWZEALAND, AUSTRALASIA, OCEANIA" }, // New Zealand
{ "🇳🇺", "🇳🇺: nu, niu, Niue, NEWZEALAND, POLYNESIA, OCEANIA" },
{ "🇹🇰", "🇹🇰: tk, tkl, Tokelau, NEWZEALAND, POLYNESIA, OCEANIA" },
{ "🇹🇴", "🇹🇴: to, ton, Tonga, POLYNESIA, OCEANIA" },
// still missing
{ "🇮🇴", "🇮🇴: io, iot, BritishIndianOcean" }, // British Indian Ocean Territory
{ "🇹🇫", "🇹🇫: tf, atf, FrenchSouthernandaAtarctic" }, // French Southern and Antarctic Lands
{ "🇬🇬", "🇬🇬: gg, ggy, Guernsey, GUERNSEY" },
{ "🇭🇲", "🇭🇲: hm, hmd, HeardandMacDonaldsIslands" }, // Heard Island and McDonald Islands
{ "🇺🇲", "🇺🇲: um, umi, UsMinorOutlyingIslands, US" }, // United States Minor Outlying Islands
};
/*
* flags changed
*/
static int flagidflags = 0; // dont display ids
static int idsall = 1;
/*
* flag for each id
*/
static char flagids[sizeof(idsflags) / sizeof(idsflags[0])];
int newressu_toggleflag(unsigned char *flag)
{
int c, ok;
if(!strcmp(flag, "ALL")) {
idsall = !idsall;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
flagids[c] = idsall;
}
flagidflags = 1; // display flags
ok = 1; // one flag toggled
} else {
ok = 0;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
if(newressu_strstr(idsflags[c].flags, flag)!=NULL) {
flagids[c] = !flagids[c];
flagidflags = 1; // display flags
ok = 1; // one flag toggled
}
}
//if(ok)
// fprintf(stdout,"\n");
}
return(ok);
}
#ifdef FORT
#include "fort.h"
#endif
void clock_bytes(int size, unsigned char *buffer) // JariK 2024
{
int c;
for(c = 0; c < size; c++)
buffer[c] = ressu_clock();
}
static unsigned char samplefilename[128] = "newressusample%d.rnd";
int input = INPUT_RESSU;
unsigned char *input_str = "ressu";
int base = -1;
static unsigned char gent[GENT_SIZE]; // orig 1024
static unsigned int gent_pos = 0;
void gent_clear()
{
memset(gent, 0, sizeof(gent));
}
#define aDEBUG18 2
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
#ifdef DEBUG23
ressu_dump("oldgent", 32, gent, 32); // first 32 bytes
#endif
gent_clear();
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(sizeof(gent), gent);
#ifdef SHA256
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(sizeof(gent), gent);
#endif
#ifdef SHA256
else if(input == INPUT_RESSUTWIST) // ressu w twist
ressutwist_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_FASTRESSU) // ressu_fast
ressu_genbytes_fast(sizeof(gent), gent);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(sizeof(gent), gent);
else if(input == INPUT_STREAM) // stream
stream_bytes(sizeof(gent), gent);
else if(input == INPUT_TEST) // test generator
test_bytes(sizeof(gent), gent);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(sizeof(gent), gent);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(sizeof(gent), gent);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(sizeof(gent), gent);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_URANDOM) // urandom
urandom_bytes(sizeof(gent), gent);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
random_bytes(sizeof(gent), gent);
#endif
else if(input == INPUT_CLOCK) // clockstream
clock_bytes(sizeof(gent), gent);
else {
fprintf(stdout,"%s: mode '%d'(%s) not available\n",
procname, input, input_str);
exit(2);
}
#ifdef DEBUG23
ressu_dump("newgent", 32, gent, 32); // first 32 bytes
#endif
} // if(gent_pos==0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
#ifdef DEBUG18
fprintf(stdout, "{%02x}", ch);
#endif
return(ch);
}
static unsigned char *basedigits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; // 64 chars
void fprintfbase(FILE *fp1, unsigned long long ll2, int base) // JariK 2023
{
int count;
unsigned long long ll, divider;
if(base == 2)
fprintf(fp1,"0b");
else if(base == 8)
fprintf(fp1,"0o");
else if(base == 10)
fprintf(fp1,"0d");
else if(base == 16)
fprintf(fp1,"0x");
ll = ll2;
divider = 1;
count = 0;
for(;;) { // count digits
ll /= base;
count++;
if(ll == 0)
break;
divider *= base; // do not count last digit
}
while(count > 0) { // print digits
fprintf(fp1,"%c", basedigits[(ll2 / divider) % base]);
divider /= base;
count--;
}
}
#define aDEBUG24 2
unsigned long newressu_gen_limit(unsigned long limit) // JariK 2022
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) { // one byte
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) { // two bytes
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) { // three bytes
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) { // four bytes
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) { // five bytes
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) { // six bytes
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) { // seven bytes
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
#define aDEBUG34
#ifdef DEBUG34
fprintf(stdout,"limit:%lu", limit);
fprintf(stdout,", highlimit:%lu", highlimit);
fprintf(stdout,", bytes:%d", bytes);
fprintf(stdout,", word:%lu", word);
fprintf(stdout,", word%%limit:%lu", (unsigned long) word % limit);
fprintf(stdout,", base:");
if(base == -1)
fprintfbase(stdout, word % limit, 16);
else
fprintfbase(stdout, word % limit, base);
fprintf(stdout,", base:0o%lo", word % limit);
fprintf(stdout,", base:0d%lu", word % limit);
fprintf(stdout,", base:0x%lx", word % limit);
fprintf(stdout,"\n");
#endif
word %= limit;
#ifdef DEBUG24
fprintf(stdout,"/");
fprintf(stdout,"%d bytes: ", bytes);
fprintf(stdout,"[");
if(base == -1)
fprintfbase(stdout, word, 16);
else
fprintfbase(stdout, word, base);
fprintf(stdout,"]");
fprintf(stdout,"/");
fflush(stdout);
#endif
return(word);
}
static int cursor_on = 0;
unsigned char cursor[4] = { '|', '/', '-', '\\' };
long int prev_secs = -1;
int crs = 0;
void stat_line_cursor_start()
{
fprintf(stderr,"%c", cursor[crs]);
fflush(stderr);
//prev_secs = -1;
cursor_on = 1;
}
void stat_line_cursor()
{
long int secs;
secs = time(NULL) % sizeof(cursor);
if(prev_secs != secs) {
if(prev_secs != -1)
crs = (crs + 1) % sizeof(cursor);
fprintf(stderr,"\b%c", cursor[crs]);
fflush(stderr);
prev_secs = secs;
}
}
void stat_line_cursor_remove()
{
if(cursor_on) {
fprintf(stderr, "\b \b");
fflush(stderr);
//prev_secs = -1;
}
cursor_on = 0;
}
#include <stdarg.h>
#define aDEBUG31 2
unsigned char *procname = NULL;
static unsigned char *prev_stat_line = NULL;
static unsigned char *stat_line = NULL;
static size_t stat_line_length = 0;
static void stat_line_begin()
{
if(stat_line != NULL)
stat_line[0] = '\0';
}
static void stat_line_printf(const unsigned char *format, ...)
{
int count;
va_list args;
static unsigned char *buffer = NULL;
static size_t buffer_length = 0;
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
if(buffer_length < count) {
buffer_length = count;
buffer = realloc(buffer, buffer_length);
va_start(args, format);
count = vsnprintf(buffer, buffer_length, format, args) + 1;
va_end(args);
}
count = 0;
if(stat_line != NULL)
count += strlen(stat_line);
count += strlen(buffer);
count++;
if(stat_line_length < count) {
unsigned char *stat_line2 = stat_line;
stat_line_length = count;
stat_line = realloc(stat_line, stat_line_length);
prev_stat_line = realloc(prev_stat_line, stat_line_length);
if(stat_line2 == NULL) {
stat_line[0] = '\0';
prev_stat_line[0] = '\0';
}
}
strcat(stat_line, buffer);
}
#define READABLE_NUMBER_BIN 2
#ifdef READABLE_NUMBER_BIN
#define READABLE_NUMBER_HIGH 1023
#define READABLE_NUMBER_DIVIDER 1024
#else
#define READABLE_NUMBER_HIGH 999
#define READABLE_NUMBER_DIVIDER 1000
#endif
#define READABLE_NUMBER_WIDTH 32
static void stat_line_get_readable(unsigned char buf10[10], unsigned long long length)
{
int c, low;
double length2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
strcpy(buf10, "***");
low = 0;
for(c = 0; length >= low &&
c < sizeof(units) - 1; c++) {
if(length >= low &&
length <= READABLE_NUMBER_HIGH) {
if(units[c] == 'B')
sprintf(buf10, "%lld", length);
else if(units[c] == 'K' ||
units[c] == 'M' ||
units[c] == 'G' ||
units[c] == 'T')
sprintf(buf10, "%.3f", length2);
else if(length == length2)
sprintf(buf10, "%lld", length);
else
sprintf(buf10, "%.1f", length2);
if(strchr(buf10, '.') != NULL) {
int d;
d = strlen(buf10) - 1;
while(d > 3 && isdigit(buf10[d])) {
buf10[d] = '\0';
d--;
}
if(buf10[strlen(buf10)-1] == '.')
buf10[strlen(buf10)-1] = '\0';
}
if(units[c] != 'B') {
char unit[10];
sprintf(unit,"%cB",units[c]);
strcat(buf10, unit);
}
break;
}
length2 = (double)length / READABLE_NUMBER_DIVIDER;
length /= READABLE_NUMBER_DIVIDER;
low = 1;
}
}
static void stat_line_readable(unsigned long long length)
{
unsigned char buf10[10];
stat_line_get_readable(buf10, length);
stat_line_printf("%s", buf10);
}
static void stat_line_dhms(unsigned long long printleft)
{
unsigned long int left2;
unsigned long int temp;
int timeprinted = 0;
left2 = printleft;
temp = left2 / (24 * 3600); // days
if(temp > 0) {
timeprinted = 1;
stat_line_printf(" %dd", temp);
left2 -= temp * (24 * 3600);
}
temp = left2 / 3600; // hours
if(temp > 0 || timeprinted) {
timeprinted = 1;
//hoursprinted = 1;
stat_line_printf(" %02dh", temp);
left2 -= temp * 3600;
}
temp = left2 / 60; // minutes
if(temp > 0 || timeprinted) {
timeprinted = 1;
stat_line_printf(" %02dm", temp);
left2 -= temp * 60;
}
temp = left2; // seconds
if(!timeprinted) {
stat_line_printf(" %d seconds", temp);
}
}
void stat_line_end()
{
int c, d;
if(stat_line != NULL && strcmp(prev_stat_line, stat_line)) { // status line changed
stat_line_cursor_remove();
#ifdef DEBUG31
fprintf(stderr, "\n");
#else
fprintf(stderr, "\r");
#endif
fprintf(stderr,"%s", stat_line);
fflush(stderr);
// previous line longer than this one,
// overwrite with spaces and backspace to
// end
d = strlen(prev_stat_line) - strlen(stat_line) + 1; // cursor too
if(d > 0) { // previous line longer
for(c = 0; c < d; c++) {
#ifdef DEBUG31
fprintf(stderr, "*");
#else
fprintf(stderr, " "); // print spaces
#endif
}
#ifndef DEBUG31
for(c = 0; c < d; c++)
fprintf(stderr, "\b"); // and backspaces
#endif
}
strcpy(prev_stat_line, stat_line);
//if(strlen(stat_line) > 0)
//stat_line_cursor_start();
//stat_line_cursor();
}
}
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2) // 2023 JariK
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
void fprintfcharacter(FILE *fp1, unsigned char *p) // 2023 JariK
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p) // 2023 JariK
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
#define DEBUG32
//#define KILO 1000
#define KILO 1024
unsigned long long getlonglong(unsigned char *p2) // 2023 JariK
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %llu", prevll);
fprintf(stderr,", multiplier: %llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
static int zero = 1, sspace = 0, snewline = 0,
scrlf = 1, chars = 72, pchars = 0, charwidth = 1,
charspaces = 0, words = 0, pwords = 0, cwords = 0,
plinesdigits = 5, slineno = 1, screen = 0,
quiet = 0, sort = 0, unique = 0,
flagprintdigits = 0;
static int calc_spaces()
{
int spaces;
spaces = 0;
if(sspace >= 2 &&
// space between word groups
( (cwords > 0 && cwords % sspace == 0) ||
// space after linenumber
// are not printed if
// not printing linenumber
(slineno && cwords == 0) ) )
spaces++;
if(sspace &&
// space between words
( (cwords > 0) ||
// space after linenumber
(slineno && cwords == 0) ) )
spaces++;
return(spaces);
}
static void print_spaces(char spacechar)
{
int sp;
for(sp = calc_spaces(); sp > 0; sp--)
fputc(spacechar, stdout);
}
static long long lines = 10, plines = 0, ptotallines = 0;
void printcolumns(int offset, int base, int startwith, int columns, int *clines) // 2023 JariK
{
//---------11111111112222222222333333333344444444445555555555666666666677
//12345678901234567890123456789012345678901234567890123456789012345678901
//=======================================================================
//00000 86747100388687087416829400778878989202760594993130062980826178851
//00001 36862623069143814543525935285460059703805218323534266522497684582
int c, d, digit, nonzero;
unsigned char digits[0x10] = "0123456789abcdef";
*clines = 0;
if(base == 2)
c = 1 << 12;
else if(base == 8)
c = 01000000;
else if(base == 10)
c = 1000000;
else if(base == 16)
c = 0x1000000;
else {
fprintf(stdout,"%s: printcolumns():", procname);
fprintf(stdout," illegal base %d", base);
fprintf(stdout,"\n");
exit(1);
}
for(;c >= 1; c /= base) { // lines, 100000's, 10000's, 1000's ... 1's
if(c >= columns)
continue;
for(d = 0; d < offset; d++)
fprintf(stdout," "); // spaces in beginning of row
nonzero = 0;
for(d = startwith; d < columns + startwith; d++) { // column numbers
digit = (d / c) % base;
if(digit != 0)
nonzero = 1;
if(nonzero || c == 1)
fprintf(stdout,"%c", digits[digit]); // nonzero digits after first nonzero
else
fprintf(stdout,"-"); // zeroes in beginning of row
}
fprintf(stdout,"\n");
(*clines)++;
}
if(pwords > 0) {
if(slineno) {
for(c = 0; c <= plinesdigits; c++) // +1
fprintf(stdout,"-");
}
for(cwords = 0; cwords < pwords; cwords++) {
print_spaces('-');
fprintf(stdout,"w");
if(charwidth == 2)
fprintf(stdout,"-");
for(c = 0; c < size - 1; c++) {
fprintf(stdout,"-");
if(charwidth == 2)
fprintf(stdout,"-");
}
}
fprintf(stdout,"\n");
(*clines)++;
}
for(d = 0; d < offset; d++)
fprintf(stdout," "); // spaces in beginning of row
for(d = startwith; d < columns + startwith; d++)
fprintf(stdout,"=");
fprintf(stdout,"\n");
(*clines)++;
}
#ifdef SAMPLE_HASH
void hashfinal2string(unsigned char *hashstring, unsigned char *final)
{
for(int c = 0; c < HashLen; c++) {
sprintf(hashstring + 2 * c, "%02x",final[c]);
}
}
#endif
static int sample = 0, dieharder = 0; // randomness analysis
// try randomness analysis with: $ dieharder -a -g 201 -f newressusample1.rnd > newressusample1.rnd.dieharder
#include <signal.h>
typedef void (*sighandler_t)(int);
void sample_handler()
{
static int times = 0;
times++;
fprintf(stderr,"Ctrl-c pressed %d times\n", times);
if(times >= 10) {
signal(SIGINT, SIG_DFL);
exit(2);
}
}
#define DEBUG39
#define FILESIZE 3 * 1024 * 1024 * 1024
#define BLOCKSIZE 384 * 1024
#define BLOCKS 8192
unsigned long long filesize = (long long)FILESIZE, blocks = BLOCKS;
unsigned int blocksize = BLOCKSIZE;
int filesize_set = 0, blocks_set = 0, blocksize_set = 0;
int purge = 1;
int purge_set = 0;
unsigned char *filesize_str = NULL, *blocks_str = NULL, *blocksize_str = NULL;
void dump_sample() // & dieharder analysis
{
#define STAT_LINE_SHOW_BLOCK 2 // on by default
#define STAT_LINE_SHOW_WRITTEN 2 // on by default
#define STAT_LINE_SHOW_SPEED 2 // on by default
#define STAT_LINE_SHOW_NOW 2 // on by default
#define STAT_LINE_SHOW_LEFT 2 // on by default
#define STAT_LINE_SHOW_READY 2 // on by default
#define STAT_LINE_LESS_WOBBLE 2 // on by default
#define TIMEFORMAT "%H:%M %Z"
#define TIMEFORMAT2 "%a %H:%M %Z"
#define DATEFORMAT "%a %d %b %Y"
unsigned long long c;
unsigned char *buffer, filename[128], command[1024];
FILE *fp1;
// find first available filename,
// or empty "fileslot"
for(c = 1; c <= 99999; c++) {
sprintf(filename, samplefilename, c);
if((fp1 = fopen(filename, "r")) != NULL) {
fclose(fp1);
continue;
}
unsigned char filename2[138];
sprintf(filename2,"%s.dieharder",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#ifdef SAMPLE_HASH
sprintf(filename2,"%s.sha256",filename);
if((fp1 = fopen(filename2, "r")) != NULL) {
fclose(fp1);
continue;
}
#endif
break;
}
// calculate missing file size parameters
if(!filesize_set)
filesize = blocks * blocksize;
else if(!blocksize_set) {
blocksize = (filesize + blocks - 1) / blocks; // round up
filesize = blocks * blocksize;
} else if(!blocks_set) {
blocks = (filesize + blocksize - 1)/ blocksize; // round up
filesize = blocks * blocksize;
}
#define EXFAT_FIX 2 // on for now
#ifdef EXFAT_FIX
if(blocksize > KILO * KILO) { // max "blocksize" 1m (exfat)
blocksize = KILO * KILO;
blocks = (filesize + blocksize - 1) / blocksize;
filesize = blocks * blocksize;
}
#endif
if(filesize != blocks * blocksize ||
blocks < 1 || blocksize < 1) {
fflush(stdout);
fprintf(stderr,"%s: sample(): mismatched parameters", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
if(filesize / blocks != blocksize) {
fflush(stdout);
fprintf(stderr,"%s: sample(): parameter overflow", procname);
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
exit(1);
}
#ifdef DEBUG39
fprintf(stderr,"blocksize:%u(", blocksize);
readablelonglong(stderr, blocksize);
fprintf(stderr,")");
fprintf(stderr,", blocks:%llu(", blocks);
readablelonglong(stderr, blocks);
fprintf(stderr,")");
fprintf(stderr,", filesize:%llu(", filesize);
readablelonglong(stderr, filesize);
fprintf(stderr,")\n");
fflush(stderr);
#endif
if((buffer = malloc(blocksize)) == NULL) {
fprintf(stderr,"%s: sample(): cannot allocate memory (buffer)\n", procname);
exit(1);
}
#define DEBUG40 2 // default on (for now)
#ifdef DEBUG40
fprintf(stderr,"%s: sample(): writing file", procname);
fprintf(stderr,", filename:%s", filename);
#ifndef SAMPLE_WRITE
fprintf(stderr,", no write");
#endif
fprintf(stderr,"\n");
#endif
#ifdef SAMPLE_HASH
unsigned char digest[HashLen];
HashCtx hash;
HashInit(&hash); // calculate hash
#endif
// variables for stat line fields
time_t start, now, left, end, took;
unsigned char speed[10], printspeed[10] = "";
#ifdef STAT_LINE_LESS_WOBBLE
time_t prevend = -1;
int countspeed = 0, countend = 0;
unsigned char prevspeed[10] = "";
unsigned int calculateleft;
#endif
time_t printleft = -1, printend = -1;
int leftprinted = 0;
unsigned long long clim = 0;
if((fp1 = fopen(filename, "a")) != NULL) {
// starting time
start = time(NULL);
clim = (unsigned long long) filesize / blocksize;
#ifdef EXFAT_FIX
int mbinblocks = (1 * KILO * KILO) / blocksize;
if(mbinblocks == 0)
mbinblocks = 1;
fprintf(stderr,"mbinblocks:%d\n", mbinblocks);
#endif
// you have to press ctrl-c 10 times
signal(SIGINT, sample_handler);
for(c = 0; c < clim; c++) {
// current time
now = time(NULL);
// estimate for ending time
end = (time_t)start + ((((double)now - start) / c) * clim);
#ifdef STAT_LINE_LESS_WOBBLE
calculateleft = 0;
if(prevend / 60 == end / 60 &&
++countend >= 30) { // 30 times same minutes --> minutes are real
printend = end;
calculateleft = 1;
} else if(prevend / 60 != end / 60) { // minutes different
prevend = end;
countend = 0;
}
#else
printend = end;
#endif
// estimate for time left
left = printend - now;
#ifdef STAT_LINE_LESS_WOBBLE
static int onlyseconds = 0;
static long long cstart, cleft, cseconds;
if(onlyseconds || (left > 0 && left < 60)) {
if(!onlyseconds) {
cstart = c;
cleft = clim - c;
cseconds = left;
onlyseconds = 1;
}
left = (double) cseconds - ((((double) c - cstart) / cleft) * cseconds);
}
if(calculateleft)
printleft = left;
#else
printleft = left;
#endif
// speed
if(now - start > 1.0)
stat_line_get_readable(speed, (unsigned long long)((double)c * blocksize / (now - start)) );
else
stat_line_get_readable(speed, (unsigned long long)((double)c * blocksize));
#ifdef STAT_LINE_LESS_WOBBLE
if(!strcmp(prevspeed, speed) &&
++countspeed >= 3) { // three times same speed --> speed is real
strcpy(printspeed, speed);
} else if(strcmp(prevspeed, speed)) {
strcpy(prevspeed, speed);
countspeed = 0;
}
#else
strcpy(printspeed, speed);
#endif
// print status line:
// blk 10, written 10MB, 269KB/sec, left 8 h 38 m, ready at Sat 17 Jul 2021 01:57:43 EEST, now Fri 17:19:32 EEST
stat_line_begin();
int print = 0;
#ifdef STAT_LINE_SHOW_BLOCK
stat_line_printf("%s", input_str);
// print block from 0 to 8192
stat_line_printf("block %d", c);
print = 1;
#endif
#ifdef STAT_LINE_SHOW_WRITTEN
// print written
if(print)
stat_line_printf(", ");
stat_line_printf("written ");
stat_line_readable((unsigned long)c * blocksize);
print = 1;
#endif
if(c > 0) {
#ifdef STAT_LINE_SHOW_SPEED
// print speed
if(printspeed[0] != '\0') {
if(print)
stat_line_printf(", ");
stat_line_printf("%s/sec", printspeed);
print = 1;
}
#endif
#if defined STAT_LINE_SHOW_NOW || \
defined STAT_LINE_SHOW_READY
char timebuf[128];
#endif
#ifdef STAT_LINE_SHOW_READY
char timebuf2[128];
#endif
#ifdef STAT_LINE_SHOW_NOW
// print now
if(print)
stat_line_printf(", ");
stat_line_printf("now");
strftime(timebuf, sizeof(timebuf), TIMEFORMAT2,
localtime((time_t *)&now));
stat_line_printf(" %s", timebuf);
print = 1;
#endif
#ifdef STAT_LINE_SHOW_LEFT
// print left
if(printleft > 0) {
if(print)
stat_line_printf(", ");
stat_line_printf("left");
stat_line_dhms(printleft);
leftprinted = 1;
print = 1;
}
#endif
#ifdef STAT_LINE_SHOW_READY
//unsigned long int end = (int)start + ((((double)now - start) / c) * clim);
if(printend > 0 && leftprinted) {
if(print)
stat_line_printf(", ");
stat_line_printf("ready at");
strftime(timebuf, sizeof(timebuf), DATEFORMAT,
localtime((time_t *) & end));
strftime(timebuf2, sizeof(timebuf2), DATEFORMAT,
localtime((time_t *) & now));
if(strcmp(timebuf, timebuf2)) {
stat_line_printf(" %s", timebuf);
}
// print end time
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *) & printend));
stat_line_printf(" %s", timebuf);
print = 1;
}
#endif
}
stat_line_end();
stat_line_cursor_start();
// do the work
stat_line_cursor();
memset(buffer, 0, blocksize);
if(input == INPUT_RESSU) // ressu prod
ressu_genbytes(blocksize, buffer);
else if(input == INPUT_PSEUDORESSU) // pseudoressu
pseudoressu_bytes(blocksize, buffer);
else if(input == INPUT_RESSUTWIST) // ressu w twist
ressutwist_bytes(blocksize, buffer);
else if(input == INPUT_FASTRESSU) // ressu fast
ressu_genbytes_fast(blocksize, buffer);
else if(input == INPUT_SINGLERESSU) // ressu single
ressu_genbytes_single(blocksize, buffer);
else if(input == INPUT_STREAM) // ressu stream
stream_bytes(blocksize, buffer);
else if(input == INPUT_TEST) // test generator
test_bytes(blocksize, buffer);
#ifdef FORT
else if(input == INPUT_FORT) // ressu fort
fort_random_data(blocksize, buffer);
else if(input == INPUT_FORTXOR) // ressu fort
fort_random_data_xor(blocksize, buffer);
#endif
#ifdef USE_RDRAND
else if(input == INPUT_RDRAND) // intel rdrand
rdrand_bytes(blocksize, buffer);
#endif
#ifdef USE_RDSEED
else if(input == INPUT_RDSEED) // intel rdseed
rdseed_bytes(blocksize, buffer);
#endif
else if(input == INPUT_URANDOM) // urandom
urandom_bytes(blocksize, buffer);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
random_bytes(blocksize, buffer);
#endif
#ifdef USE_DUMMY
else if(input == INPUT_DUMMY) {
// no generator
}
#endif
else {
fprintf(stdout,"\n%s: mode '%d'(%s) not available\n",
procname, input, input_str);
exit(2);
}
#ifdef SAMPLE_HASH
HashUpdate(&hash, buffer, blocksize); // calculate hash
#endif
#ifdef SAMPLE_WRITE
if(input != INPUT_DUMMY) {
fwrite(buffer, 1, blocksize, fp1);
#ifdef SAMPLE_SYNC
#ifdef EXFAT_FIX
if(c % mbinblocks == 0) { // fflush and sync (EXFAT)
fflush(fp1);
//sync();
fsync(fileno(fp1));
}
#endif
#endif
} // end of if(input != INPUT_DUMMY
#endif
} // end of for(c = 0; c < clim; c++
#ifdef SAMPLE_HASH
HashFinal(digest, &hash); // calculate hash
#endif
fflush(fp1); // fflush and sync (EXFAT)
//sync();
fsync(fileno(fp1));
fclose(fp1);
} else { // if((fp1=fopen
fprintf(stderr,"%s:", procname);
fprintf(stderr," sample(): cannot open file");
fprintf(stderr,", filename: %s", filename);
fprintf(stderr,"\n");
exit(2);
}
// remove last status line
//stat_line_cursor_remove();
stat_line_begin();
stat_line_printf("\rwrote ");
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf(", ");
if(now - start >= 1.0)
stat_line_readable((unsigned long)((double)c * blocksize / (now - start)) );
else
stat_line_readable((unsigned long)c * blocksize);
stat_line_printf("/sec");
end = time(NULL);
took = end - start;
stat_line_printf(", took");
stat_line_dhms(took);
//stat_line_printf(", done!");
stat_line_end();
stat_line_cursor_remove();
fprintf(stderr,"\n");
fflush(stderr);
#ifdef SAMPLE_HASH
unsigned char filename2[138];
unsigned char hashstring[2 * HashLen + 1];
hashfinal2string(hashstring, digest);
sprintf(filename2,"%s.sha256", filename);
fprintf(stderr,"%s: sample(): hashing file", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,", hashfilename:%s", filename2);
fprintf(stderr,", sha256:%s\n", hashstring);
if((fp1 = fopen(filename2, "a")) != NULL) {
fprintf(fp1,"%s\n",hashstring);
fclose(fp1);
}
sprintf(command,"sha256sum %s", filename);
fprintf(stderr,"%s: sample(): checking sha256", procname);
fprintf(stderr,", filename:%s", filename);
fprintf(stderr,", command:'%s'\n", command);
system(command);
#endif
signal(SIGINT, SIG_DFL);
free(buffer);
if(dieharder) { // randomness analysis
sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder 2>&1",
filename, filename);
//sprintf(command,"dieharder -a -g 201 -f %s > %s.dieharder", filename, filename);
fprintf(stderr,"%s: sample(): running dieharder \"%s\"\n",
procname, command);
system(command);
sprintf(command,"grep \"WEAK\\|FAILED\" %s.dieharder",
filename);
fprintf(stderr,"%s: sample(): grepping dieharder problems \"%s\"\n"
, procname, command);
system(command);
long long weak;
sprintf(command,"grep WEAK %s.dieharder", filename);
weak = command_countlines(command);
fprintf(stderr,"%s: sample(): calculating WEAK lines", procname);
fprintf(stderr, ", lines = %lld", weak);
fprintf(stderr,", \"%s\"\n", command);
long long failed;
sprintf(command,"grep FAILED %s.dieharder", filename);
failed = command_countlines(command);
fprintf(stderr,"%s: sample(): calculating FAILED lines", procname);
fprintf(stderr, ", lines = %lld", failed);
fprintf(stderr,", \"%s\"\n", command);
sprintf(command,"grep rewound %s.dieharder | tail -n1",
filename);
fprintf(stderr,"%s: sample(): grepping last rewound count \"%s\"\n",
procname, command);
system(command);
FILE *fp2;
if((fp2 = fopen("newressudieharder.skk", "a")) != NULL) { //
fprintf(fp2,"'input' = \"%s\"", input_str);
if(filesize_str != NULL)
fprintf(fp2,", 'filesize' = \"%s\"", filesize_str);
if(blocksize_str != NULL)
fprintf(fp2,", 'blocksize' = \"%s\"", blocksize_str);
if(blocks_str != NULL)
fprintf(fp2,"'blocks' = \"%s\"", blocks_str);
fprintf(fp2,", 'filename' = \"%s\"", filename);
fprintf(fp2,", 'weak' = \"%lld\"", weak);
fprintf(fp2,", 'failed' = \"%lld\"", failed);
fprintf(fp2,"\n");
fclose(fp2);
}
if(purge) {
fprintf(stderr,"%s: sample(): removing file", procname);
fprintf(stderr," %s\n", filename);
unlink(filename);
}
exit(0);
}
}
static unsigned long limit, word, uppercase = 0;
static unsigned char *digits = "0123456789", character[32];
static unsigned char digitstemp[256], *digitsext = NULL;
static unsigned char linenobuf[1024];
static unsigned char *stream_default_key = "kalakala";
static unsigned char *key = NULL;
static int print_statline = 0, columns = 0, flagdigits = 0;
int help = 0;
//
// utf8 functions
//
static int utf8characters(unsigned char *buf)
{
int characters;
unsigned char *p;
p = buf;
characters = 0;
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) // first utf8 byte
characters++;
p++;
}
if(flagdigits == 1) // semicolon separated (flags)
return(characters / 2);
else
return(characters);
}
int utf8strings(unsigned char *buf)
{
int strings = 0;
unsigned char *p = buf;
while(*p != '\0') {
if(*p == ';')
strings++;
p++;
}
return(strings);
}
#define aDEBUG47 2
int utf8lengths(unsigned char *buf)
{
int lengths, len, first = 1;
unsigned char *p;
#ifdef DEBUG47
fprintf(stdout,"digits %s", buf);
fprintf(stdout,"\nlengths ");
#endif
p = buf;
len = 0;
lengths = -1;
first = 1;
while(*p != '\0') {
if(!first &&
(*p < 0x80 || // ascii char
*p > 0xbf)) { // first utf8 byte
#ifdef DEBUG47
fprintf(stdout,"%d", len);
#endif
if(lengths == -1)
lengths = len;
else if(lengths != len)
lengths = 0;
len = 0;
}
p++;
len++;
first = 0;
}
#ifdef DEBUG47
fprintf(stdout,"%d", len);
#endif
if(lengths == -1)
lengths = len;
else if(lengths != len)
lengths = 0;
#ifdef DEBUG47
fprintf(stdout,"\nlengths %d\n\n", lengths);
#endif
return(lengths);
}
int utf8stringlengths(unsigned char *buf)
{
int lengths = -1, len;
unsigned char *p = buf;
// return(0);
len = 0;
while(*p != '\0') {
if(*p == ';') {
p++;
if(lengths == -1)
lengths = len;
else if(lengths != len)
lengths = 0;
len = 0;
}
p++;
len++;
}
if(lengths == -1)
lengths = 0;
else
lengths++; // count semicolon also
return(lengths);
}
#define aDEBUG42 2
static void codetoutf8(unsigned char *buf2, unsigned long code)
{
unsigned char *buf;
buf = buf2;
if(code <= 0x7f) {
*buf++ = code;
} else if(code <= 0x7ff) { // 110xxxxx 10xxxxxx
*buf++ = (0xc0 | ((code >> 6) & 0x1f));
*buf++ = (0x80 | (code & 0x3f));
} else if(code <= 0xffff) { // 1110xxxx 10xxxxxx 10xxxxxx
*buf++ = (0xe0 | ((code >> 12) & 0x0f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | (code & 0x3f));
} else if(code <= 0x10ffff) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*buf++ = (0xf0 | ((code >> 18) & 0x07));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x3ffffff) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xf8 | ((code >> 24) & 0x03));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x7fffffff) { // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xfc | ((code >> 30) & 0x01));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0xfffffffff) { // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xfe);
*buf++ = (0x80 | ((code >> 30) & 0x3f));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
} else if(code <= 0x3ffffffffff) { // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // these not yet needed
*buf++ = (0xff);
*buf++ = (0x80 | ((code >> 36) & 0x3f));
*buf++ = (0x80 | ((code >> 30) & 0x3f));
*buf++ = (0x80 | ((code >> 24) & 0x3f));
*buf++ = (0x80 | ((code >> 18) & 0x3f));
*buf++ = (0x80 | ((code >> 12) & 0x3f));
*buf++ = (0x80 | ((code >> 6) & 0x3f));
*buf++ = (0x80 | ((code & 0x3f)));
}
*buf = '\0';
#ifdef DEBUG42
int c, print;
fprintf(stdout,"codepoint: %lx", code);
fprintf(stdout,", bin:");
print = 0;
for(c = (sizeof(code) * 8) - 1; c >= 0; c--) {
int bit = (code >> c) & 1;
if(bit != 0)
print = 1;
if(print) {
fprintf(stdout,"%d", bit);
if(c > 0 && c % 8 == 0)
fprintf(stdout,"|");
}
}
fprintf(stdout,", oct:");
print = 0;
fprintf(stdout,"%lo", code);
fprintf(stdout,", utf8: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout,"%02x", buf2[c]);
}
fprintf(stdout,", bin: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
if(c > 0)
fprintf(stdout,"|");
for(int d = 7; d >= 0; d--) {
fprintf(stdout,"%d", buf2[c] >> d & 1);
}
}
fprintf(stdout,", oct:");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout," %3o", buf2[c]);
}
fprintf(stdout,", character: %s", buf2);
fprintf(stdout,"\n");
#endif
}
#ifdef NOTUSED
#define aDEBUG43 2
static void utf8tocode(unsigned long *code, unsigned char *buf2)
{
unsigned char *buf;
*code = 0;
buf = buf2;
if(*buf <= 0x7f) { // 0xxxxxxx
*code = *buf;
} else if(*buf < 0xc0) { // 110xxxxx 10xxxxxx
*code = 0;
} else if(*buf < 0xe0) { // 110xxxxx 10xxxxxx
*code = *buf++ & 0x1f;
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xf0) { // 1110xxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x0f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf<0xf8) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x07;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xfc) { // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x03;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xfe) { // 1111110x 10xxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*code = *buf++ & 0x01;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf < 0xff) { // 11111110 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
buf++;
*code = *buf++ & 0x3f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
} else if(*buf == 0xff) { // 11111111 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
buf++;
*code = *buf++ & 0x3f;
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
*code = (*code << 6) + (*buf++ & 0x3f);
}
#ifdef DEBUG43
int c;
fprintf(stdout, "character: %s", buf2);
fprintf(stdout, ", utf8: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout,"%02x", buf2[c]);
}
fprintf(stdout, ", bin: ");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
if(c > 0)
fprintf(stdout, "|");
for(int d = 7; d >= 0; d--)
fprintf(stdout, "%d", buf2[c] >> d & 1);
}
fprintf(stdout, ", oct:");
for(c = 0; c < 8; c++) {
if(buf2[c] == '\0')
break;
fprintf(stdout, " %3o", buf2[c]);
}
fprintf(stdout, ", codepoint: %lx", *code);
fprintf(stdout, ", bin:");
int print = 0;
for(c = (sizeof(code) * 8) - 1; c >= 0; c--) {
int bit = (*code >> c) & 1;
if(bit != 0)
print = 1;
if(print) {
fprintf(stdout, "%d", bit);
if(c > 0 && c % 8 == 0)
fprintf(stdout, "|");
}
}
fprintf(stdout, ", oct:");
fprintf(stdout, "%lo", *code);
fprintf(stdout, "\n");
#endif
}
#endif
int characterlengths = 0; // 0 multiple lengths, x lengths are same
#define aDEBUG55 2
static void utf8getcharactersemi(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
if(characterlengths != 0)
p += characterlengths * n;
else {
if(flagdigits) { // semicolon separated (flags)
while(*p != '\0') {
if(d == n)
break;
if(*p == ';') {
d++;
}
p++;
}
} else { // else if(flagdigits)
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) { // first utf8 char
if(d == n)
break;
d++;
}
p++;
}
}
}
//fprintf(stdout,"%d***%s\n",d,p);
// copy first byte and rest
// of character
if(flagdigits) { // semicolon separated (flags)
while(*p != '\0') {
if(*p == ';')
break;
*q++ = *p++; // copy first byte
}
} else {
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';
//fprintf(stdout,"character: `%s`\n", buf);
#ifdef DEBUG56
fprintf(stdout,"%s: utf8getcharacter:", procname);
fprintf(stdout," string: %s", string);
fprintf(stdout,", n: %d", n);
fprintf(stdout,", character: %s", buf);
fprintf(stdout,", characterlengths: %d", characterlengths);
fprintf(stdout,"\n");
#endif
}
static void utf8getcharacter(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
if(characterlengths != 0)
p += characterlengths * n;
else {
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) { // first utf8 char
if(d == n)
break;
d++;
}
p++;
}
}
//fprintf(stdout,"%d***%s\n",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 DEBUG56
fprintf(stdout,"%s: utf8getcharacter:", procname);
fprintf(stdout," string: %s", string);
fprintf(stdout,", n: %d", n);
fprintf(stdout,", character: %s", buf);
fprintf(stdout,", characterlengths: %d", characterlengths);
fprintf(stdout,"\n");
#endif
}
#define aDEBUG56 2
static void utf8getcharacter1(int size, unsigned char *buf, int n, unsigned char *string)
{
unsigned char *p, *q;
p = string;
q = buf;
// find first byte of character
p += n;
// 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 DEBUG56
fprintf(stdout,"%s: utf8getcharacter:", procname);
fprintf(stdout," string: %s", string);
fprintf(stdout,", n: %d", n);
fprintf(stdout,", character: %s", buf);
fprintf(stdout,", characterlengths: %d", characterlengths);
fprintf(stdout,"\n");
#endif
}
#define aDEBUG45 2
int digitscount = 10;
// display word in "digits" base (random data)
static void out_word(int size, unsigned char *buf, unsigned char *digits, unsigned long word2) // 8.5.2021 JariK
{
int c, d, len;
unsigned long word;
unsigned char string[1024], character[128];
//digitscount = utf8characters(digits);
word = word2;
len = 0;
string[0] = '\0';
if(word == 0 || digitscount < 2) {
// zero
utf8getcharactersemi(sizeof(character), character, 0, digits);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
} else {
// non zero
while(word > 0) {
utf8getcharactersemi(sizeof(character), character, word%digitscount, digits);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
word /= digitscount;
}
}
#ifdef DEBUG45
fprintf(stdout,"]\n%s: out_word a:", procname);
fprintf(stdout," orig string: %s", string);
#endif
// reverse string
if(flagdigits) // semicolon separated (flags)
strcpy(buf, string);
else {
*buf = '\0';
len = 0;
d = utf8characters(string);
for(c = d - 1; c >= 0; c--) {
utf8getcharacter(sizeof(character), character, c, string);
if(len + strlen(character) < size) {
strcat(buf, character);
len += strlen(character);
}
}
}
#ifdef DEBUG45
fprintf(stdout," reverse string: %s", string);
//fprintf(stdout,", digits: %s", digits);
fprintf(stdout,", int: %lu", word2);
fprintf(stdout,"\n[");
#endif
}
// display word in decimal (10-base) (line number)
static void out_word_10(int size, unsigned char *buf, unsigned long word2) // 8.5.2021 JariK
{
int c, d, len;
unsigned long word;
unsigned char string[128], character[32];
unsigned char *digits10 = "0123456789";
int digitscount = 10;
//digitscount = utf8characters(digits);
word = word2;
len = 0;
string[0] = '\0';
if(word == 0 || digitscount < 2) {
// zero
utf8getcharacter1(sizeof(character), character, 0, digits10);
if(len+strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
} else {
// non zero
while(word > 0) {
utf8getcharacter1(sizeof(character), character, word % digitscount, digits10);
if(len + strlen(character) < sizeof(string)) {
strcat(string, character);
len += strlen(character);
}
word /= digitscount;
}
}
// reverse string
*buf = '\0';
len = 0;
d = utf8characters(string);
for(c = d - 1;c >= 0; c--) {
utf8getcharacter1(sizeof(character), character, c, string);
if(len + strlen(character) < size) {
strcat(buf, character);
len += strlen(character);
}
}
#ifdef DEBUG45
fprintf(stdout,"]\n%s: out_word b:", procname);
fprintf(stdout," reverse string: %s", string);
//fprintf(stdout,", digits: %s", digits);
fprintf(stdout,", int: %lu", word2);
fprintf(stdout,"\n[");
#endif
}
static 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 = utf8characters(buf);
if(flagdigits) // semicolon separated (flags)
f = utf8strings(digits);
else // not
f = utf8characters(digits);
for(c = 0; c < d; c++) {
utf8getcharacter(sizeof(character2), character2, c, buf);
ok = 0;
for(e = 0; e < f; e++) {
utf8getcharactersemi(sizeof(character), character, e, digits); // semi added
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);
}
}
#ifdef DEBUG45
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
}
//
// lotto functions
//
static void line_clear(int *len, unsigned char **buf)
{
if(*len < 1) {
*len = 129;
*buf = realloc(*buf, *len);
}
**buf = '\0';
}
static 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);
}
static 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';
}
}
#define DEBUG59 2 // default is on for now
#ifdef DEBUG59
static int utf8 = 0;
#endif
#ifdef DEBUG51
static int limitsize = 0;
#endif
#define aDEBUG51 2
static void readword(unsigned char *buf)
{
int d,e;
unsigned char temp1024[1024];
if(limit != 0) {
word = 0;
if(zero) {
word = newressu_gen_limit(limit); // include zeroes
} else if(limit >= 1) {
while((word = newressu_gen_limit(limit)) == 0); // skip zeroes
}
#ifdef DEBUG51
if(type == 2)
fprintf(stdout, "(%0*lx)", limitsize, word);
else if(type == 8)
fprintf(stdout, "(%0*lo)", limitsize, word);
else if(type == 10)
fprintf(stdout, "(%0*lu)", limitsize, word);
else if(type == 16)
fprintf(stdout, "(%0*lx)", limitsize, word);
else {
fprintf(stdout, "(%02lu)", word);
}
#endif
out_word(sizeof(temp1024), temp1024, digits, word);
// fill leading zeroes
buf[0] = '\0';
utf8getcharactersemi(sizeof(character), character, 0, digits);
for(d = size - utf8characters(temp1024); d > 0; d--) {
strcat(buf, character);
}
// rest of the number
strcat(buf, temp1024);
} else if(digits != NULL) {
buf[0] = '\0';
#ifdef DEBUG51
fprintf(stdout, "(");
#endif
// fill whole word digit by digit
for(d = 0; d < size; d++) {
if(digits[0] == '0' && !zero)
e = newressu_gen_limit(digitscount - 1) + 1;
else
e = newressu_gen_limit(digitscount);
utf8getcharacter(sizeof(temp1024), temp1024, e, digits);
#ifdef DEBUG51
fprintf(stdout,"%s", temp1024);
if(charspaces == 1)
fputc(' ', stdout);
#endif
strcat(buf, temp1024);
}
#ifdef DEBUG51
fprintf(stdout, ")");
#endif
}
}
//
// stdout printing routines
//
static int line_number_length()
{
int c;
out_word_10(sizeof(linenobuf), linenobuf, lines-1);
c = strlen(linenobuf);
if(c < 5)
c = 5;
return(c);
}
static void print_line_number()
{
unsigned char linenobuf[32];
if(cwords == 0 && slineno) {
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
fprintf(stdout,"%s", linenobuf);
fprintf(stdout," ");
}
}
static void print_word(unsigned char *buf)
{
int e;
if(size != 0) {
if(charspaces == 0) {
fprintf(stdout, "%s", buf);
} else {
for(e = 0; e < size; e++) {
unsigned char temp1024[1024];
utf8getcharacter(sizeof(temp1024), temp1024, e, buf);
fprintf(stdout, "%s", temp1024);
fputc(' ', stdout);
}
}
} else {
fprintf(stdout, "%s", buf);
if(charspaces == 1) {
fputc(' ', stdout);
}
}
}
#ifdef SHA256
static void newressu_file_digest(char *filename,unsigned char *hash)
{
int c;
unsigned char buffer[1024];
FILE *fp1;
HashCtx ctx;
HashInit(&ctx);
if((fp1 = fopen(filename, "rb")) != NULL) {
while((c = fread(buffer, 1, sizeof(buffer), fp1)) > 0)
HashUpdate(&ctx, buffer, c);
fclose(fp1);
}
HashFinal(hash, &ctx);
}
#endif
#define aDEBUG55 2
#define aDEBUG57 2
void digits_add_string(unsigned char **digits, char *str)
{
int digitssize;
#ifdef DEBUG55
fprintf(stdout,"\nolddigits %s", *digits);
fprintf(stdout,"\nadddigits %s", str);
#endif
digitssize = 0;
if(*digits != NULL)
digitssize += strlen(*digits);
digitssize += strlen(str);
#ifdef DEBUG57
fprintf(stdout,"digitssize:%d\n", digitssize);
fflush(stdout);
#endif
unsigned char *prevdigits = *digits;
*digits = realloc(*digits, digitssize + 1);
if(prevdigits == NULL)
**digits = '\0';
strcat(*digits, str);
#ifdef DEBUG55
fprintf(stdout,"\nnewdigits %s", *digits);
fprintf(stdout,"\n");
#endif
}
void digits_add_limits(unsigned char **digits, int start, int end)
{
int c, digitssize;
unsigned char buffer[32];
#ifdef DEBUG55
fprintf(stdout,"\nolddigits %s", *digits);
fprintf(stdout,"\nadddigits start:%d, end:%d", start, end);
#endif
digitssize = 0;
if(*digits != NULL)
digitssize += strlen(*digits);
for(c = start; c <= end; c++) {
codetoutf8(buffer, c);
digitssize += strlen(buffer);
}
#ifdef DEBUG57
fprintf(stdout,"digitssize:%d\n", digitssize);
fflush(stdout);
#endif
unsigned char *prevdigits = *digits;
*digits = realloc(*digits, digitssize + 1);
if(prevdigits == NULL)
**digits = '\0';
for(c = start; c <= end; c++) {
codetoutf8(buffer, c);
strcat(*digits, buffer);
}
#ifdef DEBUG55
fprintf(stdout,"\nnewdigits %s", *digits);
fprintf(stdout,"\n");
#endif
}
void strtolower(unsigned char *buf)
{
while(*buf != '\0') {
*buf = tolower(*buf);
buf++;
}
}
void strtoupper(unsigned char *buf)
{
while(*buf != '\0') {
*buf = toupper(*buf);
buf++;
}
}
double getseconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((double)tv.tv_sec + (double)tv.tv_usec / 1000000);
}
int newressu_getname(int length, unsigned char *name, unsigned char **p2)
{
int len, ok = 0;
unsigned char *n, *p;
p = *p2;
n = name;
len = 0;
while(ispunct(*p) || isblank(*p)) {
p++;
}
while(*p != '\0' && !ispunct(*p) && !isblank(*p)) {
if(len < length) {
*n++ = *p;
ok = 1;
}
p++;
len++;
}
*n = '\0';
*p2 = p;
return(ok);
}
void newressu_base(int base2)
{
base = base2;
digits = malloc(base + 1);
strncpy(digits, basedigits, base);
if(uppercase == 1 && base <= 36) { // if lowercase only ([0-9] + [a-z], 10 + 26
for(int c = 0; c < base; c++) { // to uppercase
if(digits[c] >= 'a' && digits[c] <= 'z')
digits[c] = digits[c] - 'a' + 'A';
else if(digits[c] >= 'A' && digits[c] <= 'Z')
digits[c] = digits[c] - 'A' + 'a';
}
}
if(digitsext != NULL)
free(digitsext);
digitsext = digits;
digits[base] = '\0';
}
#include <sys/ioctl.h> // for TIOCGWINSZ
#define aDEBUG50 2
#define aDEBUG71 2
void call_main(char *);
#define aCALL_MAIN 2
#ifdef CALL_MAIN
#define DEBUG99 2
int main2(int argc, char *argv[]);
void call_main(char *cmd)
{
int size, round, count, chars;
unsigned char *p, *q, *argmem,*params;
char **argv;
size = 0;
for(round = 0; round < 2; round++) {
count = 0;
p = cmd;
while(*p != '\0') {
while(*p == ' ' || *p == '\t')
p++;
q = p;
chars = 0;
while(*p != ' ' && *p != '\t' && *p != '\0') {
p++;
chars++;
}
if(round == 0) // calculate size & alloc
size += chars + 1 + sizeof(char *);
else { // move parameters to arg area
strncpy(params, q, chars);
*(argv+count) = params;
params += (chars+1);
}
count++;
}
if(round == 0) { // allocate
size += sizeof(char *); // ending NULL
argmem = malloc(size);
argv = (char **)argmem;
params = argmem + sizeof(char *) * (count+1);
}
}
*(argv+count) = NULL; // ending NULL
#ifdef DEBUG99
fprintf(stdout, "size:%d,", size);
fprintf(stdout, " argmem:");
for(int c = 0; c < size; c++) {
if(c > 0 && c % 8 == 0)
fprintf(stdout, "|");
if(*(argmem+c) == '\\')
fprintf(stdout, "\\\\");
if(isprint(*(argmem + c)))
fprintf(stdout, "%c", *(argmem + c));
else
fprintf(stdout, "\\%02x", *(argmem + c));
}
fprintf(stdout, "\n");
#endif // #ifdef DEBUG99
main2(count, argv);
}
int main(int argc, char *argv[])
{
int first;
char buffer[1024];
first = 1;
buffer[0] = '\0';
for(int c = 0; c < argc; c++) {
if(!first)
strcat(buffer, " ");
strcat(buffer, argv[c]);
first = 0;
}
#ifdef DEBUG99
fprintf(stdout,"main: cmd \"%s\"\n",buffer);
#endif
call_main(buffer);
}
#endif // #ifdef CALL_MAIN
#ifdef CALL_MAIN
int main2(int argc, char *argv[])
{
#ifdef DEBUG99
fprintf(stdout, "main2args:");
for(int c = 0; c < argc; c++) {
fprintf(stdout, " %d:\"%s\"", c, argv[c]);
}
fprintf(stdout, "\n");
#endif // #ifdef DEBUG99
#else // #ifdef CALL_MAIN
static unsigned char programfiledigest[HashLen];
int main(int argc, char *argv[])
{
#endif // #ifdef CALL_MAIN
int c, d, status = 0;
#ifdef DEBUG2H
for(int c = 0; c < RESSUT_BYTES; c++)
count[c] = 0;
#endif
#define aDEBUG67 2
#ifdef DEBUG67
unsigned long long big = 0xffffffffffffffff;
fprintf(stdout,"0x%llx\n", big);
fprintf(stdout,"0o%llo\n", big);
fprintf(stdout,"0d%llu\n", big);
fprintf(stdout,"0x%llx\n", big);
for(int base = 2; base <= 64; base++) {
fprintf(stdout,"base:%d, ", base);
fprintfbase(stdout, big, base);
fprintf(stdout,"\n");
}
fprintf(stdout,"number");
for(int base = 2; base <= 64; base++) {
fprintf(stdout," %d",base);
}
fprintf(stdout,"\n");
for(unsigned long long ll = 0; ll < 1048576; ll++) {
//for(unsigned long long ll = 4096; ll > 0; ll+=4096) {
//for(unsigned long long ll = 1; ll != 0; ll *= 2) {
fprintf(stdout,"%llu:", ll);
for(int base = 2; base <= 64; base++) {
fprintf(stdout," ");
fprintfbase(stdout, ll, base);
}
fprintf(stdout,"\n");
}
fflush(stdout);
#endif
#ifdef DEBUG31
for(c = 20; c > 1; c--) {
stat_line_begin();
for(d = 0; d < c; d++) {
stat_line_printf("+");
}
stat_line_end();
}
#endif
#define aDEBUG69
#ifdef DEBUG69
stream_open(0, "⚀⚁⚂⚃⚄⚅"); // utf8
stream_open(0, "Hasta la vista, baby (Arnold Schwarzenegger, T2)"); // pass phrase
stream_open(0, "abcdefghijklmnopqrstuvwxyz" // long password (key)
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz");
stream_open(5, "\x00\x01\x02\x03\x04"); // binary string with length
#endif
#define aDEBUG73
#ifdef DEBUG73
unsigned char buf[128];
command_readline("date +%Y%m%d%H%M", sizeof(buf), buf);
fprintf(stdout,"readline date '%s'\n",buf);
#endif
#define aDEBUG74
#ifdef DEBUG74
char *ds[] = { "A", "B", "T", "J", "X", "KH", "D", "R", "S", "SH",
"DH", "C", "G", "F", "Q", "K", "L", "M", "N", "W",
"H", "Y", "E", "O" }; // --som
for(c= 0; c < sizeof(ds) / sizeof(ds[0]); c++)
fprintf(stdout," `%s`",ds[c]);
fprintf(stdout,"\n");
#endif
unsigned char *flagchars[] =
{ "🇦", "🇧", "🇨", "🇩", "🇪", "🇫", "🇬", "🇭", "🇮", "🇯",
"🇰", "🇱", "🇲", "🇳", "🇴", "🇵", "🇶", "🇷", "🇸", "🇹",
"🇺", "🇻", "🇼", "🇽", "🇾", "🇿" };
#define DEBUG70
#ifdef DEBUG70
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
unsigned char buffer20[20];
unsigned char buffer128[128];
sprintf(buffer128," %s", idsflags[c].flags);
unsigned char *p = buffer128;
if(idsflags[c].id[0] != '\0')
continue;
buffer20[0] = '\0';
for(d = 0; *p != '\0'; d++) {
if(isalpha(*p) == 0 &&
islower(*(p + 1)) != 0 &&
islower(*(p + 2)) != 0 &&
isalpha(*(p + 3)) == 0) {
strcat(buffer20, flagchars[toupper(*(p + 1)) - 'A']);
strcat(buffer20, flagchars[toupper(*(p + 2)) - 'A']);
}
p++;
}
fprintf(stdout," { \"%s\"", buffer20);
fprintf(stdout,", \"%s: %s\" },\n", buffer20, idsflags[c].flags);
fflush(stdout);
}
#endif
#define aDEBUG68A // default is off
#ifdef DEBUG68A
unsigned char *hindi = malloc(8192);
digits_add_limits(&hindi,0x900,0x97f); // Hindi (0900-097f)
unsigned char *h;
int first;
//fprintf(stdout,"hindi1: %s\n", hindi);
h = hindi;
first = 1;
while(*h != '\0') {
if(!first)
fprintf(stdout, " ");
fputc(*h, stdout); // print first char
if(*h > 0xbf) { // first char utf8
h++;
for(;;) { // print rest of the utf8 chars
if(*h > 0xbf || // new utf8 character
*h < 0x80 || // ascii character
*h == '\0') // end of string
break;
fputc(*h, stdout);
h++;
}
}
first = 0;
}
fprintf(stdout,"\n");
free(hindi);
#endif
#define aDEBUG68B
#ifdef DEBUG68B
fprintf(stdout,"hebrew: ");
unsigned char *hebrew = malloc(8192);
digits_add_limits(&hebrew, 0x590, 0x5ff); // (0590-05ff)
// ֑֖֚֒֓֔֕֗֘֙־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתׯװױײ׳״
fprintf(stdout,"%s\n", hebrew);
#endif
#define aDEBUG68C
#ifdef DEBUG68C
fprintf(stdout,"phoenician: ");
unsigned char *phoenician = malloc(8192);
digits_add_limits(&phoenician, 0x10900, 0x1091f); // (10900-1091f)
//phoenician: 𐤀𐤁𐤂𐤃𐤄𐤅𐤆𐤇𐤈𐤉𐤊𐤋𐤌𐤍𐤎𐤏𐤐𐤑𐤒𐤓𐤔𐤕𐤖𐤗𐤘𐤙𐤚𐤛𐤟
fprintf(stdout,"%s\n", phoenician);
#endif
procname = argv[0];
limit = 0;
newressu_file_digest("/proc/self/exe", programfiledigest);
gent_clear();
clockbytes = 0;
for(d = 0; d < 1024; d++)
periods[d] = 0;
#ifdef USE_TIMER
int timer = 0;
double timerstart;
#endif
#define aDEBUG72 // default is on
#ifdef DEBUG19
int flagint = 1;
#endif
idsall = 1;
newressu_toggleflag("ALL");
int flagsinit = 0;
//
// look thru command line parameters
// for flags option
//
int flagflags = 0;
for(c = 1; c < argc; c++) {
if(!strcmp("--flags", argv[c])) { // not ready
flagflags = 1;
}
}
//
// look thru command line parameters
//
for(c = 1; c < argc; c++) {
int ok = 1;
if(!strncmp("-", argv[c], 1)) {
if(!strcmp("--help", argv[c]) ||
!strcmp("-?", argv[c])) {
help = 1;
} else if(!strcmp("--quiet", argv[c])) {
quiet = !quiet;
} else if(!strcmp("--stats", argv[c]) ||
!strcmp("--stat", argv[c])) {
stats = !stats;
} else if(!strcmp("--digits", argv[c])) {
flagprintdigits = !flagprintdigits;
} else if(!strcmp("--columns", argv[c])) {
columns = !columns; // print column numbers
} else if(!strncmp("--space", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
sspace = atoi(argv[c] + 7);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
sspace = atoi(argv[c + 1]);
c++;
} else {
sspace = !sspace;
}
} else if(!strncmp("--newline", argv[c], 9)) {
if(*(argv[c] + 9) != '\0' && atoi(argv[c] + 9) > 0) {
snewline = atoi(argv[c] + 9);
} else if(c + 1 < argc && atoi(argv[c + 1]) > 0) {
snewline = atoi(argv[c + 1]);
c++;
}
} else if(!strcmp("--sample", argv[c])) {
sample = !sample;
} else if(!strcmp("--dieharder", argv[c])) {
dieharder = !dieharder;
} else if(!strcmp("--purge", argv[c])) {
purge = !purge;
purge_set = 1;
} else if(!strcmp("--save", argv[c])) {
purge = 1;
purge_set = 1;
#ifdef DEBUG59
} else if(!strcmp("--utf8", argv[c])) {
utf8 = !utf8;
#endif
} else if(!strncmp("--filesize", argv[c], 10)) {
if(*(argv[c] + 10) != '\0') {
filesize_str = argv[c] + 10;
filesize = getlonglong(filesize_str);
} else if(c + 1 < argc) {
filesize_str = argv[c + 1];
filesize = getlonglong(filesize_str);
c++;
}
filesize_set = 1;
} else if(!strncmp("--blocksize", argv[c], 11)) {
if(*(argv[c] + 11) != '\0') {
blocksize_str = argv[c] + 10;
blocksize = getlonglong(blocksize_str);
} else if(c + 1 < argc) {
blocksize_str = argv[c + 1];
blocksize = getlonglong(blocksize_str);
c++;
}
blocksize_set = 1;
} else if(!strncmp("--blocks", argv[c], 8)) {
if(*(argv[c] + 8) != '\0') {
blocks_str = argv[c] + 10;
blocks = getlonglong(blocks_str);
} else if(c + 1 < argc) {
blocks_str = argv[c + 1];
blocks = getlonglong(blocks_str);
c++;
}
blocks_set = 1;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
newressu_version();
#ifdef SHA256
fprintf(stderr,"\nsha256(");
for(int c = 0; c < HashLen; c++) {
fprintf(stderr, "%02x", programfiledigest[c]);
}
#endif
fprintf(stderr, ")\n\n");
help = 0;
exit(1);
} else if(!strcmp("--webversion", argv[c])) {
fprintf(stderr, "%s", programname); // touch these outside MAIN
fprintf(stderr,", sha256(");
for(int c = 0; c < HashLen; c++) {
fprintf(stderr, "%02x", programfiledigest[c]);
}
fprintf(stderr,")\n");
exit(0);
} else if(!strcmp("--lineno", argv[c])) {
slineno = !slineno; // print line number
} else if(!strcmp("--crlf", argv[c])) {
scrlf = !scrlf;
slineno = 0;
#ifdef DEBUG19
} else if(!strcmp("--int", argv[c])) {
flagint = !flagint;
#endif
} else if(!strcmp("--rand", argv[c])) {
digits = "0123456789";
sspace = 2;
snewline = 5;
slineno = 1; // print line number
words = 10;
chars = 0;
limit = 100000;
//size = 5;
//lines = 20000;
} 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(!strncmp("--lim", argv[c], 5)) { // limit of word
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++;
}
//fprintf(stdout,"limit:%lu, %ld bytes\n", limit, sizeof(limit));
if(sspace < 1 ) // 23.6.2021
sspace = 1;
} else if(!strncmp("--size", argv[c], 6)) { // size of word
if(isdigit(*(argv[c] + 6))) {
size = atoi(argv[c] + 6);
} else if(c + 1 < argc) {
size = atoi(argv[c + 1]);
c++;
}
limit = 0; // 23.6.2021
} else if(!strncmp("-s", argv[c], 2)) { // size of word
if(isdigit(*(argv[c] + 2))) {
size = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
size = atoi(argv[c + 1]);
c++;
}
limit = 0; // 23.6.2021
} else if(!strncmp("--bits", argv[c], 6)) {
if(isdigit(*(argv[c] + 6))) {
ressut_bits1_needed = atoi(argv[c] + 6);
} else if(c + 1 < argc) {
ressut_bits1_needed = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--bytes", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
ressut_bytes = atoi(argv[c] + 7);
} else if(c + 1 < argc) {
ressut_bytes = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("--words", argv[c], 7)) { // words per line
if(isdigit(*(argv[c] + 7))) {
words = atoi(argv[c] + 7);
} else if(c + 1 < argc) {
words = atoi(argv[c + 1]);
c++;
}
if(words < 1)
words = 1;
chars = 0;
screen = 0;
} else if(!strncmp("-w", argv[c], 2)) { // words per line
if(isdigit(*(argv[c] + 2))) {
words = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
words = atoi(argv[c + 1]);
c++;
}
if(words < 1)
words = 1;
chars = 0;
screen = 0;
} else if(!strcmp("-c*", argv[c])) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
words = 0;
} else if(!strcmp("-l*", argv[c])) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
lines = w.ws_row-1;
} else if(!strcmp("--chars*", argv[c])) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
words = 0;
} else if(!strcmp("--lines*", argv[c])) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
lines = w.ws_row-1;
} else if(!strncmp("--screen", argv[c],8)) { // screenful
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
lines = w.ws_row-1;
words = 0;
screen = 1;
} else if(!strncmp("--chars", argv[c], 7)) { // characters per line
if(isdigit(*(argv[c] + 7))) {
chars = atoi(argv[c] + 7);
} else if(c + 1 < argc) {
chars = atoi(argv[c + 1]);
c++;
}
if(chars < 1)
chars = 72;
words = 0;
screen = 0;
} else if(!strncmp("-c", argv[c], 2)) { // characters per line
if(isdigit(*(argv[c] + 2))) {
chars = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
chars = atoi(argv[c + 1]);
c++;
}
if(chars < 1)
chars = 72;
words = 0;
screen = 0;
} else if(!strncmp("--lines",argv[c], 7)) { // lines
if(isdigit(*(argv[c] + 7))) {
lines = atoll(argv[c] + 7);
} else if(c + 1 < argc) {
lines = atoll(argv[c + 1]);
c++;
}
screen = 0;
} else if(!strncmp("-l",argv[c], 2)) { // lines
if(isdigit(*(argv[c] + 2))) {
lines = atoll(argv[c] + 2);
} else if(c + 1 < argc) {
lines = atoll(argv[c + 1]);
c++;
}
screen = 0;
} else if(!strcmp("--otp1", argv[c]) || // see: one time pad
!strcmp("--otp5n", argv[c]) || // digits length 5
!strcmp("--onetimepad1", argv[c])) {
digits = "0123456789";
sspace = 1;
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("--otp2", argv[c]) || // uppercase alpha length 5
!strcmp("--otp5a", argv[c]) ||
!strcmp("--onetimepad2", argv[c]) ||
!strcmp("--diana", argv[c]) ) { // see: diana cipher, diana table
digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
sspace = 1;
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("--otp3", argv[c]) || // uppercase alpha length 4
!strcmp("--otp4a", argv[c]) ||
!strcmp("--onetimepad3", argv[c])) {
digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
sspace = 1;
charspaces = 0;
charwidth = 1;
size = 4;
type = 0;
} else if(!strncmp("--base", argv[c], 6)) {
if(isdigit(*(argv[c] + 6))) {
newressu_base(atoi(argv[c] + 6));
} else if(c + 1 < argc) {
newressu_base(atoi(argv[c + 1]));
c++;
}
if(base < 2 || base > 64) {
fprintf(stderr,"%s: base must be from 2 to 64 (%s)\n", procname, argv[c]);
exit(2);
}
} else if(!strncmp("--BASE", argv[c], 6)) {
if(isdigit(*(argv[c] + 6))) {
uppercase = 1;
newressu_base(atoi(argv[c] + 6));
} else if(c + 1 < argc) {
uppercase = 1;
newressu_base(atoi(argv[c + 1]));
c++;
}
if(base < 2 || base > 64) {
fprintf(stderr,"%s: base must be from 2 to 64 (%s)\n", procname, argv[c]);
exit(2);
}
} else if(!strcmp("-b", argv[c]) ||
!strcmp("--bin", argv[c]) ||
!strcmp("--1bit", argv[c]) ||
!strcmp("--1bits", argv[c])) {
newressu_base(2);
} else if(!strcmp("--2bits", argv[c])) {
newressu_base(4);
} else if(!strcmp("-o", argv[c]) ||
!strcmp("--oct", argv[c]) ||
!strcmp("--3bits", argv[c]) ) {
newressu_base(8);
} else if(!strcmp("-d", argv[c]) ||
!strcmp("--dec", argv[c])) {
newressu_base(10);
} else if(!strcmp("-x", argv[c]) ||
!strcmp("--hex", argv[c]) ||
!strcmp("--4bits", argv[c])) {
newressu_base(16);
} else if(!strcmp("-X", argv[c]) ||
!strcmp("--HEX", argv[c]) ||
!strcmp("--4BITS", argv[c])) {
newressu_base(16);
uppercase = 1;
} else if(!strcmp("-5", argv[c]) ||
!strcmp("--5bits", argv[c])) {
newressu_base(32);
base = 32;
} else if(!strcmp("--5BITS", argv[c])) {
newressu_base(32);
uppercase = 1;
} else if(!strcmp("-2", argv[c]) ||
!strcmp("--6bits", argv[c])) {
newressu_base(64);
} else if(!strcmp("-1", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("--numeric", argv[c]) ||
!strcmp("-11", argv[c])) {
digits =
"0123456789";
charspaces = 0;
charwidth = 1;
size = 5;
type = 10;
} else if(// !strcmp("--ALPHA", argv[c]) ||
!strcmp("--LATIN", argv[c]) ||
!strcmp("-12", argv[c]) ) {
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
charspaces = 0;
charwidth = 1;
size = 5;
} else if( //!strcmp("--alpha", argv[c]) ||
!strcmp("--latin", argv[c]) ||
!strcmp("-13", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("-13v1", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz" \
"aeiouy"; // extra vowels
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("-13v2", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz"
"aeiouy" // extra vowels
"aeiouy"; // extra vowels
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("-13v3", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz"
"aeiouy" // extra vowels
"aeiouy" // extra vowels
"aeiouy"; // extra vowels
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("-13v4", argv[c])) {
digits =
"abcdefghijklmnopqrstuvwxyz"
"aeiouy" // extra vowels
"aeiouy" // extra vowels
"aeiouy" // extra vowels
"aeiouy"; // extra vowels
charspaces = 0;
charwidth = 1;
size = 5;
type = 0;
} else if(!strcmp("-3", argv[c])) { // 9.5.2021 JariK
digits =
"!\"#$%&'()*+,-./0123456789:;<=>?@" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
"abcdefghijklmnopqrstuvwxyz{|}~";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("-9", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--dnk", argv[c]) || // Danish alphabet
!strcmp("--nor", argv[c])) { // Norwegian alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" \
"abcdefghijklmnopqrstuvwxyzæøå";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--fin", argv[c]) || // Finnish alphabet
!strcmp("--swe", argv[c])) { // Swedish alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ" \
"abcdefghijklmnopqrstuvwxyzåäö";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--rus", argv[c])) { // Russian alphabet
digits =
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ" \
"абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--est", argv[c])) { // Estonian alphabet
digits =
"ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY" \
"abcdefghijklmnopqrsšzžtuvwõäöüxy";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--ltu", argv[c])) { // Lithuanian alphabet
digits =
"AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ" \
"aąbcčdeęėfghiįyjklmnoprsštuųūvzž";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--lva", argv[c])) { // Latvian alphabet
digits =
"AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ" \
"aābcčdeēfgģhiījkķlļmnņoprsštuūvzž";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--fra", argv[c]) // French alphabet
||!strcmp("--gbr", argv[c]) // Great Britain alphabet
||!strcmp("--usa", argv[c]) // United States alphabet
||!strcmp("--ita", argv[c]) // Italian alphabet
||!strcmp("--eng", argv[c]) // English alphabet
) {
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--deu", argv[c])) { // Deutsch alphabet
digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜẞ" \
"abcdefghijklmnopqrstuvwxyzäöüß";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--grc", argv[c])) { // Greek alphabet
digits =
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ" \
"αβγδεζηθικλμνξοπρστυφχψω";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--jp", argv[c])) { // all Japanese alphabets
digits = NULL;
digits_add_string(&digits,
"ぁあぃいぅうぇえぉおかがきぎく"
"ぐけげこごさざしじすずせぜそぞた"
"だちぢっつづてでとどなにぬねのは"
"ばぱひびぴふぶぷへべぺほぼぽまみ"
"むめもゃやゅゆょよらりるれろゎわ"
"ゐゑをんゔゕゖ");
digits_add_string(&digits,
"゠ァアィイゥウェエォオカガキギク"
"グケゲコゴサザシジスズセゼソゾタ"
"ダチヂッツヅテデトドナニヌネノハ"
"バパヒビピフブプヘベペホボポマミ"
"ムメモャヤュユョヨラリルレロヮワ"
"ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ");
digits_add_limits(&digits, 0x4e00, 0x9fef);
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--jp1", argv[c]) // Japanese hiragana alphabet
|| !strcmp("--hir", argv[c])) {
digits =
"ぁあぃいぅうぇえぉおかがきぎく"
"ぐけげこごさざしじすずせぜそぞた"
"だちぢっつづてでとどなにぬねのは"
"ばぱひびぴふぶぷへべぺほぼぽまみ"
"むめもゃやゅゆょよらりるれろゎわ"
"ゐゑをんゔゕゖ";
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--jp2", argv[c]) // Japanese katakana alphabet
|| !strcmp("--kat", argv[c])) {
digits =
"゠ァアィイゥウェエォオカガキギク"
"グケゲコゴサザシジスズセゼソゾタ"
"ダチヂッツヅテデトドナニヌネノハ"
"バパヒビピフブプヘベペホボポマミ"
"ムメモャヤュユョヨラリルレロヮワ"
"ヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ";
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--cn", argv[c]) // Chinese alphabet
|| !strcmp("--jp3", argv[c]) // Japanese kanji alphabet
|| !strcmp("--kan", argv[c])) { // Japanese kanji alphabet
digits = NULL;
digits_add_limits(&digits, 0x4e00, 0x9fef);
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--kor", argv[c])) { // Korean alphabet
digits = NULL;
digits_add_limits(&digits,0xac00,0xd7a3); // Hangul Syllables (AC00–D7A3)
//digits_add_limits(&digits,0x1100,0x11ff); // Hangul Jamo (1100–11FF)
//digits_add_limits(&digits,0x3130,0x318f); // Hangul Compatibility Jamo (3130–318F)
//digits_add_limits(&digits,0xa960,0xa97f); // Hangul Jamo Extended-A (A960–A97F)
//digits_add_limits(&digits,0xd7b0,0xd7ff); //Hangul Jamo Extended-B (D7B0–D7FF)
digitsext = digits;
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--ind", argv[c]) // not ready
|| !strcmp("--hin", argv[c])) { // Hindi alphabet
//unsigned char *signs = "ऀँंःऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॕॖॗॢॣ॒॑॓॔";
digits =
"ऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढण"
"तथदधनऩपफबभमयरऱलळऴवशषसहऽॐक़ख़ग़ज़ड़"
"ढ़फ़य़ॠॡ।॥०१२३४५६७८९॰ॱॲॳॴॵॶॷॸॹॺॻॼॽॾ"
"ॿ"; // 97 characters
//digits_add_limits(&digits,0x900,0x97f); // Hindi (0900-097f)
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--heb", argv[c])) { // hebrew
// ֑֖֚֒֓֔֕֗֘֙־ֿ׀ׁׂ׃ׅׄ׆ׇאבגדהוזחטיךכלםמןנסעףפץצקרשתׯװױײ׳״
digits = "אבגדהוזחטיךכלםמןנסעףפץצקרשת";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--pho", argv[c])) { // phoenician alphabet, (fi "foinikialaiset aakkoset")
//phoenician: 𐤀𐤁𐤂𐤃𐤄𐤅𐤆𐤇𐤈𐤉𐤊𐤋𐤌𐤍𐤎𐤏𐤐𐤑𐤒𐤓𐤔𐤕𐤖𐤗𐤘𐤙𐤚𐤛𐤟
digits = "𐤀𐤁𐤂𐤃𐤄𐤅𐤆𐤇𐤈𐤉𐤊𐤋𐤌𐤍𐤎𐤏𐤐𐤑𐤒𐤓𐤔𐤕𐤖𐤗𐤘𐤙𐤚𐤛";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--som", argv[c]) ||
!strcmp("--SOM", argv[c]) ||
!strcmp("--SO", argv[c])) { // Somalia alphabet
#define aNEWSOM 2
#ifdef NEWSOM
digits = NULL;
// A, B, T, J, X, KH, D, R, S, SH, DH, C, G, F, Q, K, L, M, N, W, H, Y, E, and O
digits_add_string(&digits, "A;");
digits_add_string(&digits, "B;");
digits_add_string(&digits, "T;");
digits_add_string(&digits, "J;");
digits_add_string(&digits, "X;");
digits_add_string(&digits, "KH;");
digits_add_string(&digits, "D;");
digits_add_string(&digits, "R;");
digits_add_string(&digits, "S;");
digits_add_string(&digits, "SH;");
digits_add_string(&digits, "DH;");
digits_add_string(&digits, "C;");
digits_add_string(&digits, "G;");
digits_add_string(&digits, "F;");
digits_add_string(&digits, "Q;");
digits_add_string(&digits, "K;");
digits_add_string(&digits, "L;");
digits_add_string(&digits, "M;");
digits_add_string(&digits, "N;");
digits_add_string(&digits, "W;");
digits_add_string(&digits, "H;");
digits_add_string(&digits, "Y;");
digits_add_string(&digits, "E;");
digits_add_string(&digits, "O;");
flagdigits = 2; // semicolon separated (flags)
#else
// missing KH SH DH
digits = "ABTJXDRSCGFQKLMNWHYEO";
#endif
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--braille", argv[c])) { // Braille alphabet
digits = // 0x2800 - 0x2900
"⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
"⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿"
"⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿"
"⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
charspaces = 0;
charwidth = 1;
size = 8;
type = 0;
} else if(!strcmp("--got", argv[c])) { // Gothic alphabet
digits=
"𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷𐌸𐌹𐌺𐌻𐌼𐌽𐌾𐌿"
"𐍀𐍁𐍂𐍃𐍄𐍅𐍆𐍇𐍈𐍉𐍊";
} else if(!strcmp("---champagne", argv[c])) { // Gothic alphabet
digits = "🍾🥂🥂🥂🥂"; // 🥤🥤🥤🥤🥤🥤🥤🥤"; //
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
} else if(!strcmp("--cards", argv[c])) {
digits=
"🂡🂢🂣🂤🂥🂦🂧🂨🂩🂪🂫🂭🂮"
"🂱🂲🂳🂴🂵🂶🂷🂸🂹🂺🂻🂽🂾"
"🃁🃂🃃🃄🃅🃆🃇🃈🃉🃊🃋🃍🃎"
"🃑🃒🃓🃔🃕🃖🃗🃘🃙🃚🃛🃝🃞";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--cardsuits", argv[c])) {
digits=
"♠♡♢♣♤♥♦♧";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--chessmen", argv[c])) {
digits=
"♔♕♖♗♘♙♚♛♜♝♞♟";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--dice", argv[c])) {
digits=
"⚀⚁⚂⚃⚄⚅";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--mahjong", argv[c])) {
digits= // removed 🀄 & 🀫
"🀀🀁🀂🀃🀅🀆" \
"🀇🀈🀉🀊🀋🀌🀍🀎🀏" \
"🀐🀑🀒🀓🀔🀕🀖🀗🀘" \
"🀙🀚🀛🀜🀝🀞🀟🀠🀡" \
"🀢🀣🀤🀥🀦🀧🀨🀩🀪";
charspaces = 1;
charwidth = 2;
size = 5;
type = 0;
} else if(!strcmp("--dna", argv[c])) {
digits=
"acgt";
charspaces = 0;
charwidth = 1;
size = 4;
type = 0;
} else if(!strcmp("--DNA", argv[c])) {
digits=
"ACGT";
charspaces = 0;
charwidth = 1;
size = 4;
type = 0;
} else if(!strcmp("--pattern1", argv[c])) {
digits=
"▌▙▄";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern2", argv[c])) {
digits=
"◜◝◞◟";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern3", argv[c])) {
digits=
"\\/";
charspaces = 0;
charwidth = 1;
size = 1;
type = 0;
} else if(!strcmp("--pattern4", argv[c])) {
digits=
"◸◹◺◿";
charspaces = 1;
charwidth = 2;
size = 1;
type = 0;
} else if(!strcmp("--pattern5", argv[c])) {
digits=
"▧▨";
charspaces = 1;
charwidth = 2;
size = 1;
type = 0;
} else if(!strcmp("--alnum", argv[c]) || // 9.5.2021 JariK
!strcmp("--alpha", argv[c]) ||
!strcmp("--digit", argv[c]) ||
!strcmp("--graph", argv[c]) ||
!strcmp("--lower", argv[c]) ||
!strcmp("--print", argv[c]) ||
!strcmp("--punct", argv[c]) ||
!strcmp("--upper", argv[c]) ||
!strcmp("--xdigit", argv[c])) {
unsigned char *p = digitstemp;
for(d = 0; d < 256; d++) {
if((!strcmp("--alnum", argv[c]) && isalnum(d)) ||
(!strcmp("--alpha", argv[c]) && isalpha(d)) ||
(!strcmp("--digit", argv[c]) && isdigit(d)) ||
(!strcmp("--graph", argv[c]) && isgraph(d)) ||
(!strcmp("--lower", argv[c]) && islower(d)) ||
(!strcmp("--print", argv[c]) && isprint(d)) ||
(!strcmp("--punct", argv[c]) && ispunct(d)) ||
(!strcmp("--upper", argv[c]) && isupper(d)) ||
(!strcmp("--xdigit", argv[c]) && isxdigit(d))) {
*p++ = d;
}
}
*p = '\0';
digits = digitstemp;
size = 5;
type = 0;
} 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 || utf8characters(digits) < 2) {
fprintf(stderr,"%s: not enough digits \"%s\"\n", procname, argv[c]);
}
size = 1;
#ifdef USE_TIMER
} else if(!strcmp("--timer", argv[c])) {
timer = 1;
#endif
} else if(!strcmp("--clockstream", argv[c])) { // clockstream
input = INPUT_CLOCK;
input_str = argv[c] + 2;
} else if(!strcmp("--test", argv[c])) { // test generator
input = INPUT_TEST;
input_str = argv[c] + 2;
} else if(!strcmp("--ressu", argv[c])) {
input = INPUT_RESSU;
input_str = argv[c] + 2;
} else if(!strcmp("--pseudoressu", argv[c])) {
input = INPUT_PSEUDORESSU;
input_str = argv[c] + 2;
} else if(!strcmp("--ressutwist", argv[c]) // JariK 2023
|| !strcmp("--ressuwtwist", argv[c])
|| !strcmp("--twist", argv[c]) ) {
input = INPUT_RESSUTWIST;
input_str = argv[c] + 2;
} else if(!strcmp("--fast", argv[c])
|| !strcmp("--fastressu", argv[c]) ) {
input = INPUT_FASTRESSU;
input_str = argv[c] + 2;
} else if(!strcmp("--single", argv[c])
|| !strcmp("--singleressu", argv[c]) ) {
input = INPUT_SINGLERESSU;
input_str = argv[c] + 2;
} else if(!strcmp("--stream", argv[c])) {
input = INPUT_STREAM;
input_str = argv[c] + 2;
} else if(!strncmp("--key", argv[c], 5)) {
key = NULL;
if(*(argv[c] + 5) != '\0') {
key = argv[c] + 5;
} else if(c + 1 < argc) {
key = argv[c + 1];
c++;
}
if(key == NULL || utf8characters(key) < 1) {
fprintf(stderr,"%s: not enough key characters \"%s\"\n", procname, argv[c]);
exit(1);
}
//size = 1;
} else if(!strncmp("--fixedclock", argv[c], 12)) {
if(*(argv[c] + 12) != '\0' && atoi(argv[c] + 12) > 1) {
fixedclockchainlength = atoi(argv[c] + 12);
fixedclock = 1;
} else if(c + 1 < argc && atoi(argv[c + 1]) > 1) {
fixedclockchainlength = atoi(argv[c + 1]);
fixedclock = 1;
c++;
} else {
fixedclock = !fixedclock;
}
if(fixedclockchainlength < 5 ||
fixedclockchainlength > 255)
fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
} else if(!strncmp("--depth", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
depth = atoi(argv[c] + 7);
} else if(c + 1 < argc && isdigit(*(argv[c + 1]))) {
depth = atoi(argv[c + 1]);
c++;
} else {
depth = MAX_DEPTH;
}
if(depth < 0 || depth > MAX_DEPTH) {
fprintf(stderr,"%s: --depth must be between 0 and %d(MAX_DEPTH)\n",
procname, MAX_DEPTH);
exit(2);
}
fprintf(stderr,"depth:%d\n", depth);
} else if(!strcmp("--copyreverse", argv[c])) {
copyreverse = !copyreverse;
} else if(!strcmp("--verbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--statline", argv[c])) {
print_statline = !print_statline;
#ifdef FORT
} else if(!strcmp("--fort", argv[c])) {
input = INPUT_FORT;
input_str = argv[c] + 2;
} else if(!strcmp("--fortxor", argv[c])) {
input = INPUT_FORTXOR;
input_str = argv[c] + 2;
} else if(!strcmp("--fortverbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--fortuseweb", argv[c])) {
fort_use_web = !fort_use_web;
#endif
#ifdef USE_RDRAND
} else if(!strcmp("--rdrand", argv[c])) {
input = INPUT_RDRAND;
input_str = argv[c] + 2;
#endif
#ifdef USE_RDSEED
} else if(!strcmp("--rdseed", argv[c])) {
input = INPUT_RDSEED;
input_str = argv[c] + 2;
#endif
} else if(!strcmp("--urandom", argv[c])) {
input = INPUT_URANDOM;
input_str = argv[c] + 2;
#ifdef USE_RANDOM
} else if(!strcmp("--random", argv[c])) {
input = INPUT_RANDOM;
input_str = argv[c] + 2;
#endif
} else if(!strcmp("--dummy", argv[c])) {
input = INPUT_DUMMY;
input_str = argv[c] + 2;
} else if(!strcmp("--flags", argv[c])) { // not ready
charspaces = 0;
charwidth = 2;
size = 8;
type = 0;
flagdigits = 1; // semicolon separated (flags)
// code after command line parameter loop
} else if(!strcmp("--all", argv[c])) { // not ready
if(flagsinit) {
idsall = 1;
newressu_toggleflag("ALL");
flagsinit = 0;
}
flagdigits = 1; // semicolon separated (flags)
} else {
ok = 0;
}
unsigned char buffer[32];
int ok2 = 0;
// command line parameters for flags
if(!strncmp(argv[c], "--", 2)) {
if(flagsinit) {
idsall = 0;
newressu_toggleflag(buffer);
flagsinit = 0;
}
strcpy(buffer, argv[c] + 2); // as is, skip dashes
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
strtolower(buffer); // all letters lowercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
buffer[0] = toupper(buffer[0]); // first letter uppercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
else {
strtoupper(buffer); // all letters uppercase
if(newressu_toggleflag(buffer) == 1)
ok2 = 1;
}
}
}
}
if(flagflags && ok == 0 && ok2 == 0) {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
if(!flagflags && ok == 0 && ok2 == 0) {
fprintf(stderr,"%s: invalid option %s\n", procname, argv[c]);
exit(1);
}
if(!flagflags && ok == 0 && ok2 == 1) {
fprintf(stderr,"%s: invalid option '%s' without --flags\n", procname, argv[c]);
exit(1);
}
} // if(!strncmp
} // for(c = 0
if(size == -1 && base != -1) {
if(base == 2)
size = 8;
else if(base == 8)
size = 3;
else if(base == 10)
size = 5;
else if(base == 16)
size = 4;
else
size = 8;
}
if(size == -1 && base == -1)
size = 5;
if(base != -1) {
digitsext = digits;
charspaces = 0;
charwidth = 1;
}
if(flagflags) {
digits = NULL;
flagdigits = 1; // semicolon separated (flags)
for(d = 0; d < sizeof(idsflags) / sizeof(idsflags[0]); d++) {
unsigned char buffer[32];
if(flagids[d] == 1) {
strcpy(buffer,idsflags[d].id);
strcat(buffer,";");
digits_add_string(&digits, buffer);
}
}
if(digits == NULL)
digits = "🇫🇮;";
else
digitsext = digits;
//digits = "🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿";
//digits = "🇫🇮🇸🇪🇳🇴🇩🇰🇪🇪🇱🇻🇱🇹";
}
#define aDEBUG76
#ifdef DEBUG76
if(flagidflags) {
int first = 1;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
if(flagids[c] == 1) {
if(first) {
fprintf(stdout,"flags: ");
first = 0;
}
fprintf(stdout," %s",idsflags[c].id);
}
}
if(!first)
fprintf(stdout,"\n");
}
#endif
#ifdef DEBUG59
if(utf8) {
int xlines;
printcolumns(6, 0x10, 0, 64, &xlines);
int utf8output = 0;
for(c = 0; c < 65535 * 4; c++) {
//for(c = 0x2800; c < 0x2900; c++) { // braille
unsigned char buffer10[10];
if(c % 64 == 0) {
if(c > 0) {
fprintf(stdout,"\n");
utf8output = 0;
}
fprintf(stdout,"%5x ", c);
utf8output = 1;
}
if(c >= 0 && c < 32) {
c += 31;
fprintf(stdout, "%-32s", "--- control characters ---");
utf8output = 1;
} else if(c >= 128 && c < 256) {
c += 31;
fprintf(stdout, "%-32s", "--- utf8 characters ---");
utf8output = 1;
} else {
codetoutf8(buffer10, c);
fprintf(stdout,"%s", buffer10);
utf8output = 1;
}
}
if(utf8output)
fprintf(stdout,"\n");
fflush(stdout);
return(0);
}
#endif
#define aDEBUG60 2
#ifdef DEBUG60
int xlines;
printcolumns(0, 2, 0, 64, &xlines);
printcolumns(0, 8, 0, 64, &xlines);
for(c=1;;c*=10) {
fprintf(stdout,"c:%d\n",c);
printcolumns(0, 10, 0, c, &xlines);
}
printcolumns(0, 16, 0, 64, &xlines);
#endif
if(size == 0)
size = 1;
else if(size > 1024)
size = 1024;
if(lines < 1)
lines = 1;
#ifdef USE_TIMER
timerstart = getseconds();
#endif
if(flagdigits) // semicolon separated (flags)
digitscount = utf8strings(digits);
else // not
digitscount = utf8characters(digits);
//digitscount = utf8characters(digits);
if(flagdigits) // semicolon separated (flags)
characterlengths = utf8stringlengths(digits);
else
characterlengths = utf8lengths(digits);
//characterlengths = utf8lengths(digits);
#ifdef FORT
if(input == INPUT_FORT ||
input == INPUT_FORTXOR ) {
strcpy(fort_random_file, "newressufort.rnd");
strcpy(fort_secret_file, "newressufortsecret.rnd");
//fort_verbose = 0;
fort_init();
}
#endif
if(input == INPUT_STREAM) {
if(key == NULL)
key = stream_default_key;
stream_open(0, key);
} else if(key != NULL) {
fprintf(stderr,"%s: cannot --key without --stream\n", procname);
exit(2);
}
if(fixedclock && !copyreverse) {
fprintf(stderr,"%s: cannot --fixedclock without --copyreverse\n", procname);
exit(2);
}
if(dieharder && !sample) {
fprintf(stderr,"%s: cannot --dieharder without --sample\n", procname);
exit(2);
}
if(purge_set && (!dieharder || !sample)) {
fprintf(stderr,"%s: cannot --purge or --save without --sample and --dieharder\n", procname);
exit(2);
}
if((filesize_set || blocksize_set || blocks_set) && !sample) {
fprintf(stderr,"%s: cannot --filesize, --blocks or --blocksize without --sample\n", procname);
exit(2);
}
if(input == INPUT_TEST) {
fprintf(stderr,"%s: randomness from your generator (test_bytes)\n", procname);
}
if(sample) { // & dieharder
dump_sample();
exit(status);
} // if(sample)
#ifdef DEBUG19
if(flagint) {
unsigned char savepath[128];
save_path(sizeof(savepath), savepath);
if(!strncmp(procname, "/bin/newressu", 13) && exists_path("/var/ressu"))
set_path("/var/ressu");
else if(!strncmp(procname, "./newressu", 10) && exists_path(".ressu"))
set_path(".ressu");
else if(exists_path("/var/ressu"))
set_path("/var/ressu");
else if(exists_path("/var/newressu"))
set_path("/var/newressu");
else if(exists_path(".ressu"))
set_path(".ressu");
else
set_path("./");
unsigned char command[160], date[16], filename[64];
command_readline("date +%Y%m%d%H", sizeof(date), date);
//command_readline("date +%Y%m%d%H%M", sizeof(date), date);
sprintf(filename,"newressutest14.rnd.%s", date);
sprintf(command,"./newressutest14.sh >%s",filename);
//fprintf(stdout,"date:%s, filename:%s\n", date, filename);
if(!exists_path(filename)) {
int error;
if((error = system(command)) != 0) {
fprintf(stderr,"%s: system(): cannot execute command '%s'\n", procname, command);
}
}
//fprintf(stderr," done.\n");
fflush(stderr);
set_path(savepath);
} // if(flagint
#endif
// print used digits
if(flagprintdigits) {
int count = 0;
unsigned char *p;
fprintf(stdout,"digits:");
p = digits;
while(*p != '\0') {
if(*p < 0x80 || // ascii char
*p > 0xbf) { // first utf8 byte
count++;
#ifdef KOK
if((charwidth == 2 && count >= 32) ||
(charwidth == 1 && count >= 72) )
break;
#endif
}
fprintf(stdout,"%c", *p);
p++;
}
if(*p != '\0')
fprintf(stdout,"...");
fprintf(stdout,"\n");
}
// 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 = utf8characters(wordbuf);
}
pchars = 0;
pwords = 0;
// in beginning of line, count printed line number
if(!quiet && slineno) {
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
pchars += strlen(linenobuf);
pchars++;
}
// count words
cwords = 0;
while((chars > 0 && pchars + size * charwidth + calc_spaces(pwords) <= chars) ||
(words > 0 && pwords < words)) {
pchars += calc_spaces();
pchars += (size * charwidth);
pwords++;
cwords++;
}
// there has to be atleast one data word
if(pwords < 1) {
pchars += calc_spaces();
pchars += (size * charwidth);
pwords = 1;
}
unsigned long wordvalues = 1, wordvaluesold;
for(c = 0; c < size; c++) {
wordvaluesold = wordvalues;
wordvalues *= digitscount;
if(wordvalues / digitscount != wordvaluesold) {
wordvalues = 0;
break;
}
}
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");
exit(2);
}
} else {
if(sort == 1 && size > 0 && wordvalues > 0 && wordvalues < pwords) {
fprintf(stderr, "%s:", procname);
fprintf(stderr, " digits is less than calculated words");
fprintf(stderr, ", digits:%d(%lu)", digitscount, wordvalues);
fprintf(stderr, ", words:%d\n", pwords);
exit(2);
}
}
// "small" words as single newressu_gen_limit() call
if(limit == 0 && wordvalues > 0)
limit = wordvalues;
if(columns) {
int xlines;
printcolumns(0, 10, 0, pchars, &xlines);
lines -= xlines;
if(lines < 1)
lines = 1;
}
#ifdef TEST
if(flagint && base != -1) {
fprintf(stderr,"Last word: ");
fprintfbase(stderr, limit - 1, base);
fprintf(stderr,"\n");
}
#endif
if(stats) {
fprintf(stderr, "randomsource:%s", input_str);
fprintf(stderr, ", fixedclock:%d", fixedclock);
if(fixedclock == 1)
fprintf(stderr, ", fixedclockchainlength:%d", fixedclockchainlength);
fprintf(stderr, ", copyreverse:%d", copyreverse);
fprintf(stderr, ", size:%d", size);
fprintf(stderr, ", lines:%llu", lines);
fprintf(stderr, ", pchars:%d", pchars);
fprintf(stderr, ", pwords:%d", pwords);
fprintf(stderr, ", sspace:%d", sspace);
fprintf(stderr, ", tchars:%llu", (unsigned long long)size * pwords * lines);
fprintf(stderr, ", digitscount:%d", digitscount);
fprintf(stderr, ", characterlengths:%d", characterlengths);
fprintf(stderr, ", strlen(digits):%ld", strlen(digits));
if(wordvalues > 0)
fprintf(stderr, ", wordvalues:%lu", wordvalues);
if(limit > 0) {
fprintf(stderr, ", limit:%lu", limit);
#ifdef DEBUG51
fprintf(stderr, ", type:%d", type);
fprintf(stderr, ", limitsize%d:%d", type, limitsize);
#endif
}
fprintf(stderr, ", pid:%d", getpid());
fprintf(stderr, "\n");
}
if(help) {
struct helpline {
char *command;
char *text;
} helplines[] = {
{ "newressu --help/-?", "this help page" },
{ "newressu -d/--dec", "print random decimal digits (default)" },
{ "newressu -o/--oct", "octal digits" },
{ "newressu -x/--hex", "hexadecimal digits" },
{ "newressu -b/--bin", "binary digits" },
{ "newressu -d --space", "decimal digits, with spaces between \"words\"" },
{ "newressu -b --space", "binary digits, with spaces between \"words\"" },
{ "newressu -d -l30", "decimal digits, 30 lines" },
{ "newressu -d -l30 --lineno", "decimal digits, 30 lines, no linenumbers" },
{ "newressu --base2", "base 2 digits =decimal (0-1)" },
{ "newressu --base8", "base 8 digits =octal (0-7)" },
{ "newressu --base10", "base 10 digits =decimal (0-9)" },
{ "newressu --base16", "base 16 digits =hexadecimal (0-F)" },
{ "newressu --base62", "base 62 digits (0-9, A-Z, a-z)" },
{ "newressu --rand", "numbers in rand style listing" },
{ "newressu --space 2", "numbers in 2 number groups" },
{ "newressu --newline 5", "print numbers in 5 line groups" },
{ "newressu -l*", "fill all screen lines" },
{ "newressu -c*", "fill all screen columns" },
{ "newressu --screen", "fill screen columns and lines" },
{ "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 --isupper --limBAAAAA","print five letter uppercase words" },
{ "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 --alnum", "alphanumeric characters" },
{ "newressu --alpha", "alphabetic characters" },
{ "newressu --graph", "printables excluding space" },
{ "newressu --lower", "lowercase characters" },
{ "newressu --punct", "punctuation characters" },
{ "newressu --upper", "uppercase characters" },
{ "newressu -1", "material for passwords" },
{ "newressu --dnk/--nor", "danish/norwegian alphabet" },
{ "newressu --fin/--swe", "finnish/norwegian alphabet" },
{ "newressu --rus", "russian alphabet" },
{ "newressu --est", "estonian alphabet" },
{ "newressu --ltu", "lithuanian alphabet" },
{ "newressu --lva", "latvian alphabet" },
{ "newressu --fra/--gbr/--usa/--ita", "french/gb/us/italian alphabet" },
{ "newressu --deu", "deutsch alphabet" },
{ "newressu --grc", "greek alphabet" },
{ "newressu --jp", "japan alphabet (hiragana, katakana, kanji) " },
{ "newressu --jp1/--hir", "japan alphabet (hiragana) " },
{ "newressu --jp2/--kat", "japan alphabet (katakana) " },
{ "newressu --jp3/--kan", "japan alphabet (kanji) " },
{ "newressu --cn", "chinese alphabet" },
{ "newressu --heb", "hebrew alphabet" },
{ "newressu --hin/--ind", "hindi alphabet" },
{ "newressu --kor", "korean alphabet" },
{ "newressu --got", "gothic alphabet" },
{ "newressu --otp5n/--otp1", "\"one time pad\" (otp) with 5 numeric characters" },
{ "newressu --otp5a/--otp2", "otp with 5 uppercase letters" },
{ "newressu --otp4a/--otp3", "otp with 4 uppercase letters" },
{ "newressu --cards", "playing cards" },
{ "newressu --cardsuits", "playing card suits" },
{ "newressu --chessmen", "chess men" },
{ "newressu --dice", "print dice" },
{ "newressu --mahjong", "print mahjong pieces" },
{ "newressu -i▌▙▄ / --pattern1", "print pattern1" },
{ "newressu -i◜◝◞◟ / --pattern2", "print pattern2" },
{ "newressu -i\\\\/ / --pattern3", "print pattern2" },
{ "newressu -i▧▨ / --pattern5", "print pattern2" },
{ "newressu --ressu", "use randomness from ressu (default)" },
{ "newressu --pseudoressu", "use randomness from pseudo random ressu" },
{ "newressu --fast/--fastressu", "use randomness from fast ressu" },
{ "newressu --single/--singleressu", "use randomness from single round of ressu" },
#ifdef FORT
{ "newressu --fort", "use randomness from fort" },
#endif
#ifdef USE_RDRAND
{ "newressu --rdrand", "use randomness from intel rdrand" },
#endif
#ifdef USE_RDSEED
{ "newressu --rdseed", "use randomness from intel rdseed" },
#endif
{ "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(stdout, "%-50s", helplines[c].text);
fprintf(stdout, "%-25s", helplines[c].command);
fprintf(stdout, "\n");
}
#define DEBUG77 2
#ifdef DEBUG77
unsigned char *areaflags = "FINLAND, DENMARK, NORDIC, BALTIC, FRANCE, UK, SPAIN, EU, NORTHERNEUROPE, EASTERNEUROPE, SOUTHERNEUROPE, WESTERNEUROPE, EUROPE, EURASIA, NORTHASIA, EASTASIA, CENTRALASIA, SOUTHASIA, WESTASIA, ASIA, NORTHAFRICA, EASTAFRICA, CENTRALAFRICA, SOUTHAFRICA, WESTAFRICA, AFRICA, NORTHAMERICA, SOUTHAMERICA, USA, OCEANIA, AUSTRALASIA, MELANESIA, MICRONESIA, POLYNESIA, BRICS, ALL", *a;
unsigned char name[128];
a = areaflags;
while(*a != '\0' && newressu_getname(sizeof(name), name, &a)) {
fprintf(stdout,"area:%s",name);
int count = 0;
for(c = 0; c < sizeof(idsflags) / sizeof(idsflags[0]); c++) {
if(!strcmp(name, "ALL")) {
count++;
unsigned char *q = idsflags[c].flags;
unsigned char name2[128], name3[128];
newressu_getname(sizeof(name2), name2, &q); // flag
newressu_getname(sizeof(name2), name2, &q); // 2 char isocode
newressu_getname(sizeof(name3), name3, &q); // 3 char isocode
newressu_getname(sizeof(name3), name3, &q); // name
fprintf(stdout,", %s(%s)",name3, name2); // name and isocode2 needed
} else {
if(newressu_strstr(idsflags[c].flags, name) != NULL) {
count++;
unsigned char *q = idsflags[c].flags;
unsigned char name2[128], name3[128];
newressu_getname(sizeof(name2), name2, &q); // flag
newressu_getname(sizeof(name2), name2, &q); // 2 char isocode
newressu_getname(sizeof(name3), name3, &q); // 3 char isocode
newressu_getname(sizeof(name3), name3, &q); // name
fprintf(stdout,", %s(%s)", name3, name2); // name and isocode2 needed
}
}
}
fprintf(stdout,", count:%d",count);
fprintf(stdout,"\n");
}
#endif
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(status);
#define aDEBUG78 2
#ifdef DEBUG78
for(c = 0; c < sizeof(flagchars) / sizeof(flagchars[0]); c++) {
int first = 1;
for(d = 0; d < sizeof(flagchars) / sizeof(flagchars[0]); d++) {
char buffer[32];
buffer[0] = '\0';
if(!first)
strcat(buffer," ");
strcat(buffer, flagchars[c]);
strcat(buffer, flagchars[d]);
fprintf(stdout,"%s",buffer);
first = 0;
}
fprintf(stdout,"\n");
}
#endif
int linecnt = 0;
unsigned char *line = NULL;
unsigned char wordbuf[1025];
for(;;) {
if(!sort) { // no sort, no lotto
for(cwords = 0; cwords < pwords; cwords++) {
readword(wordbuf);
if(!quiet) {
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces(' ');
// print word
print_word(wordbuf);
newressu_output = 1;
}
} // for(cwords = 0; cwords < pwords; cwords++) {
} else { // if(!sort)
line_clear(&linecnt, &line);
// fetch and save words on this row
for(cwords = 0; cwords < pwords; /*!*/) {
readword(wordbuf);
if(line_add_string_sort(&linecnt, &line, wordbuf)) {
cwords++; // added if unique
}
} // while(cwords < pwords) {
cwords = 0;
// print words on this row
for(cwords = 0; cwords < pwords; cwords++) {
line_get_string(sizeof(wordbuf), wordbuf, cwords, line);
if(!quiet) {
// in beginning of line, print line number
print_line_number();
// want to print spaces between "words"?
print_spaces(' ');
// print word
print_word(wordbuf);
newressu_output = 1;
}
} // end of for(cwords = 0; cwords < pwords; cwords++
} // if(!sort)
if(!quiet) {
fprintf(stdout, "\n");
}
plines++;
ptotallines++;
// print empty line
if(!quiet &&
snewline > 0 &&
plines%snewline == 0) {
// if screenfull printed, use
// total lines (contains also
// empty lines), if not
// screenfull use printed
// lines (without empty lines)
if((screen && ptotallines < lines) ||
(!screen && plines < lines)) {
fprintf(stdout, "\n");
ptotallines++;
}
}
//fflush(stdout);
newressu_output = 0;
// all needed lines printed?
if(screen && snewline > 0 &&
ptotallines >= lines)
break;
if(plines >= lines)
break;
#define STATDIV (1024 * 1024 * 100)
if(print_statline) {
if(isatty(STDOUT_FILENO)) { // 0=stdin, 1=stdout, 2=stderr
print_statline = 0;
} else {
if(lines % 1000 == 0) {
unsigned char buf10[10];
unsigned long long bytes;
int pros = (int)(((double)plines / lines) * 100);
bytes = (((unsigned long long)size * pwords * plines) / STATDIV) * STATDIV;
stat_line_get_readable(buf10, bytes);
#ifdef DEBUG97
fprintf(stderr, "%lld", (unsigned long long)size * pwords * plines);
fprintf(stderr, ", %lld", bytes);
fprintf(stderr, ", %s", buf10);
fprintf(stderr, "\n");
#endif
stat_line_begin();
stat_line_printf("%s characters written:", input_str);
stat_line_readable((unsigned long) size * pwords * plines);
stat_line_printf(", %d%%", pros);
//stat_line_printf(", lines:%lld",lines);
//stat_line_printf(", plines:%lld",plines);
stat_line_end();
}
stat_line_cursor();
}
} // if(print_statline)
} // for(;;)
if(print_statline) { // 0=stdin, 1=stdout, 2=stderr
stat_line_begin();
stat_line_end();
stat_line_cursor_remove();
}
#ifdef DEBUG2H
int itemlen = 0;
for(int c = 0; c < ressuct_bytes; c++) {
unsigned char buffer[16];
sprintf(buffer, "%lu", count[c]);
if(itemlen < strlen(buffer))
itemlen = strlen(buffer);
}
for(int c = 0; c < ressuct_bytes; c++) {
if(c % 16 == 0) {
if(c > 0)
fprintf(stdout,"\n");
fprintf(stdout,"%05u ", c);
}
fprintf(stdout,"%*lu", itemlen + 1, count[c]);
}
fprintf(stdout,"\n");
#endif
#ifdef USE_TIMER
if(timer) {
double timertook = getseconds() - timerstart;
fprintf(stderr, "%s run time %f seconds", input_str, timertook);
fprintf(stderr, ", %lld lines", plines);
fprintf(stderr, ", %f useconds/line", timertook * 1000000 / plines);
fprintf(stderr, ", %d characters/line", pwords * size);
fprintf(stderr, ", %f useconds/character",
(timertook * 1000000 / plines) / (pwords * size) );
fprintf(stderr, "\n");
}
#endif
fflush(stdout);
if(digitsext != NULL)
free(digitsext);
#ifdef FORT
if(input == INPUT_FORT ||
input == INPUT_FORTXOR) {
fort_save();
}
#endif
exit(status);
}
#endif // MAIN
newressutest14.sh
/bin/newressu --int --single --space2 --newline 5 -l1 $@
/bin/newressu --int --single --space3 --newline 5 -l1 $@
/bin/newressu --int --single --space4 --newline 5 -l1 $@
/bin/newressu --int --single --space5 --newline 5 -l1 $@
/bin/newressu --int --single --space6 --newline 5 -l1 $@
/bin/newressu --int --single --6bits --space -s1 -l1 $@
/bin/newressu --int --single --6bits --space -s2 -l1 $@
/bin/newressu --int --single --6bits --space -s3 -l1 $@
/bin/newressu --int --single --6bits --space -s4 -l1 $@
/bin/newressu --int --single --6bits --space -s5 -l1 $@
/bin/newressu --int --single --6bits --space -s6 -l1 $@
/bin/newressu --int --single --6bits --space -s7 -l1 $@
/bin/newressu --int --single --6bits --space -s8 -l1 $@
/bin/newressu --int --single --6bits --space -s9 -l1 $@
/bin/newressu --int --single --6bits --space -s10 -l1 $@
/bin/newressu --int --single --rand -l1 $@
/bin/newressu --int --single --alnum -l1 $@
/bin/newressu --int --single --alpha -l1 $@
/bin/newressu --int --single --graph -l1 $@
/bin/newressu --int --single --lower -l1 $@
/bin/newressu --int --single --punct -l1 $@
/bin/newressu --int --single --upper -l1 $@
/bin/newressu --int --single -d --lim41 -w7 --zero -l1 --lotto$@
/bin/newressu --int --single --1bit -l1 $@
/bin/newressu --int --single --2bits -l1 $@
/bin/newressu --int --single --3bits -l1 $@
/bin/newressu --int --single --oct -l1 $@
/bin/newressu --int --single --4bits -l1 $@
/bin/newressu --int --single --hex -l1 $@
/bin/newressu --int --single --HEX -l1 $@
/bin/newressu --int --single --5bits -l1 $@
/bin/newressu --int --single --6bits -l1 $@
/bin/newressu --int --single --dnk -l1 $@
/bin/newressu --int --single --nor -l1 $@
/bin/newressu --int --single --fin -l1 $@
/bin/newressu --int --single --swe -l1 $@
/bin/newressu --int --single --rus -l1 $@
/bin/newressu --int --single --est -l1 $@
/bin/newressu --int --single --ltu -l1 $@
/bin/newressu --int --single --lva -l1 $@
/bin/newressu --int --single --fra -l1 $@
/bin/newressu --int --single --gbr -l1 $@
/bin/newressu --int --single --usa -l1 $@
/bin/newressu --int --single --ita -l1 $@
/bin/newressu --int --single --eng -l1 $@
/bin/newressu --int --single --deu -l1 $@
/bin/newressu --int --single --grc -l1 $@
/bin/newressu --int --single --jp -l1 $@
/bin/newressu --int --single --jp1 -l1 $@
/bin/newressu --int --single --hir -l1 $@
/bin/newressu --int --single --jp2 -l1 $@
/bin/newressu --int --single --kat -l1 $@
/bin/newressu --int --single --jp3 -l1 $@
/bin/newressu --int --single --cn -l1 $@
/bin/newressu --int --single --kan -l1 $@
/bin/newressu --int --single --kor -l1 $@
/bin/newressu --int --single --ind -l1 $@
/bin/newressu --int --single --hin -l1 $@
/bin/newressu --int --single --som -l1 $@
/bin/newressu --int --single --SOM -l1 $@
/bin/newressu --int --single --SO -l1 $@
/bin/newressu --int --single --braille -l1 $@
/bin/newressu --int --single --dna -l1 $@
/bin/newressu --int --single --DNA -l1 $@
newressu.h
void ressu_genbytes(int size, unsigned char *buffer);
unsigned long ressu_gen_limit(unsigned long limit);
void pseudoressu_bytes(int buflen, unsigned char *buf);
void inccvar();
void clearcvar();
#define INPUT_RESSU 0
#define INPUT_PSEUDORESSU 1
#define INPUT_FASTRESSU 3
#define INPUT_SINGLERESSU 4
#define INPUT_FIXED 5
#define INPUT_STREAM 10
#define INPUT_FORT 11
#define INPUT_FORTXOR 12
#define INPUT_RDRAND 13
#define INPUT_RDSEED 14
#define INPUT_URANDOM 15
#define INPUT_RANDOM 16
#define INPUT_DUMMY 17
extern int verbose;
extern int input;
extern int newressu_output;
extern char *randomgen[];
extern void pseudoressu_bytes(int, unsigned char *);
fort.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/time.h>
#include <errno.h>
#include <openssl/ssl.h>
#include "sha256.h"
#include "newressu.h"
extern unsigned char *procname;
static unsigned char *programname = "fort version 0.52 ©";
unsigned char *fortuseragent = "fort version 0.52 ©";
static unsigned char *copyright = "Copyright (c) 2020-2022 Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!";
#define FORT_INTERNAL_EVENTS 2
#define aDEBUG10 2
#define aDEBUG18 2
#define FORT_XOR_VERSION 2
#define FORT_ORIGINAL_VERSION 2
#include "fort.h"
int fort_events = 1;
int fort_use_web = 0;
#define DEBUG 2
#define FORT_MIN_POOL_SIZE 64
static unsigned int fort_internal_events = 1;
static unsigned int fort_internal_event_mode = 1;
#define FORT_USE_WEB 2
#define FORT_USE_URANDOM 2
#define aFORT_USE_RANDOM 2
#define FORT_USE_NEWRESSU_COMMAND 2
unsigned char fort_random_file[128] = "fort.rnd";
#ifdef DEBUG10
static int event_id = 0;
static char fort_events_file[128] = "fortevents.deb";
#endif
// Additional secrets to fort
// (Adversary must guess these too)
#define ADDITIONAL_SECRETS 2
#ifdef ADDITIONAL_SECRETS
unsigned char fort_secret_file[128] = "fortsecret.rnd";
unsigned char *program_secret = "OHUwiVmwm8HlqNhKxPi9rdt_8lm4jXI8hi-FCntPAQN_UXOyt4s6zQnRo__ySAd1";
#endif
#define FORT_64_POOLS 2
#ifdef FORT_64_POOLS
#define FORT_POOLS 64
typedef unsigned long FORT_COUNTER;
#else
#define FORT_POOLS 32
typedef unsigned int FORT_COUNTER;
#endif
void fort_mix();
void hash_update_cvar(HashCtx *hash)
{
hash_update(hash, (unsigned char *)&cvar,
cvarsize + 1);
inccvar();
}
#define aDEBUG8 2
void hash_update_ressu(HashCtx *hash)
{
unsigned char temp[16];
ressu_genbytes(sizeof(temp), temp);
#ifdef DEBUG8
fprintf(stdout,", ressu:");
for(int c = 0; c < sizeof(temp); c++)
fprintf(stdout,"%02x", temp[c]);
#endif
hash_update(hash, temp, sizeof(temp));
}
static IUTIME gettenths()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((IUTIME)tv.tv_sec * 10 +
(int)tv.tv_usec / 100000);
}
static IUTIME getmicroseconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((IUTIME)tv.tv_sec * 1000000 +
tv.tv_usec);
}
static IUTIME getseconds()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return((IUTIME)tv.tv_sec);
}
struct fort_pool {
unsigned long length;
HashCtx pool;
};
static struct fort_pool fort_pools[FORT_POOLS];
void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf)
{
while(len > 1 && buf[len-1] == 0)
len--;
HashUpdate(&fort_pools[*pool].pool, buf, len);
fort_pools[*pool].length += len; // (unsigned long)2097152*16384;
#ifdef DEBUG10
if(event_id < 65536) {
FILE *fp1;
if((fp1 = fopen(fort_events_file, "a")) != NULL) {
fprintf(fp1,"id=%d", event_id);
fprintf(fp1,", source=%02d", source);
fprintf(fp1,", pool=%02d", *pool);
fprintf(fp1,", mode=%d", mode);
fprintf(fp1,", len=%d", len);
fprintf(fp1,", data=");
for(int c=0;c<len;c++)
fprintf(fp1,"%02x", buf[c]);
fprintf(fp1,"\n");
fflush(fp1);
fclose(fp1);
event_id++;
}
}
#endif
switch(mode) {
case 1:
(*pool) = ((*pool) + 1) % FORT_POOLS;
break;
case 3:
break; // caller decides next pool
}
}
void fort_add_random_event_timer_start(IUTIME *micros)
{
*micros = getmicroseconds();
}
void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *micros)
{
unsigned char temp[2];
IUTIME t;
t = getmicroseconds() - *micros;
temp[0] = t & 0xff;
temp[1] = (t >> 8) & 0xff;
fort_add_random_event(pool, source, mode,
sizeof(temp), temp);
}
void fort_add_random_event_time(int *pool, int source, int mode)
{
int len;
unsigned char temp[2];
IUTIME t;
static int prev_second = -1;
t = getmicroseconds();
temp[0] = t & 0xff;
temp[1] = (t >> 8) & 0xff;
len = 2;
if(prev_second == temp[1]) {
len--;
} else {
prev_second = temp[1];
}
fort_add_random_event(pool, source, mode,
len, temp);
}
void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf, int size)
{
int n;
while(len != 0) {
n = (size<len)? size:len;
fort_add_random_event(pool, source,
mode, n, buf);
buf += n;
len -= n;
}
}
#define aDEBUG18 2
void hash_init(HashCtx *hash)
{
FORT_INTERNAL_EVENTS_START(10)
HashInit(hash);
#ifdef DEBUG18
fprintf(stdout,"init\n");
#endif
FORT_INTERNAL_EVENTS_END(11)
}
void hash_update(HashCtx *hash, unsigned char *data, int len)
{
FORT_INTERNAL_EVENTS_START(12)
HashUpdate(hash, data, len);
#ifdef DEBUG18
fprintf(stdout,"update ");
for(int d = 0; d < len; d++)
fprintf(stdout,"%02x",data[d]);
fprintf(stdout,"\n");
#endif
FORT_INTERNAL_EVENTS_END(13)
}
void hash_final(unsigned char digest[HashLen], HashCtx *hash)
{
FORT_INTERNAL_EVENTS_START(14)
HashFinal(digest, hash);
#ifdef DEBUG18
fprintf(stdout,"final ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
FORT_INTERNAL_EVENTS_END(15)
}
static unsigned char fort_key[HashLen];
void fort_rekey(unsigned char *digest)
{
HashCtx hash;
FORT_INTERNAL_EVENTS_START(16)
hash_init(&hash);
hash_update(&hash, fort_key, sizeof(fort_key));
hash_update_cvar(&hash);
hash_final(digest, &hash);
// Forget hash
memset(&hash, 0, sizeof(hash));
FORT_INTERNAL_EVENTS_END(17)
}
#define FORT_PSEUDO_LIMIT 1048576
// use
// $ ./newressu --fort -x -w32 -s2 -l2000 --space | more
// to debug...
// choose one of
// 60 (1 minute)
// 300 (5 minutes)
// 600 (10 minutes)
// 900 (15 minutes)
// 1200 (20 minutes)
// 1800 (30 minutes)
// 3600 (hour)
// 7200 (2 hours)
// 10800 (3 hours)
// 14400 (4 hours)
// 21600 (6 hours)
// 28800 (8 hours)
// 43200 (12 hours)
// 86400 (24 hours)
// to get readable report..
#define FORT_SECONDS_BETWEEN_SAVES 10 * 60
static IUTIME fort_next_save = 0;
#define TIMEFORMAT "%Z%Y%m%d%H%M%S"
void fort_save();
static char current_timezone[10];
#define aDEBUG22 2
void fort_reseed(int len, unsigned char *buf)
{
HashCtx hash;
FORT_INTERNAL_EVENTS_START(22)
hash_init(&hash);
hash_update(&hash, fort_key, sizeof(fort_key));
hash_update_cvar(&hash);
hash_update(&hash, buf, len);
#ifdef DEBUG22
fprintf(stdout,"\nprevkey ");
for(int d = 0; d < sizeof(fort_key); d++)
fprintf(stdout,"%02x", fort_key[d]);
fprintf(stdout,"\ncvar ");
for(int d = 0; d < cvarsize + 1; d++)
fprintf(stdout,"%02x", cvar[d]);
fprintf(stdout,"\ndata ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", buf[d]);
fprintf(stdout,"\ndata asc ");
for(int d = 0; d < len; d++) {
if(isprint(buf[d]))
fprintf(stdout,"%c", buf[d]);
else
fprintf(stdout,"\\%02x", buf[d]);
}
#endif
hash_final(fort_key, &hash);
#ifdef DEBUG22
fprintf(stdout,"\nnewkey ");
for(int d = 0; d < sizeof(fort_key); d++)
fprintf(stdout,"%02x", fort_key[d]);
fprintf(stdout,"\n");
#endif
memset(&hash, 0, sizeof(hash));
if(fort_next_save != 0) {
IUTIME seconds;
seconds = getseconds();
char timezone[10];
strftime(timezone, sizeof(timezone), "%Z",
localtime((time_t *)&seconds) );
if(strcmp(current_timezone, timezone)) {
fort_next_save = 1;
strcpy(current_timezone, timezone);
}
if(fort_next_save != 0 &&
seconds >= fort_next_save) {
IUTIME diff=
timegm(localtime((time_t *)&seconds)) - seconds;
fort_next_save = seconds -
((seconds + diff) %
FORT_SECONDS_BETWEEN_SAVES) +
FORT_SECONDS_BETWEEN_SAVES;
fort_save();
}
}
FORT_INTERNAL_EVENTS_END(23)
}
static FORT_COUNTER fort_reseed_count = 0;
static IUTIME fort_next_reseed = 0;
#define aDEBUG28 2
#ifdef FORT_ORIGINAL_VERSION
void fort_pseudo_random_data(int len,
unsigned char *buf)
{
unsigned char digest[HashLen];
unsigned int n, blockbytes;
#ifdef DEBUG28
int d = 0;
#endif
FORT_INTERNAL_EVENTS_START(18)
blockbytes = 0;
while(len != 0) {
FORT_INTERNAL_EVENTS_START(19)
fort_rekey(digest);
n = (len < HashLen) ? len : HashLen;
#ifdef DEBUG28
fprintf(stdout,"\nbuf(%02x): ",d++);
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",buf[c]);
fprintf(stdout,"\ndigest: ");
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",digest[c]);
fprintf(stdout,"\nsum: ");
for(int c=0;c<n;c++)
fprintf(stdout,"%02x",buf[c]^digest[c]);
fprintf(stdout,"\n");
#endif // #ifdef DEBUG18
memcpy(buf, digest, n);
buf += n;
len -= n;
blockbytes += n;
// rekey every 1048576 bytes if data left
if(blockbytes >= FORT_PSEUDO_LIMIT &&
len > 0) {
fort_rekey(fort_key);
blockbytes = 0;
}
FORT_INTERNAL_EVENTS_END(20)
}
fort_rekey(fort_key);
// Forget last bytes
memset(digest, 0, sizeof(digest));
FORT_INTERNAL_EVENTS_END(21)
}
#define aDEBUG34 2
void fort_random_data(int len, unsigned char *buf)
{
int c;
IUTIME tenths;
HashCtx hash;
unsigned char digest[HashLen];
FORT_INTERNAL_EVENTS_START(24)
tenths = gettenths();
if( (fort_next_reseed == 0) ||
(fort_next_reseed <= tenths &&
fort_pools[0].length >=
FORT_MIN_POOL_SIZE) ) {
fort_mix();
// next tenth of a second
fort_next_reseed = tenths + 1;
fort_reseed_count++;
hash_init(&hash);
c = 0;
while(c < FORT_POOLS && (fort_reseed_count
% (1 << c)) == 0) {
FORT_INTERNAL_EVENTS_START(25)
hash_final(digest, &fort_pools[c].pool);
#ifdef DEBUG34
fprintf(stdout,"\ndata %2d ",c);
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x",digest[d]);
#endif
hash_update(&hash, digest, sizeof(digest));
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
// save earlier pool to new one
hash_update(&fort_pools[c].pool,
digest, sizeof(digest));
c++;
FORT_INTERNAL_EVENTS_END(26)
}
hash_update_cvar(&hash);
hash_final(digest, &hash);
#ifdef DEBUG34
fprintf(stdout,"\ndigest ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
fort_reseed(sizeof(digest), digest);
// Forget hash context
memset(&hash, 0, sizeof(hash));
// Forget reseed key
memset(digest, 0, sizeof(digest));
}
fort_pseudo_random_data(len, buf);
FORT_INTERNAL_EVENTS_END(27)
}
#endif // #ifdef FORT_ORIGINAL_VERSION
#ifdef FORT_XOR_VERSION
void fort_pseudo_random_data_xor(int len,
unsigned char *buf)
{
unsigned char digest[HashLen];
unsigned int n, blockbytes;
#ifdef DEBUG28
int d = 0;
#endif
FORT_INTERNAL_EVENTS_START(18)
blockbytes = 0;
while(len != 0) {
FORT_INTERNAL_EVENTS_START(19)
fort_rekey(digest);
n = (len < HashLen) ? len : HashLen;
#ifdef DEBUG28
fprintf(stdout,"\nbuf(%02x): ", d++);
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", buf[c]);
fprintf(stdout,"\ndigest: ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", digest[c]);
fprintf(stdout,"\nsum: ");
for(int c = 0; c < n; c++)
fprintf(stdout,"%02x", buf[c] ^ digest[c]);
fprintf(stdout,"\n");
#endif
for(int c = 0; c < n; c++)
buf[c] ^= digest[c];
buf += n;
len -= n;
blockbytes += n;
// rekey every 1048576 bytes if data left
if(blockbytes >= FORT_PSEUDO_LIMIT &&
len > 0) {
fort_rekey(fort_key);
blockbytes = 0;
}
FORT_INTERNAL_EVENTS_END(20)
}
fort_rekey(fort_key);
// Forget last bytes
memset(digest, 0, sizeof(digest));
FORT_INTERNAL_EVENTS_END(21)
}
void fort_random_data_xor(int len, unsigned char *buf)
{
int c;
IUTIME tenths;
HashCtx hash;
unsigned char digest[HashLen];
FORT_INTERNAL_EVENTS_START(24)
tenths = gettenths();
if( (fort_next_reseed == 0) ||
(fort_next_reseed <= tenths &&
fort_pools[0].length >=
FORT_MIN_POOL_SIZE) ) {
fort_mix();
// next tenth of a second
fort_next_reseed = tenths + 1;
fort_reseed_count++;
hash_init(&hash);
c = 0;
while(c < FORT_POOLS && (fort_reseed_count
% (1 << c)) == 0) {
FORT_INTERNAL_EVENTS_START(25)
hash_final(digest, &fort_pools[c].pool);
#ifdef DEBUG34
fprintf(stdout,"\ndata %2d ", c);
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
#endif
hash_update(&hash, digest, sizeof(digest));
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
// save earlier pool to new one
hash_update(&fort_pools[c].pool,
digest, sizeof(digest));
c++;
FORT_INTERNAL_EVENTS_END(26)
}
hash_update_cvar(&hash);
hash_final(digest, &hash);
#ifdef DEBUG34
fprintf(stdout,"\ndigest ");
for(int d = 0; d < HashLen; d++)
fprintf(stdout,"%02x", digest[d]);
fprintf(stdout,"\n");
#endif
fort_reseed(sizeof(digest), digest);
// Forget hash context
memset(&hash, 0, sizeof(hash));
// Forget reseed key
memset(digest, 0, sizeof(digest));
}
fort_pseudo_random_data_xor(len, buf);
FORT_INTERNAL_EVENTS_END(27)
}
#endif // #ifdef FORT_XOR_VERSION
#define FORTCNT 128
static unsigned int fort_cnt = FORTCNT;
static unsigned char fort_bytes[FORTCNT];
static int fort_byte = 999999999;
int fort_random_data_byte()
{
if(fort_byte >= fort_cnt) {
fort_random_data(fort_cnt, fort_bytes);
fort_byte = 0;
}
return(fort_bytes[fort_byte++]);
}
void fort_clear()
{
memset(fort_bytes, 0, fort_cnt);
fort_byte = 999999998;
}
int fort_random_data_byte_limit(int limit)
{
int c;
while((c = fort_random_data_byte())>=
(256 / limit) * limit);
return(c % limit);
}
void fort_random_data_buffer(int size,
unsigned char *buffer)
{
int c;
for(c = 0; c < size; c++)
buffer[c] ^= fort_random_data_byte();
}
#define aDEBUG53 2
void fort_reseed_file(unsigned char *filename)
{
int c, cnt, bytes, characters;
#ifdef DEBUG53
unsigned char *p;
#endif
FILE *fp1;
unsigned char buffer[1024], digest[HashLen];
HashCtx hash;
bytes = 0;
characters = 0;
if((fp1 = fopen(filename, "r")) != NULL) {
HashInit(&hash);
while(fgets(buffer, sizeof(buffer), fp1) != NULL) {
cnt = strlen(buffer);
HashUpdate(&hash, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
#ifdef DEBUG53
p = buffer;
while(*p != '\0') {
if(*p == '\\')
fprintf(stdout, "\\\\");
else if(isprint(*p) || *p == '\n')
fputc(*p, stdout);
else
fprintf(stdout,"\\%02x", *p);
p++;
}
#endif
}
hash_update_cvar(&hash);
HashFinal(digest, &hash);
fort_reseed(sizeof(digest), digest);
fclose(fp1);
}
#ifdef DEBUG53
//if(verbose) {
fprintf(stdout,"fort_reseed_file %s", filename);
fprintf(stdout,", %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
//}
#endif
}
#define FORT_SAVE_SIZE 1024
#define aDEBUG57
void fort_save()
{
FILE *fp1;
unsigned char buffer[FORT_SAVE_SIZE];
memset(buffer, 0, sizeof(buffer));
if((fp1 = fopen(fort_random_file, "w")) != NULL) {
fort_pseudo_random_data(sizeof(buffer), buffer);
#ifdef DEBUG57
for(int c = 0; c < sizeof(buffer); c++) {
if(c % 32 == 0) {
if(c != 0)
fprintf(stdout,"\n");
fprintf(stdout,"save %05d ", c);
}
fprintf(stdout," %02x", buffer[c]);
}
fprintf(stdout,"\n");
#endif
fwrite(buffer, 1, sizeof(buffer), fp1);
memset(buffer, 0, sizeof(buffer));
fclose(fp1);
}
}
void fort_restore()
{
int d;
#ifdef DEBUG57
int random;
#endif
FILE *fp1;
unsigned char buffer[FORT_SAVE_SIZE];
memset(buffer, 0, sizeof(buffer));
if((fp1 = fopen(fort_random_file, "r"))
!= NULL) {
d = fread(buffer, 1, sizeof(buffer), fp1);
fclose(fp1);
#ifdef DEBUG57
random = 0;
#endif
} else {
fort_pseudo_random_data(sizeof(buffer), buffer);
ressu_genbytes(sizeof(buffer), buffer);
d = sizeof(buffer);
#ifdef DEBUG57
random = 1;
#endif
}
#ifdef DEBUG57
for(int c = 0; c < sizeof(buffer); c++) {
if(c % 32 == 0) {
if(c != 0)
fprintf(stdout,"\n");
fprintf(stdout,"restore");
if(random)
fprintf(stdout,"*");
else
fprintf(stdout," ");
fprintf(stdout," %05d ", c);
}
fprintf(stdout," %02x", buffer[c]);
}
fprintf(stdout,"\n");
#endif
fort_reseed(d, buffer);
memset(buffer, 0, sizeof(buffer));
fort_save();
}
#if defined FORT_USE_URANDOM || \
defined FORT_USE_RANDOM
static void fort_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);
}
}
#endif
#ifdef FORT_USE_WEB
static void parse_string(unsigned char *string, int size, unsigned char **p2)
{
int count;
unsigned char *p, *q;
p = *p2;
q = string;
count = 0;
// uppercase & lowercase letters, '.'
// or utf-8
while(isalnum(*p) || *p == '.' || *p > 0x80) {
if(++count < size)
*q++ = *p;
p++;
}
*q = '\0';
*p2 = p;
}
#endif // #ifdef FORT_USE_WEB
#ifdef FORT_USE_WEB
static int check_string(unsigned char *string, unsigned char *p)
{
int ok;
ok = 0;
if(!strncmp(string, p, strlen(string))) {
ok = 1;
}
return(ok);
}
#endif // #ifdef FORT_USE_WEB
void fort_internal_random_data_1(int size, char *buf)
{
ressu_genbytes(size, buf);
#ifdef FORT_XOR_VERSION
fort_pseudo_random_data_xor(size, buf);
#endif
}
void fort_internal_random_data_2(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
fort_pseudo_random_data_xor(size, buf);
#else
fort_pseudo_random_data(size, buf);
#endif
ressu_genbytes(size, buf);
}
void fort_internal_random_data_3(int size, char *buf)
{
#ifdef FORT_XOR_VERSION
fort_random_data_xor(size, buf);
#else
fort_random_data(size, buf);
#endif
}
static IUTIME fort_next_localmix = 0;
//#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
#define FORT_SECONDS_BETWEEN_LOCALMIXES 60*60
#ifdef FORT_USE_WEB
static IUTIME fort_next_webmix = 0;
//#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600
#define FORT_SECONDS_BETWEEN_WEBMIXES 12*3600
#endif
#define RANDOMNESS_IN_ALPHABETS 2
#define DEBUG65 2
void fort_strrepl(unsigned char *dest,unsigned char *oldstring, unsigned char *newstring)
{
unsigned char *stringstart;
#ifdef DEBUG65
if(verbose) {
fprintf(stdout,"fort_strrepl(): oldstring:%s", oldstring);
fprintf(stdout,", newstring:%s", newstring);
fprintf(stdout,", olddest:%s", dest);
}
#endif
if((stringstart = strstr(dest, oldstring)) != NULL) {
memmove(stringstart + strlen(newstring),
stringstart + strlen(oldstring),
strlen(stringstart + strlen(oldstring)) + 1);
memmove(stringstart, newstring, strlen(newstring));
}
#ifdef DEBUG65
if(verbose) {
fprintf(stdout,", newdest:%s", dest);
fprintf(stdout,"\n");
}
#endif
}
void fort_mix()
{
int webmix, localmix;
unsigned char temp[64];
IUTIME seconds;
seconds = getseconds();
webmix = 0;
localmix = 0;
#ifdef FORT_USE_WEB
if(fort_next_webmix == 0 ||
fort_next_webmix <= seconds) {
fort_next_webmix = seconds + FORT_SECONDS_BETWEEN_WEBMIXES;
fort_next_localmix = seconds + FORT_SECONDS_BETWEEN_LOCALMIXES;
webmix = 1;
localmix = 1;
}
#endif
if(fort_next_localmix == 0 ||
fort_next_localmix <= seconds) {
fort_next_localmix = seconds + FORT_SECONDS_BETWEEN_LOCALMIXES;
localmix = 1;
}
if(!webmix && !localmix)
return;
if(verbose) {
char timebuf[128];
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *)&seconds));
fprintf(stdout,"Fort mix time: %s\n", timebuf);
#ifdef FORT_USE_WEB
if(fort_use_web) {
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *)&fort_next_webmix));
fprintf(stdout,"Next fort webmix: %s\n", timebuf);
}
#endif
strftime(timebuf, sizeof(timebuf), TIMEFORMAT,
localtime((time_t *)&fort_next_localmix));
fprintf(stdout,"Next fort localmix: %s\n", timebuf);
}
fort_internal_random_data_1(sizeof(temp), temp);
fort_reseed(sizeof(temp), temp);
#if defined FORT_USE_WEB || \
defined USE_RDRAND || \
defined USE_RDSEED || \
defined USE_NEWRESSU_COMMAND
unsigned char digest[HashLen];
#endif
#ifdef FORT_USE_WEB
if(webmix && fort_use_web) {
char *webpages[] = {
"https://moijari.com:5001/",
"https://moijari.com:5005/",
"https://moijari.com:5006/",
};
for(int c = 0; c < sizeof(webpages) / sizeof(webpages[0]); c++) {
unsigned char *p;
unsigned char scheme[32];
unsigned char host[32];
unsigned char port[10];
unsigned char rest[128];
p = webpages[c];
parse_string(scheme, sizeof(scheme), &p);
if(check_string("://", p)) {
p += 3;
parse_string(host, sizeof(host), &p);
} else {
strcpy(host, scheme);
strcpy(scheme,"http");
}
if(check_string(":", p)) {
p++;
parse_string(port, sizeof(port), &p);
} else {
strcpy(port,"80");
}
if(*p != '/')
strcpy(rest, "/");
else
strcpy(rest, p);
if(verbose) {
fprintf(stdout,"URL:%s ", webpages[c]);
fprintf(stdout,"[scheme:%s]", scheme);
fprintf(stdout,"[host:%s]", host);
fprintf(stdout,"[port:%s]", port);
fprintf(stdout,"[rest:%s]", p);
fflush(stdout);
}
if(!strcmp(scheme,"http")) {
fort_hash_http_page(host, port, p, digest);
} else if(!strcmp(scheme,"https")) {
fort_hash_https_page(host, port, p, digest);
}
fort_reseed(sizeof(digest), digest);
}
}
#endif // #ifdef FORT_USE_WEB
if(localmix) {
#ifdef FORT_USE_URANDOM
memset(temp, 0, sizeof(temp));
fort_readfile_xor(sizeof(temp), temp,
"/dev/urandom");
fort_reseed(sizeof(temp), temp);
#endif
#ifdef FORT_USE_RANDOM
memset(temp, 0, sizeof(temp));
fort_readfile_xor(sizeof(temp), temp,
"/dev/random");
fort_reseed(sizeof(temp), temp);
#endif
#if defined USE_RDRAND || \
defined USE_RDSEED
HashCtx hash;
unsigned char digest[HashLen];
#endif
#ifdef USE_RDRAND
memset(temp, 0, sizeof(temp));
if(rdrand_bytes(sizeof(temp), temp)) {
HashInit(&hash);
hash_update_cvar(&hash);
hash_update_ressu(&hash);
HashUpdate(&hash, temp, sizeof(temp));
HashFinal(digest, &hash);
if(verbose) {
fprintf(stdout,", data: ");
for(int c = 0; c < sizeof(temp); c++) {
fprintf(stdout,"%02x", temp[c]);
}
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
newressu_output = 0;
}
fort_reseed(sizeof(digest), digest);
}
#endif // #ifdef USE_RDRAND
#ifdef USE_RDSEED
memset(temp, 0, sizeof(temp));
if(rdseed_bytes(sizeof(temp), temp)) {
HashInit(&hash);
hash_update_cvar(&hash);
hash_update_ressu(&hash);
HashUpdate(&hash, temp, sizeof(temp));
HashFinal(digest, &hash);
if(verbose) {
fprintf(stdout,", data: ");
for(int c = 0; c < sizeof(temp); c++) {
fprintf(stdout,"%02x", temp[c]);
}
fprintf(stdout,", sha256: ");
for(int c = 0; c < HashLen; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fprintf(stdout,"\n");
fflush(stdout);
newressu_output = 0;
}
fort_reseed(sizeof(digest), digest);
}
#endif // #ifdef USE_RDSEED
#ifdef FORT_USE_NEWRESSU_COMMAND
char *commands[] = {
"$newressu -2 -s8 -w8 -l1 --lineno",
"$newressu -2 -s8 -w8 -l1 --lineno --fast",
"$newressu -2 -s8 -w8 -l1 --lineno --urandom",
#ifdef USE_RDRAND
"$newressu -2 -s8 -w8 -l1 --lineno --rdrand",
#endif
#ifdef USE_RDSEED
"$newressu -2 -s8 -w8 -l1 --lineno --rdseed",
#endif
"$newressu -2 -s8 -w8 -l1 --lineno --pseudoressu",
#ifdef RANDOMNESS_IN_ALPHABETS
"$newressu --cn -s8 -w4 -l1 --lineno --single",
"$newressu --deu -s8 -w8 -l1 --lineno --single",
"$newressu --dnk -s8 -w8 -l1 --lineno --single",
"$newressu --eng -s8 -w8 -l1 --lineno --single",
"$newressu --est -s8 -w8 -l1 --lineno --single",
"$newressu --fin -s8 -w8 -l1 --lineno --single",
"$newressu --fra -s8 -w8 -l1 --lineno --single",
"$newressu --gbr -s8 -w8 -l1 --lineno --single",
"$newressu --got -s8 -w8 -l1 --lineno --single",
"$newressu --grc -s8 -w8 -l1 --lineno --single",
"$newressu --ita -s8 -w8 -l1 --lineno --single",
"$newressu --jp -s8 -w4 -l1 --lineno --single",
"$newressu --jp1 -s8 -w4 -l1 --lineno --single",
"$newressu --jp2 -s8 -w4 -l1 --lineno --single",
"$newressu --jp3 -s8 -w4 -l1 --lineno --single",
"$newressu --kor -s8 -w4 -l1 --lineno --single",
"$newressu --ltu -s8 -w8 -l1 --lineno --single",
"$newressu --lva -s8 -w8 -l1 --lineno --single",
"$newressu --nor -s8 -w8 -l1 --lineno --single",
"$newressu --rus -s8 -w8 -l1 --lineno --single",
"$newressu --swe -s8 -w8 -l1 --lineno --single",
#endif
};
for(int c = 0; c < sizeof(commands) / sizeof(commands[0]); c++) {
if(strstr(commands[c], "--fort")) {
fprintf(stderr,"%s: fort_mix(): cannot call fort recursively \"%s\"\n",
procname, commands[c]);
} else {
unsigned char command[256];
strcpy(command, commands[c]);
// string:$newressu, newstring:/bin/newressu2, olddest:$newressu -2 -s8 -w8 -l1 --lineno, newdest:/bin/newressu2 -2 -s8 -w8 -l1 --lineno
if(strstr(procname,"newressu") && strlen(procname) < 32)
fort_strrepl(command, "$newressu", procname);
else
fort_strrepl(command, "$newressu", "/bin/newressu");
fort_hash_command(command, digest);
fort_reseed(sizeof(digest), digest);
}
}
#endif // #ifdef FORT_USE_NEWRESSU_COMMAND
}
}
void file_digest(char *filename,unsigned char temp[HashLen])
{
int c;
unsigned char buffer[1024];
FILE *fp1;
HashCtx ctx;
HashInit(&ctx);
if((fp1 = fopen(filename, "rb")) != NULL) {
while((c = fread(buffer, 1, sizeof(buffer), fp1)) > 0)
HashUpdate(&ctx, buffer, c);
fclose(fp1);
}
HashFinal(temp, &ctx);
}
#define DEBUG88
void fort_init()
{
int c;
unsigned char temp32[32];
memset(temp32, 0, sizeof(temp32));
memset(fort_bytes, 0, sizeof(fort_bytes));
memset(fort_key, 0, sizeof(fort_key));
if(verbose) {
fprintf(stdout,"hash: %s",
HashName);
fprintf(stdout,", pools: %d*%ld", FORT_POOLS,
sizeof(struct fort_pool));
fprintf(stdout,", HashCtx: %ld",
sizeof(HashCtx));
fprintf(stdout,", hashsize: %d",
HashLen);
fprintf(stdout,"\n");
}
unsigned int save_fort_internal_events;
save_fort_internal_events = fort_internal_events;
fort_internal_events = 1;
fort_next_save = 0;
clearcvar();
// Initialize buffers
for(c = 0; c < FORT_POOLS; c++) {
fort_pools[c].length = 0;
HashInit(&fort_pools[c].pool);
}
// first key to fort_key
fort_internal_random_data_1(sizeof(fort_key), fort_key);
#ifdef ADDITIONAL_SECRETS
// additional constant randomness from program
fort_reseed(strlen(copyright), copyright);
fort_reseed(strlen(programname), programname);
unsigned char filedigest[HashLen];
file_digest("/proc/self/exe", filedigest);
fort_reseed(strlen(filedigest), filedigest);
fort_reseed(strlen(program_secret), program_secret);
// additional constant randomness
// from you (one more secret adversary
// has to guess)
FILE *fp1;
if((fp1 = fopen(fort_secret_file, "r")) != NULL) {
fclose(fp1);
} else {
if((fp1 = fopen(fort_secret_file, "w")) != NULL) {
fprintf(fp1,"Your secret additional constant data to fort:\n");
fclose(fp1);
unsigned char temp2[160];
sprintf(temp2,"%s -2 -l1 >>%s", procname, fort_secret_file);
system(temp2);
fprintf(stdout,"File %s written\n", fort_secret_file);
}
}
fort_reseed_file(fort_secret_file);
#endif
#ifdef DEBUG10
FILE *fp1;
// Empty events file
if((fp1 = fopen(fort_events_file, "w"))!=NULL)
fclose(fp1);
event_id = 0;
#endif // #ifdef DEBUG10
// Mix fort key with web + local
// random numbers
fort_mix();
for(c = 0; c < FORT_POOLS; c++) {
FORT_INTERNAL_EVENTS_START(31)
fort_internal_random_data_2(sizeof(temp32), temp32);
hash_update(&fort_pools[c].pool,
temp32, sizeof(temp32));
FORT_INTERNAL_EVENTS_END(32)
}
#ifdef FORT_INTERNAL_EVENTS
if(fort_internal_events) {
// Create some internal events
for(c=0; c<32; c++) {
FORT_INTERNAL_EVENTS_START(34)
fort_internal_random_data_3(sizeof(temp32), temp32);
FORT_INTERNAL_EVENTS_END(35)
}
}
#endif // #ifdef FORT_INTERNAL_EVENTS
fort_reseed_count = 0;
fort_next_reseed = 0;
// Reseed fort_key with new events
fort_internal_random_data_3(sizeof(temp32), temp32);
fort_reseed(sizeof(temp32), temp32);
fort_restore();
// Forget temp
memset(temp32, 0, sizeof(temp32));
fort_internal_events = save_fort_internal_events;
//fort_reseed_count = 0;
//fort_next_reseed = 0;
fort_next_save = 1;
}
void fort_version()
{
fprintf(stderr,"%s", programname); // touch these outside MAIN
fprintf(stderr,", %s\n", copyright);
}
#define aMAIN 2
#ifdef MAIN
unsigned char *procname;
int main(int argc, char *argv[])
{
procname = argv[0];
fort_version();
fort_init();
return(0);
}
#endif // #ifdef MAIN
fort.h
/* Perustuu Bruce Schneierin kirjassa esittämään fortuna järjestelmään.
* Written by Jari Kuivaniemi
*/
#ifndef SHA256_H
#include "sha256.h"
#endif
#define aUSE_RDRAND 2
#define aUSE_RDSEED 2
typedef unsigned long long IUTIME;
extern int fort_verbose;
extern int fort_partial_line;
extern int fort_use_web;
extern unsigned char fort_random_file[128];
extern unsigned char fort_secret_file[128];
extern unsigned char fort_pools_file[128];
#ifdef DEBUG10
static char fort_events_file[128] = "fortevents.deb";
#endif
unsigned char cvar[16];
int cvarsize;
void inccvar();
void clearcvar();
void hash_update_cvar(HashCtx *hash);
void fort_add_random_event(int *pool, int source, int mode, int len, unsigned char *buf);
void fort_add_random_event_timer_start(IUTIME *micros);
void fort_add_random_event_timer_do(int *pool, int source, int mode, IUTIME *millis);
void fort_add_random_event_split(int *pool, int source, int mode, int len, unsigned char *buf,int size);
void fort_add_random_event_time(int *pool, int source, int mode);
void fort_rekey(unsigned char *buf);
void fort_pseudo_random_data(int len,unsigned char *buf);
void fort_pseudo_random_data_xor(int len,unsigned char *buf);
void fort_reseed(int len,unsigned char *buf);
void fort_random_data(int len,unsigned char *buf);
void fort_random_data_xor(int len,unsigned char *buf);
int fort_random_data_byte();
void fort_clear();
int fort_random_data_byte_limit(int limit);
void fort_random_data_buffer(int size, unsigned char *buffer);
void fort_save();
void fort_read_file();
void fort_mix();
void fort_init();
void hash_init(HashCtx *hash);
void hash_update(HashCtx *hash, unsigned char *data, int len);
void hash_final(unsigned char digest[HashLen], HashCtx *hash);
void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash);
void fort_hash_command(unsigned char *command, unsigned char *hash);
int rdrand_bytes(int buflen, unsigned char *buf);
int rdseed_bytes(int buflen, unsigned char *buf);
#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_START(source) \
IUTIME micros; \
static int \
pool=0, pool2=0; \
if(fort_internal_events) { \
fort_add_random_event_time(&pool, \
source, fort_internal_event_mode); \
fort_add_random_event_timer_start(µs); \
}
#else
#define FORT_INTERNAL_EVENTS_START(source)
#endif
#ifdef FORT_INTERNAL_EVENTS
#define FORT_INTERNAL_EVENTS_END(source) \
if(fort_internal_events) \
fort_add_random_event_timer_do(&pool2, \
source, fort_internal_event_mode, \
µs);
#else
#define FORT_INTERNAL_EVENTS_END(source)
#endif
#ifdef FORT_EVENTS
#define FORT_EVENTS_START(source) \
IUTIME micros; \
static int \
pool=0, pool2=0; \
if(fort_events) { \
fort_add_random_event_time(&pool, \
source, fort_event_mode); \
fort_add_random_event_timer_start(µs); \
}
#else
#define FORT_EVENTS_START(source)
#endif
#ifdef FORT_EVENTS
#define FORT_EVENTS_END(source) \
if(fort_events) \
fort_add_random_event_timer_do(&pool2, \
source, fort_event_mode, \
µs);
#else
#define FORT_EVENTS_END(source)
#endif
sha256.c
/* Written from SHA256 documents by Jari Kuivaniemi, read "http://en.wikipedia.org/wiki/SHA-2" */
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include "sha256.h"
extern unsigned char *procname;
//#ifdef MAIN // in Makefile
unsigned char *sha_name = "SHA256 v1.0";
void SHA256Init(SHA256_CONTEXT *sha256)
{
sha256->state[0] = 0x6a09e667;
sha256->state[1] = 0xbb67ae85;
sha256->state[2] = 0x3c6ef372;
sha256->state[3] = 0xa54ff53a;
sha256->state[4] = 0x510e527f;
sha256->state[5] = 0x9b05688c;
sha256->state[6] = 0x1f83d9ab;
sha256->state[7] = 0x5be0cd19;
sha256->count = 0;
}
IUWORD k256[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
#define RR32(word,bits) ( ((word) >> (bits)) | ((word) << (32 - (bits))) )
#define RS32(word,bits) ( ((word) >> (bits)) )
void SHA256Transform(IUWORD state[8], IUBYTE buffer[64])
{
int i;
IUWORD w[64], s0;
IUWORD a, b, c, d, e, f, g, h;
IUWORD maj, t2, s1;
IUWORD ch, t1;
for(i = 0; i < 16; i++) {
w[i] =
(IUWORD)buffer[i * 4 + 0] << 24 |
(IUWORD)buffer[i * 4 + 1] << 16 |
(IUWORD)buffer[i * 4 + 2] << 8 |
(IUWORD)buffer[i * 4 + 3];
}
for(i=16;i<64;i++) {
s0 = (RR32(w[i - 15], 7)) ^ (RR32(w[i - 15], 18)) ^ (RS32(w[i - 15], 3));
s1 = (RR32(w[i - 2], 17)) ^ (RR32(w[i - 2], 19)) ^ (RS32(w[i - 2], 10));
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
for(i=0;i<64;i++) {
s0 = (RR32(a, 2)) ^ (RR32(a, 13)) ^ (RR32(a, 22));
maj = (a & b) ^ (a & c) ^ (b & c);
t2 = s0 + maj;
s1 = (RR32(e, 6)) ^ (RR32(e, 11)) ^ (RR32(e, 25));
ch = (e & f) ^ ((~ e) & g);
t1 = h + s1 + ch + k256[i] + w[i];
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
state[0] = state[0] + a;
state[1] = state[1] + b;
state[2] = state[2] + c;
state[3] = state[3] + d;
state[4] = state[4] + e;
state[5] = state[5] + f;
state[6] = state[6] + g;
state[7] = state[7] + h;
}
void SHA256Update(SHA256_CONTEXT *sha256, unsigned char *data, int len)
{
int i, j;
j = (int)sha256->count & 63;
sha256->count += len;
if((j + len) > 63) {
memcpy(&sha256->buffer[j], data, 64 - j); /* last bytes of next block */
SHA256Transform(sha256->state, sha256->buffer);
for (i = 64 - j ; i + 63 < len; i += 64) {
SHA256Transform(sha256->state, &data[i]);
}
j = 0;
} else
i = 0;
memcpy(&sha256->buffer[j], &data[i], len - i);
}
void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256)
{
int i, j;
unsigned char filelenght[8];
IULONG count;
count = sha256->count << 3;
SHA256Update(sha256, "\200", 1);
while((sha256->count & 63) != 56)
SHA256Update(sha256, "\0", 1);
filelenght[0] = (unsigned char)(count >> 56) & 0xff;
filelenght[1] = (unsigned char)(count >> 48) & 0xff;
filelenght[2] = (unsigned char)(count >> 40) & 0xff;
filelenght[3] = (unsigned char)(count >> 32) & 0xff;
filelenght[4] = (unsigned char)(count >> 24) & 0xff;
filelenght[5] = (unsigned char)(count >> 16) & 0xff;
filelenght[6] = (unsigned char)(count >> 8 ) & 0xff;
filelenght[7] = (unsigned char)(count & 0xff);
SHA256Update(sha256, filelenght, sizeof(filelenght));
for(i = 0, j = 0; i < 8; i++) {
digest[j++] = (unsigned char) (sha256->state[i] >> 24) & 0xff;
digest[j++] = (unsigned char) (sha256->state[i] >> 16) & 0xff;
digest[j++] = (unsigned char) (sha256->state[i] >> 8) & 0xff;
digest[j++] = (unsigned char) (sha256->state[i] ) & 0xff;
}
}
#ifdef MAIN
void printhex(char *name, unsigned char *digest, int len)
{
int c;
fprintf(stdout,"%s=", name);
for(c = 0; c < len; c++) {
fprintf(stdout,"%02x", digest[c]);
}
fflush(stdout);
}
int shahexdigit(int c)
{
if(c >= '0' && c <= '9') return(c - '0');
else if(c >= 'a' && c <= 'f') return(c - 'a' + 10);
else if(c >= 'A' && c <= 'F') return(c - 'A' + 10);
return(0);
}
void sha_test()
{
int c, d, e, ok, allok;
SHA256_CONTEXT sha256;
unsigned char result[32], *p;
fprintf(stdout,"%s", sha_name);
fprintf(stdout,", Context size: %ld", sizeof(SHA256_CONTEXT));
fprintf(stdout,", Hash size: 32");
fprintf(stdout,", IUBYTE size: %ld", sizeof(IUBYTE));
fprintf(stdout,", IUWORD size: %ld", sizeof(IUWORD));
fprintf(stdout,", IULONG size: %ld", sizeof(IULONG));
struct test {
unsigned char *string;
int count;
unsigned char *result;
} tests[] = {
{ "abc", 1, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 1, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" },
{ "a", 1000000, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0" },
{ "The quick brown fox jumps over the lazy dog", 1, "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592" },
};
allok = 1;
for(c = 0; c < sizeof(tests) / sizeof(tests[0]); c++) {
SHA256Init(&sha256);
for(d = 0; d < tests[c].count; d++)
SHA256Update(&sha256, tests[c].string, strlen(tests[c].string));
SHA256Final(result, &sha256);
p = tests[c].result;
d = 0;
ok = 1;
while(*p != '\0') {
if(*p != '\0')
e = shahexdigit(*p++);
if(*p!='\0')
e = e * 16 + shahexdigit(*p++);
if(e != result[d])
ok = 0;
d++;
}
if(ok) {
fprintf(stdout,"\nsha256 test ");
fprintf(stdout,"string: %s", tests[c].string);
fprintf(stdout,", count: %d, ", tests[c].count);
printhex("tmp32", result, sizeof(result));
fprintf(stdout,", result: %s", tests[c].result);
fprintf(stdout," ok!!!!");
fflush(stdout);
} else {
fprintf(stdout,"\nsha256 test ");
fprintf(stdout,"string: %s", tests[c].string);
fprintf(stdout,", count: %d, ", tests[c].count);
printhex("tmp32", result, sizeof(result));
fprintf(stdout,", result: %s", tests[c].result);
fprintf(stdout," failed!!!!");
fflush(stdout);
allok = 0;
}
}
if(allok) {
fprintf(stdout,", sha256 tests ok!!!!\n");
} else {
fprintf(stdout,", sha256 tests failed!!!!\n");
}
fflush(stdout);
}
int main(int argc, char *argv[])
{
sha_test();
}
#endif
sha256.h
#ifndef SHA256_H
#define SHA256_H
#define HashName "SHA256"
#define HashInit SHA256Init
#define HashUpdate SHA256Update
#define HashFinal SHA256Final
#define HashLen 32
#define HashCtx SHA256_CONTEXT
typedef unsigned char IUBYTE;
typedef unsigned int IUWORD;
typedef unsigned long long IULONG;
typedef struct {
IUWORD state[8];
IULONG count;
IUBYTE buffer[64];
} SHA256_CONTEXT;
void SHA256Init(SHA256_CONTEXT *sha256);
void SHA256Update(SHA256_CONTEXT* sha256, unsigned char *data, int len);
void SHA256Final(unsigned char digest[32], SHA256_CONTEXT *sha256);
void sha_test();
#endif
intelrandom.c
#include <stdio.h>
#include <memory.h>
#include "fort.h"
#include "newressu.h"
#if defined USE_RDRAND || \
defined USE_RDSEED
// see: https://software.intel.com/content/www/us/en/develop/articles/intel-digital-random-number-generator-drng-software-implementation-guide.html
void _cpuid(unsigned int leaf, unsigned int subleaf,
unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
{
asm volatile("cpuid"
: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
: "a" (leaf), "c" (subleaf) );
}
int _is_cpu_vendor(unsigned char *cpuvendor)
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(0, 0, &a, &b, &c, &d);
if(memcmp((char *)(&b), cpuvendor,4) == 0 &&
memcmp((char *)(&d), cpuvendor+4,4) == 0 &&
memcmp((char *)(&c), cpuvendor+8,4) == 0)
ok = 1;
return(ok);
}
#endif
#ifdef USE_RDRAND
int _has_rdrand()
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(1, 0, &a, &b, &c, &d);
if((c & 0x40000000) == 0x40000000) {
ok = 1;
}
return(ok);
}
int _rdrand_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdrand %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdrand_bytes(int buflen, unsigned char *buf)
{
int c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"Intel rdrand");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdrand()) {
if(verbose)
fprintf(stdout,"AMD rdrand");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 100) {
if((ret = _rdrand_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %016lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
newressu_output = 1;
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x", ((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout, "\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDRAND
#ifdef USE_RDSEED
int _has_rdseed()
{
int ok = 0;
unsigned int a, b, c, d;
_cpuid(7, 0, &a, &b, &c, &d);
if((b & 0x40000) == 0x40000) {
ok = 1;
}
return(ok);
}
int _rdseed_long(unsigned long *therand)
{
unsigned char ret;
asm volatile("rdseed %0; setc %1"
: "=r" (*therand), "=qm" (ret) );
return(int) ret;
}
int rdseed_bytes(int buflen, unsigned char *buf)
{
int c, n, ret = 0;
unsigned long l;
if(verbose) {
if(newressu_output == 1)
fprintf(stdout,"\n");
newressu_output = 0;
}
if(_is_cpu_vendor("GenuineIntel") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"Intel rdseed");
ret = 1;
} else if(_is_cpu_vendor("AuthenticAMD") && _has_rdseed()) {
if(verbose)
fprintf(stdout,"AMD rdseed");
ret = 1;
}
if(ret) {
while(buflen > 0) {
int tries = 0;
while(++tries < 1000) {
if((ret = _rdseed_long(&l)) == 1) { // 1 ok, 0 fail
break;
}
//fprintf(stdout," %lu",l);
}
if(verbose) {
fprintf(stdout,", t:%d ", tries);
}
if(ret == 0)
break;
n = (buflen < sizeof(l) ? buflen : sizeof(l));
if(verbose) {
for(c = 0; c < sizeof(l); c++)
fprintf(stdout,"%02x",((unsigned char *)&l)[c]);
newressu_output = 1;
}
memcpy(buf, (unsigned char *)&l, n);
buf += n;
buflen -= n;
}
}
if(verbose && newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
return(ret);
}
#endif // #ifdef USE_RDSEED
webrandom.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "sha256.h"
#include "fort.h"
extern unsigned char *procname;
extern int newressu_output;
extern int verbose;
#include <stdarg.h>
void dbs_printf(unsigned char **buf, size_t *buf_length, const unsigned char *format, ...)
{
int count;
va_list args;;
va_start(args, format);
count = vsnprintf(*buf, *buf_length, format, args) + 1;
va_end(args);
if(*buf_length < count) {
*buf_length = count;
*buf = realloc(*buf, *buf_length);
va_start(args, format);
count = vsnprintf(*buf, *buf_length, format, args) + 1;
va_end(args);
}
}
int fort_connect(unsigned char *host, unsigned char *port)
{
struct addrinfo hints, *res, *resp;
int s, status;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((status = getaddrinfo(host, port, &hints, &res)) != 0) {
fprintf(stderr,"\n%s: getaddrinfo", procname);
fprintf(stderr,", status %d", status);
fprintf(stderr,", gai_strerror(): %s", gai_strerror(status));
fprintf(stderr,", errno %d\n", errno);
fflush(stderr);
}
for(resp = res; resp != NULL; resp = resp->ai_next) {
if((s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol)) < 0)
continue;
if(connect(s, resp->ai_addr, resp->ai_addrlen) == 0)
break;
close(s);
}
freeaddrinfo(res);
return(s);
}
#define aDEBUG27 2
void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
if((s = fort_connect(host, port))<0) {
fprintf(stderr,"\n%s: cannot fort_connect()", procname);
fprintf(stderr,", status: %d", s);
fprintf(stderr,", errno: %d" , errno);
perror("fort_connect");
fflush(stderr);
}
// GET / HTTP/1.0\r\nHost: moijari.com:5006\r\n
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
if((status = write(s, msg, strlen(msg))) < 0) {
fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
perror("write");
fflush(stderr);
}
HashCtx ctx;
unsigned char buffer[1024];
HashInit(&ctx);
bytes = 0;
characters = 0;
while((cnt = read(s, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG27
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&ctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
hash_update_cvar(&ctx);
HashFinal(hash, &ctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
close(s);
}
#define aDEBUG49 2
#define aDEBUG50 2
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
SSL_METHOD *method = NULL;
SSL_CTX *ctx = NULL;
SSL *ssl;
SSL_library_init(); //see: http://h30266.www3.hpe.com/odl/axpos/opsys/vmsos84/BA554_90007/ch04s03.html
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
#ifdef DEBUG49
fprintf(stdout,"SSLv23_client_method()\n");
#endif
if((method = (SSL_METHOD *)
SSLv23_client_method()) == NULL) {
fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_new()\n");
#endif
if((ctx = SSL_CTX_new(method)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_new()\n");
#endif
if((ssl = SSL_new(ctx)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"fort_connect()\n");
#endif
if((s = fort_connect(host, port)) < 0) {
fprintf(stderr,"\n%s: cannot fort_connect()", procname);
fprintf(stderr,", status: %d", s);
fprintf(stderr,", errno: %d" , errno);
perror("fort_connect");
fflush(stderr);
}
SSL_set_fd(ssl, s);
#ifdef DEBUG49
fprintf(stdout,"SSL_connect(ssl)\n");
#endif
if((status = SSL_connect(ssl)) <= 0) {
fprintf(stderr,"\n%s: cannot SSL_connect()", procname);
fprintf(stderr,", status: %d", status);
fprintf(stderr,", errno: %d" , errno);
fprintf(stderr,", SSL_get_error(): %d\n", SSL_get_error(ssl,status));
perror("SSL_connect");
fflush(stderr);
}
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
#ifdef DEBUG49
fprintf(stdout,"SSL_write(), msg_length:%ld, msg=\"%s\"\n", msg_length,msg);
#endif
if((status = SSL_write(ssl, msg, strlen(msg))) < 0) {
fprintf(stderr,"\n%s: SSL_write()", procname);
fprintf(stderr,", status: %d", status);
fprintf(stderr,", errno: %d", errno);
fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
perror("SSL_write");
fflush(stderr);
}
fflush(stdout);
HashCtx hashctx;
unsigned char buffer[2048];
HashInit(&hashctx);
bytes = 0;
characters = 0;
#ifdef DEBUG49
fprintf(stdout, "SSL_read()\n");
#endif
int bytesneeded = 0, bytesheader = 0, bytescontent = 0;
do {
cnt = SSL_read(ssl, buffer, sizeof(buffer));
if(cnt < 0) {
int err, err2;
err = SSL_get_error(ssl, cnt);
err2 = ERR_get_error();
fprintf(stderr, "\n%s: cannot SSL_read()", procname);
fprintf(stderr, ", retval: %d", cnt);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error() %d", err);
fprintf(stderr,", ERR_get_error() %d\n", err2);
perror("SSL_read");
fflush(stderr);
break;
}
#ifdef DEBUG50
write(1, buffer, cnt);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
if(bytesneeded == 0) {
char *p;
p = buffer;
int count = 0;
while(*p != '\0') {
if(!strncmp(p, "\r\nContent-Length: ", 18)) {
bytescontent = atoi(p + 18);
}
if(!strncmp(p, "\r\n\r\n", 4)) {
bytesheader = count;
}
p++;
count++;
}
bytesneeded = bytescontent + bytesheader + 4;
}
} while(SSL_pending(ssl) || bytes < bytesneeded);
if(verbose) {
fprintf(stdout,"\nbytescontent:%d", bytescontent);
fprintf(stdout,", bytesheader:%d", bytesheader);
fprintf(stdout,", bytesneeded:%d", bytesneeded);
fflush(stdout);
}
#ifdef OLD1
#ifdef DEBUG49
fprintf(stdout,"SSL_read()\n");
#endif
while((cnt = SSL_read(ssl, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG49
fprintf(stdout,"SSL_read() round\n");
#endif
#ifdef DEBUG50
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
fflush(stdout);
if(cnt < 0) {
fprintf(stderr, "\n%s: SSL_read()", procname);
fprintf(stderr, ", status: %d", status);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
perror("SSL_read");
fflush(stderr);
}
#endif
fflush(stdout);
hash_update_cvar(&hashctx);
HashFinal(hash, &hashctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
#ifdef NOTUSED
#ifdef DEBUG49
fprintf(stdout,"SSL_shutdown()\n");
#endif
SSL_shutdown(ssl);
#endif
#ifdef DEBUG49
fprintf(stdout,"SSL_free()\n");
#endif
SSL_free(ssl);
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_free()\n");
#endif
SSL_CTX_free(ctx);
close(s);
}
commandrandom.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "sha256.h"
#include "fort.h"
extern unsigned char *procname;
extern int newressu_output;
extern int verbose;
#include <stdarg.h>
void dbs_printf(unsigned char **buf, size_t *buf_length, const unsigned char *format, ...)
{
int count;
va_list args;;
va_start(args, format);
count = vsnprintf(*buf, *buf_length, format, args) + 1;
va_end(args);
if(*buf_length < count) {
*buf_length = count;
*buf = realloc(*buf, *buf_length);
va_start(args, format);
count = vsnprintf(*buf, *buf_length, format, args) + 1;
va_end(args);
}
}
int fort_connect(unsigned char *host, unsigned char *port)
{
struct addrinfo hints, *res, *resp;
int s, status;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if((status = getaddrinfo(host, port, &hints, &res)) != 0) {
fprintf(stderr,"\n%s: getaddrinfo", procname);
fprintf(stderr,", status %d", status);
fprintf(stderr,", gai_strerror(): %s", gai_strerror(status));
fprintf(stderr,", errno %d\n", errno);
fflush(stderr);
}
for(resp = res; resp != NULL; resp = resp->ai_next) {
if((s = socket(resp->ai_family, resp->ai_socktype, resp->ai_protocol)) < 0)
continue;
if(connect(s, resp->ai_addr, resp->ai_addrlen) == 0)
break;
close(s);
}
freeaddrinfo(res);
return(s);
}
#define aDEBUG27 2
void fort_hash_http_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
if((s = fort_connect(host, port))<0) {
fprintf(stderr,"\n%s: cannot fort_connect()", procname);
fprintf(stderr,", status: %d", s);
fprintf(stderr,", errno: %d" , errno);
perror("fort_connect");
fflush(stderr);
}
// GET / HTTP/1.0\r\nHost: moijari.com:5006\r\n
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
if((status = write(s, msg, strlen(msg))) < 0) {
fprintf(stderr, "\n%s: write(), error: %d\n", procname, errno);
perror("write");
fflush(stderr);
}
HashCtx ctx;
unsigned char buffer[1024];
HashInit(&ctx);
bytes = 0;
characters = 0;
while((cnt = read(s, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG27
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&ctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
hash_update_cvar(&ctx);
HashFinal(hash, &ctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
close(s);
}
#define aDEBUG49 2
#define aDEBUG50 2
void fort_hash_https_page(unsigned char *host,unsigned char *port, unsigned char *page, unsigned char *hash) // 202011 JariK
{
int c, cnt, s, status, bytes, characters;
SSL_METHOD *method = NULL;
SSL_CTX *ctx = NULL;
SSL *ssl;
SSL_library_init(); //see: http://h30266.www3.hpe.com/odl/axpos/opsys/vmsos84/BA554_90007/ch04s03.html
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
#ifdef DEBUG49
fprintf(stdout,"SSLv23_client_method()\n");
#endif
if((method = (SSL_METHOD *)
SSLv23_client_method()) == NULL) {
fprintf(stderr,"\n%s: cannot SSLv3_server_method()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_new()\n");
#endif
if((ctx = SSL_CTX_new(method)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_CTX_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"SSL_new()\n");
#endif
if((ssl = SSL_new(ctx)) == NULL) {
fprintf(stderr,"\n%s: cannot SSL_new()", procname);
fflush(stderr);
}
#ifdef DEBUG49
fprintf(stdout,"fort_connect()\n");
#endif
if((s = fort_connect(host, port)) < 0) {
fprintf(stderr,"\n%s: cannot fort_connect()", procname);
fprintf(stderr,", status: %d", s);
fprintf(stderr,", errno: %d" , errno);
perror("fort_connect");
fflush(stderr);
}
SSL_set_fd(ssl, s);
#ifdef DEBUG49
fprintf(stdout,"SSL_connect(ssl)\n");
#endif
if((status = SSL_connect(ssl)) <= 0) {
fprintf(stderr,"\n%s: cannot SSL_connect()", procname);
fprintf(stderr,", status: %d", status);
fprintf(stderr,", errno: %d" , errno);
fprintf(stderr,", SSL_get_error(): %d\n", SSL_get_error(ssl,status));
perror("SSL_connect");
fflush(stderr);
}
unsigned char *format =
"GET %s HTTP/1.0\r\n" \
"Host: %s:%s\r\n" \
"User-Agent: %s\r\n";
static unsigned char *msg = NULL;
static size_t msg_length = 0;
extern unsigned char *fortuseragent;
dbs_printf(&msg, &msg_length, format, page, host, port, fortuseragent);
#ifdef DEBUG49
fprintf(stdout,"SSL_write(), msg_length:%ld, msg=\"%s\"\n", msg_length,msg);
#endif
if((status = SSL_write(ssl, msg, strlen(msg))) < 0) {
fprintf(stderr,"\n%s: SSL_write()", procname);
fprintf(stderr,", status: %d", status);
fprintf(stderr,", errno: %d", errno);
fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
perror("SSL_write");
fflush(stderr);
}
fflush(stdout);
HashCtx hashctx;
unsigned char buffer[2048];
HashInit(&hashctx);
bytes = 0;
characters = 0;
#ifdef DEBUG49
fprintf(stdout, "SSL_read()\n");
#endif
int bytesneeded = 0, bytesheader = 0, bytescontent = 0;
do {
cnt = SSL_read(ssl, buffer, sizeof(buffer));
if(cnt < 0) {
int err, err2;
err = SSL_get_error(ssl, cnt);
err2 = ERR_get_error();
fprintf(stderr, "\n%s: cannot SSL_read()", procname);
fprintf(stderr, ", retval: %d", cnt);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error() %d", err);
fprintf(stderr,", ERR_get_error() %d\n", err2);
perror("SSL_read");
fflush(stderr);
break;
}
#ifdef DEBUG50
write(1, buffer, cnt);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
if(bytesneeded == 0) {
char *p;
p = buffer;
int count = 0;
while(*p != '\0') {
if(!strncmp(p, "\r\nContent-Length: ", 18)) {
bytescontent = atoi(p + 18);
}
if(!strncmp(p, "\r\n\r\n", 4)) {
bytesheader = count;
}
p++;
count++;
}
bytesneeded = bytescontent + bytesheader + 4;
}
} while(SSL_pending(ssl) || bytes < bytesneeded);
if(verbose) {
fprintf(stdout,"\nbytescontent:%d", bytescontent);
fprintf(stdout,", bytesheader:%d", bytesheader);
fprintf(stdout,", bytesneeded:%d", bytesneeded);
fflush(stdout);
}
#ifdef OLD1
#ifdef DEBUG49
fprintf(stdout,"SSL_read()\n");
#endif
while((cnt = SSL_read(ssl, buffer, sizeof(buffer))) > 0) {
#ifdef DEBUG49
fprintf(stdout,"SSL_read() round\n");
#endif
#ifdef DEBUG50
write(1, buffer, cnt);
fflush(stdout);
#endif
HashUpdate(&hashctx, buffer, cnt);
bytes += cnt;
for(c = 0; c < cnt; c++) {
if(buffer[c] < 0x80 || buffer[c] > 0xbf)
characters++;
}
}
fflush(stdout);
if(cnt < 0) {
fprintf(stderr, "\n%s: SSL_read()", procname);
fprintf(stderr, ", status: %d", status);
fprintf(stderr, ", errno: %d", errno);
fprintf(stderr,", SSL_get_error(): %d", SSL_get_error(ssl,status));
perror("SSL_read");
fflush(stderr);
}
#endif
fflush(stdout);
hash_update_cvar(&hashctx);
HashFinal(hash, &hashctx);
if(verbose) {
fprintf(stdout,"\n, %d bytes read", bytes);
fprintf(stdout,", %d characters read", characters);
fprintf(stdout,", sha256: ");
for(int c = 0;c < HashLen; c++) {
fprintf(stdout,"%02x", hash[c]);
}
fprintf(stdout,"\n");
newressu_output = 0;
}
#ifdef NOTUSED
#ifdef DEBUG49
fprintf(stdout,"SSL_shutdown()\n");
#endif
SSL_shutdown(ssl);
#endif
#ifdef DEBUG49
fprintf(stdout,"SSL_free()\n");
#endif
SSL_free(ssl);
#ifdef DEBUG49
fprintf(stdout,"SSL_CTX_free()\n");
#endif
SSL_CTX_free(ctx);
close(s);
}