Sudokues everywhere: summer sudokues, new hardest steps 13 sudoku found, revisiting db8: db8 list on harder sudokues by digits and by steps, db8 source, db8 string pattern matching, 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. Toiset kymmenen lahjoitusta ostaisi koodausvissyt..

Kiitokset lahjoituksestasi.

Edellinen artikkelini (https://moijari.com/?p=1874) oli mielestäni paras tähän asti. Siinä viimeisteltiin ressu satunnaisbittigeneraattori, tutkittiin sen satunnaisuutta, tehtiin sille liitännäisrutiineja: pseudoressu_bytes, ressutwist_bytes, stream_bytes, urandom_bytes. siinä korjattiin pari bugia ressusta (+2-bugi ja bad for randomness bugi), ja metsästettiin bugia exfat:ista. artikkelissa oli sudoku loppukevennys ja ensimmäinen versio db8:sta. Lisäksi siinä tehtiin komentorivi ohjelma newressu kaiken satunnaisuuden arvontaan.

Löysin uuden vaikean steps 13 sudokun:

    A   B   C   D   E   F   G   H   I
  +-----------+-----------+-----------+
A |           | 9       8 |         1 |
B |           |     2     |     4   3 |
C |           |     1     |     6   5 |
  +-----------+-----------+-----------+
D |         9 |     3   6 | 7         |
E |           |           |           |
F |         5 |           |     1   2 |
  +-----------+-----------+-----------+
G | 9   4   1 |     5     |     2     |
H |     2   8 |           |           |
I | 6         |           |     9     |
  +-----------+-----------+-----------+
  s:1 gu:93 st:13 ro:2 clues:25

Sitten sudokusarja kesäksi: kopi pastaa nämä tekstinkäsittelyyn (esimerkiksi libre office) ja esikatsele ja muuta fonttikokoa ja sarakkeita haluamallasi tavalla ja tulosta. Voit myös joutua lisäämään tyhjiä rivejä sudokujen väliin.

Lisää sudokuja löytyy edelllisestä artikkelista (https://moijari.com/?p=1874.

    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     7     |     1     |     5   6 |
B |     2   9 | 4   8     | 1   3   7 |
C |         1 | 9         | 2       4 |
  +-----------+-----------+-----------+
D | 7         |           | 8   6     |
E |     6   8 | 7   9     | 4   2   3 |
F | 4   1   3 | 6   2     | 5   7   9 |
  +-----------+-----------+-----------+
G |         5 | 8   4     |     1   2 |
H |           |     7     |           |
I |           | 5   3   2 | 6   9   8 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:45
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 7   9   2 | 4       3 |         5 |
B | 4   5   6 | 9   8     |     3     |
C | 8       1 | 2         | 9   6     |
  +-----------+-----------+-----------+
D |         3 |           |           |
E | 5         |     9     |     2   7 |
F | 2   1   7 |         8 |     4   9 |
  +-----------+-----------+-----------+
G | 1   8     | 6   2   9 | 4   7   3 |
H |           |           | 2   5   6 |
I | 6       4 | 5         | 1       8 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:44
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     4   6 |           |     2     |
B | 8   2   7 |           |         3 |
C | 1       3 | 6         | 9       4 |
  +-----------+-----------+-----------+
D | 2   3   1 |     5   7 | 4       6 |
E | 4   7   8 | 1   6     | 3   5   2 |
F | 5       9 |           |     8   1 |
  +-----------+-----------+-----------+
G | 6   1     |     8     |           |
H |           | 7         | 2       8 |
I | 7         | 5   3   4 | 1       9 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:43
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 6   3   7 | 5   2   4 |         8 |
B |     5   8 |     1   3 |         7 |
C |         2 | 7         |     3     |
  +-----------+-----------+-----------+
D |     8     | 9       1 |     5   2 |
E |     1     | 2         |         6 |
F |         5 | 8   7   6 | 1       9 |
  +-----------+-----------+-----------+
G |         3 | 1   8   2 |           |
H |           | 3   5   7 |     6   1 |
I |     7     | 4   6   9 |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:42
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 3         |     4     | 6         |
B | 5   1   2 | 8   6     | 3         |
C | 7   6     |     3     | 1       5 |
  +-----------+-----------+-----------+
D |           |     9   2 | 4         |
E |         5 |     7   1 |     9   3 |
F |           |         4 |     1   6 |
  +-----------+-----------+-----------+
G |     7     | 4   2   6 |     3     |
H | 4         | 9   1     | 7   2     |
I |     2   3 | 7   5   8 |     6     |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:41
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     6     | 5   1   3 | 2   8   7 |
B |     1     |     7   9 |         3 |
C | 5   7     | 6         | 9   1   4 |
  +-----------+-----------+-----------+
D |     8   5 | 1         | 4         |
E | 7   3     |           |           |
F | 2       4 |     3     |         1 |
  +-----------+-----------+-----------+
G |         6 | 3         | 7       8 |
H | 3   4   7 | 2       8 | 1   5     |
I |           |         6 | 3         |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:40
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           | 2   1     | 3   8     |
B | 3   2   6 |     8   9 | 4         |
C | 8         |           |     2   6 |
  +-----------+-----------+-----------+
D | 7   4   8 |     5   3 |           |
E | 2   3     |     9   7 | 1       8 |
F |           |     4   2 | 7         |
  +-----------+-----------+-----------+
G | 5   8     | 4   7     | 6         |
H | 1       2 |     6     | 8   3     |
I |     9     |         8 |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:39
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 4   6     | 3       9 | 1         |
B |         2 |           |         6 |
C |         8 |         2 | 4   3   9 |
  +-----------+-----------+-----------+
D |     1     | 8   9   5 | 2   7   4 |
E |     4     | 2       3 | 9         |
F |           |         7 |     6   5 |
  +-----------+-----------+-----------+
G |     7     |           |     4   2 |
H |     3     |     2   6 |     1     |
I |     2   6 |         4 | 8   9     |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:38
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     5   9 |           |     4   2 |
B | 7   3   1 |         2 | 9       8 |
C |     6   4 |     8   7 |           |
  +-----------+-----------+-----------+
D | 6         |         9 |     8     |
E | 5   2     |         1 |         9 |
F |           | 7   6   5 |     3   4 |
  +-----------+-----------+-----------+
G |           |           | 5   9     |
H | 4   7     |     9   6 |         3 |
I | 9   1     | 3   7     |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:37
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |         7 | 1   3     |           |
B | 3         | 5       9 | 2   8   1 |
C |     1   5 | 2         |     3   6 |
  +-----------+-----------+-----------+
D | 2         |         4 | 9       7 |
E |     6   9 |     1     | 3         |
F | 7         | 9         | 8       4 |
  +-----------+-----------+-----------+
G | 6         |     9   3 |         8 |
H | 1   8     | 7       2 |     9   3 |
I |           |           |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:36
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     9   1 | 3         |           |
B |     3     | 1         |         2 |
C |           | 7       4 |           |
  +-----------+-----------+-----------+
D | 6   4   5 | 2       7 |     8   9 |
E |           |           | 7   4   5 |
F | 9       7 |           |           |
  +-----------+-----------+-----------+
G | 3   6   2 |         1 | 9   5     |
H |           | 8       3 |           |
I | 8   7   4 |     5   6 | 2       3 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:4 clues:35
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 4   9   8 |     1     | 7   3     |
B | 7         |         9 |         6 |
C |         1 | 7         | 9         |
  +-----------+-----------+-----------+
D |     5     |     9     |     1     |
E |     2     | 5         |           |
F |           | 6       1 | 8   5     |
  +-----------+-----------+-----------+
G |     1   2 |         4 | 5   7     |
H |           |     2   7 | 6         |
I | 9       4 |     6   5 |         1 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:2 clues:34
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     1     |           |           |
B |           | 4   9     |         3 |
C | 3         | 8         |     4   2 |
  +-----------+-----------+-----------+
D |           | 5       6 |     1     |
E |           | 9   3     | 7       6 |
F |     5     |     2     | 4   3     |
  +-----------+-----------+-----------+
G |     2   3 |     4   8 |     9     |
H |     4   5 | 3   7   2 |     6   1 |
I |         6 |           |         4 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:33
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           | 4         |           |
B | 3       2 |           | 7   4     |
C | 4   6     |           |     3   8 |
  +-----------+-----------+-----------+
D |           |     2   4 |     8     |
E |     8     | 1   5     |         9 |
F |           |         9 |           |
  +-----------+-----------+-----------+
G | 8   1   3 |     7   2 | 6       4 |
H | 6       9 |         1 |     7     |
I |     5     |     4   8 | 1         |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:32
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |         6 |           |           |
B |           | 2       7 | 5   8     |
C | 1         | 9         | 6       3 |
  +-----------+-----------+-----------+
D | 4         |     7   2 |           |
E | 6         |           |     1     |
F | 7   8   2 |     5   6 | 3         |
  +-----------+-----------+-----------+
G |         3 | 7       9 | 1       8 |
H |     7     |     4     |           |
I |     6     |         5 |     4   2 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:31
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 3         | 4       9 |           |
B |     7     |     5     |     2     |
C |           |     8   2 |           |
  +-----------+-----------+-----------+
D |     8     | 9         |           |
E | 4   2   1 |           |         9 |
F |     9     | 3         | 1   6     |
  +-----------+-----------+-----------+
G | 8   1   6 |     9   5 | 4         |
H |     3   7 |     6     |     8     |
I |           |     3     |         1 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:3 clues:30
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 8   1     |         7 |     5   9 |
B | 9   4   2 |           |         7 |
C |           | 8         |           |
  +-----------+-----------+-----------+
D | 5   3     |         6 | 9         |
E |           |     7   3 | 6         |
F |           | 2   5     |     4     |
  +-----------+-----------+-----------+
G |     9     |           | 5   3   1 |
H |           |         4 | 2         |
I |     2   5 |         9 |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:4 clues:29
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |     3     |           |         4 |
B | 4   1     |         9 |           |
C |           | 8   3     |           |
  +-----------+-----------+-----------+
D |     2     | 7   6   5 |     4     |
E |           |           | 6         |
F | 9         |           | 7   8     |
  +-----------+-----------+-----------+
G |     8   6 | 5   1     |     9     |
H | 1   4     |     7   6 | 3         |
I | 3         |         2 |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:6 clues:28
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           |     3     |           |
B |           |           | 9   6   5 |
C |     4     |         5 |           |
  +-----------+-----------+-----------+
D | 5         | 1         | 2       7 |
E |           |     7   4 |           |
F |         9 |           |     1     |
  +-----------+-----------+-----------+
G | 9         |           |           |
H |     6   1 | 7         |     3     |
I | 3   7   2 | 9   8     | 6   5   4 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:4 clues:27
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |         9 | 1         |         2 |
B |     7     | 3         |     9   6 |
C |           | 6   7     | 4   8     |
  +-----------+-----------+-----------+
D |     9   2 |         3 |           |
E |           |     5     |           |
F |     1     |           | 7       4 |
  +-----------+-----------+-----------+
G | 8         | 7         |         5 |
H |         6 | 8       1 |           |
I |           |     9     |     4     |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:5 clues:26
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |         1 | 2       4 | 8   5     |
B | 3       2 |           |           |
C |     6     |         3 | 2       7 |
  +-----------+-----------+-----------+
D | 2         |     4     |           |
E | 9   8     |         5 | 3         |
F |     5     |     9     |           |
  +-----------+-----------+-----------+
G |           |         6 |           |
H |     3     |           | 7         |
I | 5         |         7 |     6     |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:5 clues:25
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A | 7         |         3 | 2       8 |
B | 8         |         6 |     5     |
C |           |         1 |           |
  +-----------+-----------+-----------+
D | 4         |           |     7     |
E |           |           |     2     |
F |     6   9 |     8     |         1 |
  +-----------+-----------+-----------+
G |           |         4 |           |
H | 6   9     |           |         7 |
I |     3     | 6       7 |     4   9 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:5 clues:24
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           | 6   3     |     7     |
B |           |           |     6   5 |
C |     2     |     8   9 |           |
  +-----------+-----------+-----------+
D |     4   1 | 8   5     |           |
E |     6     |           | 7         |
F |           |           |     8     |
  +-----------+-----------+-----------+
G |           |           | 5       1 |
H | 3         |     1     |           |
I |         8 | 5         |     2   9 |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:7 clues:23
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           | 6       8 |         5 |
B |           |           |           |
C | 2         |     1     | 7         |
  +-----------+-----------+-----------+
D |           |         5 | 4         |
E |         3 |         9 |     6     |
F | 4         |     8     |           |
  +-----------+-----------+-----------+
G |     9     |     7     | 8   4   1 |
H |     6     |         4 |     9     |
I |         8 |           |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:5 clues:22
    A   B   C   D   E   F   G   H   I  
  +-----------+-----------+-----------+
A |           | 1   5     |           |
B |         7 |           |     5     |
C | 2         |           |           |
  +-----------+-----------+-----------+
D |         6 |         7 |           |
E | 8         |           | 3         |
F |           |         3 | 9       2 |
  +-----------+-----------+-----------+
G |           | 3         |         5 |
H | 9         |     7     |     1   3 |
I |     8   4 |     2     |           |
  +-----------+-----------+-----------+
  s:0 gu:0 st:0 ro:5 clues:21

Tässä vielä esittely edellisen raportin mielestäni tärkeimmästä asiasta db8:sta, lista tähän asti llöydetyistä sudokujen vaikeusasteista (steps luku): aiemmissa steps 12 sudokuissa oli 26 tai 24 vihjettä..

$ ./db8
DB8 version 0.04 ©
skk>digits,steps
query:digits,steps
query2:'digits', 'steps'
201 rows.
0 'digits' = "19", 'steps' = "0"
1 'digits' = "20", 'steps' = "0"
2 'digits' = "21", 'steps' = "0"
3 'digits' = "21", 'steps' = "2"
4 'digits' = "21", 'steps' = "3"
5 'digits' = "21", 'steps' = "4"
6 'digits' = "22", 'steps' = "0"
7 'digits' = "22", 'steps' = "1"
8 'digits' = "22", 'steps' = "2"
9 'digits' = "22", 'steps' = "3"
10 'digits' = "22", 'steps' = "4"
11 'digits' = "22", 'steps' = "5"
12 'digits' = "22", 'steps' = "6"
13 'digits' = "22", 'steps' = "8"
14 'digits' = "23", 'steps' = "0"
15 'digits' = "23", 'steps' = "1"
16 'digits' = "23", 'steps' = "2"
17 'digits' = "23", 'steps' = "3"
18 'digits' = "23", 'steps' = "4"
19 'digits' = "23", 'steps' = "5"
20 'digits' = "23", 'steps' = "6"
21 'digits' = "23", 'steps' = "7"
22 'digits' = "23", 'steps' = "8"
23 'digits' = "23", 'steps' = "9"
24 'digits' = "23", 'steps' = "10"
25 'digits' = "23", 'steps' = "11"
26 'digits' = "24", 'steps' = "0"
27 'digits' = "24", 'steps' = "1"
28 'digits' = "24", 'steps' = "2"
29 'digits' = "24", 'steps' = "3"
30 'digits' = "24", 'steps' = "4"
31 'digits' = "24", 'steps' = "5"
32 'digits' = "24", 'steps' = "6"
33 'digits' = "24", 'steps' = "7"
34 'digits' = "24", 'steps' = "8"
35 'digits' = "24", 'steps' = "9"
36 'digits' = "24", 'steps' = "10"
37 'digits' = "24", 'steps' = "11"
38 'digits' = "24", 'steps' = "12"
39 'digits' = "25", 'steps' = "0"
40 'digits' = "25", 'steps' = "1"
41 'digits' = "25", 'steps' = "2"
42 'digits' = "25", 'steps' = "3"
43 'digits' = "25", 'steps' = "4"
44 'digits' = "25", 'steps' = "5"
45 'digits' = "25", 'steps' = "6"
46 'digits' = "25", 'steps' = "7"
47 'digits' = "25", 'steps' = "8"
48 'digits' = "25", 'steps' = "9"
49 'digits' = "25", 'steps' = "10"
50 'digits' = "25", 'steps' = "11"
51 'digits' = "25", 'steps' = "13"
52 'digits' = "26", 'steps' = "0"
53 'digits' = "26", 'steps' = "1"
54 'digits' = "26", 'steps' = "2"
55 'digits' = "26", 'steps' = "3"
56 'digits' = "26", 'steps' = "4"
57 'digits' = "26", 'steps' = "5"
58 'digits' = "26", 'steps' = "6"
59 'digits' = "26", 'steps' = "7"
60 'digits' = "26", 'steps' = "8"
61 'digits' = "26", 'steps' = "9"
62 'digits' = "26", 'steps' = "10"
63 'digits' = "26", 'steps' = "11"
64 'digits' = "26", 'steps' = "12"
65 'digits' = "27", 'steps' = "0"
66 'digits' = "27", 'steps' = "1"
67 'digits' = "27", 'steps' = "2"
68 'digits' = "27", 'steps' = "3"
69 'digits' = "27", 'steps' = "4"
70 'digits' = "27", 'steps' = "5"
71 'digits' = "27", 'steps' = "6"
72 'digits' = "27", 'steps' = "7"
73 'digits' = "27", 'steps' = "8"
74 'digits' = "27", 'steps' = "9"
75 'digits' = "27", 'steps' = "10"
76 'digits' = "27", 'steps' = "11"
77 'digits' = "28", 'steps' = "0"
78 'digits' = "28", 'steps' = "1"
79 'digits' = "28", 'steps' = "2"
80 'digits' = "28", 'steps' = "3"
81 'digits' = "28", 'steps' = "4"
82 'digits' = "28", 'steps' = "5"
83 'digits' = "28", 'steps' = "6"
84 'digits' = "28", 'steps' = "7"
85 'digits' = "28", 'steps' = "8"
86 'digits' = "28", 'steps' = "9"
87 'digits' = "28", 'steps' = "10"
88 'digits' = "29", 'steps' = "0"
89 'digits' = "29", 'steps' = "1"
90 'digits' = "29", 'steps' = "2"
91 'digits' = "29", 'steps' = "3"
92 'digits' = "29", 'steps' = "4"
93 'digits' = "29", 'steps' = "5"
94 'digits' = "29", 'steps' = "6"
95 'digits' = "29", 'steps' = "7"
96 'digits' = "29", 'steps' = "8"
97 'digits' = "29", 'steps' = "9"
98 'digits' = "29", 'steps' = "10"
99 'digits' = "30", 'steps' = "0"
100 'digits' = "30", 'steps' = "1"
101 'digits' = "30", 'steps' = "2"
102 'digits' = "30", 'steps' = "3"
103 'digits' = "30", 'steps' = "4"
104 'digits' = "30", 'steps' = "5"
105 'digits' = "30", 'steps' = "6"
106 'digits' = "30", 'steps' = "7"
107 'digits' = "30", 'steps' = "8"
108 'digits' = "30", 'steps' = "9"
109 'digits' = "30", 'steps' = "10"
110 'digits' = "31", 'steps' = "0"
111 'digits' = "31", 'steps' = "1"
112 'digits' = "31", 'steps' = "2"
113 'digits' = "31", 'steps' = "3"
114 'digits' = "31", 'steps' = "4"
115 'digits' = "31", 'steps' = "5"
116 'digits' = "31", 'steps' = "6"
117 'digits' = "31", 'steps' = "7"
118 'digits' = "31", 'steps' = "8"
119 'digits' = "32", 'steps' = "0"
120 'digits' = "32", 'steps' = "1"
121 'digits' = "32", 'steps' = "2"
122 'digits' = "32", 'steps' = "3"
123 'digits' = "32", 'steps' = "4"
124 'digits' = "32", 'steps' = "5"
125 'digits' = "32", 'steps' = "6"
126 'digits' = "32", 'steps' = "7"
127 'digits' = "32", 'steps' = "8"
128 'digits' = "33", 'steps' = "0"
129 'digits' = "33", 'steps' = "1"
130 'digits' = "33", 'steps' = "2"
131 'digits' = "33", 'steps' = "3"
132 'digits' = "33", 'steps' = "4"
133 'digits' = "33", 'steps' = "5"
134 'digits' = "33", 'steps' = "6"
135 'digits' = "34", 'steps' = "0"
136 'digits' = "34", 'steps' = "1"
137 'digits' = "34", 'steps' = "2"
138 'digits' = "34", 'steps' = "3"
139 'digits' = "34", 'steps' = "4"
140 'digits' = "34", 'steps' = "5"
141 'digits' = "34", 'steps' = "6"
142 'digits' = "35", 'steps' = "0"
143 'digits' = "35", 'steps' = "1"
144 'digits' = "35", 'steps' = "2"
145 'digits' = "35", 'steps' = "3"
146 'digits' = "35", 'steps' = "4"
147 'digits' = "35", 'steps' = "5"
148 'digits' = "36", 'steps' = "0"
149 'digits' = "36", 'steps' = "1"
150 'digits' = "36", 'steps' = "2"
151 'digits' = "36", 'steps' = "3"
152 'digits' = "36", 'steps' = "4"
153 'digits' = "36", 'steps' = "5"
154 'digits' = "36", 'steps' = "6"
155 'digits' = "37", 'steps' = "0"
156 'digits' = "37", 'steps' = "1"
157 'digits' = "37", 'steps' = "2"
158 'digits' = "37", 'steps' = "3"
159 'digits' = "37", 'steps' = "5"
160 'digits' = "38", 'steps' = "0"
161 'digits' = "38", 'steps' = "1"
162 'digits' = "38", 'steps' = "2"
163 'digits' = "38", 'steps' = "3"
164 'digits' = "38", 'steps' = "4"
165 'digits' = "39", 'steps' = "0"
166 'digits' = "39", 'steps' = "1"
167 'digits' = "39", 'steps' = "2"
168 'digits' = "39", 'steps' = "3"
169 'digits' = "39", 'steps' = "4"
170 'digits' = "40", 'steps' = "0"
171 'digits' = "40", 'steps' = "1"
172 'digits' = "40", 'steps' = "2"
173 'digits' = "40", 'steps' = "3"
174 'digits' = "41", 'steps' = "0"
175 'digits' = "41", 'steps' = "1"
176 'digits' = "41", 'steps' = "2"
177 'digits' = "41", 'steps' = "3"
178 'digits' = "42", 'steps' = "0"
179 'digits' = "42", 'steps' = "1"
180 'digits' = "42", 'steps' = "2"
181 'digits' = "43", 'steps' = "0"
182 'digits' = "43", 'steps' = "1"
183 'digits' = "44", 'steps' = "0"
184 'digits' = "44", 'steps' = "1"
185 'digits' = "44", 'steps' = "2"
186 'digits' = "45", 'steps' = "0"
187 'digits' = "46", 'steps' = "0"
188 'digits' = "46", 'steps' = "1"
189 'digits' = "47", 'steps' = "0"
190 'digits' = "47", 'steps' = "1"
191 'digits' = "48", 'steps' = "0"
192 'digits' = "49", 'steps' = "0"
193 'digits' = "50", 'steps' = "0"
194 'digits' = "51", 'steps' = "0"
195 'digits' = "52", 'steps' = "0"
196 'digits' = "53", 'steps' = "0"
197 'digits' = "54", 'steps' = "0"
198 'digits' = "55", 'steps' = "0"
199 'digits' = "56", 'steps' = "0"
200 'digits' = "57", 'steps' = "0"
skk>exit
$

Sama lista askelittain (steps) vihjeittäin (digits)

$ ./db8
DB8 version 0.04 ©
skk>steps,digits
query:steps,digits
query2:'steps', 'digits'
201 rows.
0 'steps' = "0", 'digits' = "19"
1 'steps' = "0", 'digits' = "20"
2 'steps' = "0", 'digits' = "21"
3 'steps' = "0", 'digits' = "22"
4 'steps' = "0", 'digits' = "23"
5 'steps' = "0", 'digits' = "24"
6 'steps' = "0", 'digits' = "25"
7 'steps' = "0", 'digits' = "26"
8 'steps' = "0", 'digits' = "27"
9 'steps' = "0", 'digits' = "28"
10 'steps' = "0", 'digits' = "29"
11 'steps' = "0", 'digits' = "30"
12 'steps' = "0", 'digits' = "31"
13 'steps' = "0", 'digits' = "32"
14 'steps' = "0", 'digits' = "33"
15 'steps' = "0", 'digits' = "34"
16 'steps' = "0", 'digits' = "35"
17 'steps' = "0", 'digits' = "36"
18 'steps' = "0", 'digits' = "37"
19 'steps' = "0", 'digits' = "38"
20 'steps' = "0", 'digits' = "39"
21 'steps' = "0", 'digits' = "40"
22 'steps' = "0", 'digits' = "41"
23 'steps' = "0", 'digits' = "42"
24 'steps' = "0", 'digits' = "43"
25 'steps' = "0", 'digits' = "44"
26 'steps' = "0", 'digits' = "45"
27 'steps' = "0", 'digits' = "46"
28 'steps' = "0", 'digits' = "47"
29 'steps' = "0", 'digits' = "48"
30 'steps' = "0", 'digits' = "49"
31 'steps' = "0", 'digits' = "50"
32 'steps' = "0", 'digits' = "51"
33 'steps' = "0", 'digits' = "52"
34 'steps' = "0", 'digits' = "53"
35 'steps' = "0", 'digits' = "54"
36 'steps' = "0", 'digits' = "55"
37 'steps' = "0", 'digits' = "56"
38 'steps' = "0", 'digits' = "57"
39 'steps' = "1", 'digits' = "22"
40 'steps' = "1", 'digits' = "23"
41 'steps' = "1", 'digits' = "24"
42 'steps' = "1", 'digits' = "25"
43 'steps' = "1", 'digits' = "26"
44 'steps' = "1", 'digits' = "27"
45 'steps' = "1", 'digits' = "28"
46 'steps' = "1", 'digits' = "29"
47 'steps' = "1", 'digits' = "30"
48 'steps' = "1", 'digits' = "31"
49 'steps' = "1", 'digits' = "32"
50 'steps' = "1", 'digits' = "33"
51 'steps' = "1", 'digits' = "34"
52 'steps' = "1", 'digits' = "35"
53 'steps' = "1", 'digits' = "36"
54 'steps' = "1", 'digits' = "37"
55 'steps' = "1", 'digits' = "38"
56 'steps' = "1", 'digits' = "39"
57 'steps' = "1", 'digits' = "40"
58 'steps' = "1", 'digits' = "41"
59 'steps' = "1", 'digits' = "42"
60 'steps' = "1", 'digits' = "43"
61 'steps' = "1", 'digits' = "44"
62 'steps' = "1", 'digits' = "46"
63 'steps' = "1", 'digits' = "47"
64 'steps' = "2", 'digits' = "21"
65 'steps' = "2", 'digits' = "22"
66 'steps' = "2", 'digits' = "23"
67 'steps' = "2", 'digits' = "24"
68 'steps' = "2", 'digits' = "25"
69 'steps' = "2", 'digits' = "26"
70 'steps' = "2", 'digits' = "27"
71 'steps' = "2", 'digits' = "28"
72 'steps' = "2", 'digits' = "29"
73 'steps' = "2", 'digits' = "30"
74 'steps' = "2", 'digits' = "31"
75 'steps' = "2", 'digits' = "32"
76 'steps' = "2", 'digits' = "33"
77 'steps' = "2", 'digits' = "34"
78 'steps' = "2", 'digits' = "35"
79 'steps' = "2", 'digits' = "36"
80 'steps' = "2", 'digits' = "37"
81 'steps' = "2", 'digits' = "38"
82 'steps' = "2", 'digits' = "39"
83 'steps' = "2", 'digits' = "40"
84 'steps' = "2", 'digits' = "41"
85 'steps' = "2", 'digits' = "42"
86 'steps' = "2", 'digits' = "44"
87 'steps' = "3", 'digits' = "21"
88 'steps' = "3", 'digits' = "22"
89 'steps' = "3", 'digits' = "23"
90 'steps' = "3", 'digits' = "24"
91 'steps' = "3", 'digits' = "25"
92 'steps' = "3", 'digits' = "26"
93 'steps' = "3", 'digits' = "27"
94 'steps' = "3", 'digits' = "28"
95 'steps' = "3", 'digits' = "29"
96 'steps' = "3", 'digits' = "30"
97 'steps' = "3", 'digits' = "31"
98 'steps' = "3", 'digits' = "32"
99 'steps' = "3", 'digits' = "33"
100 'steps' = "3", 'digits' = "34"
101 'steps' = "3", 'digits' = "35"
102 'steps' = "3", 'digits' = "36"
103 'steps' = "3", 'digits' = "37"
104 'steps' = "3", 'digits' = "38"
105 'steps' = "3", 'digits' = "39"
106 'steps' = "3", 'digits' = "40"
107 'steps' = "3", 'digits' = "41"
108 'steps' = "4", 'digits' = "21"
109 'steps' = "4", 'digits' = "22"
110 'steps' = "4", 'digits' = "23"
111 'steps' = "4", 'digits' = "24"
112 'steps' = "4", 'digits' = "25"
113 'steps' = "4", 'digits' = "26"
114 'steps' = "4", 'digits' = "27"
115 'steps' = "4", 'digits' = "28"
116 'steps' = "4", 'digits' = "29"
117 'steps' = "4", 'digits' = "30"
118 'steps' = "4", 'digits' = "31"
119 'steps' = "4", 'digits' = "32"
120 'steps' = "4", 'digits' = "33"
121 'steps' = "4", 'digits' = "34"
122 'steps' = "4", 'digits' = "35"
123 'steps' = "4", 'digits' = "36"
124 'steps' = "4", 'digits' = "38"
125 'steps' = "4", 'digits' = "39"
126 'steps' = "5", 'digits' = "22"
127 'steps' = "5", 'digits' = "23"
128 'steps' = "5", 'digits' = "24"
129 'steps' = "5", 'digits' = "25"
130 'steps' = "5", 'digits' = "26"
131 'steps' = "5", 'digits' = "27"
132 'steps' = "5", 'digits' = "28"
133 'steps' = "5", 'digits' = "29"
134 'steps' = "5", 'digits' = "30"
135 'steps' = "5", 'digits' = "31"
136 'steps' = "5", 'digits' = "32"
137 'steps' = "5", 'digits' = "33"
138 'steps' = "5", 'digits' = "34"
139 'steps' = "5", 'digits' = "35"
140 'steps' = "5", 'digits' = "36"
141 'steps' = "5", 'digits' = "37"
142 'steps' = "6", 'digits' = "22"
143 'steps' = "6", 'digits' = "23"
144 'steps' = "6", 'digits' = "24"
145 'steps' = "6", 'digits' = "25"
146 'steps' = "6", 'digits' = "26"
147 'steps' = "6", 'digits' = "27"
148 'steps' = "6", 'digits' = "28"
149 'steps' = "6", 'digits' = "29"
150 'steps' = "6", 'digits' = "30"
151 'steps' = "6", 'digits' = "31"
152 'steps' = "6", 'digits' = "32"
153 'steps' = "6", 'digits' = "33"
154 'steps' = "6", 'digits' = "34"
155 'steps' = "6", 'digits' = "36"
156 'steps' = "7", 'digits' = "23"
157 'steps' = "7", 'digits' = "24"
158 'steps' = "7", 'digits' = "25"
159 'steps' = "7", 'digits' = "26"
160 'steps' = "7", 'digits' = "27"
161 'steps' = "7", 'digits' = "28"
162 'steps' = "7", 'digits' = "29"
163 'steps' = "7", 'digits' = "30"
164 'steps' = "7", 'digits' = "31"
165 'steps' = "7", 'digits' = "32"
166 'steps' = "8", 'digits' = "22"
167 'steps' = "8", 'digits' = "23"
168 'steps' = "8", 'digits' = "24"
169 'steps' = "8", 'digits' = "25"
170 'steps' = "8", 'digits' = "26"
171 'steps' = "8", 'digits' = "27"
172 'steps' = "8", 'digits' = "28"
173 'steps' = "8", 'digits' = "29"
174 'steps' = "8", 'digits' = "30"
175 'steps' = "8", 'digits' = "31"
176 'steps' = "8", 'digits' = "32"
177 'steps' = "9", 'digits' = "23"
178 'steps' = "9", 'digits' = "24"
179 'steps' = "9", 'digits' = "25"
180 'steps' = "9", 'digits' = "26"
181 'steps' = "9", 'digits' = "27"
182 'steps' = "9", 'digits' = "28"
183 'steps' = "9", 'digits' = "29"
184 'steps' = "9", 'digits' = "30"
185 'steps' = "10", 'digits' = "23"
186 'steps' = "10", 'digits' = "24"
187 'steps' = "10", 'digits' = "25"
188 'steps' = "10", 'digits' = "26"
189 'steps' = "10", 'digits' = "27"
190 'steps' = "10", 'digits' = "28"
191 'steps' = "10", 'digits' = "29"
192 'steps' = "10", 'digits' = "30"
193 'steps' = "11", 'digits' = "23"
194 'steps' = "11", 'digits' = "24"
195 'steps' = "11", 'digits' = "25"
196 'steps' = "11", 'digits' = "26"
197 'steps' = "11", 'digits' = "27"
198 'steps' = "12", 'digits' = "24"
199 'steps' = "12", 'digits' = "26"
200 'steps' = "13", 'digits' = "25"
skk>exit
$

Seuraavassa desimaaliviisas merkkijonojen vertailu db8:in:

static long db8_atol_dec(unsigned char **p, int *decimals) // JariK 2025
{
  int count = 0, decimals2 = 0;
  long num = 0;

  while(**p == '0')
    (*p)++;
  
  while(isdigit(**p) && count < 18) { // calculate 19 first digits
    num = num * 10 + (**p - '0');
    //more_printf(stdout,"%ld\n", num);
    (*p)++;
    count++;
  }
  if(**p == '.') {
    (*p)++;
    while(isdigit(**p) && count < 18) { // calculate 19 first digits
      num = num * 10 + (**p - '0');
      //more_printf(stdout,"%ld\n", num);
      (*p)++;
      count++;
      decimals2++;
    }
  }
  if(decimals != NULL)
    *decimals = decimals2;
  
  while(isdigit(**p)) { // skip rest
    (*p)++;
  }
  return(num);
}

static long db8_strcmp_numdec(unsigned char *p, unsigned char *q) // JariK 2025
{
  int dec1, dec2;
  long num1, num2;
  
  for(;;) {
    //more_printf(stdout,"p:%s, q:%s\n", p, q);
    if(isdigit(*p) && isdigit(*q)) {
      num1 = db8_atol_dec(&p, &dec1);
      num2 = db8_atol_dec(&q, &dec2);
      if(dec2 > dec1)
	num1 *= (int) pow((double) 10, (double) dec2-dec1);
      else if(dec1 > dec2)
	num2 *= (int) pow((double) 10, (double) dec1-dec2);
	
      if(num1 - num2 != 0)
	return(num1 - num2);
    } else if(*p - *q != 0) {
      return(*p - *q);
    } else {
      if(*p == '\0' || *q == '\0')
	break;
      p++;
      q++;
    }
  }
  return(0);
}

Ja uusi koodi merkkijonojen vertailuun. Tämä tekee simppeliä merkkijonojen matsäilyä huomaten ‘*’ ja ‘?’ merkkijonot. Tähti korvaa yhden tai useamman merkin ja kysymysmerkki korvaa yhden merkin: Koodi on vielä vaiheessa, db8:n käyttökoodi puuttuu vielä.

#define aDEBUG92 2
#define DEBUG96 2

int my_match(unsigned char *pattern, unsigned char *string)
{
  unsigned char *p, *s;

  p = pattern;
  s = string;

#ifdef DEBUG92
  more_printf(stdout,"\npattern=%s",p);
  more_printf(stdout,", string=%s",s);
#endif

  while(*p != '\0') {
    if(*p == '*') { // one or many characters
      if(*s == '\0')
	return(0);
      while(*s != '\0') {
	if(my_match(p + 1, ++s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(*s == '\0')
	return(0);
      s++;
    } else if(*p == *s) {
      s++;
    } else
      return(0);
    p++;
  }
  if(*s == '\0')
    return(1);
  else
    return(0);
}

int my_match_test(unsigned char *pattern, unsigned char *string)
{
  int retval;
  static unsigned int testid = 0;

  more_printf(stdout,"%d", testid++);

  more_printf(stdout," pattern=%s", pattern);
  more_printf(stdout,", string=%s", string);

  retval = my_match(pattern, string);
  if(retval)
    more_printf(stdout," match!");
  else
    more_printf(stdout," no match!");

  more_printf(stdout,"\n");
  
  return(retval);
}

int main(int argc, char *argv[])
{
...
#ifdef DEBUG96

  if(more)
    more_init(); // adjust thee screensize
  
  my_match_test("abcdef","abcdef");
  my_match_test("abc*def","abcdefdef");
  my_match_test("abc*def","abcdefdefdef");
  my_match_test("abc*","abcdef");
  my_match_test("*def","abcdef");
  my_match_test("*cd*","abcdef");
  my_match_test("ab??ef","abcdef");
  my_match_test("??def","abcdef");
  my_match_test("???def","abcdef");
  my_match_test("*gh*","abcdef");
  my_match_test("abcdef","abcgef");
  my_match_test("?*def","abcdef");
  my_match_test("?*def","abcdefg");
  my_match_test("?b","ab");
  my_match_test("a?","ab");
  my_match_test("a?c","abc");
  my_match_test("a??d","abcd");
  my_match_test("a??*d","abcd");
  my_match_test("?b","ac");
#endif
...
}

Seuraavassa db8:n alun merkkijonojen vertailu testituloste:

$ ./db8
0 pattern=abcdef, string=abcdef match!
1 pattern=abc*def, string=abcdefdef match!
2 pattern=abc*def, string=abcdefdefdef match!
3 pattern=abc*, string=abcdef match!
4 pattern=*def, string=abcdef match!
5 pattern=*cd*, string=abcdef match!
6 pattern=ab??ef, string=abcdef match!
7 pattern=??def, string=abcdef no match!
8 pattern=???def, string=abcdef match!
9 pattern=*gh*, string=abcdef no match!
10 pattern=abcdef, string=abcgef no match!
11 pattern=?*def, string=abcdef match!
12 pattern=?*def, string=abcdefg no match!
13 pattern=?b, string=ab match!
14 pattern=a?, string=ab match!
15 pattern=a?c, string=abc match!
16 pattern=a??d, string=abcd match!
17 pattern=a??*d, string=abcd no match!
18 pattern=?b, string=ac no match!
DB8 version 0.04 ©
skk>exit

Db8 tarvitsee merkkijonojen mätsäilystä version jossa merkkijonojen pituus toimitetaan erillisissä kentissä:

int my_match_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
  while(plen > 0) {
#ifdef DEBUG92
    more_printf(stdout,"\nplen=%d", plen);
    more_printf(stdout,", p=");
    db8_fputs_len(stdout, plen, p);
    more_printf(stdout,", slen=%d", slen);
    more_printf(stdout,", s=");
    db8_fputs_len(stdout, slen, s);
#endif

    if(*p == '*') { // one or many characters
      if(slen == 0)
	return(0);
      while(slen > 0) {
	s++;
	slen--;
	if(my_match_len(plen - 1, p + 1, slen, s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(slen == 0)
	return(0);
      s++;
      slen--;
    } else if(*p == *s) {
      s++;
      slen--;
    } else
      return(0);
    p++;
    plen--;
  }
  if(slen == 0)
    return(1);
  else
    return(0);
}

void db8_fputs_len(FILE *fp1, unsigned int slen, unsigned char *s)
{
  while(slen-- > 0)
    fputc(*s++, fp1);
}

Edellinen nimettynä db8:a varten:

int db8_match_pattern_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
  while(plen > 0) {
#ifdef DEBUG92
    more_printf(stdout,"\nplen=%d", plen);
    more_printf(stdout,", p=");
    db8_fputs_len(stdout, plen, p);
    more_printf(stdout,", slen=%d", slen);
    more_printf(stdout,", s=");
    db8_fputs_len(stdout, slen, s);
#endif

    if(*p == '*') { // one or many characters
      if(slen == 0)
	return(0);
      while(slen > 0) {
	s++;
	slen--;
	if(db8_match_pattern_len(plen - 1, p + 1, slen, s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(slen == 0)
	return(0);
      s++;
      slen--;
    } else if(*p == *s) {
      s++;
      slen--;
    } else
      return(0);
    p++;
    plen--;
  }
  if(slen == 0)
    return(1);
  else
    return(0);
}

Ja uuden merkkijonomätsäilyn käytöt:

static int db8_match(unsigned char *set, unsigned char *match)
{
  int ok, ok2, first1, first2;
  
  unsigned char *s, *m;

  unsigned int namelen, valuelen;
  unsigned char *name, *value;
  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8_match: match:%s", match);
    fprintf(stdout,", set:%s", set);
    fflush(stdout);
  }
#endif
  
#ifdef DEBUG48
  fprintf(stdout,"db8_match: match:%s", match);
  fprintf(stdout,", set:%s", set);
  fflush(stdout);
#endif
  
  m = match;
  first2 = 1;
  ok = 1;
  while(*m != '\0') {
    db8_skipwhite(&m);
    if(!first2) {
      if(*m == ',')
	m++;
      db8_skipwhite(&m);
    }
    first2 = 0;
    
    db8_get_element2(&namelen, &name, &valuelen, &value, &m); // match
    db8_skipwhite(&m);

    s = set;
    first1 = 1;
    ok2 = 0;
    while(*s != '\0') {
      db8_skipwhite(&s);
      if(!first1) {
	if(*s == ',')
	  s++;
	db8_skipwhite(&s);
      }
      first1 = 0;

      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s); // set
      db8_skipwhite(&s);
#ifdef OLD1
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || (valuelen == valuelen2 && !strncmp(value2, value, valuelen))) ) {
	ok2 = 1;
	break;
      }
#endif
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
	ok2 = 1;
	break;
      }
    }
    if(ok2 == 0)
      ok = 0;
  }

#ifdef DEBUG48
  fprintf(stdout,", ok:%d", ok);
  fprintf(stdout,"\n");
  fflush(stdout);
#endif
  
#ifdef DEBUG5
  fprintf(stdout,", ok:%d", ok);
  fprintf(stdout,"\n");
  fflush(stdout);
#endif

  return(ok);
}

#define aDEBUG52 2

static void db8_project(unsigned char **project, unsigned char *set, unsigned char *query)
{
  unsigned char *q, *s;

  unsigned int namelen, valuelen;
  unsigned char *name, *value;
  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

#ifdef DEBUG52
  more_printf(stdout,"db8_project: ");
  more_printf(stdout,", query:%s", query);
  more_printf(stdout,", set:%s\n", set);
  fflush(stdout); fflush(stdout);
#endif

#ifdef DEBUG52
  more_printf(stdout,"db8_project: ");
  more_printf(stdout," set:%s\n", set);
#endif
  
  if(*project != NULL)
    *(project[0]) = '\0';
  
  q = query;
  while(*q != '\0') {
    db8_skipwhite(&q);
    db8_get_element2(&namelen, &name, &valuelen, &value, &q);
    db8_skipwhite(&q);
    if(*q == ',') {
      q++;
      db8_skipwhite(&q);
    }

    s = set;
    while(*s != '\0') {
      db8_skipwhite(&s);
      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s);
      db8_skipwhite(&s);
      if(*s == ',') {
	s++;
	db8_skipwhite(&s);
      }

#ifdef OLD1
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
#endif
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
#ifdef DEBUG52
	more_printf(stdout,"db8_project: ");
	more_printf(stdout,"'%.*s'", namelen, name);
	more_printf(stdout," = \"%.*s\"", valuelen2, value2);
	more_printf(stdout,"\n");
#endif
	db8_put(project, namelen, name, valuelen2, value2);
	
      }
    } // while(*s != '\0'
  } // while(*q != '\0'
#ifdef DEBUG5
  more_printf(stdout,", project:(%s)", *project);
  more_printf(stdout,"\n");
  fflush(stdout);
#endif
}'

Kokeillaan edellistä mätsäillyä:

DB8 version 0.05 ©
skk>steps="1?"
query:steps="1?"
db8_squery(): name:steps(5), value:1?(2)
query2:'steps' = "1?"
4 rows.
0 'steps' = "10"
1 'steps' = "11"
2 'steps' = "12"
3 'steps' = "13"
skk>digits="*5"
query:digits="*5"
db8_squery(): name:digits(6), value:*5(2)
query2:'digits' = "*5"
4 rows.
0 'digits' = "25"
1 'digits' = "35"
2 'digits' = "45"
3 'digits' = "55"
skk>exit

Db8 source db8.h

struct queryheader {
  unsigned char *queryname;
  int flags;
  unsigned char *query;
  unsigned char *match;
  int count;
  int preread;
  unsigned char *cline;
  struct queryheader *next;
  struct queryline *first;
};

struct queryline {
  unsigned int rownum;
  unsigned char *line;
  unsigned int save;
  struct queryline *next;
};

#define DB8_DISTINCT 1
#define DB8_ROWSORT 2

int db8_set_filename(unsigned char *filename);
int db8_set_query(unsigned char *queryname, unsigned char *query);
int db8_set_match(unsigned char *queryname, unsigned char *match);
int db8_get_queryflags(unsigned char *queryname);
int db8_set_queryflags(unsigned char *queryname, int flags);

void db8_put(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value); // 2023 JariK

int db8_get_element(unsigned char *queryname, int row, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
int db8_get_element_current(unsigned char *queryname, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
int db8_get_element_num(unsigned char *queryname, int row, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value);
void db8_dump(unsigned char *queryname);
int db8_put_element(unsigned char *queryname, int row, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value);
int db8_save(unsigned char *queryname);
int db8_save_all();
int db8_clear(unsigned char *queryname);
int db8_clear_all();

void db8_squery(unsigned char *query); // JariK 2025 single
void db8_iquery(); // JariK 2025 interactive

extern int db8_verbose;

Db8 source db8.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include "db8.h"
#include "more.h"

extern unsigned char *procname;
static unsigned char *programname = "DB8 version 0.05 ©";
static unsigned char *copyright = "Copyright (c) 1998-2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";

//#define MAIN 2 // in Makefile
//#define QUERY 2 // in Makefile

int db8_verbose = 0;

unsigned char *db8_set = NULL;

static void db8_skipwhite(unsigned char **p)
{
  while(isblank(**p))
    (*p)++;
}

#define aDEBUG8 2
#define aDEBUG9 2
#define aDEBUG10 2
#define aDEBUG11 2

void db8_get_element2(int *namelen, unsigned char **name, int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
  unsigned char *p;

  p = *p2;
  
  db8_skipwhite(&p);

  *namelen = -1;
  if(*p == '\'') { // name
    p++;
    *namelen = 0;
    *name = p;
    while(*p != '\'' && *p != '\0') {
      p++;
      (*namelen)++;
    }
    if(*p == '\'')
      p++;
  } else
    *name = NULL;

  db8_skipwhite(&p);
  if(*p == '=') {
    p++;
  }

  db8_skipwhite(&p);

  *valuelen = -1;
  if(*p == '\"') { // value
    p++;
    *valuelen = 0;
    *value = p;
    while(*p != '\"' && *p != '\0') {
      p++;
      (*valuelen)++;
    }
    if(*p == '\"')
      p++;
  } else
    *value = NULL;

  db8_skipwhite(&p);

#ifdef DEBUG8
  if(db8_verbose) {
    fprintf(stderr,"db8_get_element2():");
    fprintf(stderr," name:%.*s(%d)", *namelen, *name, *namelen);
    fprintf(stderr,", value:%.*s(%d)", *valuelen, *value, *valuelen);
    fprintf(stderr,", next:%s",p);
    fprintf(stderr,"\n");
    fflush(stderr);
  }
#endif
  
  *p2 = p;
}

#define aDEBUG5 2

int db8_get(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 2023 JariK
{
  int firstelement, retval = 0;
  unsigned char *p;

  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

  if(*set == NULL)
    return(0);
  
  if(namelen == 0)
    namelen = strlen(name);
    
  value[0] = '\0';

  if(*set != NULL) {

    firstelement = 1;
    p = *set;
    
    // read thru elements element by element
    
    while(*p != '\0') {

      db8_skipwhite(&p);

      if(!firstelement) {
	if(*p == ',')
	  p++;
	db8_skipwhite(&p);
      }
            
      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);

      db8_skipwhite(&p);
      
      // we reached equal name
      
      if(namelen == namelen2 && !strncmp(name, name2, namelen)) {
	strncpy(value, value2, valuesize);
	if(valuesize >= valuelen2)
	  value[valuelen2] = '\0';
	else
	  value[valuesize - 1] = '\0';
	retval = strlen(value);
	break;
      }
      firstelement = 0;
    } // end of while(*p != '\0')
  } // end of if(set != NULL)
  return(retval);
}

int db8_get_num(unsigned char **set, unsigned int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 2023 JariK
{
  int firstelement, col2, retval = 0;
  unsigned char *p;

  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

  value[0] = '\0';
  
  if(*set != NULL) {
    firstelement = 1;
    p = *set;
    col2 = 0;
    // read thru elements element by element
    
    while(*p != '\0') {

      db8_skipwhite(&p);

      if(!firstelement) {
	if(*p == ',')
	  p++;
	db8_skipwhite(&p);
      }

      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);

      db8_skipwhite(&p);
      
      // we reached equal name

      if(col2 == col && name != NULL && value != NULL) {

	strncpy(name, name2, namesize);
	if(namesize >= namelen2)
	  name[namelen2] = '\0';
	else
	  name[namesize - 1] = '\0';

	strncpy(value, value2, valuesize);
	if(valuesize >= valuelen2)
	  value[valuelen2] = '\0';
	else
	  value[valuesize - 1] = '\0';

	retval = 1;
	break;
      }
      col2++;
      firstelement = 0;
    } // end of while(*p != '\0')
  } // end of if(set != NULL)
  return(retval);
}

#define aSORTED 2
#define aDEBUG17 2

void db8_put(unsigned char **set, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value) // 2023 JariK
{
  int found = 0, firstelement, lastelement;
  unsigned char *p, *currentelement = NULL;
  unsigned char *thiselement = NULL, *nextelement = NULL;

  if(namelen == 0)
    namelen = strlen(name);
  if(valuelen == 0)
    valuelen = strlen(value);

#ifdef DEBUG5
  fprintf(stdout,"\ndb8_put: oldset:%s", *set);
  if(*set != NULL)
    fprintf(stdout,"(%ld)", strlen(*set));

  fprintf(stdout,", namelen:%d", namelen);
  fprintf(stdout,", name:%.*s", namelen, name);
  fprintf(stdout,", valuelen:%d", valuelen);
  fprintf(stdout,", value:%.*s", valuelen, value);
  fflush(stdout);
#endif

  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

  firstelement = 1;
  lastelement = 0;

  if(*set != NULL && strlen(*set) == 0) {
    lastelement = 1;
    firstelement = 1;
  } else if(*set == NULL) {
    lastelement = 1;
    firstelement = 1;
  } else if(*set != NULL) {

    p = *set;
 
    // read thru elements element by element
    
    while(*p != '\0') {

      db8_skipwhite(&p);
      
      currentelement = p; // save beginning of element

      if(!firstelement) {
	if(*p == ',')
	  p++;
	db8_skipwhite(&p);
      } else {
	if(*p == '\0') {
	  lastelement = 1;
	  break;
	}
      }

      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &p);

      db8_skipwhite(&p);
      
      // we reached equal name
      
      if(namelen == namelen2 &&
	 !strncmp(name, name2, namelen) ) {
	found = 1;
	thiselement = currentelement;
	nextelement = p; // beginning of next element
	break;
      }

#ifdef SORTED

      // we reached greater name

      if(namelen == namelen2 &&
	 strncmp(name, name2, namelen) < 0) { // equal lengths less (aaaa, bbbb)
	thiselement = currentelement;
	nextelement = currentelement;
	break;

      } else {

	// common beginning of strings
	
	int comblen = namelen;
	if(comblen > namelen2)
	  comblen = namelen2;
	
	int cmp = strncmp(name, name2, comblen);
	if((cmp < 0) || // first characters less (aaaa, b)
	   (!cmp && namelen2 > namelen) ) { // first characters equal but string longer (a, aaaa)
	  thiselement = currentelement;
	  nextelement = currentelement;
	  break;
	}
      }
    
#endif
      
      if(*p == '\0')
	lastelement = 1;
  
      firstelement = 0;
    } // end of while(*p != '\0')

  } // end of if(set != NULL)

  // make new element

  long count;
  static long elementsize = 0;
  static unsigned char *element = NULL;
  unsigned char *elementfmt;

  // figure out needed commas
  if(value != NULL) {
    if((firstelement && found) || // first and existing
       (firstelement && lastelement) ) // first element in a new set (first and last)
      elementfmt = "'%.*s' = \"%.*s\""; // --> no commas (first existing or only)
    else if(firstelement) // first and not existing element
      elementfmt = "'%.*s' = \"%.*s\", "; // --> comma in the end (first new)
    else
      elementfmt = ", '%.*s' = \"%.*s\""; // ..> comma in the beginning (other)
  
    count = snprintf(element, elementsize, elementfmt, namelen, name, valuelen, value) + 1;
    if(elementsize < count) {
      elementsize = count;
      if((element = realloc(element, elementsize)) == NULL) {
	fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
	exit(1);
      }
      count = snprintf(element, elementsize, elementfmt, namelen, name, valuelen, value) + 1;
    }
  } else { // else of if(value != NULL

    if((firstelement && found) || // first and existing
       (firstelement && lastelement) ) // first element in a new set (first and last)
      elementfmt = "'%.*s'"; // --> no commas (first existing or only)
    else if(firstelement) // first and not existing element
      elementfmt = "'%.*s', "; // --> comma in the end (first new)
    else
      elementfmt = ", '%.*s'"; // ..> comma in the beginning (other)
  
    count = snprintf(element, elementsize, elementfmt, namelen, name) + 1;
    if(elementsize < count) {
      elementsize = count;
      if((element = realloc(element, elementsize)) == NULL) {
	fprintf(stderr, "%s: realloc(): cannot allocate memory\n", procname);
	exit(1);
      }
      count = snprintf(element, elementsize, elementfmt, namelen, name) + 1;
    } // end of if(elementsize < count
  } // end of if(value != NULL

  // calculate change in length

  long oldcount = 0;
  
  count = 0;
  if(*set != NULL) {
    count += strlen(*set);
    oldcount = count + 1; // + '\0'
  }
  if(found) // change in value only
    count += valuelen - valuelen2; // no punctuation marks
  else
    count += strlen(element);
  count++; // + '\0'

#ifdef DEBUG11
  if(oldcount != count) {
    fprintf(stderr, "old length:%ld %s\n", oldcount, set);
    fflush(stderr);
  }
#endif  

  if(oldcount != count) { // size changed, 

    // reallocate set according to new length

    unsigned char *tempset = *set;
    if((*set = realloc(*set, count)) == NULL) {
      fprintf(stderr,"%s: realloc(): cannot allocate memory\n", procname);
      exit(1);
    }

    // adjust these too
    
    if(thiselement != NULL)
      thiselement = *set + (thiselement - tempset);
    if(nextelement != NULL)
      nextelement = *set + (nextelement - tempset);

    if(tempset == NULL)
      *set[0] = '\0';
  }
  
  // adjust to end of set if not present
  
  if(thiselement == NULL)
    thiselement = *set + strlen(*set);
  if(nextelement == NULL)
    nextelement = *set + strlen(*set);

  // move end of the set

  memmove(thiselement + strlen(element), nextelement, strlen(nextelement) + 1); // end of string too

  // add new element
  
  memmove(thiselement, element, strlen(element));

#ifdef DEBUG11
  if(oldcount != count) {
    fprintf(stderr,"new length:%ld %s\n", count, *set);
    fflush(stderr);
  }
#endif  

#ifdef DEBUG5
  fprintf(stdout,", newset:%s\n", *set);
  fflush(stdout);
#endif
}

unsigned char db8_filename[128];

int db8_set_filename(unsigned char *filename)
{
  FILE *fp1;

#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8: set_filename");
    fprintf(stdout,", filename=%s", filename);
    fprintf(stdout,"\n");
  }
#endif
  
  if((fp1 = fopen(filename, "r"))==NULL) {
    fprintf(stderr,"%s: db8 cannot open file '%s'\n", procname, filename);
    exit(1);
  }
  fclose(fp1);

  strcpy(db8_filename, filename);

  return(0);
}

struct queryheader *firstqueryheader = NULL;

struct queryheader *db8_queryheader(unsigned char *queryname)
{
  struct queryheader **ppqh, *thisqh;

  ppqh = &firstqueryheader;
  while(*ppqh != NULL) {
    if(!strcmp(queryname, (*ppqh)->queryname))
      break;
    ppqh = &((*ppqh)->next);
  }

  if(*ppqh == NULL) { // create new
    thisqh = malloc(sizeof(struct queryheader));
    thisqh->queryname = malloc(strlen(queryname) + 1);
    strcpy(thisqh->queryname, queryname);
    thisqh->flags = 0;
    thisqh->query = NULL;
    thisqh->match = NULL;
    thisqh->count = 0;
    thisqh->preread = 20;
    thisqh->cline = NULL;
    thisqh->next = firstqueryheader;
    thisqh->first = NULL;
    firstqueryheader = thisqh;
  } else { // allready in list
    // remove from list
    thisqh = *ppqh;
    *ppqh = thisqh->next;
    // add back to 1st of list
    thisqh->next = firstqueryheader;
    firstqueryheader = thisqh;
  }
  return(thisqh);
}

int db8_set_query(unsigned char *queryname, unsigned char *query)
{
  struct queryheader *qh;

#ifdef DEBUG5
  fprintf(stdout,"db8: set_query");
  fprintf(stdout,", query:%s", query);
  fprintf(stdout,"\n");
#endif
    
  qh = db8_queryheader(queryname);

  if(qh->query != NULL)
    free(qh->query);

  qh->query = malloc(strlen(query) + 1);
  strcpy(qh->query, query);
  
  return(0);
}

#define aDEBUG42 2

int db8_set_match(unsigned char *queryname, unsigned char *match)
{
  struct queryheader *qh;

#ifdef DEBUG5
  fprintf(stdout,"db8: set_match");
  fprintf(stdout,", match:%s", match);
  fprintf(stdout,"\n");
#endif
#ifdef DEBUG42
  fprintf(stdout,"db8: set_match");
  fprintf(stdout,", match:%s", match);
  fprintf(stdout,"\n");
#endif
    
  qh = db8_queryheader(queryname);

  if(qh->match != NULL)
    free(qh->match);

  qh->match = malloc(strlen(match) + 1);
  strcpy(qh->match, match);
  
  return(0);
}

int db8_get_queryflags(unsigned char *queryname)
{
  struct queryheader *qh;

  qh = db8_queryheader(queryname);

#ifdef DEBUG5
  fprintf(stdout,"db8: get_queryflags");
  fprintf(stdout,", query=%s", queryname);
  fprintf(stdout,", flags=%d", qh->flags);
  fprintf(stdout,"\n");
#endif
  
  
  return(qh->flags);
}

int db8_set_queryflags(unsigned char *queryname, int flags)
{
  struct queryheader *qh;

#ifdef DEBUG5
  fprintf(stdout,"db8: set_queryflags");
  fprintf(stdout,", query=%s", queryname);
  fprintf(stdout,", flags=%d", flags);
  fprintf(stdout,"\n");
#endif
  
  qh = db8_queryheader(queryname);
  qh->flags = flags;
  
  return(0);
}

static struct queryline *db8_lineheader(unsigned char *queryname, int rownum)
{
  int add;
  struct queryheader *qh;
  struct queryline **ppql;

  add = 1;
  qh = db8_queryheader(queryname);
  ppql = &qh->first;
  while(*ppql != NULL) {
    if(rownum == (*ppql)->rownum) { // matching row found
      add = 0; // no need to add new
      break;
    } else if(rownum < (*ppql)->rownum) { // first larger row
      add = 1; // add new before
      break;
    }
    ppql = &((*ppql)->next);
  }
  if(add) {
    struct queryline *thisql;
    thisql = malloc(sizeof(struct queryline));
    thisql->line = NULL;
    thisql->rownum = rownum;
    thisql->save = 0;
    thisql->next = *ppql;
    *ppql = thisql;
  }
  return(*ppql);
}

#define aDEBUG26 2

#define aDEBUG92 2

void db8_fputs_len(FILE *fp1, unsigned int slen, unsigned char *s)
{
  while(slen-- > 0)
    fputc(*s++, fp1);
}

int db8_match_pattern_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
  while(plen > 0) {
#ifdef DEBUG92
    more_printf(stdout,"\nplen=%d", plen);
    more_printf(stdout,", p=");
    db8_fputs_len(stdout, plen, p);
    more_printf(stdout,", slen=%d", slen);
    more_printf(stdout,", s=");
    db8_fputs_len(stdout, slen, s);
#endif

    if(*p == '*') { // one or many characters
      if(slen == 0)
	return(0);
      while(slen > 0) {
	s++;
	slen--;
	if(db8_match_pattern_len(plen - 1, p + 1, slen, s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(slen == 0)
	return(0);
      s++;
      slen--;
    } else if(*p == *s) {
      s++;
      slen--;
    } else
      return(0);
    p++;
    plen--;
  }
  if(slen == 0)
    return(1);
  else
    return(0);
}

#define aDEBUG48 2

static int db8_match(unsigned char *set, unsigned char *match)
{
  int ok, ok2, first1, first2;
  
  unsigned char *s, *m;

  unsigned int namelen, valuelen;
  unsigned char *name, *value;
  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8_match: match:%s", match);
    fprintf(stdout,", set:%s", set);
    fflush(stdout);
  }
#endif
  
#ifdef DEBUG48
  fprintf(stdout,"db8_match: match:%s", match);
  fprintf(stdout,", set:%s", set);
  fflush(stdout);
#endif
  
  m = match;
  first2 = 1;
  ok = 1;
  while(*m != '\0') {
    db8_skipwhite(&m);
    if(!first2) {
      if(*m == ',')
	m++;
      db8_skipwhite(&m);
    }
    first2 = 0;
    
    db8_get_element2(&namelen, &name, &valuelen, &value, &m); // match
    db8_skipwhite(&m);

    s = set;
    first1 = 1;
    ok2 = 0;
    while(*s != '\0') {
      db8_skipwhite(&s);
      if(!first1) {
	if(*s == ',')
	  s++;
	db8_skipwhite(&s);
      }
      first1 = 0;

      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s); // set
      db8_skipwhite(&s);
#ifdef OLD1
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || (valuelen == valuelen2 && !strncmp(value2, value, valuelen))) ) {
	ok2 = 1;
	break;
      }
#endif
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
	ok2 = 1;
	break;
      }
    }
    if(ok2 == 0)
      ok = 0;
  }

