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.
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 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.04 ©";
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 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);
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
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 DEBUG5
fprintf(stdout,"db8_project: ");
fprintf(stdout,", query:%s", query);
fprintf(stdout,", set:%s\n", set);
fflush(stdout); fflush(stdout);
#endif
#ifdef DEBUG52
fprintf(stdout,"db8_project: ");
fprintf(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);
}
if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
(value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
#ifdef DEBUG52
fprintf(stdout,"db8_project: ");
fprintf(stdout,"'%.*s'", namelen, name);
fprintf(stdout," = \"%.*s\"", valuelen2, value2);
fprintf(stdout,"\n");
#endif
db8_put(project, namelen, name, valuelen2, value2);
}
} // while(*s != '\0'
} // while(*q != '\0'
#ifdef DEBUG5
fprintf(stdout,", project:(%s)", *project);
fprintf(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 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;
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 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;
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 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;
#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);
}
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
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
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
#ifdef TESTI
fprintf(stdout,"1:%ld\n", db8_strcmp_num("1","1"));
fprintf(stdout,"2:%ld\n", db8_strcmp_num("a","a"));
fprintf(stdout,"3:%ld\n", db8_strcmp_num("b","a"));
fprintf(stdout,"4:%ld\n", db8_strcmp_num("a","b"));
#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:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "newressu.h"
unsigned char *log_filename = "newressupi.log";
unsigned char *procname;
#include <time.h>
#include <stdarg.h>
void log_printf(const char *format, ...)
{
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.
// prompt more for full screen pages.
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 aDEBUG10 2
#define MODE3 2
#ifdef MODE1
#define LIMIT UCHAR_MAX
#define TYPE unsigned char
#endif
#ifdef MODE2
#define LIMIT USHRT_MAX
#define TYPE unsigned short
#endif
#ifdef MODE3
// rounds = 35600000000, inside = 27960200374, pi = 3.141595547640449571
#define LIMIT UINT_MAX
#define TYPE unsigned int
#endif
#ifdef MODE4
#define LIMIT ULONG_MAX
#define TYPE unsigned long
#endif
#ifdef MODE5
#define LIMIT ULLONG_MAX
#define TYPE unsigned long long
#endif
#define BLOCK 1000000000
#define RANDFUNC pseudoressu_bytes
void main(int argc, char *argv[])
{
double x, y;
#ifdef DEBUG10
double minx = 999, miny = 999, maxx = -999, maxy = -999;
#endif
TYPE llx, lly;
unsigned long long inside = 0;
procname = argv[0];
fprintf(stdout,"word size %ld",sizeof(TYPE));
fprintf(stdout,", step %1.18f", (double)2/LIMIT - (double)1/LIMIT);
fprintf(stdout,"\n");
for(long long c = 0;; c++) {
llx = 0;
lly = 0;
RANDFUNC((int)sizeof(llx), (unsigned char *)&llx);
RANDFUNC((int)sizeof(lly), (unsigned char *)&lly);
#ifdef DEBUG10
fprintf(stdout,"llx=%llx", (unsigned long long)llx);
fprintf(stdout,", lly=%llx", (unsigned long long)lly);
#endif
x = (double) llx / LIMIT;
y = (double) lly / LIMIT;
#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);
fprintf(stdout,"\n");
#endif
if(sqrt(x * x + y * y) < 1)
inside++;
if(c > 0 && c % BLOCK == 0) {
log_printf("rounds = %lld", c);
log_printf(", inside = %lld", inside);
log_printf(", pi = %1.18f", (double)4 * inside / c);
log_printf(", word size = %ld\n", sizeof(TYPE));
}
}
}
Seuraavassa pätkä pi:n haun logista (newressupi.log):
20250626220801EEST rounds = 20000000000, inside = 15707937813, pi = 3.141587562599999828
20250627002823EEST rounds = 21000000000, inside = 16493335168, pi = 3.141587651047618834
20250627024609EEST rounds = 22000000000, inside = 17278728418, pi = 3.141586985090909057
20250627050221EEST rounds = 23000000000, inside = 18064109652, pi = 3.141584287304347800
20250627071754EEST rounds = 24000000000, inside = 18849534337, pi = 3.141589056166666616
20250627093451EEST rounds = 25000000000, inside = 19634930768, pi = 3.141588922880000023
20250627115247EEST rounds = 26000000000, inside = 20420332241, pi = 3.141589575538461521
20250627144326EEST rounds = 27000000000, inside = 21205728146, pi = 3.141589354962962766