Compare commits
8 Commits
aa22651467
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
9bd2079cd4
|
|||
|
7ef782dda2
|
|||
|
6432d37df3
|
|||
|
7300ba933c
|
|||
|
bfca546924
|
|||
|
f29ae86a8a
|
|||
|
69a85dacdc
|
|||
|
314db1710f
|
140
README.md
140
README.md
@@ -10,7 +10,12 @@ Code largely based off of [https://github.com/bontibon/kjv.git](https://github.c
|
||||
usage: ./allioli [flags] [reference...]
|
||||
|
||||
-l list books
|
||||
-w <n> set custom terminal width
|
||||
-W no line wrap
|
||||
-F no footnotes
|
||||
-g show only German (no Latin)
|
||||
-L show only Latin (no German)
|
||||
-j output as JSON
|
||||
-h show help
|
||||
|
||||
Reference types:
|
||||
@@ -35,6 +40,72 @@ Code largely based off of [https://github.com/bontibon/kjv.git](https://github.c
|
||||
All verses in a chapter of a book that match a pattern
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### Bilingual Latin-German Display
|
||||
|
||||
allioli displays the original Latin Vulgate text alongside the German Allioli translation in a side-by-side format. This allows for easy comparison between the original and translated text.
|
||||
|
||||
- By default, both Latin and German are displayed side-by-side in two columns
|
||||
- Use `-g` flag to display only the German translation
|
||||
- Use `-L` flag to display only the Latin text
|
||||
|
||||
### Footnotes
|
||||
|
||||
The text includes footnotes marked with Unicode superscript numbers (e.g., ¹, ², ³). Footnotes are displayed below their corresponding verses with proper indentation.
|
||||
|
||||
- Use `-F` flag to disable footnote display if desired
|
||||
|
||||
### JSON Output
|
||||
|
||||
allioli supports structured JSON output for programmatic access to bible verses and footnotes. The JSON schema provides a hierarchical structure with book information, chapters, verses, and associated footnotes.
|
||||
|
||||
- Use `-j` flag to output in JSON format
|
||||
- All other flags (`-F`, `-g`, `-L`) are respected in JSON mode
|
||||
- The JSON structure follows this schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"book": {
|
||||
"name": "Johannes",
|
||||
"abbreviation": "Joh",
|
||||
"number": 51
|
||||
},
|
||||
"chapter": 1,
|
||||
"verses": [
|
||||
{
|
||||
"verse": 1,
|
||||
"text": {
|
||||
"latin": "...",
|
||||
"german": "..."
|
||||
},
|
||||
"footnotes": [
|
||||
{
|
||||
"number": 1,
|
||||
"text": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```bash
|
||||
# Get John 1:1 as JSON
|
||||
./allioli -j "Johannes 1:1"
|
||||
|
||||
# Get verses without footnotes
|
||||
./allioli -j -F "Johannes 1:1-3"
|
||||
|
||||
# Get only Latin text (with footnotes)
|
||||
./allioli -j -L "Johannes 1:1"
|
||||
|
||||
# Get only German text (with footnotes)
|
||||
./allioli -j -g "Johannes 1:1-5"
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
### From Source
|
||||
@@ -57,10 +128,73 @@ so for example using yay, it's a simple
|
||||
```
|
||||
|
||||
|
||||
## Current state of project
|
||||
## Example
|
||||
|
||||
You might notice the two books, 'Ester' and 'xEster'.
|
||||
The significance of this mark left over from the original XML this project has started from will be invistigated in the coming months.
|
||||
Here's for example how the beginning of John looks. The first part being an introduction to the chapter and then some verses with footnotes.
|
||||
|
||||
```
|
||||
Johannes
|
||||
Prolog (V. 18): Das Gott wesensgleiche Wort tat sich durch die Schöpfung und die
|
||||
übernatürliche Offenbarung kund und ward dennoch nicht von den sündigen Menschen erkannt. (V. 5)
|
||||
Selbst als es von seinem Vorläufer angekündigt in das Seinige kam, ward es von den Seinen nicht
|
||||
aufgenommen, denen aber, die es aufnahmen, gab es die höchste Würde. (V. 13) Dennoch ward das Wort
|
||||
Fleisch und offenbarte seine Herrlichkeit. (V. 18) I. 1-12,50 1. Das Wort wird von denen, die guten
|
||||
Willens sind, aufgenommen, aber nicht von allen mit ausreichendem Glauben. a. Mit vollkommenem
|
||||
Glauben von dem heil. Johannes dem Täufer, der ihn vor den Abgesandten des hohen Rates (V. 28) und
|
||||
vor seinen Jüngern bekennt (V. 34), von den ersten Jüngern des Herrn, nach einem zweiten Zeugnis des
|
||||
Johannes (V. 42) und der Offenbarung seiner Allwissenheit seitens des Herrn.
|
||||
|
||||
|
||||
1:1 In principio erat verbum, et verbum erat apud | Im Anfange¹ war² das Wort,³ und das Wort war
|
||||
Deum, et Deus erat verbum. | bei⁴ Gott,⁵ und Gott⁶ war das Wort.
|
||||
¹Ehe etwas ward. [Gen 1,1, Spr 8,23] Mittelbar folgt hieraus nach dem
|
||||
Sprachgebrauche der heil. Schrift die Ewigkeit des Wortes.
|
||||
²Gegensatz zu [Gen 1,1]: Im Anfange schuf Gott. Durch die Form des
|
||||
Zeitwortes war wird das Sein des Wortes als anfangs- und endlos bezeichnet.
|
||||
³Es war steht vier Mal. Was du immer ausdenken magst, der Sohn war. (Ambr.);
|
||||
du wirst keinen Zeitraum finden, in dem er nicht war. Die Offenbarung vom Sohne Gottes war
|
||||
auch den Israeliten zuteil geworden, wie [Spr 8,22-31, Weish 7, Weish 8, Sir 24, Bar 3,94,4]
|
||||
zeigen. Dieses Wort ist offenbar eine Person, denn später werden von ihm Dinge gesagt,
|
||||
welche nur von Personen ausgesagt werden können; und zwar eine göttliche Person. (V. 1, 14)
|
||||
Der Gedanke, dass das Wort Gottes persönlich, Sohn Gottes sei, war den Juden in der der
|
||||
Menschwerdung unseres Herrn unmittelbar vorhergehenden Zeit geläufig und hatte in der
|
||||
Schrift ihren Halt, z. B. [Weish 18,15, Weish 10,15]
|
||||
⁴Von dem Vater unterschieden und doch mit ihm in innigster
|
||||
Lebensgemeinschaft stehend.
|
||||
⁵Dem Vater.
|
||||
⁶Die Weglassung des Artikels im Griechischen deutet an, dass das Wort Gottes
|
||||
im zweiten Falle nicht auf eine Person bezogen wird, wie in der ersten Hälfte des Verses
|
||||
(Orig., Euseb.)
|
||||
1:10 In mundo erat, et mundus per ipsum factus | Er war in der Welt,²⁷ und die Welt ist durch
|
||||
est, et mundus eum non cognovit. | dasselbe gemacht worden, und die Welt²⁸ hat
|
||||
| ihn nicht erkannt.
|
||||
²⁷Vor der Menschwerdung (Chrys., Aug., Bed.).
|
||||
²⁸Die Menschen, welche der Welt anhängen und das Irdische suchen (Chrys., Aug.).
|
||||
1:11 In propria venit, et sui eum non receperunt. | Er kam²⁹ in sein Eigentum,³⁰ und die Seinigen
|
||||
| nahmen ihn nicht auf.³¹
|
||||
²⁹In der Menschwerdung zu allen Menschen (Chrys., Euth.), vorzüglich den
|
||||
Juden. (Aug., Bed.) Steigerung der Verkündigung.
|
||||
³⁰V. 9 wurde das Wort Licht genannt, V. 10 wird das Wirken des Wortes als
|
||||
Licht bei den Heiden, V. 11 besonders bei den Juden geschildert.
|
||||
³¹Vergl. [Sir 24,1].
|
||||
1:12 Quotquot autem receperunt eum, dedit eis | Wie viele ihn aber aufnahmen, denen³² gab er
|
||||
potestatem filios Dei fieri, his, qui credunt | Macht,³³ Kinder Gottes zu werden, denen
|
||||
in nomine ejus: | nämlich, die an seinen Namen glauben,³⁴
|
||||
³²Eine Ausnahme, wohl besonders die Heiden (Cyr.).
|
||||
³³Durch den Glauben wird der Mensch auf die Taufe vorbereitet, in der er ein
|
||||
Kind Gottes wird. (Thom.) Der Evangelist bemerkt vorweg, wie die, welche die ihnen gegebene
|
||||
Macht benutzen, Kinder Gottes werden.
|
||||
³⁴Vergl. [Mt 5,45].
|
||||
1:13 Qui non ex sanguinibus, neque ex voluntate | welche nicht aus dem Geblüte, auch nicht aus
|
||||
carnis, neque ex voluntate viri, sed ex Deo | dem Willen des Fleisches, noch aus dem Willen
|
||||
nati sunt. | des Mannes,³⁵ sondern aus Gott geboren
|
||||
| sind.³⁶
|
||||
³⁵Das Geblüt ist gleichsam der Stoff, der Wille des Fleisches die sinnliche
|
||||
wirksame Ursache, der Wille des Mannes die vernünftige wirkende Ursache. Ein Kind Gottes
|
||||
wird man nicht, wie die Juden meinten, lediglich durch leibliche Abstammung.
|
||||
³⁶Der Evangelist schildert die hohe Würde der Kindschaft, um die Gläubigen
|
||||
zur Bewahrung dieses herrlichen Vorzuges anzustacheln (Chrys., Euth. Theoph.).
|
||||
```
|
||||
|
||||
## Similar projects
|
||||
|
||||
|
||||
437
allioli.awk
437
allioli.awk
@@ -7,11 +7,9 @@ BEGIN {
|
||||
# $6 Verse
|
||||
FS = "\t"
|
||||
|
||||
MAX_WIDTH = 100
|
||||
MAX_WIDTH = 120
|
||||
if (ENVIRON["ALLIOLI_MAX_WIDTH"] ~ /^[0-9]+$/) {
|
||||
if (int(ENVIRON["ALLIOLI_MAX_WIDTH"]) < MAX_WIDTH) {
|
||||
MAX_WIDTH = int(ENVIRON["ALLIOLI_MAX_WIDTH"])
|
||||
}
|
||||
MAX_WIDTH = int(ENVIRON["ALLIOLI_MAX_WIDTH"])
|
||||
}
|
||||
|
||||
if (cmd == "ref") {
|
||||
@@ -51,8 +49,8 @@ function parseref(ref, arr) {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
if (match(ref, "^:?[1-9]+[0-9]*")) {
|
||||
# 2, 3, 3a, 4, 5, 6, 9
|
||||
if (match(ref, "^:?[0-9]+")) {
|
||||
# 2, 3, 3a, 4, 5, 6, 9 (including chapter 0)
|
||||
if (sub("^:", "", ref)) {
|
||||
arr["chapter"] = int(substr(ref, 1, RLENGTH - 1))
|
||||
ref = substr(ref, RLENGTH)
|
||||
@@ -71,11 +69,11 @@ function parseref(ref, arr) {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
if (match(ref, "^:[1-9]+[0-9]*")) {
|
||||
if (match(ref, "^:[0-9]+")) {
|
||||
# 3, 3a, 5, 6
|
||||
arr["verse"] = int(substr(ref, 2, RLENGTH - 1))
|
||||
ref = substr(ref, RLENGTH + 1)
|
||||
} else if (match(ref, "^-[1-9]+[0-9]*$")) {
|
||||
} else if (match(ref, "^-[0-9]+$")) {
|
||||
# 4
|
||||
arr["chapter_end"] = int(substr(ref, 2))
|
||||
return "range"
|
||||
@@ -90,25 +88,25 @@ function parseref(ref, arr) {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
if (match(ref, "^-[1-9]+[0-9]*$")) {
|
||||
if (match(ref, "^-[0-9]+$")) {
|
||||
# 5
|
||||
arr["verse_end"] = int(substr(ref, 2))
|
||||
return "range"
|
||||
} else if (match(ref, "-[1-9]+[0-9]*")) {
|
||||
} else if (match(ref, "-[0-9]+")) {
|
||||
# 6
|
||||
arr["chapter_end"] = int(substr(ref, 2, RLENGTH - 1))
|
||||
ref = substr(ref, RLENGTH + 1)
|
||||
} else if (ref == "") {
|
||||
# 3
|
||||
return "exact"
|
||||
} else if (match(ref, "^,[1-9]+[0-9]*")) {
|
||||
} else if (match(ref, "^,[0-9]+")) {
|
||||
# 3a
|
||||
arr["verse", arr["verse"]] = 1
|
||||
delete arr["verse"]
|
||||
do {
|
||||
arr["verse", substr(ref, 2, RLENGTH - 1)] = 1
|
||||
ref = substr(ref, RLENGTH + 1)
|
||||
} while (match(ref, "^,[1-9]+[0-9]*"))
|
||||
} while (match(ref, "^,[0-9]+"))
|
||||
|
||||
if (ref != "") {
|
||||
return "unknown"
|
||||
@@ -119,7 +117,7 @@ function parseref(ref, arr) {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
if (match(ref, "^:[1-9]+[0-9]*$")) {
|
||||
if (match(ref, "^:[0-9]+$")) {
|
||||
# 6
|
||||
arr["verse_end"] = int(substr(ref, 2))
|
||||
return "range_ext"
|
||||
@@ -151,6 +149,11 @@ function bookmatches(book, bookabbr, query) {
|
||||
}
|
||||
|
||||
function printverse(verse, word_count, characters_printed) {
|
||||
# Remove superscript footnote numbers if footnotes are disabled
|
||||
if (ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0") {
|
||||
gsub(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/, "", verse)
|
||||
}
|
||||
|
||||
if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") {
|
||||
printf("%s\n", verse)
|
||||
return
|
||||
@@ -172,17 +175,257 @@ function printverse(verse, word_count, characters_printed) {
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
function printverse_bilingual(latin, german, latin_words, german_words, latin_count, german_count, latin_idx, german_idx, col_width, latin_chars, german_chars, latin_line, german_line) {
|
||||
# Remove superscript footnote numbers if footnotes are disabled
|
||||
if (ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0") {
|
||||
gsub(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/, "", german)
|
||||
}
|
||||
|
||||
if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") {
|
||||
printf("%s | %s\n", latin, german)
|
||||
return
|
||||
}
|
||||
|
||||
# Column width is half the total width, minus separators
|
||||
col_width = int((MAX_WIDTH - 10) / 2)
|
||||
|
||||
# Split into words
|
||||
latin_count = split(latin, latin_words, " ")
|
||||
german_count = split(german, german_words, " ")
|
||||
|
||||
latin_idx = 1
|
||||
german_idx = 1
|
||||
latin_chars = 0
|
||||
german_chars = 0
|
||||
latin_line = ""
|
||||
german_line = ""
|
||||
|
||||
# Print both columns line by line
|
||||
while (latin_idx <= latin_count || german_idx <= german_count) {
|
||||
# Build Latin line
|
||||
while (latin_idx <= latin_count) {
|
||||
word = latin_words[latin_idx]
|
||||
if (latin_chars + length(word) + (latin_chars > 0 ? 1 : 0) > col_width) {
|
||||
break
|
||||
}
|
||||
if (latin_chars > 0) {
|
||||
latin_line = latin_line " "
|
||||
latin_chars++
|
||||
}
|
||||
latin_line = latin_line word
|
||||
latin_chars += length(word)
|
||||
latin_idx++
|
||||
}
|
||||
|
||||
# Build German line
|
||||
while (german_idx <= german_count) {
|
||||
word = german_words[german_idx]
|
||||
if (german_chars + length(word) + (german_chars > 0 ? 1 : 0) > col_width) {
|
||||
break
|
||||
}
|
||||
if (german_chars > 0) {
|
||||
german_line = german_line " "
|
||||
german_chars++
|
||||
}
|
||||
german_line = german_line word
|
||||
german_chars += length(word)
|
||||
german_idx++
|
||||
}
|
||||
|
||||
# Print the line with padding
|
||||
printf("\t%-*s | %s\n", col_width, latin_line, german_line)
|
||||
|
||||
# Reset for next line
|
||||
latin_line = ""
|
||||
german_line = ""
|
||||
latin_chars = 0
|
||||
german_chars = 0
|
||||
}
|
||||
}
|
||||
|
||||
function printintroductionpar(verse, word_count, characters_printed) {
|
||||
if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") {
|
||||
printf("%s\n", verse)
|
||||
return
|
||||
}
|
||||
|
||||
word_count = split(verse, words, " ")
|
||||
characters_printed=8 #account for indents at beginning of each verse
|
||||
for (i = 1; i <= word_count; i++) {
|
||||
if (characters_printed + length(words[i]) + (characters_printed > 0 ? 1 : 0) > MAX_WIDTH) {
|
||||
printf("\n")
|
||||
characters_printed = 0
|
||||
}
|
||||
if (i != 1 && characters_printed > 0) { #need first check because we set characters_printed > 0 for first line only
|
||||
printf(" ")
|
||||
characters_printed++
|
||||
}
|
||||
printf("%s", words[i])
|
||||
characters_printed += length(words[i])
|
||||
}
|
||||
printf("\n")
|
||||
printed_intrudction=1
|
||||
}
|
||||
|
||||
function to_superscript_num(num) {
|
||||
# Convert a number to Unicode superscript
|
||||
result = ""
|
||||
len = length(num)
|
||||
for (i = 1; i <= len; i++) {
|
||||
digit = substr(num, i, 1)
|
||||
if (digit == "0") result = result "⁰"
|
||||
else if (digit == "1") result = result "¹"
|
||||
else if (digit == "2") result = result "²"
|
||||
else if (digit == "3") result = result "³"
|
||||
else if (digit == "4") result = result "⁴"
|
||||
else if (digit == "5") result = result "⁵"
|
||||
else if (digit == "6") result = result "⁶"
|
||||
else if (digit == "7") result = result "⁷"
|
||||
else if (digit == "8") result = result "⁸"
|
||||
else if (digit == "9") result = result "⁹"
|
||||
else result = result digit
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function printfootnote(footnote_num, footnote, word_count, characters_printed, sup_num) {
|
||||
if ( ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0"){
|
||||
return
|
||||
}
|
||||
else{
|
||||
# Convert footnote number to superscript
|
||||
sup_num = to_superscript_num(footnote_num)
|
||||
|
||||
if (ENVIRON["ALLIOLI_NOLINEWRAP"] != "" && ENVIRON["ALLIOLI_NOLINEWRAP"] != "0") {
|
||||
printf("\t\t%s%s\n", sup_num, footnote)
|
||||
return
|
||||
}
|
||||
|
||||
if( length(footnote) < MAX_WIDTH - 17){
|
||||
for ( i=1; i <= MAX_WIDTH - length(footnote) - length(sup_num); i++){
|
||||
printf(" ")
|
||||
}
|
||||
printf("%s%s\n", sup_num, footnote)
|
||||
}
|
||||
else{
|
||||
word_count = split(footnote, words, " ")
|
||||
printf("\t\t%s", sup_num)
|
||||
characters_printed=17 #account for indents at beginning of each multiline footnote (2 tabs + sup_num)
|
||||
for (i = 1; i <= word_count; i++) {
|
||||
if (characters_printed + length(words[i]) + (characters_printed > 0 ? 1 : 0) > MAX_WIDTH - 8 ) {
|
||||
printf("\n\t")
|
||||
characters_printed = 0
|
||||
}
|
||||
if (i != 1 && characters_printed > 0) { #Do not print empty space in front of first word for the first line (since characters_printed gets initialized > 0 we need this
|
||||
printf(" ")
|
||||
characters_printed++
|
||||
}
|
||||
printf("%s", words[i])
|
||||
characters_printed += length(words[i])
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processline() {
|
||||
# JSON mode: collect data instead of printing
|
||||
if (ENVIRON["ALLIOLI_JSON_OUTPUT"] != "" && ENVIRON["ALLIOLI_JSON_OUTPUT"] != "0") {
|
||||
book_key = $3 # Use book number as key
|
||||
|
||||
# Store book info (track multiple books for dump mode)
|
||||
if (!json_book_seen[book_key]) {
|
||||
json_book_seen[book_key] = 1
|
||||
json_books[++json_book_total] = book_key
|
||||
json_book_name[book_key] = $1
|
||||
json_book_abbr[book_key] = $2
|
||||
json_book_num[book_key] = $3
|
||||
}
|
||||
|
||||
# Check if this is a footnote
|
||||
if ($6 == "" && $7 ~ /^[0-9]+$/ && NF >= 8) {
|
||||
json_footnotes[book_key, $4, $5, $7] = $8
|
||||
json_footnote_nums[book_key, $4, $5, ++json_footnote_count[book_key, $4, $5]] = $7
|
||||
}
|
||||
# Verse with content (including chapter 0 introductions)
|
||||
else if ($6 != "" || ($7 != "" && $7 !~ /^[0-9]+$/)) {
|
||||
# Store verse data
|
||||
json_latin[book_key, $4, $5] = $6
|
||||
json_german[book_key, $4, $5] = $7
|
||||
|
||||
# Track unique verses per chapter
|
||||
if (!json_verse_seen[book_key, $4, $5]) {
|
||||
json_verse_seen[book_key, $4, $5] = 1
|
||||
json_verses[book_key, $4, ++json_verse_count[book_key, $4]] = $5
|
||||
}
|
||||
|
||||
# Track chapters per book
|
||||
if (!json_chapter_seen[book_key, $4]) {
|
||||
json_chapter_seen[book_key, $4] = 1
|
||||
json_chapters[book_key, ++json_chapter_total[book_key]] = $4
|
||||
}
|
||||
}
|
||||
|
||||
outputted_records++
|
||||
return
|
||||
}
|
||||
|
||||
# Normal text output mode
|
||||
if (printed_intrudction && $5 != 0){
|
||||
printf("\n\n")
|
||||
printed_intrudction=0
|
||||
}
|
||||
if (last_book_printed != $2) {
|
||||
print $1
|
||||
last_book_printed = $2
|
||||
}
|
||||
|
||||
printf("%d:%d\t", $4, $5)
|
||||
printverse($6)
|
||||
# Determine line type based on column structure
|
||||
# Column 6 = Latin, Column 7 = German or footnote number, Column 8 = footnote text
|
||||
|
||||
# Check if this is a footnote (column 6 empty, column 7 is a number, column 8 has text)
|
||||
if ($6 == "" && $7 ~ /^[0-9]+$/ && NF >= 8) {
|
||||
printfootnote($7, $8)
|
||||
}
|
||||
# Check if this is an introduction (verse 0, column 6 empty, column 7 is text)
|
||||
else if ($5 == 0 && $6 == ""){
|
||||
printf("\n")
|
||||
printintroductionpar($7)
|
||||
}
|
||||
# Bilingual verse (both column 6 and 7 have text)
|
||||
else if ($6 != "" && $7 != "") {
|
||||
# Check language filter flags
|
||||
if (ENVIRON["ALLIOLI_ONLY_LATIN"] != "" && ENVIRON["ALLIOLI_ONLY_LATIN"] != "0") {
|
||||
# Show only Latin
|
||||
printf("%d:%d\t", $4, $5)
|
||||
printverse($6)
|
||||
} else if (ENVIRON["ALLIOLI_ONLY_GERMAN"] != "" && ENVIRON["ALLIOLI_ONLY_GERMAN"] != "0") {
|
||||
# Show only German
|
||||
printf("%d:%d\t", $4, $5)
|
||||
printverse($7)
|
||||
} else {
|
||||
# Show both side-by-side
|
||||
printf("%d:%d", $4, $5)
|
||||
printverse_bilingual($6, $7)
|
||||
}
|
||||
}
|
||||
# German-only verse (column 6 empty, column 7 has text, not a footnote)
|
||||
else if ($6 == "" && $7 != "" && $7 !~ /^[0-9]+$/) {
|
||||
printf("%d:%d\t", $4, $5)
|
||||
printverse($7)
|
||||
}
|
||||
# Latin-only verse (column 6 has text, column 7 empty) - rare but handle it
|
||||
else if ($6 != "" && $7 == "") {
|
||||
printf("%d:%d\t", $4, $5)
|
||||
printverse($6)
|
||||
}
|
||||
outputted_records++
|
||||
}
|
||||
|
||||
cmd == "dump" {
|
||||
processline()
|
||||
}
|
||||
|
||||
cmd == "ref" && mode == "exact" && bookmatches($1, $2, p["book"]) && (p["chapter"] == "" || $4 == p["chapter"]) && (p["verse"] == "" || $5 == p["verse"]) {
|
||||
processline()
|
||||
}
|
||||
@@ -204,7 +447,171 @@ cmd == "ref" && mode == "search" && (p["book"] == "" || bookmatches($1, $2, p["b
|
||||
}
|
||||
|
||||
END {
|
||||
# JSON output mode
|
||||
if ((cmd == "ref" || cmd == "dump") && ENVIRON["ALLIOLI_JSON_OUTPUT"] != "" && ENVIRON["ALLIOLI_JSON_OUTPUT"] != "0") {
|
||||
if (outputted_records == 0) {
|
||||
if (cmd == "ref") {
|
||||
print "Unknown reference: " ref
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Determine language flags
|
||||
only_latin = (ENVIRON["ALLIOLI_ONLY_LATIN"] != "" && ENVIRON["ALLIOLI_ONLY_LATIN"] != "0")
|
||||
only_german = (ENVIRON["ALLIOLI_ONLY_GERMAN"] != "" && ENVIRON["ALLIOLI_ONLY_GERMAN"] != "0")
|
||||
no_footnotes = (ENVIRON["ALLIOLI_NOFOOTNOTES"] != "" && ENVIRON["ALLIOLI_NOFOOTNOTES"] != "0")
|
||||
|
||||
# If we have multiple books (dump mode), output as array
|
||||
if (json_book_total > 1) {
|
||||
print "["
|
||||
}
|
||||
|
||||
# Output each book
|
||||
for (b_idx = 1; b_idx <= json_book_total; b_idx++) {
|
||||
book_key = json_books[b_idx]
|
||||
|
||||
# Start book object
|
||||
if (json_book_total > 1) {
|
||||
printf(" {\n")
|
||||
} else {
|
||||
print "{"
|
||||
}
|
||||
|
||||
# Book metadata
|
||||
if (json_book_total > 1) {
|
||||
printf(" \"book\": {\n")
|
||||
printf(" \"name\": \"%s\",\n", json_book_name[book_key])
|
||||
printf(" \"abbreviation\": \"%s\",\n", json_book_abbr[book_key])
|
||||
printf(" \"number\": %d\n", json_book_num[book_key])
|
||||
printf(" },\n")
|
||||
} else {
|
||||
printf(" \"book\": {\n")
|
||||
printf(" \"name\": \"%s\",\n", json_book_name[book_key])
|
||||
printf(" \"abbreviation\": \"%s\",\n", json_book_abbr[book_key])
|
||||
printf(" \"number\": %d\n", json_book_num[book_key])
|
||||
printf(" },\n")
|
||||
}
|
||||
|
||||
# Output chapters (including chapter 0 for introduction)
|
||||
indent = json_book_total > 1 ? " " : " "
|
||||
for (c_idx = 1; c_idx <= json_chapter_total[book_key]; c_idx++) {
|
||||
chapter = json_chapters[book_key, c_idx]
|
||||
|
||||
# Output chapter number and verses (works for chapter 0 and regular chapters)
|
||||
printf("%s\"chapter\": %d,\n", indent, chapter)
|
||||
printf("%s\"verses\": [\n", indent)
|
||||
|
||||
# Sort verses numerically before output
|
||||
delete sorted_verses
|
||||
for (v_idx = 1; v_idx <= json_verse_count[book_key, chapter]; v_idx++) {
|
||||
sorted_verses[v_idx] = json_verses[book_key, chapter, v_idx]
|
||||
}
|
||||
# Simple bubble sort for numeric ordering
|
||||
for (i = 1; i <= json_verse_count[book_key, chapter]; i++) {
|
||||
for (j = i + 1; j <= json_verse_count[book_key, chapter]; j++) {
|
||||
if (sorted_verses[i] + 0 > sorted_verses[j] + 0) {
|
||||
temp = sorted_verses[i]
|
||||
sorted_verses[i] = sorted_verses[j]
|
||||
sorted_verses[j] = temp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Output verses in sorted order
|
||||
for (v_idx = 1; v_idx <= json_verse_count[book_key, chapter]; v_idx++) {
|
||||
verse_num = sorted_verses[v_idx]
|
||||
|
||||
printf("%s {\n", indent)
|
||||
printf("%s \"verse\": %d,\n", indent, verse_num)
|
||||
|
||||
# Text object
|
||||
printf("%s \"text\": {", indent)
|
||||
|
||||
# Output text based on language flags
|
||||
if (only_latin) {
|
||||
printf("\n%s \"latin\": \"%s\"\n", indent, json_latin[book_key, chapter, verse_num])
|
||||
} else if (only_german) {
|
||||
# Remove superscript markers if footnotes disabled
|
||||
german_text = json_german[book_key, chapter, verse_num]
|
||||
if (no_footnotes) {
|
||||
gsub(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/, "", german_text)
|
||||
}
|
||||
printf("\n%s \"german\": \"%s\"\n", indent, german_text)
|
||||
} else {
|
||||
# Both languages
|
||||
german_text = json_german[book_key, chapter, verse_num]
|
||||
if (no_footnotes) {
|
||||
gsub(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/, "", german_text)
|
||||
}
|
||||
if (json_latin[book_key, chapter, verse_num] != "") {
|
||||
printf("\n%s \"latin\": \"%s\",\n", indent, json_latin[book_key, chapter, verse_num])
|
||||
}
|
||||
if (german_text != "") {
|
||||
printf("%s \"german\": \"%s\"\n", indent, german_text)
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s }", indent)
|
||||
|
||||
# Footnotes array (if not disabled)
|
||||
if (!no_footnotes && json_footnote_count[book_key, chapter, verse_num] > 0) {
|
||||
printf(",\n%s \"footnotes\": [\n", indent)
|
||||
for (f_idx = 1; f_idx <= json_footnote_count[book_key, chapter, verse_num]; f_idx++) {
|
||||
fn_num = json_footnote_nums[book_key, chapter, verse_num, f_idx]
|
||||
fn_text = json_footnotes[book_key, chapter, verse_num, fn_num]
|
||||
printf("%s {\n", indent)
|
||||
printf("%s \"number\": %d,\n", indent, fn_num)
|
||||
printf("%s \"text\": \"%s\"\n", indent, fn_text)
|
||||
if (f_idx < json_footnote_count[book_key, chapter, verse_num]) {
|
||||
printf("%s },\n", indent)
|
||||
} else {
|
||||
printf("%s }\n", indent)
|
||||
}
|
||||
}
|
||||
printf("%s ]\n", indent)
|
||||
} else {
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
# Close verse object
|
||||
if (v_idx < json_verse_count[book_key, chapter]) {
|
||||
printf("%s },\n", indent)
|
||||
} else {
|
||||
printf("%s }\n", indent)
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s]\n", indent)
|
||||
|
||||
# Close chapter - add comma if not last chapter
|
||||
if (c_idx < json_chapter_total[book_key]) {
|
||||
printf(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
# Close book object
|
||||
if (json_book_total > 1) {
|
||||
if (b_idx < json_book_total) {
|
||||
printf(" },\n")
|
||||
} else {
|
||||
printf(" }\n")
|
||||
}
|
||||
} else {
|
||||
print "}"
|
||||
}
|
||||
}
|
||||
|
||||
# Close array if multiple books
|
||||
if (json_book_total > 1) {
|
||||
print "]"
|
||||
}
|
||||
|
||||
exit
|
||||
}
|
||||
|
||||
# Normal text mode
|
||||
if (cmd == "ref" && outputted_records == 0) {
|
||||
print "Unknown reference: " ref
|
||||
}
|
||||
# dump mode doesn't need error handling - it outputs everything
|
||||
}
|
||||
|
||||
33
allioli.sh
33
allioli.sh
@@ -21,7 +21,12 @@ show_help() {
|
||||
echo "usage: $(basename "$0") [flags] [reference...]"
|
||||
echo
|
||||
echo " -l list books"
|
||||
echo " -w <n> set custom terminal width"
|
||||
echo " -W no line wrap"
|
||||
echo " -F no footnotes"
|
||||
echo " -g show only German (no Latin)"
|
||||
echo " -L show only Latin (no German)"
|
||||
echo " -j output as JSON"
|
||||
echo " -h show help"
|
||||
echo
|
||||
echo " Reference types:"
|
||||
@@ -61,9 +66,29 @@ while [ $# -gt 0 ]; do
|
||||
# List all book names with their abbreviations
|
||||
get_data allioli.tsv | awk -v cmd=list "$(get_data allioli.awk)"
|
||||
exit
|
||||
elif [ "$1" = "-w" ]; then
|
||||
shift
|
||||
if [ $# -eq 0 ] || [ -z "$1" ]; then
|
||||
echo "error: -w requires a width argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
export ALLIOLI_MAX_WIDTH="$1"
|
||||
shift
|
||||
elif [ "$1" = "-W" ]; then
|
||||
export ALLIOLI_NOLINEWRAP=1
|
||||
shift
|
||||
elif [ "$1" = "-F" ]; then
|
||||
export ALLIOLI_NOFOOTNOTES=1
|
||||
shift
|
||||
elif [ "$1" = "-g" ]; then
|
||||
export ALLIOLI_ONLY_GERMAN=1
|
||||
shift
|
||||
elif [ "$1" = "-L" ]; then
|
||||
export ALLIOLI_ONLY_LATIN=1
|
||||
shift
|
||||
elif [ "$1" = "-j" ]; then
|
||||
export ALLIOLI_JSON_OUTPUT=1
|
||||
shift
|
||||
elif [ "$1" = "-h" ] || [ "$isFlag" -eq 1 ]; then
|
||||
show_help
|
||||
else
|
||||
@@ -71,9 +96,11 @@ while [ $# -gt 0 ]; do
|
||||
fi
|
||||
done
|
||||
|
||||
cols=$(tput cols 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
export ALLIOLI_MAX_WIDTH="$cols"
|
||||
if [ -z "$ALLIOLI_MAX_WIDTH" ]; then
|
||||
cols=$(tput cols 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
export ALLIOLI_MAX_WIDTH="$cols"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
|
||||
100607
allioli.tsv
100607
allioli.tsv
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user