#ifdef DEBUG48
  fprintf(stdout,", ok:%d", ok);
  fprintf(stdout,"\n");
  fflush(stdout);
#endif
  
#ifdef DEBUG5
  fprintf(stdout,", ok:%d", ok);
  fprintf(stdout,"\n");
  fflush(stdout);
#endif

  return(ok);
}

static void db8_free_set(unsigned char **set)
{
  if(*set != NULL) {
    free(*set);
    *set = NULL;
  }
}

#define aDEBUG52 2

static void db8_project(unsigned char **project, unsigned char *set, unsigned char *query)
{
  unsigned char *q, *s;

  unsigned int namelen, valuelen;
  unsigned char *name, *value;
  unsigned int namelen2, valuelen2;
  unsigned char *name2, *value2;

#ifdef DEBUG52
  more_printf(stdout,"db8_project: ");
  more_printf(stdout,", query:%s", query);
  more_printf(stdout,", set:%s\n", set);
  fflush(stdout); fflush(stdout);
#endif

#ifdef DEBUG52
  more_printf(stdout,"db8_project: ");
  more_printf(stdout," set:%s\n", set);
#endif
  
  if(*project != NULL)
    *(project[0]) = '\0';
  
  q = query;
  while(*q != '\0') {
    db8_skipwhite(&q);
    db8_get_element2(&namelen, &name, &valuelen, &value, &q);
    db8_skipwhite(&q);
    if(*q == ',') {
      q++;
      db8_skipwhite(&q);
    }

    s = set;
    while(*s != '\0') {
      db8_skipwhite(&s);
      db8_get_element2(&namelen2, &name2, &valuelen2, &value2, &s);
      db8_skipwhite(&s);
      if(*s == ',') {
	s++;
	db8_skipwhite(&s);
      }

#ifdef OLD1
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || (valuelen == valuelen2 && !strncmp(value, value2, valuelen))) ) {
#endif
      if((name != NULL && namelen == namelen2 && !strncmp(name, name2, namelen)) &&
	 (value == NULL || db8_match_pattern_len(valuelen, value, valuelen2, value2) == 1)) {
#ifdef DEBUG52
	more_printf(stdout,"db8_project: ");
	more_printf(stdout,"'%.*s'", namelen, name);
	more_printf(stdout," = \"%.*s\"", valuelen2, value2);
	more_printf(stdout,"\n");
#endif
	db8_put(project, namelen, name, valuelen2, value2);
	
      }
    } // while(*s != '\0'
  } // while(*q != '\0'
