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ä.
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.01 ©";
static unsigned char *copyright = "Copyright (c) 2013-2023 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;
extern int verbose;
#define INPUT_RESSU 0
int input = 0;
void ressu_genbytes(int size, unsigned char *buffer);
int ressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
ressu_genbytes(sizeof(gent), gent);
} // 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);
}
#define CODECHARS 5
#define CODES 100000
#define ROUNDS 1
#define MODE1 2
#define aMODE2 2
void main(int argc, char *argv[])
{
int c, d, e, f, help = 0, rounds, 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("--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)
if(mode == 1) { // simple. you can also use ./newressu --otp5n -w10
for(c = 0; c < CODES; c++) {
data[c] = ressu_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 = ressu_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 = ressu_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");
}
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 merkeistä 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"
$
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"
$
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"
$
Suurin osa tästä postista son ollut exfat debukkailua, 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, summaa 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 tästä.
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
$
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 <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/time.h>
#include <math.h>
//#define SHA256 2 // in Makefile
#include "sha256.h"
//#define MAIN 2 // in Makefile
extern unsigned char *procname;
static unsigned char *programname = "Newressu version 3.993 ©";
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);
}
static unsigned long periods[1024];
static unsigned long genbytes = 0;
static unsigned long clockbytes = 0;
int verbose = 0;
int size = 5, type = 10;
#define ALL_SLICE 64 // orig 64
#define RESSUT_SLICES 32 // orig 32
#define RESSUT_BYTES (RESSUT_SLICES * ALL_SLICE) // 2048 (32 * 64)
#define RESSU_MIN_ROUNDS 2
#define RESSU_MIN_CLOCKBYTES 16 * 1024
#define GENT_SLICES 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 * 8; // orig 256
static int ressut_bits2_needed = RESSUT_SLICES * 32; // orig 1024
static int ressut_bits3_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits4_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits5_needed = RESSUT_SLICES * 64; // orig 2048
static int ressut_bits6_needed = RESSUT_SLICES * 64 * 2; // orig 2048 * 2
static int ressut_bits7_needed = RESSUT_SLICES * 64 * 8; // orig 2048 * 8
int rndbits1 = 0,
rndbits2 = 0,
rndbits3 = 0,
rndbits4 = 0,
rndbits5 = 0,
rndbits6 = 0,
rndbits7 = 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_clockbyte2() /* JariK 2013 */
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec & 0xff);
}
#define FIXEDCLOCKCHAINLENGTH 50 // orig 50
unsigned int fixedclockchainlength = FIXEDCLOCKCHAINLENGTH;
static unsigned char ressu_fixedclock() /* JariK 2022 */
{
static unsigned int clockbyte = 1, counter = 0;
if(counter == 0) {
clockbyte++;
counter += fixedclockchainlength;
}
counter--;
return(clockbyte & 0xff);
}
static unsigned char ressu_clock()
{
return ressu_clockbyte2();
//return ressu_clockbyte2() ^ ressu_fixedclock();
}
unsigned char (*clockfunc)() = &ressu_clock;
void ressu_setclock(int clockmode)
{
if(!clockmode)
clockfunc = &ressu_clock;
else
clockfunc = &ressu_fixedclock;
}
#define aDEBUG2A 2
#define aDEBUG2B 2
#define aDEBUG2C 2
static unsigned char *ressuct; // ressu random buffer lookup
static unsigned int ressuct_bytes;
static unsigned char ch;
static unsigned int ressu_nonrandom() // not really random
{
static unsigned int rando = 0;
rando = rando +
//clockbytes +
//genbytes +
//time(NULL) +
//clock() +
ressu_useconds() +
ch * ch +
ressu_clock();
#ifdef DEBUG2C
fprintf(stderr," %u", rando % ressuct_bytes);
newressu_output = 1;
#endif
return(rando);
}
unsigned long cblocks = 0;
static unsigned char ressu_clockbyte() /* JariK 2013 */
{
static int reverse = 0; // 0 = copy, 1 = reverse, 28.10.2022 JariK
static unsigned char reversebytes[257];
static unsigned int count = 0;
// dividing clock stream into blocks
// and reversing every other block
if(reverse) { // reverse
// reverse clock chain block
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"rev: %03x ", count);
#endif
for(int c = 0; c < count; c++) {
reversebytes[c] = (*clockfunc)(); // block bytes
#ifdef DEBUG2A
fprintf(stdout," %02x", reversebytes[c]);
newressu_output = 1;
#endif
}
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
cblocks++;
}
// get reversed byte to return
ch = reversebytes[--count]; // reverse
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
#endif
if(count == 0) { // reverse bytes ran out
reverse = 0; // back to copy
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
} else { // copy
// copy clock chain block as is
if(count == 0) {
count = ressuct[ressu_nonrandom() % ressuct_bytes] + 2; // block size
rndbits2 += 8;
#ifdef DEBUG2A
fprintf(stdout,"copy: %03x ", count);
#endif
cblocks++;
}
// get byte to be copied
ch = (*clockfunc)();
#ifdef DEBUG2A
fprintf(stdout," ch:%02x", ch);
newressu_output = 1;
#endif
if(--count == 0) {
reverse = 1; // back to reverse
#ifdef DEBUG2A
fprintf(stdout,"\n");
#endif
}
}
#ifdef DEBUG2A
fflush(stdout);
#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);
}
#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++) {
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++) {
#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 ||
rndbits2 < ressut_bits2_needed ||
d < RESSU_MIN_ROUNDS ||
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;
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 ||
rndbits2 < ressut_bits2_needed ||
rndbits3 < ressut_bits3_needed ||
rndbits4 < ressut_bits4_needed ||
rndbits5 < ressut_bits5_needed ||
rndbits6 < ressut_bits6_needed ||
rndbits7 < ressut_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];
}
#ifdef DEBUG3B
fprintf(stdout,"rndbits1:%d", rndbits1);
fprintf(stdout,", rndbits2:%d", rndbits2);
fprintf(stdout,", rndbits3:%d", rndbits3);
fprintf(stdout,", rndbits4:%d", rndbits4);
fprintf(stdout,", rndbits5:%d", rndbits5);
fprintf(stdout,", rndbits6:%d", rndbits6);
fprintf(stdout,", rndbits7:%d", rndbits6);
fprintf(stdout,"\n");
#endif
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, "\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 (256 bits)
#define aTOPUP_TWICE 2 // off by default
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 aDEBUG21 2
static void pseudoressu_topup()
{
unsigned char topup[TOPUP_SIZE]; // 256 bits
ressu_genbytes(sizeof(topup), topup);
#ifdef DEBUG21
ressu_dump("topup", sizeof(topup), topup, 32);
#endif
pseudoressu_addrandomness(sizeof(topup), topup);
memset(&topup, 0, sizeof(topup)); // forget topup
}
#define aDEBUG23 2
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("first 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 random one
#ifdef DEBUG23
ressu_dump("rekey", 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 random one
#ifdef DEBUG23
ressu_dump("new key", sizeof(pseudoressu_key), pseudoressu_key, 32);
#endif
}
#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]; // 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 newressu_version()
{
fprintf(stderr, "%s", programname); // touch these outside #ifdef MAIN
fprintf(stderr, ", %s", copyright);
}
#ifdef MAIN
#include <stdlib.h>
#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 aUSE_RANDOM 2
#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_readlines(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
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);
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
}
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);
}
/*
* 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
static unsigned char samplefilename[128] = "newressusample%d.rnd";
static unsigned char urandomfilename[128] = "/dev/urandom";
#ifdef USE_RANDOM
static unsigned char randomfilename[128] = "/dev/random";
#endif
static void readfile_xor(int len,
unsigned char *buf,
unsigned char *filename)
{
int c, n, n2;
unsigned char temp[64];
FILE *fp1;
if((fp1 = fopen(filename, "rb"))
!= NULL) {
while(len != 0) {
n = (len < sizeof(temp)) ? len : sizeof(temp);
n2 = fread(temp, 1, n, fp1);
for(c = 0; c < n2; c++)
buf[c] ^= temp[c];
len -= n2;
buf += n2;
}
fclose(fp1);
}
}
int input = INPUT_RESSU;
unsigned char *input_str = "ressu";
int clockmode = 0; // 0 = normal, 1 = fixed
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
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);
else if(input == INPUT_STREAM) // stream
stream_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
readfile_xor(sizeof(gent), gent, urandomfilename);
#ifdef USE_RANDOM
else if(input == INPUT_RANDOM) // random
readfile_xor(sizeof(gent), gent, randomfilename);
#endif
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);
}
#define aDEBUG24 2
#define aDEBUG26 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,"/");
#ifdef DEBUG26
fprintf(stdout,"%d bytes: ", bytes);
#endif
if(type == 2)
fprintf(stdout,"%lx", word);
else if(type == 8)
fprintf(stdout,"%lo", word);
else if(type == 10)
fprintf(stdout,"%lu", word);
else if(type == 16)
fprintf(stdout,"%lx", word);
else
fprintf(stdout,"%lu", word);
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)
{
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++;
}
}
}
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);
}
static long long lines = 10, plines = 0, ptotallines = 0;
void printcolumns(int offset, int base, int startwith, int columns, int *clines)
{
//---------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(columns < c)
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)++;
}
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(1);
}
}
#define DEBUG39
#define FILESIZE 128 * 1024 * 1024
#define BLOCKSIZE 16 * 1024
#define BLOCKS 8192
unsigned long long filesize = FILESIZE, blocks = BLOCKS;
unsigned int blocksize = BLOCKSIZE;
int filesize_set = 0, blocks_set = 0, blocksize_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
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);
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, 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_readlines(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_readlines(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);
}
exit(0);
}
}
static unsigned long limit, word;
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
static int zero = 1, sspace = 0, snewline = 0,
scrlf = 1, chars = 72, pchars = 0, charwidth = 1,
charspaces = 0, words = 0, pwords = 0,
plinesdigits = 5, slineno = 1, screen = 0,
quiet = 0, sort = 0, unique = 0,
flagprintdigits = 0;
#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(pwords == 0 && slineno) {
if(newressu_output) {
fprintf(stdout,"\n");
newressu_output = 0;
}
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
fprintf(stdout,"%s", linenobuf);
fprintf(stdout," ");
}
}
static int calc_spaces()
{
int spaces;
spaces = 0;
if(sspace >= 2 &&
// space between word groups
( (pwords > 0 && pwords % sspace == 0) ||
// space after linenumber
// are not printed if
// not printing linenumber
(slineno && pwords == 0) ) )
spaces++;
if(sspace &&
// space between words
( (pwords > 0) ||
// space after linenumber
(slineno && pwords == 0) ) )
spaces++;
return(spaces);
}
static void print_spaces()
{
int sp;
for(sp = calc_spaces(); sp > 0; sp--)
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);
}
#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 DEBUG67
fprintf(stdout,"GENT_SIZE:%d",GENT_SIZE);
fprintf(stdout,", SAMPLE_SIZE:%d",SAMPLE_BLOCKSIZE);
fprintf(stdout,"\n");
#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
#ifdef DEBUG70
unsigned char command[80];
sprintf(command,"grep \"WEAK\\|FAILED\" newressusample1.rnd.dieharder");
system(command);
#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 DEBUG75
#ifdef DEBUG75
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 aDEBUG68 // default is off
#ifdef DEBUG68
unsigned char *hindi = malloc(8192);
digits_add_limits(&hindi,0x900,0x97f); // Hindi (0900-097f)
unsigned char *h;
int first;
fprintf(stdout,"hindi1:");
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
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 DEBUG72 // default is on
#ifdef DEBUG72
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(*(argv[c] + 7) != '\0' && atoi(argv[c] + 7) > 1) {
sspace = atoi(argv[c] + 7);
} else if(c + 1 < argc && atoi(argv[c + 1]) > 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;
#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 DEBUG72
} 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)) {
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("-s", argv[c], 2)) {
if(*(argv[c] + 2) != '\0') {
size = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
size = atoi(argv[c + 1]);
c++;
}
limit = 0; // 23.6.2021
} else if(!strncmp("--bits", argv[c], 6)) {
if(*(argv[c] + 6) != '\0') {
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(*(argv[c] + 7) != '\0') {
ressut_bytes = atoi(argv[c] + 7);
} else if(c + 1 < argc) {
ressut_bytes = atoi(argv[c + 1]);
c++;
}
} else if(!strncmp("-w", argv[c], 2)) { // words per line
if(*(argv[c] + 2) != '\0') {
words = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
words = atoi(argv[c + 1]);
c++;
}
if(words < 1)
words = 1;
chars = 0;
screen = 0;
} else if(!strncmp("-c*", argv[c], 3)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
words = 0;
#ifdef DEBUG71
fprintf(stdout,"screencolumns:%d\n", chars);
#endif
} else if(!strncmp("-l*", argv[c], 3)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
lines = w.ws_row-1;
#ifdef DEBUG71
fprintf(stdout,"screenlines:%lld\n", lines);
#endif
} else if(!strncmp("--screen", argv[c],8)) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
chars = w.ws_col;
lines = w.ws_row-1;
words = 0;
screen = 1;
#ifdef DEBUG71
fprintf(stdout,"screencolumns:%d", chars);
fprintf(stdout,", screenlines:%lld\n", lines);
#endif
} else if(!strncmp("-c", argv[c], 2)) { // characters per line
if(*(argv[c] + 2) != '\0') {
chars = atoi(argv[c] + 2);
} else if(c + 1 < argc) {
chars = atoi(argv[c + 1]);
c++;
}
if(chars < 1)
chars = 72;
words = 0;
screen = 0;
} else if(!strncmp("-l",argv[c], 2)) { // lines
if(*(argv[c] + 2) != '\0') {
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(!strcmp("-b", argv[c]) ||
!strcmp("--bin", argv[c]) ||
!strcmp("--1bit", argv[c]) ||
!strcmp("--1bits", argv[c])) {
digits = "01";
charspaces = 0;
charwidth = 1;
size = 8;
type = 2;
} else if(!strcmp("--2bits", argv[c])) {
digits = "0123";
charspaces = 0;
charwidth = 1;
size = 8;
type = 2;
} else if(!strcmp("-o", argv[c]) ||
!strcmp("--oct", argv[c]) ||
!strcmp("--3bits", argv[c]) ) {
digits = "01234567";
charspaces = 0;
charwidth = 1;
size = 3;
type = 8;
} else if(!strcmp("-d", argv[c]) ||
!strcmp("--dec", argv[c])) {
digits = "0123456789";
charspaces = 0;
charwidth = 1;
size = 5;
type = 10;
} else if(!strcmp("-x", argv[c]) ||
!strcmp("--hex", argv[c]) ||
!strcmp("--4bits", argv[c])) {
digits = "0123456789abcdef";
charspaces = 0;
charwidth = 1;
size = 4;
type = 16;
} else if(!strcmp("-X", argv[c]) ||
!strcmp("--HEX", argv[c]) ||
!strcmp("--4BITS", argv[c])) {
digits = "0123456789ABCDEF";
charspaces = 0;
charwidth = 1;
size = 4;
type = 16;
} 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("-2", argv[c]) ||
!strcmp("--6bits", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz" \
"_-"; // 6 bits, 64 characters
charspaces = 0;
charwidth = 1;
size = 8;
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("-5", argv[c]) ||
!strcmp("--5bits", argv[c])) {
digits =
"0123456789" \
"ABCDEFGHIJKLMNOPQRSTUV"; // 5 bits
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("--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("--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(!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 = FIXEDCLOCKCHAINLENGTH;
ressu_setclock(clockmode);
} else if(!strcmp("--verbose", argv[c])) {
verbose = !verbose;
} else if(!strcmp("--statline", argv[c])) {
print_statline = !print_statline;
} 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;
#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(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 = "🇫🇮🇸🇪🇳🇴🇩🇰🇪🇪🇱🇻🇱🇹";
}
#ifdef DEBUG59
if(utf8) {
int xlines;
printcolumns(6, 0x10, 0, 64, &xlines);
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
#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
#define aDEBUG60 2
#ifdef DEBUG60
int xlines;
printcolumns(6, 2, 0, 64, &xlines);
printcolumns(6, 8, 0, 64, &xlines);
printcolumns(6, 10, 0, 64, &xlines);
printcolumns(6, 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(dieharder && !sample) {
fprintf(stderr,"%s: cannot --dieharder without --sample\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(sample) { // & dieharder
dump_sample();
exit(status);
} // if(sample)
#ifdef DEBUG72
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");
#ifdef DEBUG25
fprintf(stderr,"%s: procname '/bin/newressu', path exists '%s', path set\n",
procname, "/var/ressu");
fflush(stderr);
#endif
} else if(!strncmp(procname, "./newressu", 13) && exists_path(".ressu")) {
set_path(".ressu");
#ifdef DEBUG25
fprintf(stderr,"%s: procname '/bin/newressu', path exists '%s', path set\n",
procname, "/var/ressu");
fflush(stderr);
#endif
} else if(exists_path("/var/ressu")) {
set_path("/var/ressu");
#ifdef DEBUG25
fprintf(stderr,"%s: path exists '%s', set\n",
procname,"/var/ressu");
fflush(stderr);
#endif
} else if(exists_path("/var/newressu")) {
set_path("/var/newressu");
#ifdef DEBUG25
fprintf(stderr,"%s: path exists '%s', set\n",
procname,"/var/newressu");
fflush(stderr);
#endif
} else if(exists_path(".ressu")) {
set_path(".ressu");
#ifdef DEBUG25
fprintf(stderr,"%s: path exists '%s', set\n",
procname, ".ressu");
fflush(stderr);
#endif
} else if(exists_path("./")) {
set_path("./");
#ifdef DEBUG25
fprintf(stderr,"%s: path exists '%s', set\n",
procname, "./");
fflush(stderr);
#endif
} else {
set_path("./");
#ifdef DEBUG25
fprintf(stderr,"%s: path set '%s'\n",
procname, "./");
fflush(stderr);
#endif
}
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)) {
#ifdef DEBUG25
fprintf(stderr,"%s: running integrity test(s), command '%s'\n", procname, command);
fflush(stderr);
#endif
int error;
if((error = system(command)) != 0) {
fprintf(stderr,"%s: system(): cannot execute command '%s'\n", procname, command);
}
} else {
#ifdef DEBUG25
fprintf(stderr,"%s: integrity test(s) allready done this time! command: %s\n", procname,command);
fflush(stderr);
#endif
}
//fprintf(stderr," done.\n");
fflush(stderr);
set_path(savepath);
}
#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;
int linew = 0;
// in beginning of line, count printed line number
if(!quiet && slineno) {
sprintf(linenobuf,"%0*llu", plinesdigits, plines);
pchars += strlen(linenobuf);
pchars++;
}
// count words
while((chars > 0 && pchars + size * charwidth + calc_spaces() <= chars) ||
(words > 0 && pwords < words)) {
linew++;
pchars += calc_spaces();
pchars += (size*charwidth);
pwords++;
}
if(columns) {
int xlines;
printcolumns(0, 10, 0, pchars, &xlines);
lines -= xlines;
if(lines < 1)
lines = 1;
}
// there has to be atleast one data word
if(linew < 1)
linew = 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");
lines = 0;
}
} else {
if(sort == 1 && size > 0 && wordvalues > 0 && wordvalues < linew) {
fprintf(stderr, "%s:", procname);
fprintf(stderr, " digits is less than calculated words");
fprintf(stderr, ", digits:%d(%lu)", digitscount, wordvalues);
fprintf(stderr, ", words:%d\n", linew);
lines = 0;
}
}
// "small" words as single newressu_gen_limit() call
if(limit == 0 && wordvalues > 0)
limit = wordvalues;
if(stats) {
fprintf(stderr, "randomsource: %s", input_str);
fprintf(stderr, ", clockmode: %d", clockmode);
if(clockmode==1)
fprintf(stderr, ", clockchainlength: %d", fixedclockchainlength);
fprintf(stderr, ", size: %d", size);
fprintf(stderr, ", lines: %llu", lines);
fprintf(stderr, ", linew: %d", linew);
fprintf(stderr, ", pchars: %d", pchars);
fprintf(stderr, ", pwords: %d", pwords);
fprintf(stderr, ", tchars: %llu", (unsigned long long)size * linew * 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, "\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 --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 --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
pwords = 0;
while(pwords < linew) {
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;
}
pwords++;
} // while(pwords<linew) {
} else { // if(!sort)
pwords = 0;
line_clear(&linecnt, &line);
// fetch and save words on this row
while(pwords < linew) {
readword(wordbuf);
if(line_add_string_sort(&linecnt, &line, wordbuf)) {
pwords++;
}
} // while(pwords<linew) {
pwords = 0;
// print words on this row
while(pwords < linew) {
line_get_string(sizeof(wordbuf), wordbuf, pwords, 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;
}
pwords++;
} // while(pwords<linew) {
} // 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 * linew * plines) / STATDIV) * STATDIV;
stat_line_get_readable(buf10, bytes);
#ifdef DEBUG97
fprintf(stderr, "%lld", (unsigned long long)size * linew * 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 * linew * 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 USE_TIMER
if(timer) {
double timertook=getseconds()-timerstart;
fprintf(stderr, "run time %f seconds", 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);
}