26 Commits
Author SHA1 Message Date
wkh 5020d7e982 Version 0.8.0: gefaltete Indizes markiert, Review abgeschlossen
index -x schreibt Offset-x in den Kopf der .i-Datei, search bisektiert in
der Ordnung des Index. Beim Umstieg .h- und mit -x gebaute .i-Indizes neu
bauen.
2026-10-30 10:13:59 +01:00
wkh d6733e737e jointable -n vergleicht Schlüssel als Zahlen, Review Punkt 9 abgeschlossen 2026-10-30 10:07:48 +01:00
wkh 158ce5dee2 Review abgeschlossen: awk-Brücke und Repo bleiben so 2026-10-30 10:03:52 +01:00
wkh c2ea36c6d6 Schneller Start ohne RubyGems, Rational statt BigDecimal, Helfer in Rdb::Helpers
bin/rdb läuft mit --disable-gems (ca. 85 statt 170 ms je Befehl), dafür
rechnen Summen und /act mit Rational. Hilfsfunktionen und Konstanten liegen
nicht mehr auf Object, Kopf-/Strichzeile und awk-Aufruf an einer Stelle.
Tests laufen parallel: 21 statt 70 Sekunden.
2026-10-30 10:01:36 +01:00
wkh 1c489f6994 Schnellzugriff per Seek, FNV-1a-Hash, Dezimalrechnung für Summen und /act
search, seek, delete und update.rdb lesen bei -mh, -mi, -mr nur Indexeintrag
und Satz. Hashindizes (.h) müssen neu gebaut werden. total, mean, subtotal
und die /act-Befehle rechnen mit BigDecimal, gerundet wird halb auf.
2026-10-30 09:54:05 +01:00
wkh 75c2424307 Fehler behoben: Umlaute, Latin-1, Fehlermeldungen, atomares Schreiben
Spaltennamen mit Umlauten in Ausdrücken, Latin-1-Dateien als UTF-8,
Fehler als eine Zeile (RDB_DEBUG=1 für Backtrace), Werte mit Tab oder
Zeilenumbruch abgelehnt, Tabellen und Indexe über Temp-Datei und rename,
update.rdb gibt den Satz bei Editorfehler zurück, sorttable -r stabil.
2026-10-30 09:48:42 +01:00
wkh 9f6c450492 Sicherheit: report/screen maskieren Shell-Eingaben, Sperren privat und atomar
report setzt Zellwerte in <!befehl!> maskiert ein, screen verlangt gültige
Variablennamen, lock/unlock nutzen /tmp/rdb-locks-<UID> mit flock, vilock
sperrt per Hardlink. EDITOR darf Argumente haben. Doku und Tests ergänzt.
2026-10-30 09:45:18 +01:00
wkh df8bcdfaf1 Handbuch-Beispiele als Test, search/seek mit Schlüsseltabelle
- doc/handbuch.txt: OCR-Text des COHERENT-/rdb-Handbuchs
- demo/handbuch/ und test/handbuch_test.rb: Beispiele aus dem Lehrbuchteil, mise run test führt sie mit aus
- search/seek: Schlüsselspalten aus dem Kopf der Schlüsseltabelle
- gregorian -u ohne führende Null im Monat, mean ganzzahlig ohne .00
- Mit justify aufgefüllte Spaltennamen werden wieder gefunden
- coherent.pdf in .gitignore
2026-10-14 21:48:46 +02:00
wkh a38311021d README: mise trust nach dem Clone, Testanzahl 114 2026-10-13 15:32:01 +02:00
wkh 140b521493 rdb-Handbuch.pdf hinzugefügt 2026-10-13 15:26:48 +02:00
wkh 7872307583 bin: Symlinks nicht mehr im Repo, rdb install legt sie an
Die Symlinks zeigten mit absolutem Pfad auf bin/rdb und waren auf jedem
Rechner geändert. Jetzt ignoriert .gitignore alles in bin/ außer rdb.
README weist auf mise run install bzw. bin/rdb install nach dem Clone hin.
2026-10-13 15:26:34 +02:00
wkh 80941b6f03 Version 0.7.0: Kantonstarife 2026 (taxCH_AI/AR/SG/GR) 2026-10-12 00:27:06 +02:00
wkh a02e5cb109 column -d: Spalten löschen 2026-10-12 00:10:36 +02:00
wkh a9f3c0b255 demo: Reste von splittable (colorsaa-ac) entfernt 2026-10-11 23:58:58 +02:00
wkh 2e03c0a440 rdb man: Titel der Themen-Seiten (dashline, headline ...) aus .TH 2026-10-11 23:56:05 +02:00
wkh 6b9810b075 mise: Rust 1.99 und Scryer Prolog 0.10 für die Prolog-Ausgaben 2026-10-11 23:32:07 +02:00
wkh b11e3da453 splittable: klare Fehler für -0 und mehr als 676 Stücke 2026-10-11 23:23:37 +02:00
wkh 1c66773ff4 Version 0.6.0: Steuertabellen 2026, record mit negativen Nummern, select-Hinweis 2026-10-11 22:55:35 +02:00
wkh e1bdb6c703 Changelog geordnet 2026-10-11 22:51:52 +02:00
wkh 777a3b56e2 record: 0 und 1 = erste Zeile, negative Nummern zählen vom Ende 2026-10-11 22:51:43 +02:00
wkh d5286c3600 record: Nummern unter 1 und Text sind ein Fehler statt Zeilen vom Ende 2026-10-11 22:48:42 +02:00
wkh f83d1bd6f8 Steuertabellen 2026 für DE, AT, CH (Bund) und LI (Land) zu tax 2026-10-11 22:44:45 +02:00
wkh 6c0d675c5d Hinweis zu select (README, row.man); Backslash in rdb man korrigiert 2026-10-11 22:35:37 +02:00
wkh d2c4343136 Version 0.5.0: pick, Zeilen auf dem Terminal wählen 2026-10-11 22:25:45 +02:00
wkh e7a7577900 Version 0.4.0: mask, eine Eingabemaske mit eigener Oberfläche 2026-10-11 22:08:38 +02:00
wkh 837a73366d demo: Eingabemaske entry für screen 2026-10-11 21:54:38 +02:00
215 changed files with 24005 additions and 497 deletions
+3
View File
@@ -0,0 +1,3 @@
/bin/*
!/bin/rdb
/coherent.pdf
+75 -1
View File
@@ -5,7 +5,81 @@ Alle wichtigen Änderungen stehen hier. Das Format folgt
folgen [Semantic Versioning](https://semver.org/lang/de/). Die Version steht in folgen [Semantic Versioning](https://semver.org/lang/de/). Die Version steht in
`lib/rdb/version.rb`; `rdb --version` zeigt sie an. `lib/rdb/version.rb`; `rdb --version` zeigt sie an.
## [Unveröffentlicht] ## [0.8.0] - 2026-10-30
**Beim Umstieg:** Hashindizes (`.h`) und mit `index -x` gebaute Indizes (`.i`) neu bauen.
### Hinzugefügt
- `doc/handbuch.txt`: der Text des gedruckten Handbuchs „COHERENT /rdb Relational Database Manager“ (346 Seiten), per OCR aus dem Scan, mit PDF- und Buchseiten.
- `demo/handbuch/`: die Beispiele aus dem Lehrbuchteil (Kapitel 2, 3, 6, 7, 10, 11, 15) mit ihren Tabellen. `beispiele.txt` hält Befehl und gedruckte Ausgabe, `test/handbuch_test.rb` vergleicht sie; `mise run test` führt ihn mit aus. Druckfehler des Buchs und Stellen, an denen wir abweichen, sind dort vermerkt.
### Geändert
- `testall` und die Tests setzen `EDITOR=true`, damit kein echter Editor startet.
- `search` und `seek` ohne Schlüsselspalte nehmen die Spaltennamen aus dem Kopf einer Schlüsseltabelle auf der Standardeingabe (`search -mh mailtable < name`, Handbuch S. 105). Vorher galt immer die erste Spalte der Datentabelle.
- `gregorian -u` schreibt den Monat ohne führende Null (`6/01/89`), wie im Handbuch.
- `mean` schreibt einen ganzzahligen Mittelwert ohne `.00` (`4786`, Handbuch S. 26).
### Verbessert
- Schnellzugriff: `search`, `seek`, `delete` und `update.rdb` lesen bei `-mh`, `-mi` und `-mr` nur noch den Indexeintrag und den einen Satz (Seek auf Byte-Positionen, bei `.i` Halbierung über die Datei), nicht mehr Tabelle und Index vollständig. `Data` liest die Zeilen erst, wenn eine Methode alle braucht.
- Die Hashfunktion ist FNV-1a statt der Bytesumme. Vorher fielen 3000 fünfstellige Nummern in 30 Plätze (größter Eimer 223), jetzt liegt der größte Eimer bei etwa 4. **Hashindizes (`.h`) müssen neu gebaut werden** (`index -mh`).
- `total`, `mean`, `subtotal` und die /act-Befehle rechnen exakt mit `Rational` statt `Float`: `0.1 + 0.2 + 0.7` ergibt `1.0`, Beträge summieren sich auf den Rappen genau, und es wird kaufmännisch gerundet (halb auf).
- `bin/rdb` startet mit `ruby --disable-gems`: jeder Befehl ist in etwa doppelt so schnell gestartet (ca. 85 statt 170 ms), weil RubyGems nicht geladen wird. `rdb` braucht nur die Standardbibliothek.
- Die Tests laufen parallel (`parallelize_me!`; `MT_CPU=1` für nacheinander). Zusammen mit dem schnelleren Start dauert die Suite 21 statt 70 Sekunden.
- Intern: Hilfsfunktionen der Befehlsdateien liegen in `Rdb::Helpers` statt auf `Object`, die Konstanten (`STATS`, `TERM_CAPS` ...) in `Rdb`. Kopf- und Strichzeile entstehen an einer Stelle (`Table.head_text`, `dash_cells`, `headed?`), `awk` baut auf `awk_text` auf.
### Sicherheit
- `report`: Spaltenwerte in `<!befehl <Spalte>!>` wurden unmaskiert in einen Shell-Aufruf eingesetzt, eine Zelle konnte so Befehle ausführen. Sie werden jetzt mit `Shellwords.escape` eingesetzt.
- `screen`: Spaltennamen, die keine gültigen Shell-Variablennamen sind, brechen mit einer Meldung ab, statt ins erzeugte Skript zu gelangen.
- `lock`/`unlock`: Sperrdateien liegen in `/tmp/rdb-locks-<UID>/` (Modus 0700, Besitzer und Symlinks geprüft) statt lose in `/tmp`; Lesen und Schreiben laufen unter `flock`.
- `vilock`: die Sperre wird atomar über einen Hardlink genommen (vorher `exist?` und `rename` mit Lücke dazwischen).
### Behoben
- `EDITOR` mit Argumenten (`nvim -f`) in `vilock` und `update.rdb` wurde als ein Programmname behandelt; der Editor startete nie. Scheitert der Editor, meldet `update.rdb` das, statt „record replaced“ zu schreiben.
- `update.rdb e`: Der Satz blieb leer, wenn der Editor scheiterte oder abgebrochen wurde. Er wird jetzt in jedem Fall zurückgeschrieben.
- Spaltennamen mit Umlauten (`row 'Über > 3'`) scheiterten mit einem awk-Fehler. Der Ausdrucksumsetzer kennt jetzt Unicode-Buchstaben.
- Dateien, die kein UTF-8 sind (Latin-1 aus COHERENT-Zeiten), brachen mit `invalid byte sequence` ab. Sie werden als Latin-1 gelesen und als UTF-8 ausgegeben.
- Fehler wie ungültige Regex, ungültiges Datum oder Ein-/Ausgabefehler endeten mit einem Ruby-Backtrace. Jetzt eine Zeile; `RDB_DEBUG=1` zeigt den Backtrace. Ein geschlossenes Pipe-Ende (`| head`) und Ctrl-C beenden still.
- `append`, `enter`, `replace` und `ve` schrieben Werte mit Tab oder Zeilenumbruch und machten die Tabelle kaputt. Sie lehnen solche Werte jetzt ab.
- Tabellen, Indexdateien und `substitute` werden über eine temporäre Datei mit `rename` geschrieben; ein Abbruch lässt die alte Datei statt einer halben neuen.
- `index -mb` und `-mi` sortieren nach dem Schlüssel ohne umgebende Leerzeichen, so wie `search` vergleicht.
- `sorttable -r` kehrte auch die Reihenfolge gleicher Schlüssel um; sie bleibt jetzt erhalten.
- `index -x` vermerkt die Faltung im Kopf der `.i`-Datei (`Offset-x`). `search` bisektiert in der Ordnung des Index: ohne `-x` in einem gefalteten Index wurden Sätze übersehen, mit `-x` in einem ungefalteten ebenso (dort und bei `-mb` liest die Teilsuche jetzt alle Einträge). `append` hält einen gefalteten Index in seiner Ordnung.
- `jointable -n` wurde stillschweigend ignoriert. Wie in der Man-Page vergleicht es die Schlüssel jetzt als Zahlen (`01`, `1` und ` 1.0` passen zusammen).
- Spaltennamen, die `justify` mit Leerzeichen aufgefüllt hat, wurden nicht mehr gefunden: `column Name` lieferte eine leere Spalte, `index` brach ab. Leerraum um die Namen im Kopf zählt jetzt nicht mehr.
## [0.7.0] - 2026-10-12
### Hinzugefügt
- `column -d Spalte ...` (und `project -d`) löscht Spalten: alle anderen bleiben in ihrer Reihenfolge. Fehler bei unbekannter Spalte oder wenn alle gelöscht würden. Dazu Abschnitt in `man/column.man`, Beispiel in `testall.cmds` und Tests.
- Kantonstarife 2026 für `tax`: `demo/taxCH_AI2026`, `taxCH_AR2026`, `taxCH_SG2026`, `taxCH_GR2026` (Präfix `taxCH_` für die Schweiz; einfache Staatssteuer für Alleinstehende, vor Steuerfuss, Gemeinde und Kirche), erzeugt mit `tools/gen_tax_tables.rb`. Mit Tests, Beispiel in `testall.cmds` und Erklärung zum Steuerfuss im README.
### Behoben
- `rdb man dashline` (und `headline`, `backup`, `dbase`, `accounting_ter`) zeigte als Überschrift eine Makrozeile (`dashline -- .PP`). Themen-Seiten ohne Beschreibung nehmen jetzt den Titel aus der `.TH`-Zeile.
- `splittable -0` und mehr als 676 Stücke endeten mit einem Ruby-Abbruch (im zweiten Fall nach 676 geschriebenen Dateien). Jetzt eine Fehlermeldung, und es wird vorher geprüft, damit nichts halb geschrieben wird.
## [0.6.0] - 2026-10-11
### Hinzugefügt
- Steuertabellen 2026 für `tax`: `demo/taxDE2026`, `taxAT2026`, `taxCH2026` (nur Bundessteuer), `taxLI2026` (nur Landessteuer), erzeugt mit `tools/gen_tax_tables.rb`, mit Tests.
### Geändert
- `record`: 0 und 1 sind die erste Zeile, negative Zahlen zählen vom Ende (`-1` letzte, `-2` vorletzte ...). Außerhalb der Tabelle kommt eine leere Tabelle, Text und Dezimalzahlen sind ein Fehler. (Vorher lieferten 0, -1 und Text ungewollt Zeilen vom Ende.) `testall.cmds` und `man/record.man` zeigen es.
- README und `man/row.man` erklären, warum `select` in bash/zsh/ksh einen Syntaxfehler gibt und wie man es trotzdem aufruft.
### Behoben
- `rdb man` zeigte `\\select` in den Man-Pages als `\elect`: ein doppelter Backslash wird jetzt zuerst geschützt.
## [0.5.0] - 2026-10-11
### Hinzugefügt
- `pick`: Tabelle auf dem Terminal durchblättern, filtern und eine oder mehrere Zeilen (`-m`) auswählen; die Auswahl geht als Tabelle auf die Standardausgabe. `-k` nimmt die Tasten aus einem String. Dazu `man/pick.man`, Beispiele in `testall.cmds` und Tests (auch mit Pseudo-Terminal).
## [0.4.0] - 2026-10-11
### Hinzugefügt
- `mask`: Eingabemaske mit eigener Oberfläche (Felder mit Breite, Schaltflächen, Rahmen `-b`, `-s` zeigt das Bild ohne Terminal). Schreibt die Eingabe als Tabelle auf die Standardausgabe. Die Vorlage kommt wie bei `screen` von der Standardeingabe (`mask < entry`). Dazu `man/mask.man`, `demo/maskform` und Tests (auch mit Pseudo-Terminal).
- `demo/entry`: beschriftete Eingabemaske für `screen` (README erklärt den Unterschied zu `form`).
## [0.3.0] - 2026-10-11 ## [0.3.0] - 2026-10-11
+149 -7
View File
@@ -10,11 +10,21 @@ sind nach dem Handbuch neu geschrieben.
## Einrichten ## Einrichten
``` ```
mise trust # einmal nach dem Clone: mise.toml freigeben
mise install # Ruby 3.4 mise install # Ruby 3.4
mise run install # legt die Symlinks row, column, total ... in bin/ an mise run install # legt die Symlinks row, column, total ... in bin/ an
mise run test # 76 Tests mise run test # 136 Tests und die Beispiele aus dem Handbuch
``` ```
Ohne `mise trust` brechen in einem frisch geklonten Ordner alle `mise`-Befehle ab.
> **Wichtig: Nach jedem Clone zuerst die Symlinks anlegen.**
> Im Repository liegt nur `bin/rdb`. Die Befehle `row`, `column`, `total` ...
> sind Symlinks darauf und werden **nicht** mit eingecheckt (`.gitignore`).
> Ohne `mise run install` (oder ohne mise: `bin/rdb install`) gibt es sie nicht,
> und Aufrufe wie `row ...` enden mit `command not found`. Auch `testall` und
> die Tests brauchen sie. Nach neuen Befehlen den Schritt wiederholen.
Danach steht `bin/` im PATH, solange man im Projektordner ist (`mise.toml`). Danach steht `bin/` im PATH, solange man im Projektordner ist (`mise.toml`).
Jeder Befehl ist ein Symlink auf `bin/rdb`, das am Aufrufnamen erkennt, was zu Jeder Befehl ist ein Symlink auf `bin/rdb`, das am Aufrufnamen erkennt, was zu
tun ist. Es geht auch ohne Symlinks: `rdb row 'Cost > 5' < demo/inventory`. tun ist. Es geht auch ohne Symlinks: `rdb row 'Cost > 5' < demo/inventory`.
@@ -40,6 +50,8 @@ Dasselbe gilt für **Listen** (ein Datensatz als `Spalte<Tab>Wert`-Zeilen, die
Datei beginnt mit einer Leerzeile). `tabletolist` und `listtotable` wandeln um, Datei beginnt mit einer Leerzeile). `tabletolist` und `listtotable` wandeln um,
die meisten Befehle lesen beides. die meisten Befehle lesen beides.
`column -d Spalte ...` löscht Spalten (alle anderen bleiben), `column Spalte ...` wählt sie aus.
`row`, `compute` und `validate` übergeben ihren Ausdruck an awk, nachdem sie `row`, `compute` und `validate` übergeben ihren Ausdruck an awk, nachdem sie
Spaltennamen durch `$N` ersetzt haben. Es gilt also awk-Syntax. Spaltennamen durch `$N` ersetzt haben. Es gilt also awk-Syntax.
@@ -77,6 +89,110 @@ Eine Zeile mit `##` erscheint als Überschrift in der Ausgabe, eine mit `#` ist
ein stiller Kommentar. Neue Befehle brauchen hier ein Beispiel, sonst schlägt der Test ein stiller Kommentar. Neue Befehle brauchen hier ein Beispiel, sonst schlägt der Test
`test_testall_mentions_every_command` fehl. `test_testall_mentions_every_command` fehl.
## Beispiele aus dem gedruckten Handbuch
`doc/handbuch.txt` ist der Text des gedruckten Handbuchs „COHERENT /rdb Relational
Database Manager“ (Mark Williams, 346 Seiten), per OCR aus dem Scan `coherent.pdf`.
Er ist nicht korrigiert: Tabulatoren fehlen, Tabellen können verrutscht sein. Jede
Seite ist mit PDF- und Buchseite markiert (Buchseite = PDF-Seite − 10). Kapitel 1–16
sind ein Lehrbuch, Kapitel 17 enthält dieselben Man-Pages wie `man/`.
`demo/handbuch/` enthält die Beispiele aus dem Lehrbuch mit ihren Tabellen, ein
Unterordner je Kapitel. `beispiele.txt` hält zu jedem Beispiel den Befehl und die
Ausgabe, wie sie im Buch steht; `test/handbuch_test.rb` führt alles aus und vergleicht
(ohne Leerraum, das Buch richtet mit Leerzeichen aus). In der Datei bedeutet:
```
@ kap03 die folgenden Befehle laufen in diesem Unterordner
## S. 26 ... Überschrift mit Buchseite
$ befehl darunter die Ausgabe laut Buch
# ... Kommentar, z. B. ein Druckfehler des Buchs (die Ausgabe ist korrigiert)
! ... hier weichen wir bewusst ab; nicht verglichen, der Test meldet aber,
wenn die Ausgabe doch wieder zum Buch passt
```
## Vorlagen: `form` und `entry`
- `demo/form` ist eine Vorlage für `report` und `letter`: sie setzt Spaltenwerte in einen Text ein.
Sie hat keine Beschriftungen und nennt `Name` zweimal.
- `demo/entry` ist eine Eingabemaske für `screen`: jedes Feld kommt einmal vor und hat eine
Beschriftung. `screen < entry > maske.sh` erzeugt das Skript. Starten:
`CLEAR=$(clear.rdb) sh maske.sh > tabelle 2>&1`. Die Tabelle geht auf stderr (wie im Original),
daher das `2>&1`. Mit `form` würde die Maske leer und doppelt aussehen.
## Eingabemasken: `mask`
`mask` ist die Variante von `screen` mit eigener Oberfläche (nur Ruby, kein ncurses). Es zeichnet die
Vorlage (von der Standardeingabe, wie `screen`; ein Dateiname geht auch) selbst und schreibt die Eingabe als Tabelle auf die Standardausgabe, also pipefähig:
```
mask -b < demo/maskform Rahmen (-b), Felder, Schaltflächen
mask < demo/maskform > neu Tabelle in eine Datei
mask < demo/maskform | append -h kunden oder direkt in eine Tabelle
mask -s < demo/maskform nur das Bild und die Feldpositionen, ohne Terminal
```
In der Vorlage: `<Spalte>` oder `<Spalte:20>` ist ein Feld (mit Breite), `[ Speichern ]` eine Schaltfläche,
`[ Abbrechen ]` (oder Cancel, Abort, Quit) bricht ab, `<!date!>` fügt Befehlsausgabe ein. Kommt eine Spalte mehrfach
vor, ist es ein Feld. Tab/Pfeile wechseln, Enter bestätigt, Esc bricht ab (Status 1, keine Ausgabe).
## Zeilen auswählen: `pick`
`pick` zeigt eine Tabelle auf dem Terminal, man scrollt, filtert und wählt eine oder mehrere Zeilen. Die Tabelle
kommt von der Standardeingabe, die gewählten Zeilen gehen als Tabelle auf die Standardausgabe, also mitten in der Pipe:
```
pick < inventory eine Zeile wählen
pick -m < inventory | total Amount Value mehrere (Leertaste markiert, a alle)
column Item Description < inventory | pick -m | jointable - owners
pick -m -k 'down space down enter' < inventory Tasten aus einem String (Skripte, Tests)
```
Pfeile, Bild auf/ab, Pos1/Ende scrollen; `/` filtert (Enter behält den Filter, Esc löscht ihn); Enter wählt;
Esc bricht ab (Status 1, keine Ausgabe). Ohne Markierung gilt die Zeile unter dem Cursor.
## Steuertabellen 2026 für `tax`
`demo/` enthält vier Tarife für das Steuerjahr 2026 im Format von `tax` (income, tax, percent), jeweils für
Alleinstehende (Grundtarif). Erzeugt mit `ruby tools/gen_tax_tables.rb`.
| Datei | Land | Quelle | Genauigkeit |
|---|---|---|---|
| `taxDE2026` | Deutschland, Einkommensteuer | § 32a EStG (Grundfreibetrag 12 348 €) | Kurvenstücke durch Geraden genähert, Abweichung unter 0,15 € (die Formel rundet ab, `tax` auf) |
| `taxAT2026` | Österreich, Einkommensteuer | § 33 EStG (0 % bis 13 539 €, dann 20/30/40/48/50/55 %) | exakt, vor Absetzbeträgen |
| `taxCH2026` | Schweiz, **nur direkte Bundessteuer** | Art. 36 DBG, ESTV-Rundschreiben 2-215-D-2025 | Stufen exakt, das Gesetz rechnet in 100-Franken-Schritten |
| `taxLI2026` | Liechtenstein, **nur Landessteuer** | Art. 19 SteG (LR 640.0, Fassung 01.07.2026) | exakt |
| `taxCH_AI2026` | Kanton Appenzell I.Rh., einfache Staatssteuer | Art. 38 StG (ESTV-Kantonsblatt) | exakt |
| `taxCH_AR2026` | Kanton Appenzell A.Rh., einfache Staatssteuer (Alleinstehendentarif) | Art. 39 StG, Beträge ab 2024 | exakt |
| `taxCH_SG2026` | Kanton St. Gallen, einfache Staatssteuer | Art. 50 StG, Beträge ab 2026 | exakt |
| `taxCH_GR2026` | Kanton Graubünden, einfache Kantonssteuer | Art. 39 StG, indexierte Beträge ab 2025 | exakt |
```
tax 60000 < demo/taxDE2026 14233
tax 60000 < demo/taxAT2026 15447
tax 60000 < demo/taxCH2026 671
tax 60000 < demo/taxLI2026 1396 (mal 1 + Gemeindezuschlag, 150 % bis 250 %)
```
Der Betrag ist die Steuer auf das **zu versteuernde** Einkommen. Abzüge, Sozialversicherung, Absetzbeträge,
Kirchensteuer und Soli sind nicht enthalten. Für die Schweiz kommen Kanton und Gemeinde dazu (sie sind meist
höher als der Bund), für Liechtenstein der Gemeindezuschlag: gesamt = Landessteuer × (1 + Zuschlag/100).
Ehepaar- und Alleinerziehendentarife fehlen. Das ist keine Steuerberatung.
**Kantone (AI, AR, SG, GR):** Die Dateien tragen den Präfix `taxCH_` (Schweiz) vor dem Kantonskürzel; `taxCH2026` ist die Bundessteuer. Die Tabellen geben die *einfache Steuer* wieder. Sie wird mit dem Steuerfuss multipliziert,
und Gemeinde und Kirche kommen dazu. Der Kanton setzt den Steuerfuss pro Jahr fest:
| Kanton | Steuerfuss Kanton 2026 | Quelle |
|---|---|---|
| AI | 96 % | Kantonsblatt AI (Grossratsbeschluss 1.12.2025) |
| SG | 105 % | Budgetbeschluss des Kantonsrats (Websuche, nicht im Kantonsblatt) |
| GR | 92 % | Grosser Rat, Budget 2026 (Websuche) |
| AR | nicht ermittelt | AR rechnet in Steuereinheiten, die Zahl für 2026 habe ich nicht gefunden |
Beispiel AI bei 60 000: `tax 60000 < demo/taxCH_AI2026` = 3770, mal 0,96 = 3619 (Kantonssteuer, ohne Bezirk, Gemeinde und Kirche).
Oberhalb einer Grenze gilt bei allen vier Kantonen ein fester Satz auf das *ganze* Einkommen (AI ab 200 000 mit 8 %,
AR ab 260 800 mit 2,6 %, SG ab 264 500 mit 8,5 %, GR ab 780 440 mit 11 %); in der Tabelle ist das die letzte Zeile.
## Befehle ## Befehle
| Gruppe | Befehle | | Gruppe | Befehle |
@@ -91,7 +207,7 @@ ein stiller Kommentar. Neue Befehle brauchen hier ein Beispiel, sonst schlägt d
| Text | `cap` `uppercase` `lowercase` `substitute` `trimblank` `padstring` `length` `filesize` `ascii` `chr` `word` `prompt` `not` `path` | | Text | `cap` `uppercase` `lowercase` `substitute` `trimblank` `padstring` `length` `filesize` `ascii` `chr` `word` `prompt` `not` `path` |
| Umwandeln | `tabletolist` `listtotable` `listtosh` `tabletofix` `fixtotable` `tabletostruct` `tabletotbl` `tabletofact` `tabletorule` `tabletom4` `tabletosed` `translate` `uniondict` | | Umwandeln | `tabletolist` `listtotable` `listtosh` `tabletofix` `fixtotable` `tabletostruct` `tabletotbl` `tabletofact` `tabletorule` `tabletom4` `tabletosed` `translate` `uniondict` |
| Datum, Namen | `julian` `gregorian` `computedate` `todaysdate` `soundex` `like` `hashkey` | | Datum, Namen | `julian` `gregorian` `computedate` `todaysdate` `soundex` `like` `hashkey` |
| Berichte | `report` `reportwriter` `screen` `label` `letter` | | Berichte | `report` `reportwriter` `screen` `mask` `pick` `label` `letter` |
| Terminal, Hilfe | `termput` `tset` `clear.rdb` `cursor` `menu` `rdb` `commands` `helpme` `whatis` `whatwill` `howmany` `man` | | Terminal, Hilfe | `termput` `tset` `clear.rdb` `cursor` `menu` `rdb` `commands` `helpme` `whatis` `whatwill` `howmany` `man` |
| Betrieb | `testall` `testsearch` `timesearch` `rmcore` `cpdir.rdb` | | Betrieb | `testall` `testsearch` `timesearch` `rmcore` `cpdir.rdb` |
| Buchhaltung (/act) | `act` `chartdup` `foot` `adjust` `balance` `close` `consolidate` `getjournal` `fillform` `calculate` `tax` `cashflow` `calcpay` `w2` `bom` `explode` `sale` `invoice` `cstate` `update.inv` | | Buchhaltung (/act) | `act` `chartdup` `foot` `adjust` `balance` `close` `consolidate` `getjournal` `fillform` `calculate` `tax` `cashflow` `calcpay` `w2` `bom` `explode` `sale` `invoice` `cstate` `update.inv` |
@@ -123,10 +239,30 @@ er nicht mehr passt (außer mit `-a`). Beide halten die Indizes aktuell.
## Unterschiede zum Original ## Unterschiede zum Original
- Es gibt kein COHERENT-Programmmaterial, daher sind die **Ausgaben nur anhand der - Es gibt kein COHERENT-Programmmaterial, daher sind die **Ausgaben nur anhand der
Man-Pages geprüft**, nicht gegen das echte /rdb. Die Beispiele aus dem Man-Pages und dem gedruckten Handbuch geprüft**, nicht gegen das echte /rdb. Die
Handbuch sind als Tests enthalten (`test/rdb_test.rb`). Beispiele aus den Man-Pages sind als Tests enthalten (`test/rdb_test.rb`), die aus
- Die Indexdateien haben ein eigenes, einfaches Format (das Original ist nicht dem Lehrbuch in `demo/handbuch/` (`test/handbuch_test.rb`).
dokumentiert). Sie sind nicht mit alten /rdb-Dateien austauschbar. - Die Indexdateien sind dem Original nachgebaut, aber nicht gleich (Handbuch S. 103–108):
die Hashtabelle `.h` hat 2n statt 2n+1 Plätze (Hashfunktion FNV-1a), und in `.i` steht der
Schlüssel vor dem Offset statt dahinter. Ein mit `index -x` gebauter `.i`
heißt in der zweiten Spalte `Offset-x`. Alte /rdb-Indizes sowie `.h`- und mit `-x` gebaute
`.i`-Dateien von Versionen vor 0.8.0 muss man neu bauen.
- Summen, Mittelwerte und /act-Beträge sind Dezimalzahlen (`Rational`), gerundet wird halb auf.
- Dateien, die kein UTF-8 sind, liest `rdb` als Latin-1 und schreibt sie als UTF-8. Fehler
erscheinen als eine Zeile; mit `RDB_DEBUG=1` kommt der Ruby-Backtrace. Werte mit Tab oder
Zeilenumbruch lehnen `append`, `enter`, `replace` und `ve` ab.
- `lock`/`unlock` legen ihre Sperrdateien in `/tmp/rdb-locks-<UID>/` ab (Modus 0700, `flock`),
nicht als `/tmp/L<Tabelle>` wie in den Man-Pages. Eine Sperre eines abgestürzten Prozesses
wird nicht erkannt; `unlock` hebt sie auf.
- `vilock` sperrt atomar über einen Hardlink; `EDITOR` darf Argumente haben (`nvim -f`).
Nach `kill -9` bleibt `LOCK<Tabelle>` liegen und muss von Hand zurückbenannt werden.
- `report`: Spaltenwerte in `<!befehl <Spalte>!>` werden für die Shell maskiert und kommen
als ein Wort an; nicht in Anführungszeichen setzen. `screen` verlangt Spaltennamen, die
gültige Shell-Variablennamen sind (Buchstaben, Ziffern, `_`).
- `sorttable` lässt Zeilen mit gleichem Schlüssel in ihrer Reihenfolge; das Original
ordnet sie nach der ganzen Zeile, wie `sort` (Handbuch S. 94).
- `subtotal` schreibt bei einer Summe von null ein leeres Feld; das Handbuch zeigt
`0` und die Kontonummern als `101.0` (S. 30).
- Spaltennamen unterscheiden wie im Original Groß- und Kleinschreibung. Mit - Spaltennamen unterscheiden wie im Original Groß- und Kleinschreibung. Mit
`RDB_ICASE=1` (z. B. in `mise.toml` unter `[env]`) wird sie ignoriert: `RDB_ICASE=1` (z. B. in `mise.toml` unter `[env]`) wird sie ignoriert:
ein exakter Treffer gewinnt, mehrere ähnliche sind ein Fehler. In ein exakter Treffer gewinnt, mehrere ähnliche sind ein Fehler. In
@@ -135,6 +271,10 @@ er nicht mehr passt (außer mit `-a`). Beide halten die Indizes aktuell.
`row`, `compute`, `column`, `sorttable`, `jointable`, `rename`, `validate` und `row`, `compute`, `column`, `sorttable`, `jointable`, `rename`, `validate` und
`rdb` haben dazu den Abschnitt „Case of Column Names“; er ist die einzige `rdb` haben dazu den Abschnitt „Case of Column Names“; er ist die einzige
Ergänzung gegenüber den Original-Seiten. Ergänzung gegenüber den Original-Seiten.
- `select` ist in bash, zsh und ksh ein reserviertes Wort. `select 'Cost > 5' < inventory` endet dort
mit `syntax error near unexpected token '<'`, weil die Shell das Schlüsselwort vor dem `PATH` auswertet.
Es gibt dasselbe unter dem Namen `row`. Außerdem gehen `\select ...`, `command select ...` und
`rdb select ...`.
- `jointable` braucht keine vorsortierten Tabellen. - `jointable` braucht keine vorsortierten Tabellen.
- `ve` ist ein zeilenorientierter Editor, kein Bildschirmeditor. - `ve` ist ein zeilenorientierter Editor, kein Bildschirmeditor.
- `soundex` nutzt den Standard-Algorithmus. Die Beispielwerte im Handbuch - `soundex` nutzt den Standard-Algorithmus. Die Beispielwerte im Handbuch
@@ -147,13 +287,15 @@ er nicht mehr passt (außer mit `-a`). Beide halten die Indizes aktuell.
## Aufbau ## Aufbau
``` ```
bin/rdb das eine Programm (und die Symlinks darauf) bin/rdb das eine Programm (die Symlinks darauf legt `rdb install` an, nicht im Repo)
lib/rdb.rb Registry der Befehle lib/rdb.rb Registry der Befehle
lib/rdb/table.rb Tabellen und Listen lesen und schreiben lib/rdb/table.rb Tabellen und Listen lesen und schreiben
lib/rdb/fast.rb Schnellzugriff über Byte-Offsets lib/rdb/fast.rb Schnellzugriff über Byte-Offsets
lib/rdb/cmd/*.rb die Befehle, nach Gruppen lib/rdb/cmd/*.rb die Befehle, nach Gruppen
man/ Man-Pages (troff-Quellen aus den MWC-Archiven) man/ Man-Pages (troff-Quellen aus den MWC-Archiven)
demo/ Beispieltabellen; testall.cmds = je ein Beispiel pro Befehl, testall.old = letzter Lauf demo/ Beispieltabellen; testall.cmds = je ein Beispiel pro Befehl, testall.old = letzter Lauf
demo/handbuch/ die Beispiele aus dem gedruckten Handbuch, je Kapitel ein Ordner
doc/handbuch.txt Text des gedruckten Handbuchs (OCR)
test/ Tests test/ Tests
``` ```
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
+3 -1
View File
@@ -1,8 +1,10 @@
#!/usr/bin/env ruby #!/usr/bin/env -S ruby --disable-gems
# frozen_string_literal: true # frozen_string_literal: true
# rdb -- every /rdb command is this one program, looking at the name it was # rdb -- every /rdb command is this one program, looking at the name it was
# called by. `row`, `column`, `total` ... are symlinks to it (`rdb install`). # called by. `row`, `column`, `total` ... are symlinks to it (`rdb install`).
# --disable-gems: rdb needs only the standard library, and skipping RubyGems
# makes each command start about twice as fast.
require_relative '../lib/rdb' require_relative '../lib/rdb'
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb
-1
View File
@@ -1 +0,0 @@
/home/wkh/Development/Coherent/rdb/bin/rdb

Some files were not shown because too many files have changed in this diff Show More