#ifdef DEBUG5
  more_printf(stdout,", project:(%s)", *project);
  more_printf(stdout,"\n");
  fflush(stdout);
#endif
}

#define aDEBUG63 2
#define aDEBUG54 2

static unsigned char *db8_fgets(int *stringlen, unsigned char **string, FILE *fp1)
{
  int count, retval, done;
  unsigned char buffer[128];
  unsigned char *buf = *string;

  if(buf != NULL)
    buf[0] = '\0';

  retval = 1;
  done = 0;

  for(;;) {
    if(fgets(buffer, sizeof(buffer), fp1) == NULL) {
      retval = 0;
      break;
    }
    
    if(buffer[strlen(buffer)-1] == '\n') {
      buffer[strlen(buffer)-1] = '\0';
      done = 1;
    }

#ifdef DEBUG54
    fprintf(stdout,"db8_fgets: buffer: %s\n", buffer);
#endif
    count = 0;
    if(buf != NULL)
      count += strlen(buf);
    count += strlen(buffer) + 1;
    
    if(*stringlen < count) {
      unsigned char *prevbuf = buf;
      *stringlen = count;
      buf = realloc(buf, *stringlen);
      if(prevbuf == NULL)
	buf[0] = '\0';
    }
    
    strcat(buf, buffer);

    if(done)
      break;
  }
  *string = buf;

#ifdef DEBUG54
    fprintf(stdout,"db8_fgets: string: %s\n", *string);
#endif
  
#ifdef DEBUG63
  fprintf(stdout,"%s\n", *string);
#endif
  
  if(retval == 0)
    return(NULL);
  else {
    return(*string);
  }
}

