Sudokues everywhere: summer sudokues, new hardest steps 13 sudoku found, revisiting db8: db8 list on harder sudokues by digits and by steps, db8 source, trying to find pi using pseudoressu pseudo random bit generator

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

Published
Categorized as muuta

Leave a comment