Suomessa lahjoituksen voi tehdä, mutta sitä ei voi pyytää. Jos haluat lahjoittaa kuitenkin projektille, laita lahjoituksesi Danske Bank tilille FI15 8312 0710 7275 83 (SWIFT:DABAFIHH), maksun saaja Jari Kuivaniemi. Kirjoita viestikenttään nimesi ja asuinpaikkakuntasi. Jos lahjoitat sata euroa tai enemmän ja haluat vastalahjan, voit saada vastalahjana sudokun tai tämänhetkisen sorsan. Vastalahjasudokua tai sorsaa varten kirjoita sähköpostiviesti osoitteeseen moijaricom@gmail.com ja laita viestiin aiemmat pankkitapahtuman viestissä mainitut nimesi ja asuinpaikkakuntasi ja postiosoitteesi vastalahjan lähetystä varten. Laita sähköpostiviestin otsakkeeksi “vastalahjasudoku” tai “vastalahjasorsa”. Lähetän yhden sudokun jokaisesta sata euroa ylittävästä lahjoituksesta. Sorsa tulee tietenkin vain yhteen kertaan.
Myös pienet lahjoitukset (euro tai kaksi) ovat tervetulleita. Itseasiassa optimi oisi kolme euroa kerran kuussa, kymmenellä lahjoituksella saisin maksettua jo palvellimen kuukausimaksun. Toiset kymmenen lahjoitusta ostaisi koodausvissyt..
Kiitokset lahjoituksestasi.
Edellinen artikkelini (https://moijari.com/?p=1874) oli mielestäni paras tähän asti. Siinä viimeisteltiin ressu satunnaisbittigeneraattori, tutkittiin sen satunnaisuutta, tehtiin sille liitännäisrutiineja: pseudoressu_bytes, ressutwist_bytes, stream_bytes, urandom_bytes. siinä korjattiin pari bugia ressusta (+2-bugi ja bad for randomness bugi), ja metsästettiin bugia exfat:ista. artikkelissa oli sudoku loppukevennys ja ensimmäinen versio db8:sta. Lisäksi siinä tehtiin komentorivi ohjelma newressu kaiken satunnaisuuden arvontaan.
Löysin uuden vaikean steps 13 sudokun:
A B C D E F G H I
+-----------+-----------+-----------+
A | | 9 8 | 1 |
B | | 2 | 4 3 |
C | | 1 | 6 5 |
+-----------+-----------+-----------+
D | 9 | 3 6 | 7 |
E | | | |
F | 5 | | 1 2 |
+-----------+-----------+-----------+
G | 9 4 1 | 5 | 2 |
H | 2 8 | | |
I | 6 | | 9 |
+-----------+-----------+-----------+
s:1 gu:93 st:13 ro:2 clues:25
Sitten sudokusarja kesäksi: kopi pastaa nämä tekstinkäsittelyyn (esimerkiksi libre office) ja esikatsele ja muuta fonttikokoa ja sarakkeita haluamallasi tavalla ja tulosta. Voit myös joutua lisäämään tyhjiä rivejä sudokujen väliin.
Lisää sudokuja löytyy edelllisestä artikkelista (https://moijari.com/?p=1874.
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 1 | 5 6 |
B | 2 9 | 4 8 | 1 3 7 |
C | 1 | 9 | 2 4 |
+-----------+-----------+-----------+
D | 7 | | 8 6 |
E | 6 8 | 7 9 | 4 2 3 |
F | 4 1 3 | 6 2 | 5 7 9 |
+-----------+-----------+-----------+
G | 5 | 8 4 | 1 2 |
H | | 7 | |
I | | 5 3 2 | 6 9 8 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:45
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 9 2 | 4 3 | 5 |
B | 4 5 6 | 9 8 | 3 |
C | 8 1 | 2 | 9 6 |
+-----------+-----------+-----------+
D | 3 | | |
E | 5 | 9 | 2 7 |
F | 2 1 7 | 8 | 4 9 |
+-----------+-----------+-----------+
G | 1 8 | 6 2 9 | 4 7 3 |
H | | | 2 5 6 |
I | 6 4 | 5 | 1 8 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:44
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 6 | | 2 |
B | 8 2 7 | | 3 |
C | 1 3 | 6 | 9 4 |
+-----------+-----------+-----------+
D | 2 3 1 | 5 7 | 4 6 |
E | 4 7 8 | 1 6 | 3 5 2 |
F | 5 9 | | 8 1 |
+-----------+-----------+-----------+
G | 6 1 | 8 | |
H | | 7 | 2 8 |
I | 7 | 5 3 4 | 1 9 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:43
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 3 7 | 5 2 4 | 8 |
B | 5 8 | 1 3 | 7 |
C | 2 | 7 | 3 |
+-----------+-----------+-----------+
D | 8 | 9 1 | 5 2 |
E | 1 | 2 | 6 |
F | 5 | 8 7 6 | 1 9 |
+-----------+-----------+-----------+
G | 3 | 1 8 2 | |
H | | 3 5 7 | 6 1 |
I | 7 | 4 6 9 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:42
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | 4 | 6 |
B | 5 1 2 | 8 6 | 3 |
C | 7 6 | 3 | 1 5 |
+-----------+-----------+-----------+
D | | 9 2 | 4 |
E | 5 | 7 1 | 9 3 |
F | | 4 | 1 6 |
+-----------+-----------+-----------+
G | 7 | 4 2 6 | 3 |
H | 4 | 9 1 | 7 2 |
I | 2 3 | 7 5 8 | 6 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:41
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | 5 1 3 | 2 8 7 |
B | 1 | 7 9 | 3 |
C | 5 7 | 6 | 9 1 4 |
+-----------+-----------+-----------+
D | 8 5 | 1 | 4 |
E | 7 3 | | |
F | 2 4 | 3 | 1 |
+-----------+-----------+-----------+
G | 6 | 3 | 7 8 |
H | 3 4 7 | 2 8 | 1 5 |
I | | 6 | 3 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:40
A B C D E F G H I
+-----------+-----------+-----------+
A | | 2 1 | 3 8 |
B | 3 2 6 | 8 9 | 4 |
C | 8 | | 2 6 |
+-----------+-----------+-----------+
D | 7 4 8 | 5 3 | |
E | 2 3 | 9 7 | 1 8 |
F | | 4 2 | 7 |
+-----------+-----------+-----------+
G | 5 8 | 4 7 | 6 |
H | 1 2 | 6 | 8 3 |
I | 9 | 8 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:39
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 6 | 3 9 | 1 |
B | 2 | | 6 |
C | 8 | 2 | 4 3 9 |
+-----------+-----------+-----------+
D | 1 | 8 9 5 | 2 7 4 |
E | 4 | 2 3 | 9 |
F | | 7 | 6 5 |
+-----------+-----------+-----------+
G | 7 | | 4 2 |
H | 3 | 2 6 | 1 |
I | 2 6 | 4 | 8 9 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:38
A B C D E F G H I
+-----------+-----------+-----------+
A | 5 9 | | 4 2 |
B | 7 3 1 | 2 | 9 8 |
C | 6 4 | 8 7 | |
+-----------+-----------+-----------+
D | 6 | 9 | 8 |
E | 5 2 | 1 | 9 |
F | | 7 6 5 | 3 4 |
+-----------+-----------+-----------+
G | | | 5 9 |
H | 4 7 | 9 6 | 3 |
I | 9 1 | 3 7 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:37
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 1 3 | |
B | 3 | 5 9 | 2 8 1 |
C | 1 5 | 2 | 3 6 |
+-----------+-----------+-----------+
D | 2 | 4 | 9 7 |
E | 6 9 | 1 | 3 |
F | 7 | 9 | 8 4 |
+-----------+-----------+-----------+
G | 6 | 9 3 | 8 |
H | 1 8 | 7 2 | 9 3 |
I | | | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:36
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 1 | 3 | |
B | 3 | 1 | 2 |
C | | 7 4 | |
+-----------+-----------+-----------+
D | 6 4 5 | 2 7 | 8 9 |
E | | | 7 4 5 |
F | 9 7 | | |
+-----------+-----------+-----------+
G | 3 6 2 | 1 | 9 5 |
H | | 8 3 | |
I | 8 7 4 | 5 6 | 2 3 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:4 clues:35
A B C D E F G H I
+-----------+-----------+-----------+
A | 4 9 8 | 1 | 7 3 |
B | 7 | 9 | 6 |
C | 1 | 7 | 9 |
+-----------+-----------+-----------+
D | 5 | 9 | 1 |
E | 2 | 5 | |
F | | 6 1 | 8 5 |
+-----------+-----------+-----------+
G | 1 2 | 4 | 5 7 |
H | | 2 7 | 6 |
I | 9 4 | 6 5 | 1 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:2 clues:34
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | | |
B | | 4 9 | 3 |
C | 3 | 8 | 4 2 |
+-----------+-----------+-----------+
D | | 5 6 | 1 |
E | | 9 3 | 7 6 |
F | 5 | 2 | 4 3 |
+-----------+-----------+-----------+
G | 2 3 | 4 8 | 9 |
H | 4 5 | 3 7 2 | 6 1 |
I | 6 | | 4 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:33
A B C D E F G H I
+-----------+-----------+-----------+
A | | 4 | |
B | 3 2 | | 7 4 |
C | 4 6 | | 3 8 |
+-----------+-----------+-----------+
D | | 2 4 | 8 |
E | 8 | 1 5 | 9 |
F | | 9 | |
+-----------+-----------+-----------+
G | 8 1 3 | 7 2 | 6 4 |
H | 6 9 | 1 | 7 |
I | 5 | 4 8 | 1 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:32
A B C D E F G H I
+-----------+-----------+-----------+
A | 6 | | |
B | | 2 7 | 5 8 |
C | 1 | 9 | 6 3 |
+-----------+-----------+-----------+
D | 4 | 7 2 | |
E | 6 | | 1 |
F | 7 8 2 | 5 6 | 3 |
+-----------+-----------+-----------+
G | 3 | 7 9 | 1 8 |
H | 7 | 4 | |
I | 6 | 5 | 4 2 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:31
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | 4 9 | |
B | 7 | 5 | 2 |
C | | 8 2 | |
+-----------+-----------+-----------+
D | 8 | 9 | |
E | 4 2 1 | | 9 |
F | 9 | 3 | 1 6 |
+-----------+-----------+-----------+
G | 8 1 6 | 9 5 | 4 |
H | 3 7 | 6 | 8 |
I | | 3 | 1 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:3 clues:30
A B C D E F G H I
+-----------+-----------+-----------+
A | 8 1 | 7 | 5 9 |
B | 9 4 2 | | 7 |
C | | 8 | |
+-----------+-----------+-----------+
D | 5 3 | 6 | 9 |
E | | 7 3 | 6 |
F | | 2 5 | 4 |
+-----------+-----------+-----------+
G | 9 | | 5 3 1 |
H | | 4 | 2 |
I | 2 5 | 9 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:4 clues:29
A B C D E F G H I
+-----------+-----------+-----------+
A | 3 | | 4 |
B | 4 1 | 9 | |
C | | 8 3 | |
+-----------+-----------+-----------+
D | 2 | 7 6 5 | 4 |
E | | | 6 |
F | 9 | | 7 8 |
+-----------+-----------+-----------+
G | 8 6 | 5 1 | 9 |
H | 1 4 | 7 6 | 3 |
I | 3 | 2 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:6 clues:28
A B C D E F G H I
+-----------+-----------+-----------+
A | | 3 | |
B | | | 9 6 5 |
C | 4 | 5 | |
+-----------+-----------+-----------+
D | 5 | 1 | 2 7 |
E | | 7 4 | |
F | 9 | | 1 |
+-----------+-----------+-----------+
G | 9 | | |
H | 6 1 | 7 | 3 |
I | 3 7 2 | 9 8 | 6 5 4 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:4 clues:27
A B C D E F G H I
+-----------+-----------+-----------+
A | 9 | 1 | 2 |
B | 7 | 3 | 9 6 |
C | | 6 7 | 4 8 |
+-----------+-----------+-----------+
D | 9 2 | 3 | |
E | | 5 | |
F | 1 | | 7 4 |
+-----------+-----------+-----------+
G | 8 | 7 | 5 |
H | 6 | 8 1 | |
I | | 9 | 4 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:5 clues:26
A B C D E F G H I
+-----------+-----------+-----------+
A | 1 | 2 4 | 8 5 |
B | 3 2 | | |
C | 6 | 3 | 2 7 |
+-----------+-----------+-----------+
D | 2 | 4 | |
E | 9 8 | 5 | 3 |
F | 5 | 9 | |
+-----------+-----------+-----------+
G | | 6 | |
H | 3 | | 7 |
I | 5 | 7 | 6 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:5 clues:25
A B C D E F G H I
+-----------+-----------+-----------+
A | 7 | 3 | 2 8 |
B | 8 | 6 | 5 |
C | | 1 | |
+-----------+-----------+-----------+
D | 4 | | 7 |
E | | | 2 |
F | 6 9 | 8 | 1 |
+-----------+-----------+-----------+
G | | 4 | |
H | 6 9 | | 7 |
I | 3 | 6 7 | 4 9 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:5 clues:24
A B C D E F G H I
+-----------+-----------+-----------+
A | | 6 3 | 7 |
B | | | 6 5 |
C | 2 | 8 9 | |
+-----------+-----------+-----------+
D | 4 1 | 8 5 | |
E | 6 | | 7 |
F | | | 8 |
+-----------+-----------+-----------+
G | | | 5 1 |
H | 3 | 1 | |
I | 8 | 5 | 2 9 |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:7 clues:23
A B C D E F G H I
+-----------+-----------+-----------+
A | | 6 8 | 5 |
B | | | |
C | 2 | 1 | 7 |
+-----------+-----------+-----------+
D | | 5 | 4 |
E | 3 | 9 | 6 |
F | 4 | 8 | |
+-----------+-----------+-----------+
G | 9 | 7 | 8 4 1 |
H | 6 | 4 | 9 |
I | 8 | | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:5 clues:22
A B C D E F G H I
+-----------+-----------+-----------+
A | | 1 5 | |
B | 7 | | 5 |
C | 2 | | |
+-----------+-----------+-----------+
D | 6 | 7 | |
E | 8 | | 3 |
F | | 3 | 9 2 |
+-----------+-----------+-----------+
G | | 3 | 5 |
H | 9 | 7 | 1 3 |
I | 8 4 | 2 | |
+-----------+-----------+-----------+
s:0 gu:0 st:0 ro:5 clues:21
Tässä vielä esittely edellisen raportin mielestäni tärkeimmästä asiasta db8:sta, lista tähän asti llöydetyistä sudokujen vaikeusasteista (steps luku): aiemmissa steps 12 sudokuissa oli 26 tai 24 vihjettä..
$ ./db8
DB8 version 0.04 ©
skk>digits,steps
query:digits,steps
query2:'digits', 'steps'
201 rows.
0 'digits' = "19", 'steps' = "0"
1 'digits' = "20", 'steps' = "0"
2 'digits' = "21", 'steps' = "0"
3 'digits' = "21", 'steps' = "2"
4 'digits' = "21", 'steps' = "3"
5 'digits' = "21", 'steps' = "4"
6 'digits' = "22", 'steps' = "0"
7 'digits' = "22", 'steps' = "1"
8 'digits' = "22", 'steps' = "2"
9 'digits' = "22", 'steps' = "3"
10 'digits' = "22", 'steps' = "4"
11 'digits' = "22", 'steps' = "5"
12 'digits' = "22", 'steps' = "6"
13 'digits' = "22", 'steps' = "8"
14 'digits' = "23", 'steps' = "0"
15 'digits' = "23", 'steps' = "1"
16 'digits' = "23", 'steps' = "2"
17 'digits' = "23", 'steps' = "3"
18 'digits' = "23", 'steps' = "4"
19 'digits' = "23", 'steps' = "5"
20 'digits' = "23", 'steps' = "6"
21 'digits' = "23", 'steps' = "7"
22 'digits' = "23", 'steps' = "8"
23 'digits' = "23", 'steps' = "9"
24 'digits' = "23", 'steps' = "10"
25 'digits' = "23", 'steps' = "11"
26 'digits' = "24", 'steps' = "0"
27 'digits' = "24", 'steps' = "1"
28 'digits' = "24", 'steps' = "2"
29 'digits' = "24", 'steps' = "3"
30 'digits' = "24", 'steps' = "4"
31 'digits' = "24", 'steps' = "5"
32 'digits' = "24", 'steps' = "6"
33 'digits' = "24", 'steps' = "7"
34 'digits' = "24", 'steps' = "8"
35 'digits' = "24", 'steps' = "9"
36 'digits' = "24", 'steps' = "10"
37 'digits' = "24", 'steps' = "11"
38 'digits' = "24", 'steps' = "12"
39 'digits' = "25", 'steps' = "0"
40 'digits' = "25", 'steps' = "1"
41 'digits' = "25", 'steps' = "2"
42 'digits' = "25", 'steps' = "3"
43 'digits' = "25", 'steps' = "4"
44 'digits' = "25", 'steps' = "5"
45 'digits' = "25", 'steps' = "6"
46 'digits' = "25", 'steps' = "7"
47 'digits' = "25", 'steps' = "8"
48 'digits' = "25", 'steps' = "9"
49 'digits' = "25", 'steps' = "10"
50 'digits' = "25", 'steps' = "11"
51 'digits' = "25", 'steps' = "13"
52 'digits' = "26", 'steps' = "0"
53 'digits' = "26", 'steps' = "1"
54 'digits' = "26", 'steps' = "2"
55 'digits' = "26", 'steps' = "3"
56 'digits' = "26", 'steps' = "4"
57 'digits' = "26", 'steps' = "5"
58 'digits' = "26", 'steps' = "6"
59 'digits' = "26", 'steps' = "7"
60 'digits' = "26", 'steps' = "8"
61 'digits' = "26", 'steps' = "9"
62 'digits' = "26", 'steps' = "10"
63 'digits' = "26", 'steps' = "11"
64 'digits' = "26", 'steps' = "12"
65 'digits' = "27", 'steps' = "0"
66 'digits' = "27", 'steps' = "1"
67 'digits' = "27", 'steps' = "2"
68 'digits' = "27", 'steps' = "3"
69 'digits' = "27", 'steps' = "4"
70 'digits' = "27", 'steps' = "5"
71 'digits' = "27", 'steps' = "6"
72 'digits' = "27", 'steps' = "7"
73 'digits' = "27", 'steps' = "8"
74 'digits' = "27", 'steps' = "9"
75 'digits' = "27", 'steps' = "10"
76 'digits' = "27", 'steps' = "11"
77 'digits' = "28", 'steps' = "0"
78 'digits' = "28", 'steps' = "1"
79 'digits' = "28", 'steps' = "2"
80 'digits' = "28", 'steps' = "3"
81 'digits' = "28", 'steps' = "4"
82 'digits' = "28", 'steps' = "5"
83 'digits' = "28", 'steps' = "6"
84 'digits' = "28", 'steps' = "7"
85 'digits' = "28", 'steps' = "8"
86 'digits' = "28", 'steps' = "9"
87 'digits' = "28", 'steps' = "10"
88 'digits' = "29", 'steps' = "0"
89 'digits' = "29", 'steps' = "1"
90 'digits' = "29", 'steps' = "2"
91 'digits' = "29", 'steps' = "3"
92 'digits' = "29", 'steps' = "4"
93 'digits' = "29", 'steps' = "5"
94 'digits' = "29", 'steps' = "6"
95 'digits' = "29", 'steps' = "7"
96 'digits' = "29", 'steps' = "8"
97 'digits' = "29", 'steps' = "9"
98 'digits' = "29", 'steps' = "10"
99 'digits' = "30", 'steps' = "0"
100 'digits' = "30", 'steps' = "1"
101 'digits' = "30", 'steps' = "2"
102 'digits' = "30", 'steps' = "3"
103 'digits' = "30", 'steps' = "4"
104 'digits' = "30", 'steps' = "5"
105 'digits' = "30", 'steps' = "6"
106 'digits' = "30", 'steps' = "7"
107 'digits' = "30", 'steps' = "8"
108 'digits' = "30", 'steps' = "9"
109 'digits' = "30", 'steps' = "10"
110 'digits' = "31", 'steps' = "0"
111 'digits' = "31", 'steps' = "1"
112 'digits' = "31", 'steps' = "2"
113 'digits' = "31", 'steps' = "3"
114 'digits' = "31", 'steps' = "4"
115 'digits' = "31", 'steps' = "5"
116 'digits' = "31", 'steps' = "6"
117 'digits' = "31", 'steps' = "7"
118 'digits' = "31", 'steps' = "8"
119 'digits' = "32", 'steps' = "0"
120 'digits' = "32", 'steps' = "1"
121 'digits' = "32", 'steps' = "2"
122 'digits' = "32", 'steps' = "3"
123 'digits' = "32", 'steps' = "4"
124 'digits' = "32", 'steps' = "5"
125 'digits' = "32", 'steps' = "6"
126 'digits' = "32", 'steps' = "7"
127 'digits' = "32", 'steps' = "8"
128 'digits' = "33", 'steps' = "0"
129 'digits' = "33", 'steps' = "1"
130 'digits' = "33", 'steps' = "2"
131 'digits' = "33", 'steps' = "3"
132 'digits' = "33", 'steps' = "4"
133 'digits' = "33", 'steps' = "5"
134 'digits' = "33", 'steps' = "6"
135 'digits' = "34", 'steps' = "0"
136 'digits' = "34", 'steps' = "1"
137 'digits' = "34", 'steps' = "2"
138 'digits' = "34", 'steps' = "3"
139 'digits' = "34", 'steps' = "4"
140 'digits' = "34", 'steps' = "5"
141 'digits' = "34", 'steps' = "6"
142 'digits' = "35", 'steps' = "0"
143 'digits' = "35", 'steps' = "1"
144 'digits' = "35", 'steps' = "2"
145 'digits' = "35", 'steps' = "3"
146 'digits' = "35", 'steps' = "4"
147 'digits' = "35", 'steps' = "5"
148 'digits' = "36", 'steps' = "0"
149 'digits' = "36", 'steps' = "1"
150 'digits' = "36", 'steps' = "2"
151 'digits' = "36", 'steps' = "3"
152 'digits' = "36", 'steps' = "4"
153 'digits' = "36", 'steps' = "5"
154 'digits' = "36", 'steps' = "6"
155 'digits' = "37", 'steps' = "0"
156 'digits' = "37", 'steps' = "1"
157 'digits' = "37", 'steps' = "2"
158 'digits' = "37", 'steps' = "3"
159 'digits' = "37", 'steps' = "5"
160 'digits' = "38", 'steps' = "0"
161 'digits' = "38", 'steps' = "1"
162 'digits' = "38", 'steps' = "2"
163 'digits' = "38", 'steps' = "3"
164 'digits' = "38", 'steps' = "4"
165 'digits' = "39", 'steps' = "0"
166 'digits' = "39", 'steps' = "1"
167 'digits' = "39", 'steps' = "2"
168 'digits' = "39", 'steps' = "3"
169 'digits' = "39", 'steps' = "4"
170 'digits' = "40", 'steps' = "0"
171 'digits' = "40", 'steps' = "1"
172 'digits' = "40", 'steps' = "2"
173 'digits' = "40", 'steps' = "3"
174 'digits' = "41", 'steps' = "0"
175 'digits' = "41", 'steps' = "1"
176 'digits' = "41", 'steps' = "2"
177 'digits' = "41", 'steps' = "3"
178 'digits' = "42", 'steps' = "0"
179 'digits' = "42", 'steps' = "1"
180 'digits' = "42", 'steps' = "2"
181 'digits' = "43", 'steps' = "0"
182 'digits' = "43", 'steps' = "1"
183 'digits' = "44", 'steps' = "0"
184 'digits' = "44", 'steps' = "1"
185 'digits' = "44", 'steps' = "2"
186 'digits' = "45", 'steps' = "0"
187 'digits' = "46", 'steps' = "0"
188 'digits' = "46", 'steps' = "1"
189 'digits' = "47", 'steps' = "0"
190 'digits' = "47", 'steps' = "1"
191 'digits' = "48", 'steps' = "0"
192 'digits' = "49", 'steps' = "0"
193 'digits' = "50", 'steps' = "0"
194 'digits' = "51", 'steps' = "0"
195 'digits' = "52", 'steps' = "0"
196 'digits' = "53", 'steps' = "0"
197 'digits' = "54", 'steps' = "0"
198 'digits' = "55", 'steps' = "0"
199 'digits' = "56", 'steps' = "0"
200 'digits' = "57", 'steps' = "0"
skk>exit
$
Sama lista askelittain (steps) vihjeittäin (digits)
$ ./db8
DB8 version 0.04 ©
skk>steps,digits
query:steps,digits
query2:'steps', 'digits'
201 rows.
0 'steps' = "0", 'digits' = "19"
1 'steps' = "0", 'digits' = "20"
2 'steps' = "0", 'digits' = "21"
3 'steps' = "0", 'digits' = "22"
4 'steps' = "0", 'digits' = "23"
5 'steps' = "0", 'digits' = "24"
6 'steps' = "0", 'digits' = "25"
7 'steps' = "0", 'digits' = "26"
8 'steps' = "0", 'digits' = "27"
9 'steps' = "0", 'digits' = "28"
10 'steps' = "0", 'digits' = "29"
11 'steps' = "0", 'digits' = "30"
12 'steps' = "0", 'digits' = "31"
13 'steps' = "0", 'digits' = "32"
14 'steps' = "0", 'digits' = "33"
15 'steps' = "0", 'digits' = "34"
16 'steps' = "0", 'digits' = "35"
17 'steps' = "0", 'digits' = "36"
18 'steps' = "0", 'digits' = "37"
19 'steps' = "0", 'digits' = "38"
20 'steps' = "0", 'digits' = "39"
21 'steps' = "0", 'digits' = "40"
22 'steps' = "0", 'digits' = "41"
23 'steps' = "0", 'digits' = "42"
24 'steps' = "0", 'digits' = "43"
25 'steps' = "0", 'digits' = "44"
26 'steps' = "0", 'digits' = "45"
27 'steps' = "0", 'digits' = "46"
28 'steps' = "0", 'digits' = "47"
29 'steps' = "0", 'digits' = "48"
30 'steps' = "0", 'digits' = "49"
31 'steps' = "0", 'digits' = "50"
32 'steps' = "0", 'digits' = "51"
33 'steps' = "0", 'digits' = "52"
34 'steps' = "0", 'digits' = "53"
35 'steps' = "0", 'digits' = "54"
36 'steps' = "0", 'digits' = "55"
37 'steps' = "0", 'digits' = "56"
38 'steps' = "0", 'digits' = "57"
39 'steps' = "1", 'digits' = "22"
40 'steps' = "1", 'digits' = "23"
41 'steps' = "1", 'digits' = "24"
42 'steps' = "1", 'digits' = "25"
43 'steps' = "1", 'digits' = "26"
44 'steps' = "1", 'digits' = "27"
45 'steps' = "1", 'digits' = "28"
46 'steps' = "1", 'digits' = "29"
47 'steps' = "1", 'digits' = "30"
48 'steps' = "1", 'digits' = "31"
49 'steps' = "1", 'digits' = "32"
50 'steps' = "1", 'digits' = "33"
51 'steps' = "1", 'digits' = "34"
52 'steps' = "1", 'digits' = "35"
53 'steps' = "1", 'digits' = "36"
54 'steps' = "1", 'digits' = "37"
55 'steps' = "1", 'digits' = "38"
56 'steps' = "1", 'digits' = "39"
57 'steps' = "1", 'digits' = "40"
58 'steps' = "1", 'digits' = "41"
59 'steps' = "1", 'digits' = "42"
60 'steps' = "1", 'digits' = "43"
61 'steps' = "1", 'digits' = "44"
62 'steps' = "1", 'digits' = "46"
63 'steps' = "1", 'digits' = "47"
64 'steps' = "2", 'digits' = "21"
65 'steps' = "2", 'digits' = "22"
66 'steps' = "2", 'digits' = "23"
67 'steps' = "2", 'digits' = "24"
68 'steps' = "2", 'digits' = "25"
69 'steps' = "2", 'digits' = "26"
70 'steps' = "2", 'digits' = "27"
71 'steps' = "2", 'digits' = "28"
72 'steps' = "2", 'digits' = "29"
73 'steps' = "2", 'digits' = "30"
74 'steps' = "2", 'digits' = "31"
75 'steps' = "2", 'digits' = "32"
76 'steps' = "2", 'digits' = "33"
77 'steps' = "2", 'digits' = "34"
78 'steps' = "2", 'digits' = "35"
79 'steps' = "2", 'digits' = "36"
80 'steps' = "2", 'digits' = "37"
81 'steps' = "2", 'digits' = "38"
82 'steps' = "2", 'digits' = "39"
83 'steps' = "2", 'digits' = "40"
84 'steps' = "2", 'digits' = "41"
85 'steps' = "2", 'digits' = "42"
86 'steps' = "2", 'digits' = "44"
87 'steps' = "3", 'digits' = "21"
88 'steps' = "3", 'digits' = "22"
89 'steps' = "3", 'digits' = "23"
90 'steps' = "3", 'digits' = "24"
91 'steps' = "3", 'digits' = "25"
92 'steps' = "3", 'digits' = "26"
93 'steps' = "3", 'digits' = "27"
94 'steps' = "3", 'digits' = "28"
95 'steps' = "3", 'digits' = "29"
96 'steps' = "3", 'digits' = "30"
97 'steps' = "3", 'digits' = "31"
98 'steps' = "3", 'digits' = "32"
99 'steps' = "3", 'digits' = "33"
100 'steps' = "3", 'digits' = "34"
101 'steps' = "3", 'digits' = "35"
102 'steps' = "3", 'digits' = "36"
103 'steps' = "3", 'digits' = "37"
104 'steps' = "3", 'digits' = "38"
105 'steps' = "3", 'digits' = "39"
106 'steps' = "3", 'digits' = "40"
107 'steps' = "3", 'digits' = "41"
108 'steps' = "4", 'digits' = "21"
109 'steps' = "4", 'digits' = "22"
110 'steps' = "4", 'digits' = "23"
111 'steps' = "4", 'digits' = "24"
112 'steps' = "4", 'digits' = "25"
113 'steps' = "4", 'digits' = "26"
114 'steps' = "4", 'digits' = "27"
115 'steps' = "4", 'digits' = "28"
116 'steps' = "4", 'digits' = "29"
117 'steps' = "4", 'digits' = "30"
118 'steps' = "4", 'digits' = "31"
119 'steps' = "4", 'digits' = "32"
120 'steps' = "4", 'digits' = "33"
121 'steps' = "4", 'digits' = "34"
122 'steps' = "4", 'digits' = "35"
123 'steps' = "4", 'digits' = "36"
124 'steps' = "4", 'digits' = "38"
125 'steps' = "4", 'digits' = "39"
126 'steps' = "5", 'digits' = "22"
127 'steps' = "5", 'digits' = "23"
128 'steps' = "5", 'digits' = "24"
129 'steps' = "5", 'digits' = "25"
130 'steps' = "5", 'digits' = "26"
131 'steps' = "5", 'digits' = "27"
132 'steps' = "5", 'digits' = "28"
133 'steps' = "5", 'digits' = "29"
134 'steps' = "5", 'digits' = "30"
135 'steps' = "5", 'digits' = "31"
136 'steps' = "5", 'digits' = "32"
137 'steps' = "5", 'digits' = "33"
138 'steps' = "5", 'digits' = "34"
139 'steps' = "5", 'digits' = "35"
140 'steps' = "5", 'digits' = "36"
141 'steps' = "5", 'digits' = "37"
142 'steps' = "6", 'digits' = "22"
143 'steps' = "6", 'digits' = "23"
144 'steps' = "6", 'digits' = "24"
145 'steps' = "6", 'digits' = "25"
146 'steps' = "6", 'digits' = "26"
147 'steps' = "6", 'digits' = "27"
148 'steps' = "6", 'digits' = "28"
149 'steps' = "6", 'digits' = "29"
150 'steps' = "6", 'digits' = "30"
151 'steps' = "6", 'digits' = "31"
152 'steps' = "6", 'digits' = "32"
153 'steps' = "6", 'digits' = "33"
154 'steps' = "6", 'digits' = "34"
155 'steps' = "6", 'digits' = "36"
156 'steps' = "7", 'digits' = "23"
157 'steps' = "7", 'digits' = "24"
158 'steps' = "7", 'digits' = "25"
159 'steps' = "7", 'digits' = "26"
160 'steps' = "7", 'digits' = "27"
161 'steps' = "7", 'digits' = "28"
162 'steps' = "7", 'digits' = "29"
163 'steps' = "7", 'digits' = "30"
164 'steps' = "7", 'digits' = "31"
165 'steps' = "7", 'digits' = "32"
166 'steps' = "8", 'digits' = "22"
167 'steps' = "8", 'digits' = "23"
168 'steps' = "8", 'digits' = "24"
169 'steps' = "8", 'digits' = "25"
170 'steps' = "8", 'digits' = "26"
171 'steps' = "8", 'digits' = "27"
172 'steps' = "8", 'digits' = "28"
173 'steps' = "8", 'digits' = "29"
174 'steps' = "8", 'digits' = "30"
175 'steps' = "8", 'digits' = "31"
176 'steps' = "8", 'digits' = "32"
177 'steps' = "9", 'digits' = "23"
178 'steps' = "9", 'digits' = "24"
179 'steps' = "9", 'digits' = "25"
180 'steps' = "9", 'digits' = "26"
181 'steps' = "9", 'digits' = "27"
182 'steps' = "9", 'digits' = "28"
183 'steps' = "9", 'digits' = "29"
184 'steps' = "9", 'digits' = "30"
185 'steps' = "10", 'digits' = "23"
186 'steps' = "10", 'digits' = "24"
187 'steps' = "10", 'digits' = "25"
188 'steps' = "10", 'digits' = "26"
189 'steps' = "10", 'digits' = "27"
190 'steps' = "10", 'digits' = "28"
191 'steps' = "10", 'digits' = "29"
192 'steps' = "10", 'digits' = "30"
193 'steps' = "11", 'digits' = "23"
194 'steps' = "11", 'digits' = "24"
195 'steps' = "11", 'digits' = "25"
196 'steps' = "11", 'digits' = "26"
197 'steps' = "11", 'digits' = "27"
198 'steps' = "12", 'digits' = "24"
199 'steps' = "12", 'digits' = "26"
200 'steps' = "13", 'digits' = "25"
skk>exit
$
Seuraavassa desimaaliviisas merkkijonojen vertailu db8:in:
static long db8_atol_dec(unsigned char **p, int *decimals) // JariK 2025
{
int count = 0, decimals2 = 0;
long num = 0;
while(**p == '0')
(*p)++;
while(isdigit(**p) && count < 18) { // calculate 19 first digits
num = num * 10 + (**p - '0');
//more_printf(stdout,"%ld\n", num);
(*p)++;
count++;
}
if(**p == '.') {
(*p)++;
while(isdigit(**p) && count < 18) { // calculate 19 first digits
num = num * 10 + (**p - '0');
//more_printf(stdout,"%ld\n", num);
(*p)++;
count++;
decimals2++;
}
}
if(decimals != NULL)
*decimals = decimals2;
while(isdigit(**p)) { // skip rest
(*p)++;
}
return(num);
}
static long db8_strcmp_numdec(unsigned char *p, unsigned char *q) // JariK 2025
{
int dec1, dec2;
long num1, num2;
for(;;) {
//more_printf(stdout,"p:%s, q:%s\n", p, q);
if(isdigit(*p) && isdigit(*q)) {
num1 = db8_atol_dec(&p, &dec1);
num2 = db8_atol_dec(&q, &dec2);
if(dec2 > dec1)
num1 *= (int) pow((double) 10, (double) dec2-dec1);
else if(dec1 > dec2)
num2 *= (int) pow((double) 10, (double) dec1-dec2);
if(num1 - num2 != 0)
return(num1 - num2);
} else if(*p - *q != 0) {
return(*p - *q);
} else {
if(*p == '\0' || *q == '\0')
break;
p++;
q++;
}
}
return(0);
}
Ja uusi koodi merkkijonojen vertailuun. Tämä tekee simppeliä merkkijonojen matsäilyä huomaten ‘*’ ja ‘?’ merkkijonot. Tähti korvaa yhden tai useamman merkin ja kysymysmerkki korvaa yhden merkin: Koodi on vielä vaiheessa, db8:n käyttökoodi puuttuu vielä.
#define aDEBUG92 2
#define DEBUG96 2
int my_match(unsigned char *pattern, unsigned char *string)
{
unsigned char *p, *s;
p = pattern;
s = string;
#ifdef DEBUG92
more_printf(stdout,"\npattern=%s",p);
more_printf(stdout,", string=%s",s);
#endif
while(*p != '\0') {
if(*p == '*') { // one or many characters
if(*s == '\0')
return(0);
while(*s != '\0') {
if(my_match(p + 1, ++s))
return(1);
}
} else if(*p == '?') { // one character
if(*s == '\0')
return(0);
s++;
} else if(*p == *s) {
s++;
} else
return(0);
p++;
}
if(*s == '\0')
return(1);
else
return(0);
}
int my_match_test(unsigned char *pattern, unsigned char *string)
{
int retval;
static unsigned int testid = 0;
more_printf(stdout,"%d", testid++);
more_printf(stdout," pattern=%s", pattern);
more_printf(stdout,", string=%s", string);
retval = my_match(pattern, string);
if(retval)
more_printf(stdout," match!");
else
more_printf(stdout," no match!");
more_printf(stdout,"\n");
return(retval);
}
int main(int argc, char *argv[])
{
...
#ifdef DEBUG96
if(more)
more_init(); // adjust thee screensize
my_match_test("abcdef","abcdef");
my_match_test("abc*def","abcdefdef");
my_match_test("abc*def","abcdefdefdef");
my_match_test("abc*","abcdef");
my_match_test("*def","abcdef");
my_match_test("*cd*","abcdef");
my_match_test("ab??ef","abcdef");
my_match_test("??def","abcdef");
my_match_test("???def","abcdef");
my_match_test("*gh*","abcdef");
my_match_test("abcdef","abcgef");
my_match_test("?*def","abcdef");
my_match_test("?*def","abcdefg");
my_match_test("?b","ab");
my_match_test("a?","ab");
my_match_test("a?c","abc");
my_match_test("a??d","abcd");
my_match_test("a??*d","abcd");
my_match_test("?b","ac");
#endif
...
}
Seuraavassa db8:n alun merkkijonojen vertailu testituloste:
$ ./db8
0 pattern=abcdef, string=abcdef match!
1 pattern=abc*def, string=abcdefdef match!
2 pattern=abc*def, string=abcdefdefdef match!
3 pattern=abc*, string=abcdef match!
4 pattern=*def, string=abcdef match!
5 pattern=*cd*, string=abcdef match!
6 pattern=ab??ef, string=abcdef match!
7 pattern=??def, string=abcdef no match!
8 pattern=???def, string=abcdef match!
9 pattern=*gh*, string=abcdef no match!
10 pattern=abcdef, string=abcgef no match!
11 pattern=?*def, string=abcdef match!
12 pattern=?*def, string=abcdefg no match!
13 pattern=?b, string=ab match!
14 pattern=a?, string=ab match!
15 pattern=a?c, string=abc match!
16 pattern=a??d, string=abcd match!
17 pattern=a??*d, string=abcd no match!
18 pattern=?b, string=ac no match!
DB8 version 0.04 ©
skk>exit
Db8 tarvitsee merkkijonojen mätsäilystä version jossa merkkijonojen pituus toimitetaan erillisissä kentissä:
int my_match_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
while(plen > 0) {
#ifdef DEBUG92
more_printf(stdout,"\nplen=%d", plen);
more_printf(stdout,", p=");
db8_fputs_len(stdout, plen, p);
more_printf(stdout,", slen=%d", slen);
more_printf(stdout,", s=");
db8_fputs_len(stdout, slen, s);
#endif
if(*p == '*') { // one or many characters
if(slen == 0)
return(0);
while(slen > 0) {
s++;
slen--;
if(my_match_len(plen - 1, p + 1, slen, s))
return(1);
}
} else if(*p == '?') { // one character
if(slen == 0)
return(0);
s++;
slen--;
} else if(*p == *s) {
s++;
slen--;
} else
return(0);
p++;
plen--;
}
if(slen == 0)
return(1);
else
return(0);
}
void db8_fputs_len(FILE *fp1, unsigned int slen, unsigned char *s)
{
while(slen-- > 0)
fputc(*s++, fp1);
}
Edellinen nimettynä db8:a varten:
int db8_match_pattern_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
while(plen > 0) {
#ifdef DEBUG92
more_printf(stdout,"\nplen=%d", plen);
more_printf(stdout,", p=");
db8_fputs_len(stdout, plen, p);
more_printf(stdout,", slen=%d", slen);
more_printf(stdout,", s=");
db8_fputs_len(stdout, slen, s);
#endif
if(*p == '*') { // one or many characters
if(slen == 0)
return(0);
while(slen > 0) {
s++;
slen--;
if(db8_match_pattern_len(plen - 1, p + 1, slen, s))
return(1);
}
} else if(*p == '?') { // one character
if(slen == 0)
return(0);
s++;
slen--;
} else if(*p == *s) {
s++;
slen--;
} else
return(0);
p++;
plen--;
}
if(slen == 0)
return(1);
else
return(0);
}
Ja uuden merkkijonomätsäilyn käytöt:
static int db8_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 DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8_match: match:%s", match);
fprintf(stdout,", set:%s", set);
fflush(stdout);
}
#endif
#ifdef DEBUG48
fprintf(stdout,"db8_match: match:%s", match);
fprintf(stdout,", set:%s", set);
fflush(stdout);
#endif
m = match;
first2 = 1;
ok = 1;
while(*m != '\0') {
db8_skipwhite(&m);
if(!first2) {
if(*m == ',')
m++;
db8_skipwhite(&m);
}
first2 = 0;
db8_get_element2(&namelen, &name, &valuelen, &value, &m); // match
db8_skipwhite(&m);
s = set;
first1 = 1;
ok2 = 0;
while(*s != '\0') {
db8_skipwhite(&s);
if(!first1) {
if(*s == ',')
s++;
db8_skipwhite(&s);
}
first1 = 0;
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s); // set
db8_skipwhite(&s);
#ifdef OLD1
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value2, value, valuelen))) ) {
ok2 = 1;
break;
}
#endif
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
ok2 = 1;
break;
}
}
if(ok2 == 0)
ok = 0;
}
#ifdef DEBUG48
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
#ifdef DEBUG5
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
return(ok);
}
#define aDEBUG52 2
static void db8_project(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;
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout,", query:%s", query);
more_printf(stdout,", set:%s\n", set);
fflush(stdout); fflush(stdout);
#endif
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout," set:%s\n", set);
#endif
if(*project != NULL)
*(project[0]) = '\0';
q = query;
while(*q != '\0') {
db8_skipwhite(&q);
db8_get_element2(&namelen, &name, &valuelen, &value, &q);
db8_skipwhite(&q);
if(*q == ',') {
q++;
db8_skipwhite(&q);
}
s = set;
while(*s != '\0') {
db8_skipwhite(&s);
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s);
db8_skipwhite(&s);
if(*s == ',') {
s++;
db8_skipwhite(&s);
}
#ifdef OLD1
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
#endif
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout,"'%.*s'", namelen, name);
more_printf(stdout," = \"%.*s\"", valuelen2, value2);
more_printf(stdout,"\n");
#endif
db8_put(project, namelen, name, valuelen2, value2);
}
} // while(*s != '\0'
} // while(*q != '\0'
#ifdef DEBUG5
more_printf(stdout,", project:(%s)", *project);
more_printf(stdout,"\n");
fflush(stdout);
#endif
}'
Kokeillaan edellistä mätsäillyä:
DB8 version 0.05 ©
skk>steps="1?"
query:steps="1?"
db8_squery(): name:steps(5), value:1?(2)
query2:'steps' = "1?"
4 rows.
0 'steps' = "10"
1 'steps' = "11"
2 'steps' = "12"
3 'steps' = "13"
skk>digits="*5"
query:digits="*5"
db8_squery(): name:digits(6), value:*5(2)
query2:'digits' = "*5"
4 rows.
0 'digits' = "25"
1 'digits' = "35"
2 'digits' = "45"
3 'digits' = "55"
skk>exit
Db8 source db8.h
struct queryheader {
unsigned char *queryname;
int flags;
unsigned char *query;
unsigned char *match;
int count;
int preread;
unsigned char *cline;
struct queryheader *next;
struct queryline *first;
};
struct queryline {
unsigned int rownum;
unsigned char *line;
unsigned int save;
struct queryline *next;
};
#define DB8_DISTINCT 1
#define DB8_ROWSORT 2
int db8_set_filename(unsigned char *filename);
int db8_set_query(unsigned char *queryname, unsigned char *query);
int db8_set_match(unsigned char *queryname, unsigned char *match);
int db8_get_queryflags(unsigned char *queryname);
int db8_set_queryflags(unsigned char *queryname, int flags);
void db8_put(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value); // 2023 JariK
int db8_get_element(unsigned char *queryname, int row, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
int db8_get_element_current(unsigned char *queryname, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
int db8_get_element_num(unsigned char *queryname, int row, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
void db8_dump(unsigned char *queryname);
int db8_put_element(unsigned char *queryname, int row, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value);
int db8_save(unsigned char *queryname);
int db8_save_all();
int db8_clear(unsigned char *queryname);
int db8_clear_all();
void db8_squery(unsigned char *query); // JariK 2025 single
void db8_iquery(); // JariK 2025 interactive
extern int db8_verbose;
Db8 source db8.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "db8.h"
#include "more.h"
extern unsigned char *procname;
static unsigned char *programname = "DB8 version 0.05 ©";
static unsigned char *copyright = "Copyright (c) 1998-2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
//#define MAIN 2 // in Makefile
//#define QUERY 2 // in Makefile
int db8_verbose = 0;
unsigned char *db8_set = NULL;
static void db8_skipwhite(unsigned char **p)
{
while(isblank(**p))
(*p)++;
}
#define aDEBUG8 2
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2
void db8_get_element2(int *namelen, unsigned char **name, int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db8_skipwhite(&p);
*namelen = -1;
if(*p == '\'') { // name
p++;
*namelen = 0;
*name = p;
while(*p != '\'' && *p != '\0') {
p++;
(*namelen)++;
}
if(*p == '\'')
p++;
} else
*name = NULL;
db8_skipwhite(&p);
if(*p == '=') {
p++;
}
db8_skipwhite(&p);
*valuelen = -1;
if(*p == '\"') { // value
p++;
*valuelen = 0;
*value = p;
while(*p != '\"' && *p != '\0') {
p++;
(*valuelen)++;
}
if(*p == '\"')
p++;
} else
*value = NULL;
db8_skipwhite(&p);
#ifdef DEBUG8
if(db8_verbose) {
fprintf(stderr,"db8_get_element2():");
fprintf(stderr," name:%.*s(%d)", *namelen, *name, *namelen);
fprintf(stderr,", value:%.*s(%d)", *valuelen, *value, *valuelen);
fprintf(stderr,", next:%s",p);
fprintf(stderr,"\n");
fflush(stderr);
}
#endif
*p2 = p;
}
#define aDEBUG5 2
int db8_get(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 2023 JariK
{
int firstelement, retval = 0;
unsigned char *p;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
if(*set == NULL)
return(0);
if(namelen == 0)
namelen = strlen(name);
value[0] = '\0';
if(*set != NULL) {
firstelement = 1;
p = *set;
// read thru elements element by element
while(*p != '\0') {
db8_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db8_skipwhite(&p);
}
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);
db8_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(set != NULL)
return(retval);
}
int db8_get_num(unsigned char **set, unsigned int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 2023 JariK
{
int firstelement, col2, retval = 0;
unsigned char *p;
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
value[0] = '\0';
if(*set != NULL) {
firstelement = 1;
p = *set;
col2 = 0;
// read thru elements element by element
while(*p != '\0') {
db8_skipwhite(&p);
if(!firstelement) {
if(*p == ',')
p++;
db8_skipwhite(&p);
}
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);
db8_skipwhite(&p);
// we reached equal name
if(col2 == col && name != NULL && value != NULL) {
strncpy(name, name2, namesize);
if(namesize >= namelen2)
name[namelen2] = '\0';
else
name[namesize - 1] = '\0';
strncpy(value, value2, valuesize);
if(valuesize >= valuelen2)
value[valuelen2] = '\0';
else
value[valuesize - 1] = '\0';
retval = 1;
break;
}
col2++;
firstelement = 0;
} // end of while(*p != '\0')
} // end of if(set != NULL)
return(retval);
}
#define aSORTED 2
#define aDEBUG17 2
void db8_put(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value) // 2023 JariK
{
int found = 0, firstelement, lastelement;
unsigned char *p, *currentelement = NULL;
unsigned char *thiselement = NULL, *nextelement = NULL;
if(namelen == 0)
namelen = strlen(name);
if(valuelen == 0)
valuelen = strlen(value);
#ifdef DEBUG5
fprintf(stdout,"\ndb8_put: oldset:%s", *set);
if(*set != NULL)
fprintf(stdout,"(%ld)", strlen(*set));
fprintf(stdout,", namelen:%d", namelen);
fprintf(stdout,", name:%.*s", namelen, name);
fprintf(stdout,", valuelen:%d", valuelen);
fprintf(stdout,", value:%.*s", valuelen, value);
fflush(stdout);
#endif
unsigned int namelen2, valuelen2;
unsigned char *name2, *value2;
firstelement = 1;
lastelement = 0;
if(*set != NULL && strlen(*set) == 0) {
lastelement = 1;
firstelement = 1;
} else if(*set == NULL) {
lastelement = 1;
firstelement = 1;
} else if(*set != NULL) {
p = *set;
// read thru elements element by element
while(*p != '\0') {
db8_skipwhite(&p);
currentelement = p; // save beginning of element
if(!firstelement) {
if(*p == ',')
p++;
db8_skipwhite(&p);
} else {
if(*p == '\0') {
lastelement = 1;
break;
}
}
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);
db8_skipwhite(&p);
// 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')
} // end of if(set != NULL)
// make new element
long count;
static long elementsize = 0;
static unsigned char *element = NULL;
unsigned char *elementfmt;
// figure out needed commas
if(value != NULL) {
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)
count = snprintf(element, elementsize, elementfmt, namelen, name, valuelen, 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, namelen, name, valuelen, value) + 1;
}
} else { // else of if(value != NULL
if((firstelement && found) || // first and existing
(firstelement && lastelement) ) // first element in a new set (first and last)
elementfmt = "'%.*s'"; // --> no commas (first existing or only)
else if(firstelement) // first and not existing element
elementfmt = "'%.*s', "; // --> comma in the end (first new)
else
elementfmt = ", '%.*s'"; // ..> comma in the beginning (other)
count = snprintf(element, elementsize, elementfmt, namelen, name) + 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, namelen, name) + 1;
} // end of if(elementsize < count
} // end of if(value != NULL
// calculate change in length
long oldcount = 0;
count = 0;
if(*set != NULL) {
count += strlen(*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(stderr, "old length:%ld %s\n", oldcount, set);
fflush(stderr);
}
#endif
if(oldcount != count) { // size changed,
// reallocate set according to new length
unsigned char *tempset = *set;
if((*set = realloc(*set, count)) == NULL) {
fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
exit(1);
}
// adjust these too
if(thiselement != NULL)
thiselement = *set + (thiselement - tempset);
if(nextelement != NULL)
nextelement = *set + (nextelement - tempset);
if(tempset == NULL)
*set[0] = '\0';
}
// adjust to end of set if not present
if(thiselement == NULL)
thiselement = *set + strlen(*set);
if(nextelement == NULL)
nextelement = *set + strlen(*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(stderr,"new length:%ld %s\n", count, *set);
fflush(stderr);
}
#endif
#ifdef DEBUG5
fprintf(stdout,", newset:%s\n", *set);
fflush(stdout);
#endif
}
unsigned char db8_filename[128];
int db8_set_filename(unsigned char *filename)
{
FILE *fp1;
#ifdef DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8: set_filename");
fprintf(stdout,", filename=%s", filename);
fprintf(stdout,"\n");
}
#endif
if((fp1 = fopen(filename, "r"))==NULL) {
fprintf(stderr,"%s: db8 cannot open file '%s'\n", procname, filename);
exit(1);
}
fclose(fp1);
strcpy(db8_filename, filename);
return(0);
}
struct queryheader *firstqueryheader = NULL;
struct queryheader *db8_queryheader(unsigned char *queryname)
{
struct queryheader **ppqh, *thisqh;
ppqh = &firstqueryheader;
while(*ppqh != NULL) {
if(!strcmp(queryname, (*ppqh)->queryname))
break;
ppqh = &((*ppqh)->next);
}
if(*ppqh == NULL) { // create new
thisqh = malloc(sizeof(struct queryheader));
thisqh->queryname = malloc(strlen(queryname) + 1);
strcpy(thisqh->queryname, queryname);
thisqh->flags = 0;
thisqh->query = NULL;
thisqh->match = NULL;
thisqh->count = 0;
thisqh->preread = 20;
thisqh->cline = NULL;
thisqh->next = firstqueryheader;
thisqh->first = NULL;
firstqueryheader = thisqh;
} else { // allready in list
// remove from list
thisqh = *ppqh;
*ppqh = thisqh->next;
// add back to 1st of list
thisqh->next = firstqueryheader;
firstqueryheader = thisqh;
}
return(thisqh);
}
int db8_set_query(unsigned char *queryname, unsigned char *query)
{
struct queryheader *qh;
#ifdef DEBUG5
fprintf(stdout,"db8: set_query");
fprintf(stdout,", query:%s", query);
fprintf(stdout,"\n");
#endif
qh = db8_queryheader(queryname);
if(qh->query != NULL)
free(qh->query);
qh->query = malloc(strlen(query) + 1);
strcpy(qh->query, query);
return(0);
}
#define aDEBUG42 2
int db8_set_match(unsigned char *queryname, unsigned char *match)
{
struct queryheader *qh;
#ifdef DEBUG5
fprintf(stdout,"db8: set_match");
fprintf(stdout,", match:%s", match);
fprintf(stdout,"\n");
#endif
#ifdef DEBUG42
fprintf(stdout,"db8: set_match");
fprintf(stdout,", match:%s", match);
fprintf(stdout,"\n");
#endif
qh = db8_queryheader(queryname);
if(qh->match != NULL)
free(qh->match);
qh->match = malloc(strlen(match) + 1);
strcpy(qh->match, match);
return(0);
}
int db8_get_queryflags(unsigned char *queryname)
{
struct queryheader *qh;
qh = db8_queryheader(queryname);
#ifdef DEBUG5
fprintf(stdout,"db8: get_queryflags");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", flags=%d", qh->flags);
fprintf(stdout,"\n");
#endif
return(qh->flags);
}
int db8_set_queryflags(unsigned char *queryname, int flags)
{
struct queryheader *qh;
#ifdef DEBUG5
fprintf(stdout,"db8: set_queryflags");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", flags=%d", flags);
fprintf(stdout,"\n");
#endif
qh = db8_queryheader(queryname);
qh->flags = flags;
return(0);
}
static struct queryline *db8_lineheader(unsigned char *queryname, int rownum)
{
int add;
struct queryheader *qh;
struct queryline **ppql;
add = 1;
qh = db8_queryheader(queryname);
ppql = &qh->first;
while(*ppql != NULL) {
if(rownum == (*ppql)->rownum) { // matching row found
add = 0; // no need to add new
break;
} else if(rownum < (*ppql)->rownum) { // first larger row
add = 1; // add new before
break;
}
ppql = &((*ppql)->next);
}
if(add) {
struct queryline *thisql;
thisql = malloc(sizeof(struct queryline));
thisql->line = NULL;
thisql->rownum = rownum;
thisql->save = 0;
thisql->next = *ppql;
*ppql = thisql;
}
return(*ppql);
}
#define aDEBUG26 2
#define aDEBUG92 2
void db8_fputs_len(FILE *fp1, unsigned int slen, unsigned char *s)
{
while(slen-- > 0)
fputc(*s++, fp1);
}
int db8_match_pattern_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
while(plen > 0) {
#ifdef DEBUG92
more_printf(stdout,"\nplen=%d", plen);
more_printf(stdout,", p=");
db8_fputs_len(stdout, plen, p);
more_printf(stdout,", slen=%d", slen);
more_printf(stdout,", s=");
db8_fputs_len(stdout, slen, s);
#endif
if(*p == '*') { // one or many characters
if(slen == 0)
return(0);
while(slen > 0) {
s++;
slen--;
if(db8_match_pattern_len(plen - 1, p + 1, slen, s))
return(1);
}
} else if(*p == '?') { // one character
if(slen == 0)
return(0);
s++;
slen--;
} else if(*p == *s) {
s++;
slen--;
} else
return(0);
p++;
plen--;
}
if(slen == 0)
return(1);
else
return(0);
}
#define aDEBUG48 2
static int db8_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 DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8_match: match:%s", match);
fprintf(stdout,", set:%s", set);
fflush(stdout);
}
#endif
#ifdef DEBUG48
fprintf(stdout,"db8_match: match:%s", match);
fprintf(stdout,", set:%s", set);
fflush(stdout);
#endif
m = match;
first2 = 1;
ok = 1;
while(*m != '\0') {
db8_skipwhite(&m);
if(!first2) {
if(*m == ',')
m++;
db8_skipwhite(&m);
}
first2 = 0;
db8_get_element2(&namelen, &name, &valuelen, &value, &m); // match
db8_skipwhite(&m);
s = set;
first1 = 1;
ok2 = 0;
while(*s != '\0') {
db8_skipwhite(&s);
if(!first1) {
if(*s == ',')
s++;
db8_skipwhite(&s);
}
first1 = 0;
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s); // set
db8_skipwhite(&s);
#ifdef OLD1
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value2, value, valuelen))) ) {
ok2 = 1;
break;
}
#endif
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
ok2 = 1;
break;
}
}
if(ok2 == 0)
ok = 0;
}
#ifdef DEBUG48
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
#ifdef DEBUG5
fprintf(stdout,", ok:%d", ok);
fprintf(stdout,"\n");
fflush(stdout);
#endif
return(ok);
}
static void db8_free_set(unsigned char **set)
{
if(*set != NULL) {
free(*set);
*set = NULL;
}
}
#define aDEBUG52 2
static void db8_project(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;
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout,", query:%s", query);
more_printf(stdout,", set:%s\n", set);
fflush(stdout); fflush(stdout);
#endif
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout," set:%s\n", set);
#endif
if(*project != NULL)
*(project[0]) = '\0';
q = query;
while(*q != '\0') {
db8_skipwhite(&q);
db8_get_element2(&namelen, &name, &valuelen, &value, &q);
db8_skipwhite(&q);
if(*q == ',') {
q++;
db8_skipwhite(&q);
}
s = set;
while(*s != '\0') {
db8_skipwhite(&s);
db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s);
db8_skipwhite(&s);
if(*s == ',') {
s++;
db8_skipwhite(&s);
}
#ifdef OLD1
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
#endif
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
#ifdef DEBUG52
more_printf(stdout,"db8_project: ");
more_printf(stdout,"'%.*s'", namelen, name);
more_printf(stdout," = \"%.*s\"", valuelen2, value2);
more_printf(stdout,"\n");
#endif
db8_put(project, namelen, name, valuelen2, value2);
}
} // while(*s != '\0'
} // while(*q != '\0'
#ifdef DEBUG5
more_printf(stdout,", project:(%s)", *project);
more_printf(stdout,"\n");
fflush(stdout);
#endif
}
#define aDEBUG63 2
#define aDEBUG54 2
static unsigned char *db8_fgets(int *stringlen, unsigned char **string, FILE *fp1)
{
int count, retval, done;
unsigned char buffer[128];
unsigned char *buf = *string;
if(buf != NULL)
buf[0] = '\0';
retval = 1;
done = 0;
for(;;) {
if(fgets(buffer, sizeof(buffer), fp1) == NULL) {
retval = 0;
break;
}
if(buffer[strlen(buffer)-1] == '\n') {
buffer[strlen(buffer)-1] = '\0';
done = 1;
}
#ifdef DEBUG54
fprintf(stdout,"db8_fgets: buffer: %s\n", buffer);
#endif
count = 0;
if(buf != NULL)
count += strlen(buf);
count += strlen(buffer) + 1;
if(*stringlen < count) {
unsigned char *prevbuf = buf;
*stringlen = count;
buf = realloc(buf, *stringlen);
if(prevbuf == NULL)
buf[0] = '\0';
}
strcat(buf, buffer);
if(done)
break;
}
*string = buf;
#ifdef DEBUG54
fprintf(stdout,"db8_fgets: string: %s\n", *string);
#endif
#ifdef DEBUG63
fprintf(stdout,"%s\n", *string);
#endif
if(retval == 0)
return(NULL);
else {
return(*string);
}
}
#define aDEBUG62 2
static void db8_renumbersets(unsigned char *queryname) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql;
int rownum;
qh = db8_queryheader(queryname);
ql = qh->first;
rownum = 0;
while(ql != NULL) {
ql->rownum = rownum;
#ifdef DEBUG62
more_printf(stdout,"db8_renumbersets:");
more_printf(stdout," %d:", rownum);
more_printf(stdout," %s", ql->line);
more_printf(stdout,"\n");
#endif
rownum++;
ql = ql->next;
}
}
static void db8_countsets(unsigned char *queryname) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql;
int rows;
qh = db8_queryheader(queryname);
ql = qh->first;
rows = 0;
while(ql != NULL) {
#ifdef DEBUG62
more_printf(stdout,"db8_countsets:");
more_printf(stdout," %d:", rows);
more_printf(stdout," %s", ql->line);
more_printf(stdout,"\n");
#endif
rows++;
ql = ql->next;
}
qh->count = rows;
if(qh->flags)
more_printf(stdout,"%d rows.\n", rows);
}
#ifdef OLD
static long db8_atol(unsigned char **p, int *length) // JariK 2025
{
int count = 0;
long num = 0;
while(isdigit(**p) && count < 18) { // calculate 19 first digits
num = num * 10 + (**p - '0');
//more_printf(stdout,"%ld\n", num);
(*p)++;
count++;
}
if(length != NULL)
*length = count;
while(isdigit(**p)) { // skip rest
(*p)++;
}
return(num);
}
#endif
static long db8_atol_dec(unsigned char **p, int *decimals) // JariK 2025
{
int count = 0, decimals2 = 0;
long num = 0;
while(**p == '0')
(*p)++;
while(isdigit(**p) && count < 18) { // calculate 19 first digits
num = num * 10 + (**p - '0');
//more_printf(stdout,"%ld\n", num);
(*p)++;
count++;
}
if(**p == '.') {
(*p)++;
while(isdigit(**p) && count < 18) { // calculate 19 first digits
num = num * 10 + (**p - '0');
//more_printf(stdout,"%ld\n", num);
(*p)++;
count++;
decimals2++;
}
}
if(decimals != NULL)
*decimals = decimals2;
while(isdigit(**p)) { // skip rest
(*p)++;
}
return(num);
}
#ifdef OLD
static long db8_strcmp_num(unsigned char *p, unsigned char *q) // JariK 2025
{
long num1, num2;
for(;;) {
//more_printf(stdout,"p:%s, q:%s\n", p, q);
if(isdigit(*p) && isdigit(*q)) {
num1 = db8_atol(&p, NULL);
num2 = db8_atol(&q, NULL);
if(num1 - num2 != 0)
return(num1 - num2);
} else if(*p - *q != 0) {
return(*p - *q);
} else {
if(*p == '\0' || *q == '\0')
break;
p++;
q++;
}
}
return(0);
}
#endif
#include <math.h>
static long db8_strcmp_numdec(unsigned char *p, unsigned char *q) // JariK 2025
{
int dec1, dec2;
long num1, num2;
for(;;) {
//more_printf(stdout,"p:%s, q:%s\n", p, q);
if(isdigit(*p) && isdigit(*q)) {
num1 = db8_atol_dec(&p, &dec1);
num2 = db8_atol_dec(&q, &dec2);
if(dec2 > dec1)
num1 *= (int) pow((double) 10, (double) dec2-dec1);
else if(dec1 > dec2)
num2 *= (int) pow((double) 10, (double) dec1-dec2);
if(num1 - num2 != 0)
return(num1 - num2);
} else if(*p - *q != 0) {
return(*p - *q);
} else {
if(*p == '\0' || *q == '\0')
break;
p++;
q++;
}
}
return(0);
}
static int db8_matchandproject(unsigned char *queryname, unsigned char *row)
{
struct queryheader *qh;
int match;
unsigned char *project = NULL;
qh = db8_queryheader(queryname);
match = 0;
if(qh->match == NULL ||
strstr(row, qh->match) != NULL)
match = 1;
if(match) {
match = 0;
if(qh->query == NULL)
match = 1;
else if(db8_match(row, qh->query)) {
db8_free_set(&project);
db8_project(&project, row, qh->query);
strcpy(row, project);
match = 1;
}
}
return(match);
}
#ifdef OLD1
int db8_get_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
int rownum2, count, match;
struct queryheader *qh;
struct queryline *ql, *qline;
static unsigned char *row = NULL;
static unsigned int rowlen = 0;
static unsigned char *project = NULL;
FILE *fp1;
if(namelen == 0)
namelen = strlen(name);
#ifdef DEBUG5
fprintf(stdout,"db8_get_element");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", row=%d", rownum);
fprintf(stdout,", namelen=%u", namelen);
fprintf(stdout,", name=%s", name);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
#endif
qh = db8_queryheader(queryname);
ql = qh->first;
while(ql != NULL) {
if(rownum == ql->rownum) {
break;
} else if(rownum < ql->rownum) {
ql = NULL;
break;
}
ql = ql->next;
}
qline = ql;
if(ql == NULL) {
if((fp1 = fopen(db8_filename,"r")) == NULL) {
fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
exit(1);
}
rownum2 = 0;
count = 0;
for(;;) {
if(db8_fgets(&rowlen, &row, fp1) == NULL)
break;
#ifdef DEBUG68
fprintf(stdout,">%s\n", row);
#endif
//if(buffer[strlen(buffer) - 1] == '\n')
// buffer[strlen(buffer) - 1] = '\0';
match = 0;
if(qh->match == NULL ||
strstr(row, qh->match) != NULL)
match = 1;
if(match) {
match = 0;
if(qh->query == NULL)
match = 1;
else if(db8_match(row, qh->query)) {
db8_free_set(&project);
db8_project(&project, row, qh->query);
strcpy(row, project);
fprintf(stdout,"\n====row:%s", row);
match = 1;
}
}
if(match) {
if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
ql = db8_lineheader(queryname, rownum2);
if((ql->line = malloc(strlen(row) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, row);
#ifdef DEBUG64
fprintf(stdout,"db8_get_element:");
fprintf(stdout," rownum:%u", rownum2);
fprintf(stdout," row:%s", ql->line);
fprintf(stdout,"\n");
#endif
if(rownum == rownum2)
qline = ql;
count++;
if(qh->preread == 0 || // no preread
count > rownum + qh->preread) // preread enough
break;
}
rownum2++;
}
}
fclose(fp1);
}
if(qline != NULL && qline->line != NULL) {
#ifdef DEBUG69
fprintf(stdout,"db8_get_element:");
fprintf(stdout," rownum:%u", rownum);
fprintf(stdout,", row:%s", qline->line);
#endif
int retval = db8_get(&qline->line, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval); // 2023 JariK
} else
return(0);
}
int db8_get_element_num(unsigned char *queryname, int rownum, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
int rownum2, count, match;
struct queryheader *qh;
struct queryline *ql, *qline;
static unsigned char *row = NULL;
static unsigned int rowlen = 0;
static unsigned char *project = NULL;
FILE *fp1;
if(*namelen == 0)
*namelen = strlen(name);
#ifdef DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8_get_element_num");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", rownum=%d", rownum);
fprintf(stdout,", col=%d", col);
fprintf(stdout,", namesize=%u", namesize);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
}
#endif
qh = db8_queryheader(queryname);
ql = qh->first;
while(ql != NULL) {
if(rownum == ql->rownum) {
break;
} else if(rownum < ql->rownum) {
ql = NULL;
break;
}
ql = ql->next;
}
qline = ql;
if(ql == NULL) {
if((fp1 = fopen(db8_filename,"r")) == NULL) {
fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
exit(1);
}
rownum2 = 0;
count = 0;
for(;;) {
if(db8_fgets(&rowlen, &row, fp1) == NULL)
break;
#ifdef DEBUG68
fprintf(stdout,">%s\n", row);
#endif
match = 0;
if(qh->match == NULL ||
strstr(row, qh->match) != NULL)
match = 1;
if(match) {
match = 0;
if(qh->query == NULL)
match = 1;
else if(db8_match(row, qh->query)) {
db8_project(&project, row, qh->query);
strcpy(row, project);
match = 1;
}
}
//fprintf(stdout,"match:%d\n",match);
if(match) {
if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
ql = db8_lineheader(queryname, rownum2);
if((ql->line = malloc(strlen(row) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, row);
#ifdef DEBUG68
fprintf(stdout,"=%s\n", row);
#endif
#ifdef DEBUG64
fprintf(stdout,"db8_get_element_num:");
fprintf(stdout," rownum:%u", rownum2);
fprintf(stdout," row:%s", ql->line);
fprintf(stdout,"\n");
#endif
if(rownum == rownum2)
qline = ql;
count++;
if(qh->preread == 0 || // no preread
count > rownum + qh->preread) // preread enough
break;
}
rownum2++;
}
}
fclose(fp1);
}
if(qline != NULL && qline->line != NULL) {
#ifdef DEBUG69
fprintf(stdout,"db8_get_element_num:");
fprintf(stdout," rownum:%u", rownum);
fprintf(stdout,", row:%s", qline->line);
#endif
int retval = db8_get_num(&qline->line, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval);
} else
return(0);
}
#endif
#ifdef OLD1
struct queryline *db8_cache_set(unsigned char *queryname, int rownum, unsigned char *set)
{
struct queryline *ql;
#ifdef DEBUG59
fprintf(stdout,"db8_cache_set:");
fprintf(stdout," %d", rownum);
fprintf(stdout," %s", set);
fprintf(stdout,"\n");
#endif
ql = db8_lineheader(queryname, rownum);
if((ql->line = malloc(strlen(set) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, set);
return(ql);
}
struct queryline *db8_cacheset_flags(unsigned char *queryname, int rownum, unsigned char *set) // JariK 2025
{
int add;
struct queryheader *qh;
struct queryline **ppql;
qh = db8_queryheader(queryname);
add = 1;
ppql = &qh->first;
while(*ppql != NULL) {
if((qh->flags & DB8_DISTINCT) &&
!strcmp(set, (*ppql)->line) ) {
add = 0;
break;
}
if((qh->flags & DB8_ROWSORT) &&
db8_strcmp_numdec(set, (*ppql)->line) < 0) {
//strcmp(set, (*ppql)->line) < 0) {
add = 1;
break;
}
ppql = &((*ppql)->next);
}
if(add) {
struct queryline *ql;
ql = malloc(sizeof(struct queryline));
if((ql->line = malloc(strlen(set) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, set);
#ifdef DEBUG61
more_printf(stdout,"db8_cacheset_flags:");
more_printf(stdout," %d:", rownum);
more_printf(stdout," %s", ql->line);
more_printf(stdout,"\n");
#endif
ql->rownum = 0;
ql->next = *ppql;
*ppql = ql;
}
return(NULL);
}
struct queryline *db8_get_line(unsigned char *queryname, int rownum) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql, *qline;
static unsigned char *row = NULL;
static unsigned int rowlen = 0;
int rownum2, count;
FILE *fp1;
qh = db8_queryheader(queryname);
ql = qh->first;
while(ql != NULL) {
if(rownum == ql->rownum) {
break;
} else if(rownum < ql->rownum) {
ql = NULL;
break;
}
ql = ql->next;
}
if(ql == NULL && qh->flags && qh->count != 0)
return(NULL);
qline = ql;
if(ql == NULL) {
if((fp1 = fopen(db8_filename,"r")) == NULL) {
fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
exit(1);
}
rownum2 = 0;
count = 0;
for(;;) {
if(db8_fgets(&rowlen, &row, fp1) == NULL)
break;
if(db8_matchandproject(queryname, row)) {
if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
if(qh->flags) {
ql = db8_cacheset_flags(queryname, rownum2, row);
} else {
ql = db8_cache_set(queryname, rownum2, row);
}
#ifdef DEBUG65
more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
if(qh->flags) // sorting --> read all
continue;
if(rownum == rownum2)
qline = ql;
count++;
if(qh->preread == 0 ||
count > rownum + qh->preread)
break;
}
rownum2++;
}
}
fclose(fp1);
if(qh->flags) {
db8_renumbersets(queryname);
db8_countsets(queryname);
qline = qh->first;
}
}
return(qline);
}
#endif // end of #ifdef OLD1
struct queryline *db8_getline_cache(unsigned char *queryname, int rownum) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql;
qh = db8_queryheader(queryname);
ql = qh->first;
while(ql != NULL) {
if(rownum == ql->rownum) {
break;
} else if(rownum < ql->rownum) {
ql = NULL;
break;
}
ql = ql->next;
}
return(ql);
}
#define aDEBUG61 2
#define aDEBUG57 2
#define aDEBUG58 2
#define aDEBUG65 2
#define aDEBUG59 2
struct queryline *db8_getline(unsigned char *queryname, int rownum) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql, *qline;
static unsigned char *row = NULL;
static unsigned int rowlen = 0;
int rownum2, count;
FILE *fp1;
qh = db8_queryheader(queryname);
ql = db8_getline_cache(queryname, rownum);
qline = ql;
if(ql == NULL) {
if((fp1 = fopen(db8_filename,"r")) == NULL) {
fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
exit(1);
}
rownum2 = 0;
count = 0;
for(;;) {
if(db8_fgets(&rowlen, &row, fp1) == NULL)
break;
#ifdef DEBUG58
more_printf(stdout,"input: ");
more_printf(stdout,"%s", row);
more_printf(stdout,"\n");
#endif
if(db8_matchandproject(queryname, row)) {
if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
ql = db8_lineheader(queryname, rownum);
if((ql->line = malloc(strlen(row) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, row);
#ifdef DEBUG57
more_printf(stdout,"selected: ");
more_printf(stdout,"%s", row);
more_printf(stdout,"\n");
#endif
#ifdef DEBUG65
more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
if(rownum == rownum2)
qline = ql;
count++;
if(qh->preread == 0 ||
count > rownum + qh->preread)
break;
} // end of if(rownum2
rownum2++;
} // end of if(db8_matchandproject
} // end of for(;;
fclose(fp1);
db8_countsets(queryname);
} // end of if(ql == NULL
qh->cline = qline->line;
return(qline);
}
struct queryline *db8_getline_flags(unsigned char *queryname, int rownum) // JariK 2025
{
struct queryheader *qh;
struct queryline *ql, *qline, **ppql;
static unsigned char *row = NULL;
static unsigned int rowlen = 0;
int rownum2;
FILE *fp1;
qh = db8_queryheader(queryname);
ql = db8_getline_cache(queryname, rownum);
if(ql == NULL && qh->count != 0) { // flags --> read only once
qh->cline = NULL;
return(NULL);
}
qline = ql;
if(ql == NULL) {
if((fp1 = fopen(db8_filename,"r")) == NULL) {
fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
exit(1);
}
rownum2 = 0;
for(;;) {
if(db8_fgets(&rowlen, &row, fp1) == NULL)
break;
#ifdef DEBUG58
more_printf(stdout,"input: ");
more_printf(stdout,"%s", row);
more_printf(stdout,"\n");
#endif
if(db8_matchandproject(queryname, row)) {
int add = 1;
ppql = &qh->first;
while(*ppql != NULL) {
if((qh->flags & DB8_DISTINCT) &&
!strcmp(row, (*ppql)->line) ) {
add = 0;
break;
}
if((qh->flags & DB8_ROWSORT) &&
db8_strcmp_numdec(row, (*ppql)->line) < 0) {
//strcmp(row, (*ppql)->line) < 0) {
add = 1;
break;
}
ppql = &((*ppql)->next);
} // end of while(*ppql != NULL
if(add) {
struct queryline *ql;
ql = malloc(sizeof(struct queryline));
if((ql->line = malloc(strlen(row) + 1)) == NULL) {
fprintf(stderr,"%s: cannot malloc memory\n", procname);
exit(1);
}
strcpy(ql->line, row);
#ifdef DEBUG57
more_printf(stdout,"selected: ");
more_printf(stdout,"%s", row);
more_printf(stdout,"\n");
#endif
#ifdef DEBUG61
more_printf(stdout,"db8_cacheset_flags:");
more_printf(stdout," %d:", rownum);
more_printf(stdout," %s", ql->line);
more_printf(stdout,"\n");
#endif
ql->rownum = 0; // rownumbers come from renumber
ql->next = *ppql;
*ppql = ql;
} // end of if(add
#ifdef DEBUG65
more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
rownum2++;
} // end of if(db8_matchandproject
} // end of for(;;
fclose(fp1);
db8_renumbersets(queryname); // flags
db8_countsets(queryname);
qline = qh->first;
}
qh->cline = qline->line;
return(qline);
}
#define aDEBUG69 2
int db8_get_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
struct queryheader *qh;
struct queryline *ql;
qh = db8_queryheader(queryname);
if(namelen == 0)
namelen = strlen(name);
#ifdef DEBUG5
fprintf(stdout,"db8_get_element");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", row=%d", rownum);
fprintf(stdout,", namelen=%u", namelen);
fprintf(stdout,", name=%s", name);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
#endif
if(qh->flags)
ql = db8_getline_flags(queryname, rownum);
else
ql = db8_getline(queryname, rownum);
if(ql != NULL && ql->line != NULL) {
#ifdef DEBUG69
fprintf(stdout,"db8_get_element:");
fprintf(stdout," rownum:%u", rownum);
fprintf(stdout,", row:%s", ql->line);
#endif
int retval = db8_get(&ql->line, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval); // 2023 JariK
} else
return(0);
}
int db8_get_element_current(unsigned char *queryname, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 20250602 JariK
{
struct queryheader *qh;
qh = db8_queryheader(queryname);
if(namelen == 0)
namelen = strlen(name);
#ifdef DEBUG5
fprintf(stdout,"db8_get_element");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", row=%d", rownum);
fprintf(stdout,", namelen=%u", namelen);
fprintf(stdout,", name=%s", name);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
#endif
if(qh->cline != NULL) {
int retval = db8_get(&qh->cline, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval); // 2023 JariK
} else
return(0);
}
int db8_get_element_num(unsigned char *queryname, int rownum, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
struct queryheader *qh;
struct queryline *ql;
if(*namelen == 0)
*namelen = strlen(name);
qh = db8_queryheader(queryname);
#ifdef DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8_get_element_num");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", rownum=%d", rownum);
fprintf(stdout,", col=%d", col);
fprintf(stdout,", namesize=%u", namesize);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
}
#endif
if(qh->flags)
ql = db8_getline_flags(queryname, rownum);
else
ql = db8_getline(queryname, rownum);
if(ql != NULL && ql->line != NULL) {
#ifdef DEBUG69
fprintf(stdout,"db8_get_element_num:");
fprintf(stdout," rownum:%u", rownum);
fprintf(stdout,", row:%s", ql->line);
#endif
int retval = db8_get_num(&ql->line, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval);
} else
return(0);
}
int db8_get_element_num_current(unsigned char *queryname, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
struct queryheader *qh;
if(*namelen == 0)
*namelen = strlen(name);
qh = db8_queryheader(queryname);
#ifdef DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8_get_element_num");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", col=%d", col);
fprintf(stdout,", namesize=%u", namesize);
fprintf(stdout,", valuesize=%u", valuesize);
fprintf(stdout,"\n");
}
#endif
if(qh->cline != NULL) {
#ifdef DEBUG69
fprintf(stdout,"db8_get_element_num:");
fprintf(stdout," rownum:%u", rownum);
fprintf(stdout,", row:%s", ql->line);
#endif
int retval = db8_get_num(&qh->cline, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
fprintf(stdout,", valuelen=%u", *valuelen);
fprintf(stdout,", value=%.*s", *valuelen, value);
fprintf(stdout,"\n");
#endif
return(retval);
} else
return(0);
}
int db8_put_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value)
{
struct queryline *ql;
if(namelen == 0)
namelen = strlen(name);
if(valuelen == 0)
valuelen = strlen(value);
#ifdef DEBUG5
if(db8_verbose) {
fprintf(stdout,"db8: put_element");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,", rownum=%d", rownum);
fprintf(stdout,", namelen=%u", namelen);
fprintf(stdout,", name=%.*s", namelen, name);
fprintf(stdout,", valuelen=%u", valuelen);
fprintf(stdout,", value=%.*s", valuelen, value);
fprintf(stdout,"\n");
}
#endif
//db8_set = db8_find_set(queryname, rownum);
ql = db8_lineheader(queryname, rownum);
db8_put(&ql->line, namelen, name, valuelen, value); // 2023 JariK
ql->save = 1;
return(0);
}
void db8_dump(unsigned char *queryname)
{
struct queryheader *qh;
struct queryline *ql;
qh = db8_queryheader(queryname);
fprintf(stdout,"qh=%p", qh);
fprintf(stdout,", queryname=%s", qh->queryname);
fprintf(stdout,", flags=%d", qh->flags);
fprintf(stdout,", query=%s", qh->query);
fprintf(stdout,", count=%d", qh->count);
fprintf(stdout,", preread=%d", qh->preread);
fprintf(stdout,", next=%p", qh->next);
fprintf(stdout,", first=%p", qh->first);
fprintf(stdout,"\n");
ql = qh->first;
while(ql != NULL) {
fprintf(stdout,"ql=%p", ql);
fprintf(stdout,", rownum=%d", ql->rownum);
fprintf(stdout,", save=%d", ql->save);
fprintf(stdout,", next=%p", ql->next);
fprintf(stdout,", line=%p", ql->line);
if(ql->line != NULL)
fprintf(stdout," %s", ql->line);
fprintf(stdout,"\n");
ql = ql->next;
}
fflush(stdout);
}
int db8_save(unsigned char *queryname)
{
struct queryheader *qh;
struct queryline *ql;
#ifdef DEBUG5
if(db8_verbose == 1) {
fprintf(stdout,"db8_save:");
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,"\n");
}
#endif
qh = db8_queryheader(queryname);
fprintf(stdout,"%s\n", db8_set);
FILE *fp1;
if((fp1 = fopen(db8_filename, "a"))==NULL) {
fprintf(stdout,"%s: db8 cannot open file '%s'\n", procname, db8_filename);
exit(1);
}
ql = qh->first;
while(ql != NULL) {
if(ql->save) {
fprintf(fp1,"%s\n", ql->line);
ql->save = 0;
}
ql = ql->next;
}
fclose(fp1);
db8_dump(queryname);
return(0);
}
int db8_save_all()
{
struct queryheader *qh;
#ifdef DEBUG5
if(db8_verbose == 1) {
fprintf(stdout,"db8_save_all:\n");
}
#endif
qh = firstqueryheader;
while(qh != NULL) {
db8_save(qh->queryname);
qh = qh->next;
}
return(0);
}
int db8_clear(unsigned char *queryname)
{
struct queryheader **ppqh, *qh;
struct queryline *ql, *qlnext;
#ifdef DEBUG5
if(db8_verbose == 1) {
fprintf(stdout,"clear %s", queryname);
fprintf(stdout,", query=%s", queryname);
fprintf(stdout,"\n");
}
#endif
ppqh = &firstqueryheader;
while(*ppqh != NULL) {
if(!strcmp(queryname, (*ppqh)->queryname))
break;
ppqh = &((*ppqh)->next);
}
if(*ppqh != NULL) {
qh = *ppqh;
ql = qh->first;
*ppqh = qh->next;
free(qh);
while(ql != NULL) {
qlnext = ql->next;
if(ql->line != NULL)
free(ql->line);
free(ql);
ql = qlnext;
}
}
return(0);
}
int db8_clear_all()
{
struct queryheader *qh, *qhnext;
#ifdef DEBUG5
if(db8_verbose == 1) {
fprintf(stdout,"db8_clear_all:\n");
}
#endif
qh = firstqueryheader;
while(qh != NULL) {
qhnext = qh->next;
db8_clear(qh->queryname);
qh = qhnext;
}
return(0);
}
int db8_exit()
{
#ifdef DEBUG5
if(db8_verbose == 1) {
fprintf(stdout,"db8_exit:\n");
}
#endif
return(0);
}
void db8_version()
{
fprintf(stdout, "%s", programname); // touch these outside #ifdef MAIN
fprintf(stdout, ", %s", copyright);
}
#ifdef QUERY
#include <signal.h>
int ctrlcquit = 0;
static void sig_handler()
{
fprintf(stderr,"Ctrl-c pressed\n");
ctrlcquit = 1;
//signal(SIGINT, SIG_DFL);
}
static int db8_ischar(int c)
{
if(isalpha(c) || isdigit(c) || c >= 0x80 || c == '_')
return(1);
else
return(0);
}
int db8_isquote(int c)
{
if(ispunct(c) && c != ',' && c != '=')
return(1);
else
return(0);
}
#define aDEBUG60
static int namequote = -1, valuequote = -1;
static void db8_get_element3(int *namelen, unsigned char **name, int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
unsigned char *p;
p = *p2;
db8_skipwhite(&p);
if(namequote == -1) {
if(db8_isquote(*p))
namequote = *p;
else
namequote = 0;
}
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 1 %s %c(%d)\n", p, valuequote, valuequote);
#endif
*namelen = -1;
if((*p == namequote && namequote) ||
(db8_ischar(*p) && !namequote)) { // name
*namelen = 0;
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 2 %s\n", p);
#endif
if(namequote) {
p++;
*name = p;
while(*p != namequote && *p != '\0') {
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 3 %s\n", p);
#endif
p++;
(*namelen)++;
}
if(*p == namequote)
p++;
} else {
*name = p;
while(db8_ischar(*p)) {
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 4 %s\n", p);
#endif
p++;
(*namelen)++;
}
}
} else
*name = NULL;
db8_skipwhite(&p);
if(*p == '=') {
p++;
db8_skipwhite(&p);
}
if(valuequote == -1) {
if(db8_isquote(*p))
valuequote = *p;
else
valuequote = 0;
}
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 5 %s %c(%d)\n", p, valuequote, valuequote);
#endif
*valuelen = -1;
if((*p == valuequote && valuequote) ||
(db8_ischar(*p) && !valuequote)) { // value
*valuelen = 0;
if(valuequote) {
p++;
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 6 %s\n", p);
#endif
*value = p;
while(*p != valuequote && *p != '\0') {
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 7 %s\n", p);
#endif
p++;
(*valuelen)++;
}
if(*p == valuequote)
p++;
} else {
*value = p;
while(db8_ischar(*p)) {
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 8 %s\n", p);
#endif
p++;
(*valuelen)++;
}
}
} else
*value = NULL;
db8_skipwhite(&p);
#ifdef DEBUG60
fprintf(stdout,"db8_get_element: 9 %s\n", p);
#endif
*p2 = p;
}
void db8_squery(unsigned char *query) // JariK 2025 single
{
int row, col, first, ok, print;
unsigned int namelen;
unsigned int valuelen;
unsigned char *name, *value;
unsigned char *q;
unsigned char *query2 = NULL;
if(more)
more_init(); // adjust thee screensize
q = query;
fprintf(stdout,"query:%s\n", query);
fflush(stdout);
namequote = -1;
valuequote = -1;
while(*q != '\0') {
db8_skipwhite(&q);
db8_get_element3(&namelen, &name, &valuelen, &value, &q);
if(name == NULL)
break;
db8_skipwhite(&q);
if(*q == ',') {
q++;
db8_skipwhite(&q);
}
fprintf(stderr,"db8_squery():");
fprintf(stderr," name:%.*s(%d)", namelen, name, namelen);
fprintf(stderr,", value:%.*s(%d)", valuelen, value, valuelen);
fprintf(stderr,"\n");
db8_put(&query2, namelen, name, valuelen, value);
}
db8_set_filename(db8_filename);
fprintf(stdout,"query2:%s\n", query2);
db8_clear("query");
db8_set_query("query", query2);
//db8_set_queryflags("query", 0);
//db8_set_queryflags("query", DB8_DISTINCT);
//db8_set_queryflags("query", DB8_ROWSORT);
db8_set_queryflags("query", DB8_ROWSORT | DB8_DISTINCT);
free(query2);
row = 0;
unsigned int namesize2, namelen2, valuesize2, valuelen2;
unsigned char name2[128], value2[128];
namesize2 = sizeof(name2);
valuesize2 = sizeof(value2);
for(;;) {
morequit = 0;
print = 0;
first = 1;
col = 0;
ok = 0;
if(db8_get_queryflags("query"))
db8_getline_flags("query", row);
else
db8_getline("query", row);
for(;;) {
//fprintf(stdout,"row:%d, col:%d, ", row, col);
if(db8_get_element_num_current("query", col, namesize2, &namelen2, name2, valuesize2, &valuelen2, value2))
ok = 1;
else
break;
if(col == 0)
fprintf(stdout,"%d ", row);
if(!first)
fprintf(stdout,", ");
print = 1;
more_printf(stdout,"'%s' = \"%s\"", name2, value2);
fflush(stdout);
col++;
first = 0;
}
if(print) {
more_printf(stdout,"\n");
fflush(stdout);
}
#ifdef DB8_QUERY_CALL
extern void db8_query_call();
db8_get_element_num("query", row, 0, namesize2, &namelen2, name2, valuesize2, &valuelen2, value2);
db8_query_call("");
#endif
if(!ok)
break;
if(more && morequit)
break;
if(ctrlcquit) {
ctrlcquit = 0;
break;
}
row++;
}
//db8_dump("query");
}
unsigned char prompt[128] = "skk>";
static int db8_isword(unsigned char **p2, unsigned char *word)
{
unsigned char *p;
int wlen = strlen(word);
p = *p2;
db8_skipwhite(&p);
if(!strncmp(word, p, wlen) &&
( (isblank(*(p + wlen))) ||
(ispunct(*(p + wlen))) ||
(*(p + wlen) == '\0') ) ) {
p += wlen;
db8_skipwhite(&p);
*p2 = p;
return(1);
} else
return(0);
}
void db8_iquery() // JariK 2025 interactive
{
unsigned char *command = NULL, *p;
int commandsize = 0;
ctrlcquit = 0;
signal(SIGINT, sig_handler);
fprintf(stdout,"%s\n", programname);
for(;;) {
fprintf(stdout, "%s", prompt);
db8_fgets(&commandsize, &command, stdin);
p = command;
db8_skipwhite(&p);
if(*p == '\0')
continue;
if(db8_isword(&p, "more")) {
if(db8_isword(&p, "on")) {
more = 1;
continue;
}
if(db8_isword(&p, "off")) {
more = 0;
continue;
}
more = !more;
fprintf(stderr,"more ");
if(more)
fprintf(stderr,"on");
else
fprintf(stderr,"off");
fprintf(stderr,"\n");
continue;
}
if(db8_isword(&p, "copyright") ||
db8_isword(&p, "version") ) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
continue;
}
if(db8_isword(&p, "exit"))
break;
if(db8_isword(&p, "quit"))
break;
if(db8_isword(&p, "*")) {
db8_squery(NULL);
} else
db8_squery(p);
}
signal(SIGINT, SIG_DFL);
}
#endif
#ifdef MAIN
#define aDEBUG92 2
#define DEBUG96 2
int my_match(unsigned char *pattern, unsigned char *string)
{
unsigned char *p, *s;
p = pattern;
s = string;
while(*p != '\0') {
#ifdef DEBUG92
more_printf(stdout,"\npattern=%s",p);
more_printf(stdout,", string=%s",s);
#endif
if(*p == '*') { // one or many characters
if(*s == '\0')
return(0);
while(*s != '\0') {
if(my_match(p + 1, ++s))
return(1);
}
} else if(*p == '?') { // one character
if(*s == '\0')
return(0);
s++;
} else if(*p == *s) {
s++;
} else
return(0);
p++;
}
if(*s == '\0')
return(1);
else
return(0);
}
int my_match_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
while(plen > 0) {
#ifdef DEBUG92
more_printf(stdout,"\nplen=%d", plen);
more_printf(stdout,", p=");
db8_fputs_len(stdout, plen, p);
more_printf(stdout,", slen=%d", slen);
more_printf(stdout,", s=");
db8_fputs_len(stdout, slen, s);
#endif
if(*p == '*') { // one or many characters
if(slen == 0)
return(0);
while(slen > 0) {
s++;
slen--;
if(my_match_len(plen - 1, p + 1, slen, s))
return(1);
}
} else if(*p == '?') { // one character
if(slen == 0)
return(0);
s++;
slen--;
} else if(*p == *s) {
s++;
slen--;
} else
return(0);
p++;
plen--;
}
if(slen == 0)
return(1);
else
return(0);
}
int my_match_test(unsigned char *p, unsigned char *s) // 2025 JariK
{
int retval, plen, slen;
static unsigned int testid = 0;
more_printf(stdout,"%d", testid);
more_printf(stdout,", p=%s", p);
more_printf(stdout,", s=%s", s);
retval = my_match(p, s);
if(retval)
more_printf(stdout," match!");
else
more_printf(stdout," no match!");
more_printf(stdout,"\n");
more_printf(stdout,"%d", testid++);
plen = strlen(p);
slen = strlen(s);
//more_printf(stdout," plen=%d", plen);
more_printf(stdout,", p=%s", p);
//more_printf(stdout,", slen=%d", slen);
more_printf(stdout,", s=%s", s);
retval = my_match_len(plen, p, slen, s);
if(retval)
more_printf(stdout," match!");
else
more_printf(stdout," no match!");
more_printf(stdout,"\n");
return(retval);
}
unsigned char *procname;
char *query = NULL;
unsigned char filename[128] = "newressusudoku.skk.db";
int main(int argc, char *argv[])
{
int c, args = 0, help = 0;
procname = argv[0];
more = 0;
if(isatty(STDOUT_FILENO))
more = 1;
// look thru command line parameters
for(c = 1; c < argc; c++) {
if(!strcmp("--help", argv[c])) {
help = 1;
} else if(!strcmp("--args", argv[c])) {
args = !args;
} else if(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strncmp("--skkfile", argv[c], 9)) { // JariK 2025
if(*(argv[c] + 9) != '\0') {
strcpy(filename, argv[c] + 9);
} else if(c + 1 < argc) {
strcpy(filename, argv[c + 1]);
c++;
}
} else if(!strncmp("--query", argv[c], 7)) { // JariK 2025
query = NULL;
if(*(argv[c] + 7) != '\0') {
query = argv[c] + 7;
} else if(c + 1 < argc && *(argv[c + 1]) != '-') {
query = argv[c + 1];
c++;
}
} else if(!strncmp("--more", argv[c], 6)) { // JariK 2025
more = !more;
}
}
if(help) {
fprintf(stderr,"%s: %s", procname, procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--skkfile[filename]]");
fprintf(stderr," [--query[querytext]]");
fprintf(stderr," [--more]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
#ifdef DEBUG96
if(more)
more_init(); // adjust thee screensize
more_printf(stdout, "zero delimited match\n");
my_match_test("?","");
my_match_test("*","");
my_match_test("a?","a");
my_match_test("a*","a");
my_match_test("abcdef","abcdef");
my_match_test("abc*def","abcdefdef");
my_match_test("abc*def","abcdefdefdef");
my_match_test("abc*","abcdef");
my_match_test("*def","abcdef");
my_match_test("*cd*","abcdef");
my_match_test("*cd*","abcdefcdefcdef");
my_match_test("ab??ef","abcdef");
my_match_test("??def","abcdef");
my_match_test("???def","abcdef");
my_match_test("*gh*","abcdef");
my_match_test("abcdef","abcgef");
my_match_test("?*def","abcdef");
my_match_test("?*def","abcdefg");
my_match_test("?b","ab");
my_match_test("a?","ab");
my_match_test("a?c","abc");
my_match_test("a??d","abcd");
my_match_test("a??*d","abcd");
my_match_test("?b","ac");
#endif
if(args) {
fprintf(stderr,"argc: %d\n", argc);
for(c = 0; c < argc; c++) {
fprintf(stderr,"argv[%d]: %s\n", c, argv[c]);
}
exit(1);
}
#ifdef TEST
unsigned long l = 0;
c = 0;
for(;;) {
unsigned long oldl = l;
l = l * 10 + 9;
fprintf(stdout,"%d %lu\n", c++, l);
if((l - 9) / 10 != oldl)
break;
}
#endif
db8_set_filename(filename);
if(query !=NULL)
db8_squery(query);
else
db8_iquery();
exit(0);
}
#endif
Db8 source more.c
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <termios.h>
static unsigned char *programname = "more version 0.1 ©";
static unsigned char *copyright = "Copyright (c) 2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
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 more_backspacechars(int chars)
{
int c;
for(c = 0; c < chars; c++)
fputc('\b', stdout);
for(c = 0; c < chars; c++)
fputc(' ', stdout);
for(c = 0; c < chars; c++)
fputc('\b', stdout);
}
int more = 1;
int screenlinesleft = 0, screenmaxchars, screenmaxlines;
int screenchars = 0;
int morequit = 0;
#include <sys/ioctl.h> // for TIOCGWINSZ
void more_init()
{
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
screenmaxchars = w.ws_col;
screenmaxlines = w.ws_row - 1;
screenlinesleft = screenmaxlines;
}
void more_version()
{
fprintf(stderr, "%s", programname); // touch these outside #ifdef MAIN
fprintf(stderr, ", %s", copyright);
}
void more_wait()
{
int c;
unsigned char *moretext = "---more---";
fprintf(stderr,"%s", moretext);
if(more) {
startprompt();
// wait until something below is pressed
for(;;) {
c = getchar();
if(c == ' ') {
more_init(); // adjust for screensize
screenlinesleft = screenmaxlines; // full screen
break;
} else if(c == '\n') {
more_init(); // adjust for screensize
screenlinesleft = 1; // one line
break;
} else if(c == 'q') { // quit
morequit = 1;
break;
}
}
more_backspacechars(strlen(moretext));
endprompt();
} // end of if(more
}
#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++;
}
}
Toinen tärkeä asia edellisessä postissa oli tietysti satunnaisbittigeneraattori: seuraava ohjelma yrittää laskea pi:n pseudoressun satunnaisbittien perusteella:
Pi ohjelmassa on jo aiemmista posteista tuttuja pätkiä:
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2) // 2023 JariK
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
void fprintfcharacter(FILE *fp1, unsigned char *p) // 2023 JariK
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p) // 2023 JariK
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
#define DEBUG32 2
//#define KILO 1000
#define KILO 1024
unsigned long long getlonglong(unsigned char *p2) // 2023 JariK
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %llu", prevll);
fprintf(stderr,", multiplier: %llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
Toinen tuttu pätkä, jolla arvotaan satunnaisuus:
#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
pseudoressu_bytes(sizeof(gent), gent);
} // if(gent_pos == 0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
Ja pi ohjelma kokonaisuudessaan:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "newressu.h"
unsigned char *procname;
static unsigned char *programname = "newressupi version 0.06 ©";
static unsigned char *copyright = "Copyright (c) 2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";
unsigned char *log_filename = "newressupi.log";
#include <time.h>
#include <stdarg.h>
void log_printf(const char *format, ...) // JariK 2025
{
int count;
va_list args;
static char *printbuf = NULL;
static int printbuf_len = 0;
static int printtime = 1;
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.
// print all characters to log adding time and date.
fputs(printbuf, stdout);
FILE *fp1;
if((fp1 = fopen(log_filename, "a")) != NULL) {
if(printtime) {
time_t now = time(NULL);
unsigned char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%Y%m%d%H%M%S%Z", localtime((time_t *)&now));
fputs(timestamp, fp1);
fputc(' ', fp1);
printtime = 0;
}
fputs(printbuf, fp1);
fclose(fp1);
if(printbuf[strlen(printbuf) - 1] == '\n')
printtime = 1;
}
}
#define KILO 1024
void readablelonglong(FILE *fp1, unsigned long long ll2) // 2023 JariK
{
int c;
unsigned long long multiplier, ll = ll2;
// B = byte
// K = kilo 10^3 2^10
// M = mega 10^6 2^20
// G = giga 10^9 2^30
// T = tera 10^12 2^40
// P = peta 10^15 2^50
// E = exa 10^18 2^60
// Z = zetta 10^21 2^70
// Y = yotta 10^24 2^80
char units[] = "BKMGTPEZY";
c = 0;
multiplier = 1;
while(ll >= KILO) {
ll /= KILO;
multiplier *= KILO;
c++;
}
if(ll * multiplier != ll2)
fprintf(fp1,"~"); // approximately
fprintf(fp1,"%llu%c", ll, units[c]);
}
void fprintfcharacter(FILE *fp1, unsigned char *p) // 2023 JariK
{
fputc(*p, fp1); // print first char
if(*p > 0xbf) { // first char utf8
p++;
for(;;) { // print rest of the utf8 chars
if(*p > 0xbf || // new utf8 character
*p < 0x80 || // ascii character
*p == '\0') // end of string
break;
fputc(*p, fp1);
p++;
}
}
}
int getdigit(unsigned char *p) // 2023 JariK
{
int digit;
if(*p >= '0' && *p <= '9')
digit = *p - '0';
else if(*p >= 'a' && *p <= 'z')
digit = (*p - 'a') + 10;
else if(*p >= 'A' && *p <= 'Z')
digit = (*p - 'A') + 10;
else
digit = -1; // not found, illegal
return(digit);
}
#define DEBUG32 2
//#define KILO 1000
#define KILO 1024
unsigned long long getlonglong(unsigned char *p2) // 2023 JariK
{
int digit, base = 10;
unsigned char *p = p2;
unsigned long long totll, ll, prevll, multiplier;
totll = 0;
while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...
unsigned char *prevp = p;
if(!strncmp("0x", p, 2)) {
base = 16;
p += 2;
} else if(!strncmp("0d", p, 2)) {
base = 10;
p += 2;
} else if(!strncmp("0o", p, 2)) {
base = 8;
p += 2;
} else if(!strncmp("0b", p, 2)) {
base = 2;
p += 2;
}
ll = 0;
while((digit = getdigit(p)) != -1 && digit < base) {
ll = ll * base + digit;
p++;
}
multiplier = 1;
if(*p == 'k' || *p == 'K') {
multiplier = KILO;
p++;
} else if(*p == 'm' || *p == 'M') {
multiplier = (KILO * KILO);
p++;
} else if(*p == 'g' || *p == 'G') {
multiplier = (KILO * KILO * KILO);
p++;
} else if(*p == 't' || *p == 'T') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'p' || *p == 'P') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
p++;
} else if(*p == 'e' || *p == 'E') {
multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
p++;
}
prevll = ll;
ll *= multiplier;
if(ll / multiplier != prevll) {
fflush(stdout);
fprintf(stderr,"%s: multiply overflow", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d", base);
fprintf(stderr,", ll: %llu", prevll);
fprintf(stderr,", multiplier: %llu", multiplier);
fprintf(stderr,"\n");
fflush(stderr);
}
if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
p++;
totll += ll;
#ifdef DEBUG32
fprintf(stderr,"string:'%s'", p2);
fprintf(stderr,", base:%d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,", multiplier:%llu(", multiplier);
readablelonglong(stderr, multiplier);
fprintf(stderr,")");
fprintf(stderr,", prevll:%llu(", prevll);
readablelonglong(stderr, prevll);
fprintf(stderr,")");
fprintf(stderr,", ll:%llu(", ll);
readablelonglong(stderr, ll);
fprintf(stderr,")");
fprintf(stderr,", totll:%llu(", totll);
readablelonglong(stderr, totll);
fprintf(stderr,")");
fprintf(stderr,"\n");
#endif
if(prevp == p) // no progress
break;
}
if(*p != '\0') {
fflush(stdout);
fprintf(stderr,"%s: illegal digit", procname);
fprintf(stderr,", string:'%s'", p2);
fprintf(stderr,", digit:'");
fprintfcharacter(stderr, p);
fprintf(stderr,"'");
fprintf(stderr,", value: %d", digit);
fprintf(stderr,", base: %d(", base);
readablelonglong(stderr, base);
fprintf(stderr,")");
fprintf(stderr,"\n");
fflush(stderr);
}
return(totll);
}
#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;
int newressu_genbyte()
{
unsigned char ch;
if(gent_pos == 0) {
memset(gent, 0, sizeof(gent));
pseudoressu_bytes(sizeof(gent), gent);
} // if(gent_pos == 0
ch = gent[gent_pos];
gent_pos = (gent_pos + 1) % sizeof(gent);
return(ch);
}
#define DEBUG13 2
unsigned long newressu_gen_limit(unsigned long limit)
{
int c;
unsigned long word;
static unsigned long lastlimit = 0, highlimit;
static int bytes;
if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
lastlimit = limit;
if(limit <= 0x100) {
// highest multiplier of limit that fits to needed bytes
highlimit = (0x100 / limit) * limit;
// number of bytes needed
bytes = 1;
} else if(limit <= 0x10000) {
highlimit = (0x10000 / limit) * limit;
bytes = 2;
} else if(limit <= 0x1000000) {
highlimit = (0x1000000 / limit) * limit;
bytes = 3;
} else if(limit <= 0x100000000) {
highlimit = (0x100000000 / limit) * limit;
bytes = 4;
} else if(limit <= 0x10000000000) {
highlimit = (0x10000000000 / limit) * limit;
bytes = 5;
} else if(limit <= 0x1000000000000) {
highlimit = (0x1000000000000 / limit) * limit;
bytes = 6;
} else if(limit <= 0x100000000000000) {
highlimit = (0x100000000000000 / limit) * limit;
bytes = 7;
} else { // if(limit <= 0xffffffffffffffff) {
highlimit = (0xffffffffffffffff / limit) * limit;
bytes = 8;
}
#ifdef DEBUG13
fprintf(stdout,"%s: newressu_gen_limit:", procname);
fprintf(stdout," limit:%lu(", limit);
readablelonglong(stdout, limit);
fprintf(stdout,")");
fprintf(stdout,", highlimit:%lu(", highlimit);
readablelonglong(stdout, highlimit);
fprintf(stdout,")");
fprintf(stdout,", bytes:%u", bytes);
fprintf(stdout,"\n");
#endif
} // if(lastlimit != limit)
for(;;) {
word = 0;
for(c = 0; c < bytes; c++)
word = word << 8 | newressu_genbyte();
if(word < highlimit)
break;
}
word %= limit;
return(word);
}
#define aDEBUG10 2
//#define BLOCK 1000000000
#define BLOCK 1000000000
unsigned int block = BLOCK;
#define RANDFUNC pseudoressu_bytes
#define DECIMALS 20
void main(int argc, char *argv[])
{
int c, bytes = 0, help = 0;
unsigned long long limit = 0, divider, round, llx, lly, inside = 0;
double x, y;
#ifdef DEBUG10
double minx = 999, miny = 999, maxx = -999, maxy = -999;
#endif
procname = argv[0];
// 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(!strcmp("--copyright", argv[c]) ||
!strcmp("--version", argv[c])) {
fprintf(stderr, "%s", programname);
fprintf(stderr, ", %s\n", copyright);
exit(0);
} else if(!strncmp("--bytes", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
bytes = atoi(argv[c] + 7);
} else if(c + 1 < argc) {
bytes = atoi(argv[c + 1]);
c++;
}
if(bytes < 1 || bytes > 8) {
fprintf(stderr,"%s: --bytes must be between 1 and 8\n", procname);
exit(1);
}
limit = 0;
} else if(!strncmp("--limit", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
limit = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
limit = getlonglong(argv[c + 1]);
c++;
}
if(limit < 2) {
fprintf(stderr,"%s: --limit must be greater or equal than 2\n", procname);
exit(1);
}
bytes = 0;
} else if(!strncmp("--block", argv[c], 7)) {
if(isdigit(*(argv[c] + 7))) {
block = getlonglong(argv[c] + 7);
} else if(c + 1 < argc) {
block = getlonglong(argv[c + 1]);
c++;
}
if(block < 2) {
fprintf(stderr,"%s: --block must be greater or equal than 2\n", procname);
exit(1);
}
}
}
}
// print help message if needed
if(help) {
fprintf(stderr,"%s: %s", procname, procname);
fprintf(stderr," [--help]");
fprintf(stderr," [--copyright]");
fprintf(stderr," [--version]");
fprintf(stderr," [--bytes n]");
fprintf(stderr," [--limit n]");
fprintf(stderr," [--block n]");
fprintf(stderr,"\n");
exit(1);
} // end of if(help)
#ifdef OLD1
switch(bytes) {
case 1:
divider = 0xff;
break;
case 2:
divider = 0xffff;
break;
case 3:
divider = 0xffffff;
break;
case 4:
divider = 0xffffffff;
break;
case 5:
divider = 0xffffffffff;
break;
case 6:
divider = 0xffffffffffff;
break;
case 7:
divider = 0xffffffffffffff;
break;
case 8:
divider = (unsigned long long) 0xffffffffffffffff;
break;
}
#endif // end of #ifdef OLD1
if(limit == 0 && bytes == 0)
bytes = 4;
if(bytes != 0) {
divider = 0;
for(c = 0; c < bytes; c++) {
divider = (divider << 8) + 0xff;
}
} else
divider = limit - 1;
if(bytes)
fprintf(stdout,"bytes %d", bytes);
if(limit) {
fprintf(stdout,"limit %llu(", limit);
readablelonglong(stdout, limit);
fprintf(stdout,")");
}
fprintf(stdout,", block %u", block);
fprintf(stdout,", step %1.*f", DECIMALS, (double)2 / divider - (double)1 / divider);
fprintf(stdout,", divider %llu(", divider);
readablelonglong(stdout, divider);
fprintf(stdout,")");
fprintf(stdout,"\n");
for(round = 0;; round++) {
llx = 0;
lly = 0;
#ifdef DEBUG10
fprintf(stdout,"rounds=%llu", round);
#endif
if(bytes) {
RANDFUNC(bytes, (unsigned char *)&llx); // little endian
RANDFUNC(bytes, (unsigned char *)&lly); // little endian
//RANDFUNC(bytes, (unsigned char *)&llx + 8 - bytes); // big endian
//RANDFUNC(bytes, (unsigned char *)&lly + 8 - bytes); // big endian
} else if(limit) {
llx = newressu_gen_limit(limit);
lly = newressu_gen_limit(limit);
}
#ifdef DEBUG10
fprintf(stdout,", llx=%llx", (unsigned long long)llx);
fprintf(stdout,", lly=%llx", (unsigned long long)lly);
#endif
x = (double) llx / divider; // random number between 0 and 1
y = (double) lly / divider; // random number between 0 and 1
#ifdef DEBUG10
fprintf(stdout,", x=%f", x);
fprintf(stdout,", y=%f", y);
#endif
#ifdef DEBUG10
if(minx > x)
minx = x;
if(miny > y)
miny = y;
if(maxx < x)
maxx = x;
if(maxy < y)
maxy = y;
fprintf(stdout,", minx=%f", minx);
fprintf(stdout,", miny=%f", miny);
fprintf(stdout,", maxx=%f", maxx);
fprintf(stdout,", maxy=%f", maxy);
#endif
if(sqrt(x * x + y * y) < 1)
inside++;
#ifdef DEBUG10
fprintf(stdout,", inside=%llu", inside);
fprintf(stdout,", pi=%1.*f", DECIMALS, (double)4 * inside / round);
fprintf(stdout,"\n");
#endif
if(round > 0 && round % block == 0) {
log_printf("rounds = %llu", round);
log_printf(", inside = %llu", inside);
log_printf(", pi = %1.*f", DECIMALS, (double)4 * inside / round);
if(bytes != 0)
log_printf(", bytes = %d", bytes);
if(limit != 0)
log_printf(", limit = %llu", limit);
log_printf("\n");
}
}
}
Seuraavassa pätkä pi:n haun logista (newressupi.log):
20250728111134EEST rounds = 591000000000, inside = 464170507728, pi = 3.14159396093400999916, bytes = 7
20250728111628EEST rounds = 633000000000, inside = 497156881071, pi = 3.14159166553554491941, bytes = 6
20250728112348EEST rounds = 955000000000, inside = 750055265602, pi = 3.14159273550575912637, limit = 17293822569102704640
20250728112357EEST rounds = 733000000000, inside = 575689846725, pi = 3.14155441596180073915, bytes = 2
20250728112552EEST rounds = 599000000000, inside = 470453646868, pi = 3.14159363517863088333, bytes = 8
20250728113232EEST rounds = 656000000000, inside = 515221382817, pi = 3.14159379766463420225, bytes = 5
20250728114328EEST rounds = 685000000000, inside = 537997696622, pi = 3.14159238903357662664, bytes = 4
20250728114727EEST rounds = 956000000000, inside = 750840642527, pi = 3.14159264655648540199, limit = 17293822569102704640
20250728114944EEST rounds = 724000000000, inside = 568627945710, pi = 3.14159086027624301352, bytes = 3
20250728120621EEST rounds = 782000000000, inside = 612285705793, pi = 3.13189619331457791418, bytes = 1
20250728120946EEST rounds = 957000000000, inside = 751626011893, pi = 3.14159252619853690547, limit = 17293822569102704640
20250728122446EEST rounds = 592000000000, inside = 464955901877, pi = 3.14159393160135147482, bytes = 7
20250728122640EEST rounds = 734000000000, inside = 576475228866, pi = 3.14155438074114456981, bytes = 2
20250728123006EEST rounds = 634000000000, inside = 497942282544, pi = 3.14159168797476340274, bytes = 6
20250728123126EEST rounds = 958000000000, inside = 752411423621, pi = 3.14159258296868459936, limit = 17293822569102704640
20250728123623EEST rounds = 657000000000, inside = 516006768084, pi = 3.14159371740639281612, bytes = 5
20250728124124EEST rounds = 600000000000, inside = 471239037042, pi = 3.14159358027999990881, bytes = 8
20250728124919EEST rounds = 686000000000, inside = 538783103661, pi = 3.14159244117201152946, bytes = 4
20250728125049EEST rounds = 725000000000, inside = 569413330861, pi = 3.14159079095724136366, bytes = 3
20250728125306EEST rounds = 959000000000, inside = 753196826239, pi = 3.14159260162252351734, limit = 17293822569102704640
20250728130422EEST rounds = 783000000000, inside = 613068702173, pi = 3.13189630739719016006, bytes = 1
20250728131320EEST rounds = 960000000000, inside = 753982213607, pi = 3.14159255669583314940, limit = 17293822569102704640
20250728132348EEST rounds = 735000000000, inside = 577260619699, pi = 3.14155439291972804483, bytes = 2