#define aDEBUG62 2

static void db8_renumbersets(unsigned char *queryname) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql;
  int rownum;
  
  qh = db8_queryheader(queryname);
  ql = qh->first;
  rownum = 0;
  while(ql != NULL) {
    ql->rownum = rownum;
#ifdef DEBUG62
    more_printf(stdout,"db8_renumbersets:");
    more_printf(stdout," %d:", rownum);
    more_printf(stdout," %s", ql->line);
    more_printf(stdout,"\n");
#endif
    rownum++;
    ql = ql->next;
  }
}

static void db8_countsets(unsigned char *queryname) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql;
  int rows;
  
  qh = db8_queryheader(queryname);
  ql = qh->first;
  rows = 0;
  while(ql != NULL) {
#ifdef DEBUG62
    more_printf(stdout,"db8_countsets:");
    more_printf(stdout," %d:", rows);
    more_printf(stdout," %s", ql->line);
    more_printf(stdout,"\n");
#endif
    rows++;
    ql = ql->next;
  }
  qh->count = rows;
  if(qh->flags)
    more_printf(stdout,"%d rows.\n", rows);
}

#ifdef OLD

static long db8_atol(unsigned char **p, int *length) // JariK 2025
{
  int count = 0;
  long num = 0;

  while(isdigit(**p) && count < 18) { // calculate 19 first digits
    num = num * 10 + (**p - '0');
    //more_printf(stdout,"%ld\n", num);
    (*p)++;
    count++;
  }
  if(length != NULL)
    *length = count;
     
  while(isdigit(**p)) { // skip rest
    (*p)++;
  }
  return(num);
}

#endif

static long db8_atol_dec(unsigned char **p, int *decimals) // JariK 2025
{
  int count = 0, decimals2 = 0;
  long num = 0;

  while(**p == '0')
    (*p)++;
  
  while(isdigit(**p) && count < 18) { // calculate 19 first digits
    num = num * 10 + (**p - '0');
    //more_printf(stdout,"%ld\n", num);
    (*p)++;
    count++;
  }
  if(**p == '.') {
    (*p)++;
    while(isdigit(**p) && count < 18) { // calculate 19 first digits
      num = num * 10 + (**p - '0');
      //more_printf(stdout,"%ld\n", num);
      (*p)++;
      count++;
      decimals2++;
    }
  }
  if(decimals != NULL)
    *decimals = decimals2;
  
  while(isdigit(**p)) { // skip rest
    (*p)++;
  }
  return(num);
}

#ifdef OLD

static long db8_strcmp_num(unsigned char *p, unsigned char *q) // JariK 2025
{
  long num1, num2;

  for(;;) {
    //more_printf(stdout,"p:%s, q:%s\n", p, q);
    if(isdigit(*p) && isdigit(*q)) {
      num1 = db8_atol(&p, NULL);
      num2 = db8_atol(&q, NULL);
      if(num1 - num2 != 0)
	return(num1 - num2);
    } else if(*p - *q != 0) {
      return(*p - *q);
    } else {
      if(*p == '\0' || *q == '\0')
	break;
      p++;
      q++;
    }
  }
  return(0);
}

#endif

#include <math.h>

static long db8_strcmp_numdec(unsigned char *p, unsigned char *q) // JariK 2025
{
  int dec1, dec2;
  long num1, num2;
  
  for(;;) {
    //more_printf(stdout,"p:%s, q:%s\n", p, q);
    if(isdigit(*p) && isdigit(*q)) {
      num1 = db8_atol_dec(&p, &dec1);
      num2 = db8_atol_dec(&q, &dec2);
      if(dec2 > dec1)
	num1 *= (int) pow((double) 10, (double) dec2-dec1);
      else if(dec1 > dec2)
	num2 *= (int) pow((double) 10, (double) dec1-dec2);
	
      if(num1 - num2 != 0)
	return(num1 - num2);
    } else if(*p - *q != 0) {
      return(*p - *q);
    } else {
      if(*p == '\0' || *q == '\0')
	break;
      p++;
      q++;
    }
  }
  return(0);
}

static int db8_matchandproject(unsigned char *queryname, unsigned char *row)
{
  struct queryheader *qh;
  int match;
  unsigned char *project = NULL;
  
  qh = db8_queryheader(queryname);
  match = 0;
  if(qh->match == NULL ||
     strstr(row, qh->match) != NULL)
    match = 1;
  if(match) {
    match = 0;
    if(qh->query == NULL)
      match = 1;
    else if(db8_match(row, qh->query)) {
      db8_free_set(&project);
      db8_project(&project, row, qh->query);
      strcpy(row, project);
      match = 1;
    }
  }
  return(match);
}

#ifdef OLD1

int db8_get_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
  int rownum2, count, match;
  struct queryheader *qh;
  struct queryline *ql, *qline;
  static unsigned char *row = NULL;
  static unsigned int rowlen = 0;
  static unsigned char *project = NULL;
 
  FILE *fp1;
  
  if(namelen == 0)
    namelen = strlen(name);
  
#ifdef DEBUG5
  fprintf(stdout,"db8_get_element");
  fprintf(stdout,", query=%s", queryname);
  fprintf(stdout,", row=%d", rownum);
  fprintf(stdout,", namelen=%u", namelen);
  fprintf(stdout,", name=%s", name);
  fprintf(stdout,", valuesize=%u", valuesize);
  fprintf(stdout,"\n");
#endif
  
  qh = db8_queryheader(queryname);

  ql = qh->first;
  while(ql != NULL) {
    if(rownum == ql->rownum) {
      break;
    } else if(rownum < ql->rownum) {
      ql = NULL;
      break;
    }
    ql = ql->next;
  }
  qline = ql;
  if(ql == NULL) {
    if((fp1 = fopen(db8_filename,"r")) == NULL) {
      fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
      exit(1);
    }
    rownum2 = 0;
    count = 0;
    for(;;) {
      if(db8_fgets(&rowlen, &row, fp1) == NULL)
	break;

#ifdef DEBUG68
      fprintf(stdout,">%s\n", row);
#endif
  
      //if(buffer[strlen(buffer) - 1] == '\n')
      //  buffer[strlen(buffer) - 1] = '\0';
      match = 0;
      if(qh->match == NULL ||
	 strstr(row, qh->match) != NULL)
	match = 1;
      if(match) {
	match = 0;
	if(qh->query == NULL)
	  match = 1;
	else if(db8_match(row, qh->query)) {
	  db8_free_set(&project);
	  db8_project(&project, row, qh->query);
	  strcpy(row, project);
	  fprintf(stdout,"\n====row:%s", row);
	  match = 1;
	}
      }
      if(match) {
	if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
	  ql = db8_lineheader(queryname, rownum2);
	  if((ql->line = malloc(strlen(row) + 1)) == NULL) {
	    fprintf(stderr,"%s: cannot malloc memory\n", procname);
	    exit(1);
	  }
	  strcpy(ql->line, row);
#ifdef DEBUG64
	  fprintf(stdout,"db8_get_element:");
	  fprintf(stdout," rownum:%u", rownum2);
	  fprintf(stdout," row:%s", ql->line);
	  fprintf(stdout,"\n");
#endif
	  if(rownum == rownum2)
	    qline = ql;
	  count++;
	  if(qh->preread == 0 || // no preread
	     count > rownum + qh->preread) // preread enough
	    break;
	}
	rownum2++;
      }
    }
    fclose(fp1);
  }
  if(qline != NULL && qline->line != NULL) {
#ifdef DEBUG69
    fprintf(stdout,"db8_get_element:");
    fprintf(stdout," rownum:%u", rownum);
    fprintf(stdout,", row:%s", qline->line);
#endif
  
    int retval = db8_get(&qline->line, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval); // 2023 JariK
  } else
    return(0);
}

int db8_get_element_num(unsigned char *queryname, int rownum, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
  int rownum2, count, match;
  struct queryheader *qh;
  struct queryline *ql, *qline;
  static unsigned char *row = NULL;
  static unsigned int rowlen = 0;
  static unsigned char *project = NULL;
  FILE *fp1;
  
  if(*namelen == 0)
    *namelen = strlen(name);
  
#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8_get_element_num");
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,", rownum=%d", rownum);
    fprintf(stdout,", col=%d", col);
    fprintf(stdout,", namesize=%u", namesize);
    fprintf(stdout,", valuesize=%u", valuesize);
    fprintf(stdout,"\n");
  }
#endif
  
  qh = db8_queryheader(queryname);

  ql = qh->first;
  while(ql != NULL) {
    if(rownum == ql->rownum) {
      break;
    } else if(rownum < ql->rownum) {
      ql = NULL;
      break;
    }
    ql = ql->next;
  }
  qline = ql;
  if(ql == NULL) {
    if((fp1 = fopen(db8_filename,"r")) == NULL) {
      fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
      exit(1);
    }
    rownum2 = 0;
    count = 0;
    for(;;) {
      if(db8_fgets(&rowlen, &row, fp1) == NULL)
	break;

#ifdef DEBUG68
      fprintf(stdout,">%s\n", row);
#endif
  
      match = 0;
      if(qh->match == NULL ||
	 strstr(row, qh->match) != NULL)
	match = 1;
      if(match) {
	match = 0;
	if(qh->query == NULL)
	  match = 1;
	else if(db8_match(row, qh->query)) {
	  db8_project(&project, row, qh->query);
	  strcpy(row, project);
	  match = 1;
	}
      }
      //fprintf(stdout,"match:%d\n",match);
      if(match) {
	if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
	  ql = db8_lineheader(queryname, rownum2);
	  if((ql->line = malloc(strlen(row) + 1)) == NULL) {
	    fprintf(stderr,"%s: cannot malloc memory\n", procname);
	    exit(1);
	  }
	  strcpy(ql->line, row);
#ifdef DEBUG68
	  fprintf(stdout,"=%s\n", row);
#endif
#ifdef DEBUG64
	  fprintf(stdout,"db8_get_element_num:");
	  fprintf(stdout," rownum:%u", rownum2);
	  fprintf(stdout," row:%s", ql->line);
	  fprintf(stdout,"\n");
#endif
	  if(rownum == rownum2)
	    qline = ql;
	  count++;
	  if(qh->preread == 0 || // no preread
	     count > rownum + qh->preread) // preread enough
	    break;
	}
	rownum2++;
      }
    }
    fclose(fp1);
  }
  
  if(qline != NULL && qline->line != NULL) {
#ifdef DEBUG69
    fprintf(stdout,"db8_get_element_num:");
    fprintf(stdout," rownum:%u", rownum);
    fprintf(stdout,", row:%s", qline->line);
#endif
    int retval = db8_get_num(&qline->line, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval);
  } else
    return(0);
}

#endif

#ifdef OLD1

struct queryline *db8_cache_set(unsigned char *queryname, int rownum, unsigned char *set)
{
  struct queryline *ql;
  
#ifdef DEBUG59
  fprintf(stdout,"db8_cache_set:");
  fprintf(stdout," %d", rownum);
  fprintf(stdout," %s", set);
  fprintf(stdout,"\n");
#endif
  
  ql = db8_lineheader(queryname, rownum);
  if((ql->line = malloc(strlen(set) + 1)) == NULL) {
    fprintf(stderr,"%s: cannot malloc memory\n", procname);
    exit(1);
  }
  strcpy(ql->line, set);

  return(ql);
}

struct queryline *db8_cacheset_flags(unsigned char *queryname, int rownum, unsigned char *set) // JariK 2025
{
  int add;
  struct queryheader *qh;
  struct queryline **ppql;
  
  qh = db8_queryheader(queryname);

  add = 1;

  ppql = &qh->first;

  while(*ppql != NULL) {
    if((qh->flags & DB8_DISTINCT) &&
       !strcmp(set, (*ppql)->line) ) {
      add = 0;
      break;
    }
    if((qh->flags & DB8_ROWSORT) &&
       db8_strcmp_numdec(set, (*ppql)->line) < 0) {
      //strcmp(set, (*ppql)->line) < 0) {
      add = 1;
      break;
    }
    ppql = &((*ppql)->next);
  }

  if(add) {
    struct queryline *ql;
    ql = malloc(sizeof(struct queryline));
    if((ql->line = malloc(strlen(set) + 1)) == NULL) {
      fprintf(stderr,"%s: cannot malloc memory\n", procname);
      exit(1);
    }
    strcpy(ql->line, set);
#ifdef DEBUG61
    more_printf(stdout,"db8_cacheset_flags:");
    more_printf(stdout," %d:", rownum);
    more_printf(stdout," %s", ql->line);
    more_printf(stdout,"\n");
#endif
    ql->rownum = 0;
    ql->next = *ppql;
    *ppql = ql;
  }
  
  return(NULL);
}

struct queryline *db8_get_line(unsigned char *queryname, int rownum) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql, *qline;
  static unsigned char *row = NULL;
  static unsigned int rowlen = 0;
  int rownum2, count;
  
  FILE *fp1;
  
  qh = db8_queryheader(queryname);

  ql = qh->first;
  while(ql != NULL) {
    if(rownum == ql->rownum) {
      break;
    } else if(rownum < ql->rownum) {
      ql = NULL;
      break;
    }
    ql = ql->next;
  }

  if(ql == NULL && qh->flags && qh->count != 0)
    return(NULL);

  qline = ql;
  if(ql == NULL) {
    if((fp1 = fopen(db8_filename,"r")) == NULL) {
      fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
      exit(1);
    }
    rownum2 = 0;
    count = 0;
    for(;;) {
      if(db8_fgets(&rowlen, &row, fp1) == NULL)
	break;
      if(db8_matchandproject(queryname, row)) {
	if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
	  if(qh->flags) {
	    ql = db8_cacheset_flags(queryname, rownum2, row);
	  } else {
	    ql = db8_cache_set(queryname, rownum2, row);
	  }
#ifdef DEBUG65
	  more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
	  if(qh->flags) // sorting --> read all
	    continue;
	  if(rownum == rownum2)
	    qline = ql;
	  count++;
	  if(qh->preread == 0 ||
	     count > rownum + qh->preread)
	    break;
	}
	rownum2++;
      }
    }

    fclose(fp1);

    if(qh->flags) {
      db8_renumbersets(queryname);
      db8_countsets(queryname);
      qline = qh->first;
    }
  }

  return(qline);
}

#endif // end of #ifdef OLD1

struct queryline *db8_getline_cache(unsigned char *queryname, int rownum) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql;
  
  qh = db8_queryheader(queryname);

  ql = qh->first;
  while(ql != NULL) {
    if(rownum == ql->rownum) {
      break;
    } else if(rownum < ql->rownum) {
      ql = NULL;
      break;
    }
    ql = ql->next;
  }
  return(ql);
}

#define aDEBUG61 2
#define aDEBUG57 2
#define aDEBUG58 2
#define aDEBUG65 2
#define aDEBUG59 2

struct queryline *db8_getline(unsigned char *queryname, int rownum) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql, *qline;
  static unsigned char *row = NULL;
  static unsigned int rowlen = 0;
  int rownum2, count;
  
  FILE *fp1;
  
  qh = db8_queryheader(queryname);

  ql = db8_getline_cache(queryname, rownum);
  
  qline = ql;

  if(ql == NULL) {
    if((fp1 = fopen(db8_filename,"r")) == NULL) {
      fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
      exit(1);
    }
    rownum2 = 0;
    count = 0;
    for(;;) {
      if(db8_fgets(&rowlen, &row, fp1) == NULL)
	break;
#ifdef DEBUG58
      more_printf(stdout,"input:    ");
      more_printf(stdout,"%s", row);
      more_printf(stdout,"\n");
#endif
      if(db8_matchandproject(queryname, row)) {
	if(rownum2 >= rownum && rownum2 <= rownum + qh->preread) {
	  ql = db8_lineheader(queryname, rownum);
	  if((ql->line = malloc(strlen(row) + 1)) == NULL) {
	    fprintf(stderr,"%s: cannot malloc memory\n", procname);
	    exit(1);
	  }
	  strcpy(ql->line, row);
#ifdef DEBUG57
	  more_printf(stdout,"selected: ");
	  more_printf(stdout,"%s", row);
	  more_printf(stdout,"\n");
#endif

#ifdef DEBUG65
	  more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
	  if(rownum == rownum2)
	    qline = ql;
	  count++;
	  if(qh->preread == 0 ||
	     count > rownum + qh->preread)
	    break;
	} // end of if(rownum2
	rownum2++;
      } // end of if(db8_matchandproject
    } // end of for(;;

    fclose(fp1);

    db8_countsets(queryname);
  } // end of if(ql == NULL

  qh->cline = qline->line;
    
  return(qline);
}

struct queryline *db8_getline_flags(unsigned char *queryname, int rownum) // JariK 2025
{
  struct queryheader *qh;
  struct queryline *ql, *qline, **ppql;

  static unsigned char *row = NULL;
  static unsigned int rowlen = 0;
  int rownum2;
  
  FILE *fp1;

  qh = db8_queryheader(queryname);

  ql = db8_getline_cache(queryname, rownum);
  
  if(ql == NULL && qh->count != 0) { // flags --> read only once
    qh->cline = NULL;
    return(NULL);
  }

  qline = ql;

  if(ql == NULL) {
    if((fp1 = fopen(db8_filename,"r")) == NULL) {
      fprintf(stderr,"%s: cannot open file, filename = %s\n", procname, db8_filename);
      exit(1);
    }
    rownum2 = 0;
    for(;;) {
      if(db8_fgets(&rowlen, &row, fp1) == NULL)
	break;
#ifdef DEBUG58
      more_printf(stdout,"input:    ");
      more_printf(stdout,"%s", row);
      more_printf(stdout,"\n");
#endif
      if(db8_matchandproject(queryname, row)) {
	int add = 1;

	ppql = &qh->first;
	
	while(*ppql != NULL) {
	  if((qh->flags & DB8_DISTINCT) &&
	     !strcmp(row, (*ppql)->line) ) {
	    add = 0;
	    break;
	  }
	  if((qh->flags & DB8_ROWSORT) &&
	     db8_strcmp_numdec(row, (*ppql)->line) < 0) {
	    //strcmp(row, (*ppql)->line) < 0) {
	    add = 1;
	    break;
	  }
	  ppql = &((*ppql)->next);
	} // end of while(*ppql != NULL
	
	if(add) {
	  struct queryline *ql;
	  ql = malloc(sizeof(struct queryline));
	  if((ql->line = malloc(strlen(row) + 1)) == NULL) {
	    fprintf(stderr,"%s: cannot malloc memory\n", procname);
	    exit(1);
	  }
	  strcpy(ql->line, row);
#ifdef DEBUG57
	  more_printf(stdout,"selected: ");
	  more_printf(stdout,"%s", row);
	  more_printf(stdout,"\n");
#endif
#ifdef DEBUG61
	  more_printf(stdout,"db8_cacheset_flags:");
	  more_printf(stdout," %d:", rownum);
	  more_printf(stdout," %s", ql->line);
	  more_printf(stdout,"\n");
#endif
	  ql->rownum = 0; // rownumbers come from renumber
	  ql->next = *ppql;
	  *ppql = ql;
	} // end of if(add
	
#ifdef DEBUG65
	more_printf(stdout,"%d %s*\n", rownum2, row);
#endif
	rownum2++;
      } // end of if(db8_matchandproject
    } // end of for(;;

    fclose(fp1);

    db8_renumbersets(queryname); // flags
    db8_countsets(queryname);
    qline = qh->first;
  }
    
  qh->cline = qline->line;

  return(qline);
}

#define aDEBUG69 2

int db8_get_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
  struct queryheader *qh;
  struct queryline *ql;

  qh = db8_queryheader(queryname);
  
  if(namelen == 0)
    namelen = strlen(name);
  
#ifdef DEBUG5
  fprintf(stdout,"db8_get_element");
  fprintf(stdout,", query=%s", queryname);
  fprintf(stdout,", row=%d", rownum);
  fprintf(stdout,", namelen=%u", namelen);
  fprintf(stdout,", name=%s", name);
  fprintf(stdout,", valuesize=%u", valuesize);
  fprintf(stdout,"\n");
#endif
  
  if(qh->flags)
    ql = db8_getline_flags(queryname, rownum);
  else
    ql = db8_getline(queryname, rownum);
    
  if(ql != NULL && ql->line != NULL) {
#ifdef DEBUG69
    fprintf(stdout,"db8_get_element:");
    fprintf(stdout," rownum:%u", rownum);
    fprintf(stdout,", row:%s", ql->line);
#endif
  
    int retval = db8_get(&ql->line, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval); // 2023 JariK
  } else
    return(0);
}

int db8_get_element_current(unsigned char *queryname, unsigned int namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value) // 20250602 JariK
{
  struct queryheader *qh;

  qh = db8_queryheader(queryname);
  
  if(namelen == 0)
    namelen = strlen(name);
  
#ifdef DEBUG5
  fprintf(stdout,"db8_get_element");
  fprintf(stdout,", query=%s", queryname);
  fprintf(stdout,", row=%d", rownum);
  fprintf(stdout,", namelen=%u", namelen);
  fprintf(stdout,", name=%s", name);
  fprintf(stdout,", valuesize=%u", valuesize);
  fprintf(stdout,"\n");
#endif
  
  if(qh->cline != NULL) {
    int retval = db8_get(&qh->cline, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval); // 2023 JariK
  } else
    return(0);
}

int db8_get_element_num(unsigned char *queryname, int rownum, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
  struct queryheader *qh;
  struct queryline *ql;
  
  if(*namelen == 0)
    *namelen = strlen(name);
  
  qh = db8_queryheader(queryname);

#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8_get_element_num");
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,", rownum=%d", rownum);
    fprintf(stdout,", col=%d", col);
    fprintf(stdout,", namesize=%u", namesize);
    fprintf(stdout,", valuesize=%u", valuesize);
    fprintf(stdout,"\n");
  }
#endif

  if(qh->flags)
    ql = db8_getline_flags(queryname, rownum);
  else
    ql = db8_getline(queryname, rownum);
    
  if(ql != NULL && ql->line != NULL) {
#ifdef DEBUG69
    fprintf(stdout,"db8_get_element_num:");
    fprintf(stdout," rownum:%u", rownum);
    fprintf(stdout,", row:%s", ql->line);
#endif
    int retval = db8_get_num(&ql->line, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval);
  } else
    return(0);
}

int db8_get_element_num_current(unsigned char *queryname, int col, unsigned int namesize, unsigned int *namelen, unsigned char *name, unsigned int valuesize, unsigned int *valuelen, unsigned char *value)
{
  struct queryheader *qh;
  
  if(*namelen == 0)
    *namelen = strlen(name);
  
  qh = db8_queryheader(queryname);

#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8_get_element_num");
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,", col=%d", col);
    fprintf(stdout,", namesize=%u", namesize);
    fprintf(stdout,", valuesize=%u", valuesize);
    fprintf(stdout,"\n");
  }
#endif

  if(qh->cline != NULL) {
#ifdef DEBUG69
    fprintf(stdout,"db8_get_element_num:");
    fprintf(stdout," rownum:%u", rownum);
    fprintf(stdout,", row:%s", ql->line);
#endif
    int retval = db8_get_num(&qh->cline, col, namesize, namelen, name, valuesize, valuelen, value); // 2023 JariK
#ifdef DEBUG69
    fprintf(stdout,", valuelen=%u", *valuelen);
    fprintf(stdout,", value=%.*s", *valuelen, value);
    fprintf(stdout,"\n");
#endif
    return(retval);
  } else
    return(0);
}

int db8_put_element(unsigned char *queryname, int rownum, unsigned int namelen, unsigned char *name, unsigned int valuelen, unsigned char *value)
{
  struct queryline *ql;
  
  if(namelen == 0)
    namelen = strlen(name);
  if(valuelen == 0)
    valuelen = strlen(value);
  
#ifdef DEBUG5
  if(db8_verbose) {
    fprintf(stdout,"db8: put_element");
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,", rownum=%d", rownum);
    fprintf(stdout,", namelen=%u", namelen);
    fprintf(stdout,", name=%.*s", namelen, name);
    fprintf(stdout,", valuelen=%u", valuelen);
    fprintf(stdout,", value=%.*s", valuelen, value);
    fprintf(stdout,"\n");
  }
#endif
  
  //db8_set = db8_find_set(queryname, rownum);

  ql = db8_lineheader(queryname, rownum);
  db8_put(&ql->line, namelen, name, valuelen, value); // 2023 JariK
  ql->save = 1;
  return(0);
}

void db8_dump(unsigned char *queryname)
{
  struct queryheader *qh;
  struct queryline *ql;

  qh = db8_queryheader(queryname);
  fprintf(stdout,"qh=%p", qh);
  fprintf(stdout,", queryname=%s", qh->queryname);
  fprintf(stdout,", flags=%d", qh->flags);
  fprintf(stdout,", query=%s", qh->query);
  fprintf(stdout,", count=%d", qh->count);
  fprintf(stdout,", preread=%d", qh->preread);
  fprintf(stdout,", next=%p", qh->next);
  fprintf(stdout,", first=%p", qh->first);
  fprintf(stdout,"\n");
  
  ql = qh->first;
  while(ql != NULL) {
    fprintf(stdout,"ql=%p", ql);
    fprintf(stdout,", rownum=%d", ql->rownum);
    fprintf(stdout,", save=%d", ql->save);
    fprintf(stdout,", next=%p", ql->next);
    fprintf(stdout,", line=%p", ql->line);
    if(ql->line != NULL)
      fprintf(stdout," %s", ql->line);
    fprintf(stdout,"\n");
    ql = ql->next;
  }
  fflush(stdout);
}

int db8_save(unsigned char *queryname)
{
  struct queryheader *qh;
  struct queryline *ql;

#ifdef DEBUG5
  if(db8_verbose == 1) {
    fprintf(stdout,"db8_save:");
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,"\n");
  }
#endif

  qh = db8_queryheader(queryname);

  fprintf(stdout,"%s\n", db8_set);

  FILE *fp1;
  if((fp1 = fopen(db8_filename, "a"))==NULL) {
    fprintf(stdout,"%s: db8 cannot open file '%s'\n", procname, db8_filename);
    exit(1);
  }
  ql = qh->first;
  while(ql != NULL) {
    if(ql->save) {
      fprintf(fp1,"%s\n", ql->line);
      ql->save = 0;
    }
    ql = ql->next;
  }
  
  fclose(fp1);

  db8_dump(queryname);

  return(0);
}

int db8_save_all()
{
  struct queryheader *qh;

#ifdef DEBUG5
  if(db8_verbose == 1) {
    fprintf(stdout,"db8_save_all:\n");
  }
#endif
  
  qh = firstqueryheader;
  while(qh != NULL) {
    db8_save(qh->queryname);
    qh = qh->next;
  }
  return(0);
}

int db8_clear(unsigned char *queryname)
{
  struct queryheader **ppqh, *qh;
  struct queryline *ql, *qlnext;
  
#ifdef DEBUG5
  if(db8_verbose == 1) {
    fprintf(stdout,"clear %s", queryname);
    fprintf(stdout,", query=%s", queryname);
    fprintf(stdout,"\n");
  }
#endif

  ppqh = &firstqueryheader;
  while(*ppqh != NULL) {
    if(!strcmp(queryname, (*ppqh)->queryname))
      break;
    ppqh = &((*ppqh)->next);
  }

  if(*ppqh != NULL) {
    qh = *ppqh;
    ql = qh->first;
    *ppqh = qh->next;
    free(qh);
    
    while(ql != NULL) {
      qlnext = ql->next;
      if(ql->line != NULL)
	free(ql->line);
      free(ql);
      ql = qlnext;
    }
  }
  return(0);
}

int db8_clear_all()
{
  struct queryheader *qh, *qhnext;

#ifdef DEBUG5
  if(db8_verbose == 1) {
    fprintf(stdout,"db8_clear_all:\n");
  }
#endif
  
  qh = firstqueryheader;
  while(qh != NULL) {
    qhnext = qh->next;
    db8_clear(qh->queryname);
    qh = qhnext;
  }
  return(0);
}

int db8_exit()
{
#ifdef DEBUG5
  if(db8_verbose == 1) {
    fprintf(stdout,"db8_exit:\n");
  }
#endif
  
  return(0);
}

void db8_version()
{
  fprintf(stdout, "%s", programname); // touch these outside #ifdef MAIN
  fprintf(stdout, ", %s", copyright);
}
#ifdef QUERY
#include <signal.h>

int ctrlcquit = 0;

static void sig_handler()
{
  fprintf(stderr,"Ctrl-c pressed\n");
  ctrlcquit = 1;
  //signal(SIGINT, SIG_DFL);
}

static int db8_ischar(int c)
{
  if(isalpha(c) || isdigit(c) || c >= 0x80 || c == '_')
    return(1);
  else
    return(0);
}

int db8_isquote(int c)
{
  if(ispunct(c) && c != ',' && c != '=')
    return(1);
  else
    return(0);
}

#define aDEBUG60

static int namequote = -1, valuequote = -1;

static void db8_get_element3(int *namelen, unsigned char **name, int *valuelen, unsigned char **value, unsigned char **p2) // 2023 JariK
{
  unsigned char *p;

  p = *p2;
  
  db8_skipwhite(&p);

  if(namequote == -1) {
    if(db8_isquote(*p))
      namequote = *p;
    else
      namequote = 0;
  }
#ifdef DEBUG60
  fprintf(stdout,"db8_get_element: 1 %s %c(%d)\n", p, valuequote, valuequote);
#endif
  *namelen = -1;
  if((*p == namequote && namequote) ||
     (db8_ischar(*p) && !namequote)) { // name
    *namelen = 0;
#ifdef DEBUG60
    fprintf(stdout,"db8_get_element: 2 %s\n", p);
#endif
    if(namequote) {
      p++;
      *name = p;
      while(*p != namequote && *p != '\0') {
#ifdef DEBUG60
	fprintf(stdout,"db8_get_element: 3 %s\n", p);
#endif
	p++;
	(*namelen)++;
      }
      if(*p == namequote)
	p++;
    } else {
      *name = p;
      while(db8_ischar(*p)) {
#ifdef DEBUG60
	fprintf(stdout,"db8_get_element: 4 %s\n", p);
#endif
	p++;
	(*namelen)++;
      }
    }
  } else
    *name = NULL;

  db8_skipwhite(&p);
  if(*p == '=') {
    p++;
    db8_skipwhite(&p);
  }

  if(valuequote == -1) {
    if(db8_isquote(*p))
      valuequote = *p;
    else
      valuequote = 0;
  }
  
#ifdef DEBUG60
  fprintf(stdout,"db8_get_element: 5 %s %c(%d)\n", p, valuequote, valuequote);
#endif
  *valuelen = -1;
  if((*p == valuequote && valuequote) ||
     (db8_ischar(*p) && !valuequote)) { // value
    *valuelen = 0;
    if(valuequote) {
      p++;
#ifdef DEBUG60
      fprintf(stdout,"db8_get_element: 6 %s\n", p);
#endif
      *value = p;
      while(*p != valuequote && *p != '\0') {
#ifdef DEBUG60
	fprintf(stdout,"db8_get_element: 7 %s\n", p);
#endif
	p++;
	(*valuelen)++;
      }
      if(*p == valuequote)
	p++;
    } else {
      *value = p;
      while(db8_ischar(*p)) {
#ifdef DEBUG60
	fprintf(stdout,"db8_get_element: 8 %s\n", p);
#endif
	p++;
	(*valuelen)++;
      }
    }
  } else
    *value = NULL;

  db8_skipwhite(&p);

#ifdef DEBUG60
  fprintf(stdout,"db8_get_element: 9 %s\n", p);
#endif
  *p2 = p;
}

void db8_squery(unsigned char *query) // JariK 2025 single
{
  int row, col, first, ok, print;

  unsigned int namelen;
  unsigned int valuelen;
  unsigned char *name, *value;

  unsigned char *q;
  unsigned char *query2 = NULL;

  if(more)
    more_init(); // adjust thee screensize
  
  q = query;
  fprintf(stdout,"query:%s\n", query);
  fflush(stdout);

  namequote = -1;
  valuequote = -1;  
  while(*q != '\0') {
    db8_skipwhite(&q);
    db8_get_element3(&namelen, &name, &valuelen, &value, &q);
    if(name == NULL)
      break;
    db8_skipwhite(&q);
    if(*q == ',') {
      q++;
      db8_skipwhite(&q);
    }
    fprintf(stderr,"db8_squery():");
    fprintf(stderr," name:%.*s(%d)", namelen, name, namelen);
    fprintf(stderr,", value:%.*s(%d)", valuelen, value, valuelen);
    fprintf(stderr,"\n");
    db8_put(&query2, namelen, name, valuelen, value);
  }
  db8_set_filename(db8_filename);
  fprintf(stdout,"query2:%s\n", query2);
  db8_clear("query");
  db8_set_query("query", query2);
  //db8_set_queryflags("query", 0);
  //db8_set_queryflags("query", DB8_DISTINCT);
  //db8_set_queryflags("query", DB8_ROWSORT);
  db8_set_queryflags("query", DB8_ROWSORT | DB8_DISTINCT);

  free(query2);

  row = 0;

  unsigned int namesize2, namelen2, valuesize2, valuelen2;
  unsigned char name2[128], value2[128];

  namesize2 = sizeof(name2);
  valuesize2 = sizeof(value2);

  for(;;) {

    morequit = 0;
    print = 0;
    first = 1;
    col = 0;
    ok = 0;

    if(db8_get_queryflags("query"))
      db8_getline_flags("query", row);
    else
      db8_getline("query", row);

    for(;;) {
      //fprintf(stdout,"row:%d, col:%d, ", row, col);
      
      if(db8_get_element_num_current("query", col, namesize2, &namelen2, name2, valuesize2, &valuelen2, value2))
	ok = 1;
      else
	break;

      if(col == 0)
	fprintf(stdout,"%d ", row);
      
      if(!first)
	fprintf(stdout,", ");

      print = 1;
      
      more_printf(stdout,"'%s' = \"%s\"", name2, value2);
      fflush(stdout);
      col++;
      first = 0;      
    }
    if(print) {
      more_printf(stdout,"\n");
      fflush(stdout);
    }
#ifdef DB8_QUERY_CALL
    extern void db8_query_call();
    db8_get_element_num("query", row, 0, namesize2, &namelen2, name2, valuesize2, &valuelen2, value2);
    db8_query_call("");
#endif
    if(!ok)
      break;
    if(more && morequit)
      break;
    if(ctrlcquit) {
      ctrlcquit = 0;
      break;
    }
    
    row++;
  }
  //db8_dump("query");
}

unsigned char prompt[128] = "skk>";

static int db8_isword(unsigned char **p2, unsigned char *word)
{
  unsigned char *p;

  int wlen = strlen(word);
  
  p = *p2;
  db8_skipwhite(&p);
  if(!strncmp(word, p, wlen) &&
     ( (isblank(*(p + wlen))) ||
       (ispunct(*(p + wlen))) ||
       (*(p + wlen) == '\0') ) ) {
    p += wlen;
    db8_skipwhite(&p);
    *p2 = p;
    return(1);
  } else
    return(0);
}

void db8_iquery() // JariK 2025 interactive
{
  unsigned char *command = NULL, *p;
  int commandsize = 0;

  ctrlcquit = 0;
  signal(SIGINT, sig_handler);
  fprintf(stdout,"%s\n", programname);
  
  for(;;) {
    fprintf(stdout, "%s", prompt);
    db8_fgets(&commandsize, &command, stdin);
    p = command;
    db8_skipwhite(&p);
    if(*p == '\0')
       continue;
    if(db8_isword(&p, "more")) {
      if(db8_isword(&p, "on")) {
	more = 1;
	continue;
      }
      if(db8_isword(&p, "off")) {
	more = 0;
	continue;
      }
      more = !more;
      fprintf(stderr,"more ");
      if(more)
	fprintf(stderr,"on");
      else
	fprintf(stderr,"off");
      fprintf(stderr,"\n");
      continue;
    }
    if(db8_isword(&p, "copyright") ||
       db8_isword(&p, "version") ) {
      fprintf(stderr, "%s", programname);
      fprintf(stderr, ", %s\n", copyright);
      continue;
    }
    if(db8_isword(&p, "exit"))
      break;
    if(db8_isword(&p, "quit"))
      break;
    if(db8_isword(&p, "*")) {
      db8_squery(NULL);      
    } else
      db8_squery(p);
  }
  signal(SIGINT, SIG_DFL);
}

#endif

#ifdef MAIN

#define aDEBUG92 2
#define DEBUG96 2

int my_match(unsigned char *pattern, unsigned char *string)
{
  unsigned char *p, *s;

  p = pattern;
  s = string;

  while(*p != '\0') {
#ifdef DEBUG92
    more_printf(stdout,"\npattern=%s",p);
    more_printf(stdout,", string=%s",s);
#endif

    if(*p == '*') { // one or many characters
      if(*s == '\0')
	return(0);
      while(*s != '\0') {
	if(my_match(p + 1, ++s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(*s == '\0')
	return(0);
      s++;
    } else if(*p == *s) {
      s++;
    } else
      return(0);
    p++;
  }
  if(*s == '\0')
    return(1);
  else
    return(0);
}

int my_match_len(unsigned int plen, unsigned char *p, unsigned int slen, unsigned char *s)
{
  while(plen > 0) {
#ifdef DEBUG92
    more_printf(stdout,"\nplen=%d", plen);
    more_printf(stdout,", p=");
    db8_fputs_len(stdout, plen, p);
    more_printf(stdout,", slen=%d", slen);
    more_printf(stdout,", s=");
    db8_fputs_len(stdout, slen, s);
#endif

    if(*p == '*') { // one or many characters
      if(slen == 0)
	return(0);
      while(slen > 0) {
	s++;
	slen--;
	if(my_match_len(plen - 1, p + 1, slen, s))
	  return(1);
      }
    } else if(*p == '?') { // one character
      if(slen == 0)
	return(0);
      s++;
      slen--;
    } else if(*p == *s) {
      s++;
      slen--;
    } else
      return(0);
    p++;
    plen--;
  }
  if(slen == 0)
    return(1);
  else
    return(0);
}

int my_match_test(unsigned char *p, unsigned char *s) // 2025 JariK
{
  int retval, plen, slen;
  static unsigned int testid = 0;

  more_printf(stdout,"%d", testid);

  more_printf(stdout,", p=%s", p);
  more_printf(stdout,", s=%s", s);

  retval = my_match(p, s);
  if(retval)
    more_printf(stdout," match!");
  else
    more_printf(stdout," no match!");

  more_printf(stdout,"\n");

  more_printf(stdout,"%d", testid++);

  plen = strlen(p);
  slen = strlen(s);

  //more_printf(stdout," plen=%d", plen);
  more_printf(stdout,", p=%s", p);
  //more_printf(stdout,", slen=%d", slen);
  more_printf(stdout,", s=%s", s);

  retval = my_match_len(plen, p, slen, s);
  if(retval)
    more_printf(stdout," match!");
  else
    more_printf(stdout," no match!");

  more_printf(stdout,"\n");
    
  return(retval);
}

unsigned char *procname;

char *query = NULL;
unsigned char filename[128] = "newressusudoku.skk.db";

int main(int argc, char *argv[])
{
  int c, args = 0, help = 0;
  
  procname = argv[0];

  more = 0;
  if(isatty(STDOUT_FILENO))
    more = 1;
  
  // look thru command line parameters
  
  for(c = 1; c < argc; c++) {
    
    if(!strcmp("--help", argv[c])) {
      help = 1;

    } else if(!strcmp("--args", argv[c])) {
      args = !args;

    } else if(!strcmp("--copyright", argv[c]) ||
	      !strcmp("--version", argv[c])) {
      fprintf(stderr, "%s", programname);
      fprintf(stderr, ", %s\n", copyright);
      exit(0);
      
    } else if(!strncmp("--skkfile", argv[c], 9)) { // JariK 2025
      if(*(argv[c] + 9) != '\0') {
	strcpy(filename, argv[c] + 9);
      } else if(c + 1 < argc) {
	strcpy(filename, argv[c + 1]);
	c++;
      }

    } else if(!strncmp("--query", argv[c], 7)) { // JariK 2025
      query = NULL;
      if(*(argv[c] + 7) != '\0') {
	query = argv[c] + 7;
      } else if(c + 1 < argc && *(argv[c + 1]) != '-') {
	query = argv[c + 1];
	c++;
      }
      
    } else if(!strncmp("--more", argv[c], 6)) { // JariK 2025
      more = !more;

    }
  }

  if(help) {
    fprintf(stderr,"%s: %s", procname, procname);
    fprintf(stderr," [--help]");
    fprintf(stderr," [--copyright]");
    fprintf(stderr," [--version]");
    fprintf(stderr," [--skkfile[filename]]");
    fprintf(stderr," [--query[querytext]]");
    fprintf(stderr," [--more]");
    fprintf(stderr,"\n");
    exit(1);
  } // end of if(help)

#ifdef DEBUG96

  if(more)
    more_init(); // adjust thee screensize

  more_printf(stdout, "zero delimited match\n");
  my_match_test("?","");
  my_match_test("*","");
  my_match_test("a?","a");
  my_match_test("a*","a");
  my_match_test("abcdef","abcdef");
  my_match_test("abc*def","abcdefdef");
  my_match_test("abc*def","abcdefdefdef");
  my_match_test("abc*","abcdef");
  my_match_test("*def","abcdef");
  my_match_test("*cd*","abcdef");
  my_match_test("*cd*","abcdefcdefcdef");
  my_match_test("ab??ef","abcdef");
  my_match_test("??def","abcdef");
  my_match_test("???def","abcdef");
  my_match_test("*gh*","abcdef");
  my_match_test("abcdef","abcgef");
  my_match_test("?*def","abcdef");
  my_match_test("?*def","abcdefg");
  my_match_test("?b","ab");
  my_match_test("a?","ab");
  my_match_test("a?c","abc");
  my_match_test("a??d","abcd");
  my_match_test("a??*d","abcd");
  my_match_test("?b","ac");
#endif

  if(args) {
    fprintf(stderr,"argc: %d\n", argc);
    for(c = 0; c < argc; c++) {
      fprintf(stderr,"argv[%d]: %s\n", c, argv[c]);
    }
    exit(1);
  }

#ifdef TEST

  unsigned long l = 0;
  c = 0;
  for(;;) {
    unsigned long oldl = l;
    l = l * 10 + 9;
    fprintf(stdout,"%d %lu\n", c++, l);
    if((l - 9) / 10 != oldl)
      break;
  }

#endif

  db8_set_filename(filename);
  
  if(query !=NULL)
    db8_squery(query);
  else
    db8_iquery();

  exit(0);
}

#endif

Db8 source more.c

#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include <termios.h>

static unsigned char *programname = "more version 0.1 ©";
static unsigned char *copyright = "Copyright (c) 2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";

struct termios old, new;

void startprompt()
{
  setvbuf(stdout, NULL, _IONBF, 0);
  tcgetattr(0, &old);
  new = old;
  new.c_lflag &= ~(ICANON | ECHO);
  //new.c_lflag &= ~(ISIG | ICANON | ECHO);
  new.c_cc[VMIN] = 1;
  new.c_cc[VTIME] = 2;
  tcsetattr(0, TCSANOW, &new);
}

void endprompt()
{
  tcsetattr(0, TCSANOW, &old);
}

void more_backspacechars(int chars)
{
  int c;
  
  for(c = 0; c < chars; c++)
    fputc('\b', stdout);
  for(c = 0; c < chars; c++)
    fputc(' ', stdout);
  for(c = 0; c < chars; c++) 
    fputc('\b', stdout);
}

int more = 1;

int screenlinesleft = 0, screenmaxchars, screenmaxlines;
int screenchars = 0;
int morequit = 0;

#include <sys/ioctl.h> // for TIOCGWINSZ

void more_init()
{
  struct winsize w;
  ioctl(0, TIOCGWINSZ, &w);
  screenmaxchars = w.ws_col;
  screenmaxlines = w.ws_row - 1;
  screenlinesleft = screenmaxlines;
}

void more_version()
{
  fprintf(stderr, "%s", programname); // touch these outside #ifdef MAIN
  fprintf(stderr, ", %s", copyright);
}

void more_wait()
{
  int c;
  unsigned char *moretext = "---more---";
  
  fprintf(stderr,"%s", moretext);

  if(more) {
    startprompt();

    // wait until something below is pressed
  
    for(;;) {
      c = getchar();
      if(c == ' ') {
	more_init(); // adjust for screensize
	screenlinesleft = screenmaxlines; // full screen
	break;
      } else if(c == '\n') {
	more_init(); // adjust for screensize
	screenlinesleft = 1; // one line
	break;
      } else if(c == 'q') { // quit
	morequit = 1;
	break;
      }
    }
  
    more_backspacechars(strlen(moretext));
  
    endprompt();
  } // end of if(more
}

#include <stdarg.h>

void more_printf(FILE *fp1, const char *format, ...)
{
  int count;
  va_list args;
  unsigned char *p;
  static char *printbuf = NULL;
  static int printbuf_len = 0;

  va_start(args, format);
  count = vsnprintf(printbuf, printbuf_len, format, args) + 1;
  va_end(args);

  if(printbuf_len < count) {
    printbuf_len = count;
    printbuf = realloc(printbuf, printbuf_len);
    va_start(args, format);
    count = vsnprintf(printbuf, printbuf_len, format, args) + 1;
    va_end(args);
  }

  // print all characters from printbuf.
  // prompt more for full screen pages.
  
  p = printbuf;
  while(*p!='\0') {
    fputc(*p, fp1);
    if(*p == '\n' || ++screenchars == screenmaxchars) {
      screenchars = 0;
      if(more && --screenlinesleft == 0) {
	more_wait();
      }
    }
    p++;
  }
}

Toinen tärkeä asia edellisessä postissa oli tietysti satunnaisbittigeneraattori: seuraava ohjelma yrittää laskea pi:n pseudoressun satunnaisbittien perusteella:

Pi ohjelmassa on jo aiemmista posteista tuttuja pätkiä:

#define KILO 1024

void readablelonglong(FILE *fp1, unsigned long long ll2) // 2023 JariK
{
  int c;
  unsigned long long multiplier, ll = ll2;
  
  // B = byte
  // K = kilo   10^3   2^10
  // M = mega   10^6   2^20
  // G = giga   10^9   2^30
  // T = tera   10^12  2^40
  // P = peta   10^15  2^50
  // E = exa    10^18  2^60
  // Z = zetta  10^21  2^70
  // Y = yotta  10^24  2^80

  char units[] = "BKMGTPEZY";

  c = 0;
  multiplier = 1;
  while(ll >= KILO) {
    ll /= KILO;
    multiplier *= KILO;
    c++;
  }

  if(ll * multiplier != ll2)
    fprintf(fp1,"~"); // approximately

  fprintf(fp1,"%llu%c", ll, units[c]);
}

void fprintfcharacter(FILE *fp1, unsigned char *p) // 2023 JariK
{
  fputc(*p, fp1); // print first char
  if(*p > 0xbf) { // first char utf8
    p++;
    for(;;) { // print rest of the utf8 chars
      if(*p > 0xbf || // new utf8 character
	 *p < 0x80 || // ascii character
	 *p == '\0') // end of string
	break;
      fputc(*p, fp1);
      p++;
    }
  }
}

int getdigit(unsigned char *p) // 2023 JariK
{
  int digit;
  
  if(*p >= '0' && *p <= '9')
    digit = *p - '0';
  else if(*p >= 'a' && *p <= 'z')
    digit = (*p - 'a') + 10;
  else if(*p >= 'A' && *p <= 'Z')
    digit = (*p - 'A') + 10;
  else
    digit = -1; // not found, illegal

  return(digit);
}

#define DEBUG32 2

//#define KILO 1000
#define KILO 1024

unsigned long long getlonglong(unsigned char *p2) // 2023 JariK
{
  int digit, base = 10;
  unsigned char *p = p2;
  unsigned long long totll, ll, prevll, multiplier;
  
  totll = 0;

  while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...

    unsigned char *prevp = p;
    
    if(!strncmp("0x", p, 2)) {
      base = 16;
      p += 2;
      
    } else if(!strncmp("0d", p, 2)) {
      base = 10;
      p += 2;
      
    } else if(!strncmp("0o", p, 2)) {
      base = 8;
      p += 2;
      
    } else if(!strncmp("0b", p, 2)) {
      base = 2;
      p += 2;
      
    }
    
    ll = 0;
    while((digit = getdigit(p)) != -1 && digit < base) {
      ll = ll * base + digit;
      p++;
    }
    
    multiplier = 1;
    
    if(*p == 'k' || *p == 'K') {
      multiplier = KILO;
      p++;
      
    } else if(*p == 'm' || *p == 'M') {
      multiplier = (KILO * KILO);
      p++;
      
    } else if(*p == 'g' || *p == 'G') {
      multiplier = (KILO * KILO * KILO);
      p++;
      
    } else if(*p == 't' || *p == 'T') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
      p++;
      
    } else if(*p == 'p' || *p == 'P') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
      p++;
      
    } else if(*p == 'e' || *p == 'E') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
      p++;
      
    }
    
    prevll = ll;
    ll *= multiplier;
    if(ll / multiplier != prevll) {
      fflush(stdout);
      fprintf(stderr,"%s: multiply overflow", procname);
      fprintf(stderr,", string:'%s'", p2);
      fprintf(stderr,", digit:'");
      fprintfcharacter(stderr, p);
      fprintf(stderr,"'");
      fprintf(stderr,", value: %d", digit);
      fprintf(stderr,", base: %d", base);
      fprintf(stderr,", ll: %llu", prevll);
      fprintf(stderr,", multiplier: %llu", multiplier);
      fprintf(stderr,"\n");
      fflush(stderr);
    }
  
    if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
      p++;
    
    totll += ll;

#ifdef DEBUG32
    fprintf(stderr,"string:'%s'", p2);
    fprintf(stderr,", base:%d(", base);
    readablelonglong(stderr, base);
    fprintf(stderr,")");
    fprintf(stderr,", multiplier:%llu(", multiplier);
    readablelonglong(stderr, multiplier);
    fprintf(stderr,")");
    fprintf(stderr,", prevll:%llu(", prevll);
    readablelonglong(stderr, prevll);
    fprintf(stderr,")");
    fprintf(stderr,", ll:%llu(", ll);
    readablelonglong(stderr, ll);
    fprintf(stderr,")");
    fprintf(stderr,", totll:%llu(", totll);
    readablelonglong(stderr, totll);
    fprintf(stderr,")");
    fprintf(stderr,"\n");
#endif
    
    if(prevp == p) // no progress
      break;
  }
  
  if(*p != '\0') {
    fflush(stdout);
    fprintf(stderr,"%s: illegal digit", procname);
    fprintf(stderr,", string:'%s'", p2);
    fprintf(stderr,", digit:'");
    fprintfcharacter(stderr, p);
    fprintf(stderr,"'");
    fprintf(stderr,", value: %d", digit);
    fprintf(stderr,", base: %d(", base);
    readablelonglong(stderr, base);
    fprintf(stderr,")");
    fprintf(stderr,"\n");
    fflush(stderr);
  }

  return(totll);
}

Toinen tuttu pätkä, jolla arvotaan satunnaisuus:

#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;

int newressu_genbyte()
{
  unsigned char ch;

  if(gent_pos == 0) {
    memset(gent, 0, sizeof(gent));
    pseudoressu_bytes(sizeof(gent), gent);
  } // if(gent_pos == 0
  ch = gent[gent_pos];
  gent_pos = (gent_pos + 1) % sizeof(gent);

  return(ch);
}

unsigned long newressu_gen_limit(unsigned long limit)
{
  int c;
  unsigned long word;
  static unsigned long lastlimit = 0, highlimit;
  static int bytes;

  if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
    lastlimit = limit;
    if(limit <= 0x100) {
      // highest multiplier of limit that fits to needed bytes
      highlimit = (0x100 / limit) * limit;
      // number of bytes needed
      bytes = 1;
    } else if(limit <= 0x10000) {
      highlimit = (0x10000 / limit) * limit;
      bytes = 2;
    } else if(limit <= 0x1000000) {
      highlimit = (0x1000000 / limit) * limit;
      bytes = 3;
    } else if(limit <= 0x100000000) {
      highlimit = (0x100000000 / limit) * limit;
      bytes = 4;
    } else if(limit <= 0x10000000000) {
      highlimit = (0x10000000000 / limit) * limit;
      bytes = 5;
    } else if(limit <= 0x1000000000000) {
      highlimit = (0x1000000000000 / limit) * limit;
      bytes = 6;
    } else if(limit <= 0x100000000000000) {
      highlimit = (0x100000000000000 / limit) * limit;
      bytes = 7;
    } else { // if(limit <= 0xffffffffffffffff) {
      highlimit = (0xffffffffffffffff / limit) * limit;      
      bytes = 8;
    }
  } // if(lastlimit != limit)

  for(;;) {
    word = 0;
    for(c = 0; c < bytes; c++)
      word = word << 8 | newressu_genbyte();
    if(word < highlimit)
      break;
  }

  word %= limit;

  return(word);
}

Ja pi ohjelma kokonaisuudessaan:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "newressu.h"

unsigned char *procname;
static unsigned char *programname = "newressupi version 0.06 ©";
static unsigned char *copyright = "Copyright (c) 2025 Jari Kuivaniemi (moijari.com), Helsinki, Finland. Kaikki oikeudet pidätetään!";

unsigned char *log_filename = "newressupi.log";

#include <time.h>

#include <stdarg.h>

void log_printf(const char *format, ...) // JariK 2025
{
  int count;
  va_list args;
  static char *printbuf = NULL;
  static int printbuf_len = 0;
  static int printtime = 1;
  va_start(args, format);
  count = vsnprintf(printbuf, printbuf_len, format, args) + 1;
  va_end(args);

  if(printbuf_len < count) {
    printbuf_len = count;
    printbuf = realloc(printbuf, printbuf_len);
    va_start(args, format);
    count = vsnprintf(printbuf, printbuf_len, format, args) + 1;
    va_end(args);
  }

  // print all characters from printbuf.
  // print all characters to log adding time and date.
  
  fputs(printbuf, stdout);

  FILE *fp1;
  if((fp1 = fopen(log_filename, "a")) != NULL) {
    if(printtime) {
      time_t now = time(NULL);
      unsigned char timestamp[32];
      strftime(timestamp, sizeof(timestamp), "%Y%m%d%H%M%S%Z", localtime((time_t *)&now));
      fputs(timestamp, fp1);
      fputc(' ', fp1);
      printtime = 0;
    }
    fputs(printbuf, fp1);
    fclose(fp1);
    if(printbuf[strlen(printbuf) - 1] == '\n')
      printtime = 1;
  }
}

#define KILO 1024

void readablelonglong(FILE *fp1, unsigned long long ll2) // 2023 JariK
{
  int c;
  unsigned long long multiplier, ll = ll2;
  
  // B = byte
  // K = kilo   10^3   2^10
  // M = mega   10^6   2^20
  // G = giga   10^9   2^30
  // T = tera   10^12  2^40
  // P = peta   10^15  2^50
  // E = exa    10^18  2^60
  // Z = zetta  10^21  2^70
  // Y = yotta  10^24  2^80

  char units[] = "BKMGTPEZY";

  c = 0;
  multiplier = 1;
  while(ll >= KILO) {
    ll /= KILO;
    multiplier *= KILO;
    c++;
  }

  if(ll * multiplier != ll2)
    fprintf(fp1,"~"); // approximately

  fprintf(fp1,"%llu%c", ll, units[c]);
}

void fprintfcharacter(FILE *fp1, unsigned char *p) // 2023 JariK
{
  fputc(*p, fp1); // print first char
  if(*p > 0xbf) { // first char utf8
    p++;
    for(;;) { // print rest of the utf8 chars
      if(*p > 0xbf || // new utf8 character
	 *p < 0x80 || // ascii character
	 *p == '\0') // end of string
	break;
      fputc(*p, fp1);
      p++;
    }
  }
}

int getdigit(unsigned char *p) // 2023 JariK
{
  int digit;
  
  if(*p >= '0' && *p <= '9')
    digit = *p - '0';
  else if(*p >= 'a' && *p <= 'z')
    digit = (*p - 'a') + 10;
  else if(*p >= 'A' && *p <= 'Z')
    digit = (*p - 'A') + 10;
  else
    digit = -1; // not found, illegal

  return(digit);
}

#define DEBUG32 2

//#define KILO 1000
#define KILO 1024

unsigned long long getlonglong(unsigned char *p2) // 2023 JariK
{
  int digit, base = 10;
  unsigned char *p = p2;
  unsigned long long totll, ll, prevll, multiplier;
  
  totll = 0;

  while(*p != '\0') { // works also: 1g100m & 1m20k and 1t1t etc...

    unsigned char *prevp = p;
    
    if(!strncmp("0x", p, 2)) {
      base = 16;
      p += 2;
      
    } else if(!strncmp("0d", p, 2)) {
      base = 10;
      p += 2;
      
    } else if(!strncmp("0o", p, 2)) {
      base = 8;
      p += 2;
      
    } else if(!strncmp("0b", p, 2)) {
      base = 2;
      p += 2;
      
    }
    
    ll = 0;
    while((digit = getdigit(p)) != -1 && digit < base) {
      ll = ll * base + digit;
      p++;
    }
    
    multiplier = 1;
    
    if(*p == 'k' || *p == 'K') {
      multiplier = KILO;
      p++;
      
    } else if(*p == 'm' || *p == 'M') {
      multiplier = (KILO * KILO);
      p++;
      
    } else if(*p == 'g' || *p == 'G') {
      multiplier = (KILO * KILO * KILO);
      p++;
      
    } else if(*p == 't' || *p == 'T') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO);
      p++;
      
    } else if(*p == 'p' || *p == 'P') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO);
      p++;
      
    } else if(*p == 'e' || *p == 'E') {
      multiplier = ((unsigned long long)KILO * KILO * KILO * KILO * KILO * KILO);
      p++;
      
    }
    
    prevll = ll;
    ll *= multiplier;
    if(ll / multiplier != prevll) {
      fflush(stdout);
      fprintf(stderr,"%s: multiply overflow", procname);
      fprintf(stderr,", string:'%s'", p2);
      fprintf(stderr,", digit:'");
      fprintfcharacter(stderr, p);
      fprintf(stderr,"'");
      fprintf(stderr,", value: %d", digit);
      fprintf(stderr,", base: %d", base);
      fprintf(stderr,", ll: %llu", prevll);
      fprintf(stderr,", multiplier: %llu", multiplier);
      fprintf(stderr,"\n");
      fflush(stderr);
    }
  
    if(*p == 'b' || *p == 'B') // remove last b (for bytes in 1tb, 1gb or 1mb)
      p++;
    
    totll += ll;

#ifdef DEBUG32
    fprintf(stderr,"string:'%s'", p2);
    fprintf(stderr,", base:%d(", base);
    readablelonglong(stderr, base);
    fprintf(stderr,")");
    fprintf(stderr,", multiplier:%llu(", multiplier);
    readablelonglong(stderr, multiplier);
    fprintf(stderr,")");
    fprintf(stderr,", prevll:%llu(", prevll);
    readablelonglong(stderr, prevll);
    fprintf(stderr,")");
    fprintf(stderr,", ll:%llu(", ll);
    readablelonglong(stderr, ll);
    fprintf(stderr,")");
    fprintf(stderr,", totll:%llu(", totll);
    readablelonglong(stderr, totll);
    fprintf(stderr,")");
    fprintf(stderr,"\n");
#endif
    
    if(prevp == p) // no progress
      break;
  }
  
  if(*p != '\0') {
    fflush(stdout);
    fprintf(stderr,"%s: illegal digit", procname);
    fprintf(stderr,", string:'%s'", p2);
    fprintf(stderr,", digit:'");
    fprintfcharacter(stderr, p);
    fprintf(stderr,"'");
    fprintf(stderr,", value: %d", digit);
    fprintf(stderr,", base: %d(", base);
    readablelonglong(stderr, base);
    fprintf(stderr,")");
    fprintf(stderr,"\n");
    fflush(stderr);
  }

  return(totll);
}

#define GENT_SIZE 1024
static unsigned char gent[GENT_SIZE];
static unsigned int gent_pos = 0;

int newressu_genbyte()
{
  unsigned char ch;

  if(gent_pos == 0) {
    memset(gent, 0, sizeof(gent));
    pseudoressu_bytes(sizeof(gent), gent);
  } // if(gent_pos == 0
  ch = gent[gent_pos];
  gent_pos = (gent_pos + 1) % sizeof(gent);

  return(ch);
}

#define DEBUG13 2

unsigned long newressu_gen_limit(unsigned long limit)
{
  int c;
  unsigned long word;
  static unsigned long lastlimit = 0, highlimit;
  static int bytes;

  if(lastlimit != limit) { // if limit changes, calculate new highlimit and bytes
    lastlimit = limit;
    if(limit <= 0x100) {
      // highest multiplier of limit that fits to needed bytes
      highlimit = (0x100 / limit) * limit;
      // number of bytes needed
      bytes = 1;
    } else if(limit <= 0x10000) {
      highlimit = (0x10000 / limit) * limit;
      bytes = 2;
    } else if(limit <= 0x1000000) {
      highlimit = (0x1000000 / limit) * limit;
      bytes = 3;
    } else if(limit <= 0x100000000) {
      highlimit = (0x100000000 / limit) * limit;
      bytes = 4;
    } else if(limit <= 0x10000000000) {
      highlimit = (0x10000000000 / limit) * limit;
      bytes = 5;
    } else if(limit <= 0x1000000000000) {
      highlimit = (0x1000000000000 / limit) * limit;
      bytes = 6;
    } else if(limit <= 0x100000000000000) {
      highlimit = (0x100000000000000 / limit) * limit;
      bytes = 7;
    } else { // if(limit <= 0xffffffffffffffff) {
      highlimit = (0xffffffffffffffff / limit) * limit;      
      bytes = 8;
    }
#ifdef DEBUG13
    fprintf(stdout,"%s: newressu_gen_limit:", procname);
    fprintf(stdout," limit:%lu(", limit);
    readablelonglong(stdout, limit);
    fprintf(stdout,")");
    fprintf(stdout,", highlimit:%lu(", highlimit);
    readablelonglong(stdout, highlimit);
    fprintf(stdout,")");
    fprintf(stdout,", bytes:%u", bytes);
    fprintf(stdout,"\n");
#endif
  } // if(lastlimit != limit)

  for(;;) {
    word = 0;
    for(c = 0; c < bytes; c++)
      word = word << 8 | newressu_genbyte();
    if(word < highlimit)
      break;
  }

  word %= limit;

  return(word);
}

#define aDEBUG10 2

//#define BLOCK 1000000000
#define BLOCK 1000000000
unsigned int block = BLOCK;
#define RANDFUNC pseudoressu_bytes

#define DECIMALS 20

void main(int argc, char *argv[])
{
  int c, bytes = 0, help = 0;
  unsigned long long limit = 0, divider, round, llx, lly, inside = 0;
  double x, y;
#ifdef DEBUG10
  double minx = 999, miny = 999, maxx = -999, maxy = -999;
#endif

  procname = argv[0];

  // look thru command line parameters
  
  for(c = 1; c < argc; c++) {
    if(!strncmp("-",argv[c], 1)) {

      if(!strcmp("--help", argv[c]) ||
	 !strcmp("-?", argv[c])) {
	help = 1;

      } else if(!strcmp("--copyright", argv[c]) ||
	 !strcmp("--version", argv[c])) {
	fprintf(stderr, "%s", programname);
	fprintf(stderr, ", %s\n", copyright);
	exit(0);

      } else if(!strncmp("--bytes", argv[c], 7)) {
	if(isdigit(*(argv[c] + 7))) {
	  bytes = atoi(argv[c] + 7);
	} else if(c + 1 < argc) {
	  bytes = atoi(argv[c + 1]);
	  c++;
	}
	if(bytes < 1 || bytes > 8) {
	  fprintf(stderr,"%s: --bytes must be between 1 and 8\n", procname);
	  exit(1);
	}
	limit = 0;

      } else if(!strncmp("--limit", argv[c], 7)) {
	if(isdigit(*(argv[c] + 7))) {
	  limit = getlonglong(argv[c] + 7);
	} else if(c + 1 < argc) {
	  limit = getlonglong(argv[c + 1]);
	  c++;
	}
	if(limit < 2) {
	  fprintf(stderr,"%s: --limit must be greater or equal than 2\n", procname);
	  exit(1);
	}
	bytes = 0;

      } else if(!strncmp("--block", argv[c], 7)) {
	if(isdigit(*(argv[c] + 7))) {
	  block = getlonglong(argv[c] + 7);
	} else if(c + 1 < argc) {
	  block = getlonglong(argv[c + 1]);
	  c++;
	}
	if(block < 2) {
	  fprintf(stderr,"%s: --block must be greater or equal than 2\n", procname);
	  exit(1);
	}
      }
    }
  }
  
  // print help message if needed
  
  if(help) {
    fprintf(stderr,"%s: %s", procname, procname);
    fprintf(stderr," [--help]");
    fprintf(stderr," [--copyright]");
    fprintf(stderr," [--version]");
    fprintf(stderr," [--bytes n]");
    fprintf(stderr," [--limit n]");
    fprintf(stderr," [--block n]");
    fprintf(stderr,"\n");
    exit(1);
  } // end of if(help)

#ifdef OLD1
  
  switch(bytes) {
    case 1:
      divider = 0xff;
      break;
    case 2:
      divider = 0xffff;
      break;
    case 3:
      divider = 0xffffff;
      break;
    case 4:
      divider = 0xffffffff;
      break;
    case 5:
      divider = 0xffffffffff;
      break;
    case 6:
      divider = 0xffffffffffff;
      break;
    case 7:
      divider = 0xffffffffffffff;
      break;
    case 8:
      divider = (unsigned long long) 0xffffffffffffffff;
      break;
  }

#endif // end of #ifdef OLD1

  if(limit == 0 && bytes == 0)
    bytes = 4;

  if(bytes != 0) {
    divider = 0;
    for(c = 0; c < bytes; c++) {
      divider = (divider << 8) + 0xff;
    }
  } else
    divider = limit - 1;

  if(bytes)
    fprintf(stdout,"bytes %d", bytes);
  if(limit) {
    fprintf(stdout,"limit %llu(", limit);
    readablelonglong(stdout, limit);
    fprintf(stdout,")");
  }
  fprintf(stdout,", block %u", block);
  fprintf(stdout,", step %1.*f", DECIMALS, (double)2 / divider - (double)1 / divider);
  fprintf(stdout,", divider %llu(", divider);
  readablelonglong(stdout, divider);
  fprintf(stdout,")");
  fprintf(stdout,"\n");

  for(round = 0;; round++) {
    llx = 0;
    lly = 0;

#ifdef DEBUG10
    fprintf(stdout,"rounds=%llu", round);
#endif

    if(bytes) {
      RANDFUNC(bytes, (unsigned char *)&llx); // little endian
      RANDFUNC(bytes, (unsigned char *)&lly); // little endian
      //RANDFUNC(bytes, (unsigned char *)&llx + 8 - bytes); // big endian
      //RANDFUNC(bytes, (unsigned char *)&lly + 8 - bytes); // big endian
    } else if(limit) {
      llx = newressu_gen_limit(limit);
      lly = newressu_gen_limit(limit);
    }

#ifdef DEBUG10
    fprintf(stdout,", llx=%llx", (unsigned long long)llx);
    fprintf(stdout,", lly=%llx", (unsigned long long)lly);
#endif

    x = (double) llx / divider; // random number between 0 and 1
    y = (double) lly / divider; // random number between 0 and 1
    
#ifdef DEBUG10
    fprintf(stdout,", x=%f", x);
    fprintf(stdout,", y=%f", y);
#endif
    
#ifdef DEBUG10

    if(minx > x)
      minx = x;    
    if(miny > y)
      miny = y;
    if(maxx < x)
      maxx = x;    
    if(maxy < y)
      maxy = y;

    fprintf(stdout,", minx=%f", minx);
    fprintf(stdout,", miny=%f", miny);
    fprintf(stdout,", maxx=%f", maxx);
    fprintf(stdout,", maxy=%f", maxy);
#endif

    if(sqrt(x * x + y * y) < 1)
      inside++;

#ifdef DEBUG10
    fprintf(stdout,", inside=%llu", inside);
    fprintf(stdout,", pi=%1.*f", DECIMALS, (double)4 * inside / round);
    fprintf(stdout,"\n");
#endif

    if(round > 0 && round % block == 0) {
      log_printf("rounds = %llu", round);
      log_printf(", inside = %llu", inside);
      log_printf(", pi = %1.*f", DECIMALS, (double)4 * inside / round);
      if(bytes != 0)
	log_printf(", bytes = %d", bytes);
      if(limit != 0)
	log_printf(", limit = %llu", limit);
      log_printf("\n");
    }
  }
}

Seuraavassa pätkä pi:n haun logista (newressupi.log):

20250728111134EEST rounds = 591000000000, inside = 464170507728, pi = 3.14159396093400999916, bytes = 7
20250728111628EEST rounds = 633000000000, inside = 497156881071, pi = 3.14159166553554491941, bytes = 6
20250728112348EEST rounds = 955000000000, inside = 750055265602, pi = 3.14159273550575912637, limit = 17293822569102704640
20250728112357EEST rounds = 733000000000, inside = 575689846725, pi = 3.14155441596180073915, bytes = 2
20250728112552EEST rounds = 599000000000, inside = 470453646868, pi = 3.14159363517863088333, bytes = 8
20250728113232EEST rounds = 656000000000, inside = 515221382817, pi = 3.14159379766463420225, bytes = 5
20250728114328EEST rounds = 685000000000, inside = 537997696622, pi = 3.14159238903357662664, bytes = 4
20250728114727EEST rounds = 956000000000, inside = 750840642527, pi = 3.14159264655648540199, limit = 17293822569102704640
20250728114944EEST rounds = 724000000000, inside = 568627945710, pi = 3.14159086027624301352, bytes = 3
20250728120621EEST rounds = 782000000000, inside = 612285705793, pi = 3.13189619331457791418, bytes = 1
20250728120946EEST rounds = 957000000000, inside = 751626011893, pi = 3.14159252619853690547, limit = 17293822569102704640
20250728122446EEST rounds = 592000000000, inside = 464955901877, pi = 3.14159393160135147482, bytes = 7
20250728122640EEST rounds = 734000000000, inside = 576475228866, pi = 3.14155438074114456981, bytes = 2
20250728123006EEST rounds = 634000000000, inside = 497942282544, pi = 3.14159168797476340274, bytes = 6
20250728123126EEST rounds = 958000000000, inside = 752411423621, pi = 3.14159258296868459936, limit = 17293822569102704640
20250728123623EEST rounds = 657000000000, inside = 516006768084, pi = 3.14159371740639281612, bytes = 5
20250728124124EEST rounds = 600000000000, inside = 471239037042, pi = 3.14159358027999990881, bytes = 8
20250728124919EEST rounds = 686000000000, inside = 538783103661, pi = 3.14159244117201152946, bytes = 4
20250728125049EEST rounds = 725000000000, inside = 569413330861, pi = 3.14159079095724136366, bytes = 3
20250728125306EEST rounds = 959000000000, inside = 753196826239, pi = 3.14159260162252351734, limit = 17293822569102704640
20250728130422EEST rounds = 783000000000, inside = 613068702173, pi = 3.13189630739719016006, bytes = 1
20250728131320EEST rounds = 960000000000, inside = 753982213607, pi = 3.14159255669583314940, limit = 17293822569102704640
20250728132348EEST rounds = 735000000000, inside = 577260619699, pi = 3.14155439291972804483, bytes = 2

Published
Categorized as muuta

Leave a comment