bbl.awk (13541B)
1 BEGIN { 2 # $1 Book name 3 # $2 Book abbreviation 4 # $3 Book number 5 # $4 Chapter number 6 # $5 Verse number 7 # $6 Verse 8 FS = "\t" 9 10 header_ended = 0 11 outputted_records = 0 12 MAX_WIDTH = envint("KJV_MAX_WIDTH", 80, 8, 80) 13 NO_LINE_WRAP = envbool("KJV_NOLINEWRAP") 14 NO_VERSE_NUMBERS = envbool("KJV_NOVERSENUMBERS") 15 NO_CHAPTER_HEADINGS = envbool("KJV_NOCHAPTERHEADINGS") 16 NO_TITLE = envbool("KJV_NOTITLE") 17 NO_VERSE_BREAK = envbool("KJV_NOVERSEBREAK") 18 if (NO_VERSE_BREAK) { 19 NO_VERSE_NUMBERS = 1 20 } 21 if(envbool("KJV_NOFORMAT")) { 22 NO_LINE_WRAP = 1 23 NO_CHAPTER_HEADINGS = 1 24 NO_TITLE = 1 25 NO_VERSE_BREAK = 1 26 } 27 28 if (!is_set(cmd)) { 29 cmd = "list" 30 } 31 32 if (cmd == "ref") { 33 if (lang == "he") { 34 re["num"] = "[ק-ת]?([יכלמנסעפצ]?[א-ט]?|טו|טז)" 35 re["book"] = "([א-ת]+ )?[א-ת]+" 36 re["chsep"] = ":" 37 } 38 else { 39 re["num"] = "[1-9]+[0-9]*" 40 re["book"] = "[1-9]?[a-zA-Z ]+" 41 re["chsep"] = ":?" 42 } 43 mode = parseref(p, ref) 44 } 45 } 46 47 cmd == "clean" { 48 processline() 49 } 50 51 cmd == "list" { 52 if (/^#/) { 53 next 54 } 55 if (!($2 in seen_books)) { 56 printf("%s (%s)\n", $1, $2) 57 seen_books[$2] = 1 58 } 59 } 60 61 function parseref(arr, q, i) { 62 # NOTE: For Hebrew, the colon between book and chapter is required 63 # 0. * 64 # 1. <book> 65 # 1a. <book>[, ?<book>]... 66 # 2. <book>:?<chapter> 67 # 2a. <book>:?<chapter>[, ?<chapter>]... 68 # 3. <book>:?<chapter>:<verse> 69 # 3a. <book>:?<chapter>:<verse>[, ?<verse>]... 70 # 3b. <book>:?<chapter>:<verse>[, ?<chapter>:<verse>]... 71 # 4. <book>:?<chapter>-<chapter> 72 # 5. <book>:?<chapter>:<verse>-<verse> 73 # 6. <book>:?<chapter>[:<verse>]-<chapter>:<verse> 74 # 7. /~?<search> 75 # 8. <book>/~?search 76 # 8a. <book>[, ?<book>].../~?search 77 # 9. <book>:?<chapter>/~?search 78 #10. @ <number of verses>? 79 #11. <book> @ <number of verses>? 80 #12. <book>:?<chapter> @ <number of verses>? 81 82 if (q == "*") { 83 return "all" 84 } 85 if (match(q, re["book"]) == 1) { 86 # 1, 1a, 2, 2a, 3, 3a, 3b, 4, 5, 6, 8, 9, 11, 12 87 arr["book", cleanbook(substr(q, 1, RLENGTH))] = 1 88 q = substr(q, RLENGTH + 1) 89 } else if (sub("^ */ *", "", q)) { 90 # 7 91 if (sub("^~ *", "", q)) { 92 arr["search"] = roughpattern(q) 93 return "rough_search" 94 } else { 95 arr["search"] = q 96 return "search" 97 } 98 } 99 100 if (match(q, sprintf("^%s%s", re["chsep"], re["num"]))) { 101 # 2, 2a, 3, 3a, 3b, 4, 5, 6, 9, 12 102 if (sub("^:", "", q)) { 103 arr["chapter"] = num(substr(q, 1, RLENGTH - 1)) 104 q = substr(q, RLENGTH) 105 } else { 106 arr["chapter"] = num(substr(q, 1, RLENGTH)) 107 q = substr(q, RLENGTH + 1) 108 } 109 } else if (sub("^ */ *", "", q)) { 110 # 8 111 if (sub("^~ *", "", q)) { 112 arr["search"] = roughpattern(q) 113 return "rough_search" 114 } else { 115 arr["search"] = q 116 return "search" 117 } 118 } else if (match(q, sprintf("^(,%s)+", re["book"]))) { 119 # 1a 120 # TODO make compatible with chapter/verse/searches etc. 121 split(q, temp_arr, ",") 122 for (i in temp_arr) { 123 if (temp_arr[i] != "") { 124 arr["book", cleanbook(temp_arr[i])] = 1 125 } 126 } 127 return "exact" 128 } else if (q == "") { 129 # 1 130 return "exact" 131 } 132 133 if (match(q, sprintf("^:%s", re["num"]))) { 134 # 3, 3a, 3b, 5, 6 135 arr["verse"] = num(substr(q, 2, RLENGTH - 1)) 136 q = substr(q, RLENGTH + 1) 137 } else if (match(q, sprintf("^-%s$", re["num"]))) { 138 # 4 139 arr["chapter_end"] = num(substr(q, 2)) 140 return "range" 141 } else if (sub("^ */ *", "", q)) { 142 # 9 143 if (sub("^~ *", "", q)) { 144 arr["search"] = roughpattern(q) 145 return "rough_search" 146 } else { 147 arr["search"] = q 148 return "search" 149 } 150 } else if (q == "") { 151 # 2 152 return "exact" 153 } else if (match(q, sprintf("^(, ?%s)+$", re["num"]))) { 154 # 2a 155 arr["chapter", arr["chapter"]] = 1 156 delete arr["chapter"] 157 while (match(q, sprintf("^, ?%s", re["num"]))) { 158 if(sub("^, ", "", q)) { 159 arr["chapter", substr(q, 1, RLENGTH - 2)] = 1 160 q = substr(q, RLENGTH - 1) 161 } else { 162 arr["chapter", substr(q, 2, RLENGTH - 1)] = 1 163 q = substr(q, RLENGTH + 1) 164 } 165 } 166 167 if (q != "") { 168 return "unknown" 169 } 170 171 return "exact_ch_set" 172 } else if (match(q, "^ *@ *")) { 173 # 10, 11, 12 174 q = substr(q, RLENGTH + 1) 175 if (match(q, sprintf("^%s", re["num"]))) { 176 arr["numberOfVerses"] = num(q) 177 } else { 178 arr["numberOfVerses"] = 1 179 } 180 NO_LINE_WRAP = 1 181 return "random" 182 } 183 184 if (match(q, sprintf("^-%s$", re["num"]))) { 185 # 5 186 arr["verse_end"] = num(substr(q, 2)) 187 return "range" 188 } else if (match(q, sprintf("-%s", re["num"]))) { 189 # 6 190 arr["chapter_end"] = num(substr(q, 2, RLENGTH - 1)) 191 q = substr(q, RLENGTH + 1) 192 } else if (q == "") { 193 # 3 194 return "exact" 195 } else if (match(q, sprintf("^(, ?%s)+$", re["num"]))) { 196 # 3a 197 arr["verse", arr["verse"]] = 1 198 delete arr["verse"] 199 while (match(q, sprintf("^, ?%s", re["num"]))) { 200 if(sub("^, ", "", q)) { 201 arr["verse", substr(q, 1, RLENGTH - 2)] = 1 202 q = substr(q, RLENGTH - 1) 203 } else { 204 arr["verse", substr(q, 2, RLENGTH - 1)] = 1 205 q = substr(q, RLENGTH + 1) 206 } 207 } 208 209 if (q != "") { 210 return "unknown" 211 } 212 213 return "exact_set" 214 } else if (match(q, sprintf("^, ?%s:%s", re["num"], re["num"]))) { 215 # 3b 216 arr["chapter:verse", arr["chapter"] ":" arr["verse"]] = 1 217 delete arr["chapter"] 218 delete arr["verse"] 219 do { 220 if(sub("^, ", "", q)) { 221 arr["chapter:verse", substr(q, 1, RLENGTH - 2)] = 1 222 q = substr(q, RLENGTH - 1) 223 } else { 224 arr["chapter:verse", substr(q, 2, RLENGTH - 1)] = 1 225 q = substr(q, RLENGTH + 1) 226 } 227 } while (match(q, sprintf("^, ?%s:%s", re["num"], re["num"]))) 228 229 if (q != "") { 230 return "unknown" 231 } 232 233 return "exact_set" 234 } else { 235 return "unknown" 236 } 237 238 if (match(q, sprintf("^:%s$", re["num"]))) { 239 # 6 240 arr["verse_end"] = num(substr(q, 2)) 241 return "range_ext" 242 } else { 243 return "unknown" 244 } 245 } 246 247 function cleanbook(book) { 248 book = tolower(book) 249 gsub(" +", "", book) 250 return book 251 } 252 253 function bookmatches(book, bookabbr, query) { 254 book = cleanbook(book) 255 if (book == query) { 256 return book 257 } 258 bookabbr = cleanbook(bookabbr) 259 if (bookabbr == query) { 260 return book 261 } 262 if (substr(book, 1, length(query)) == query) { 263 return book 264 } 265 } 266 267 function hasbook(book, bookabbr, query) { 268 for(query in p){ 269 if (sub("^book" SUBSEP, "", query) && bookmatches(book, bookabbr, query)) { 270 return book 271 } 272 } 273 } 274 275 function roughpattern(regex) { 276 # TODO Can mess with search pattern if regex is used on command line 277 regex = tolower(regex) 278 if (lang == "el") { 279 polytonic["α"] = "[αάἀ-ἆὰᾀ-ᾆᾳ-ᾷ]" 280 polytonic["ε"] = "[εέἐ-ἕὲ]" 281 polytonic["η"] = "[ηήἠ-ἧὴᾐ-ᾗῃ-ῇ]" 282 polytonic["ι"] = "[ιίΐϊἰ-ἷὶῒ-ῖ]" 283 polytonic["ο"] = "[οόὀ-ὅὸ]" 284 polytonic["υ"] = "[υΰϋύὐ-ὗὺῢῦ]" 285 polytonic["ω"] = "[ωώὠ-ὧὼᾠ-ᾧῳ-ῷ]" 286 for (letter in polytonic) { 287 gsub(letter, polytonic[letter], regex) 288 } 289 } 290 else if (lang =="la" ) { 291 gsub("a", "[aá]", regex) 292 gsub("e", "[eéë]", regex) 293 gsub("i", "[ií]", regex) 294 gsub("o", "[oó]", regex) 295 gsub("u", "[uú]", regex) 296 gsub("y", "[yý]", regex) 297 gsub("æ", "[æǽ]", regex) 298 gsub("œ", "[œœ́]", regex) 299 } 300 return regex 301 } 302 303 function printverse(verse, word_count, characters_printed, i) { 304 if (NO_LINE_WRAP) { 305 if (NO_VERSE_BREAK) { 306 printf("%s ", verse) 307 } else { 308 printf("%s\n", verse) 309 } 310 return 311 } 312 313 word_count = split(verse, words, " ") 314 for (i = 1; i <= word_count; i++) { 315 if (characters_printed + length(words[i]) + (characters_printed > 0 ? 1 : 0) > MAX_WIDTH - 8) { 316 if(cross_ref || NO_VERSE_BREAK) { 317 printf("\n") 318 } else { 319 printf("\n\t") 320 } 321 characters_printed = 0 322 } 323 if (characters_printed > 0) { 324 printf(" ") 325 characters_printed++ 326 } 327 printf("%s", words[i]) 328 characters_printed += length(words[i]) 329 } 330 if (NO_VERSE_BREAK) { 331 printf(" ") 332 } else { 333 printf("\n") 334 } 335 } 336 337 function process_alias(alias, aliasabbr, book_names, arr, i) { 338 if (hasbook(alias, aliasabbr)) { 339 delete p["book", cleanbook(alias)] 340 delete p["book", cleanbook(aliasabbr)] 341 split(book_names, arr, ",") 342 for(i in arr) { 343 p["book", cleanbook(arr[i])] = 1 344 } 345 } 346 } 347 348 function processline() { 349 newbook = (last_book_printed != $2) 350 if (newbook) { 351 if(cross_ref) { 352 print("") 353 } else if (NO_TITLE) { 354 if (last_book_printed) { 355 print("") 356 } 357 } else { 358 if ($2 in long_title) { 359 printf("%s (%s)\n", long_title[$2], $2) 360 } else { 361 print($1) 362 } 363 } 364 last_book_printed = $2 365 } 366 367 if (cross_ref || NO_CHAPTER_HEADINGS || NO_VERSE_NUMBERS) { 368 if (NO_VERSE_NUMBERS && last_chapter_printed != $4) { 369 if (cross_ref) { 370 if(NO_CHAPTER_HEADINGS) { 371 print("") 372 } else { 373 print("\n") 374 } 375 } else if (NO_CHAPTER_HEADINGS) { 376 if (last_chapter_printed) { 377 print("") 378 } 379 } else { 380 if (NO_VERSE_BREAK && !newbook) { 381 print("") 382 } 383 print($4) 384 } 385 last_chapter_printed = $4 386 } 387 } else { 388 printf("%s:%s\t", $4, $5) 389 } 390 printverse($6) 391 outputted_records++ 392 } 393 394 395 cmd == "ref" && !header_ended { 396 if (/^#/) { 397 header_ended = 1 398 next 399 } else { 400 process_alias($1, $2, $3) 401 next 402 } 403 } 404 405 /^#/ && cmd == "ref" { 406 long_title[$3] = $4 407 next 408 } 409 410 cmd == "ref" && mode == "all" { 411 processline() 412 } 413 414 cmd == "ref" && mode == "exact" && hasbook($1, $2) && (p["chapter"] == "" || $4 == p["chapter"]) && (p["verse"] == "" || $5 == p["verse"]) { 415 processline() 416 } 417 418 cmd == "ref" && mode == "random" && (p["book"] == "" || hasbook($1, $2)) && (p["chapter"] == "" || $4 == p["chapter"]) { 419 print 420 outputted_records++ 421 } 422 423 cmd == "ref" && mode == "exact_ch_set" && hasbook($1, $2) && p["chapter", $4] { 424 processline() 425 } 426 427 cmd == "ref" && mode == "exact_set" && hasbook($1, $2) && (((p["chapter"] == "" || $4 == p["chapter"]) && p["verse", $5]) || p["chapter:verse", $4 ":" $5]) { 428 processline() 429 } 430 431 cmd == "ref" && mode == "range" && hasbook($1, $2) && ((p["chapter_end"] == "" && $4 == p["chapter"]) || ($4 >= p["chapter"] && $4 <= p["chapter_end"])) && (p["verse"] == "" || $5 >= p["verse"]) && (p["verse_end"] == "" || $5 <= p["verse_end"]) { 432 processline() 433 } 434 435 cmd == "ref" && mode == "range_ext" && hasbook($1, $2) && (($4 == p["chapter"] && $5 >= p["verse"] && p["chapter"] != p["chapter_end"]) || ($4 > p["chapter"] && $4 < p["chapter_end"]) || ($4 == p["chapter_end"] && $5 <= p["verse_end"] && p["chapter"] != p["chapter_end"]) || (p["chapter"] == p["chapter_end"] && $4 == p["chapter"] && $5 >= p["verse"] && $5 <= p["verse_end"])) { 436 processline() 437 } 438 439 cmd == "ref" && (mode == "search" || mode == "rough_search") && (p["book"] == "" || hasbook($1, $2)) && (p["chapter"] == "" || $4 == p["chapter"]) && match(mode == "rough_search" ? tolower($6) : $6, p["search"]) { 440 processline() 441 } 442 443 END { 444 if (cmd == "ref") { 445 if (outputted_records == 0) { 446 if (!is_set(ref)) { 447 print "Opted to search by ref but no ref was specified" 448 } else { 449 print "Unknown reference: " ref 450 } 451 exit 1 452 } else if (is_set(mode) && mode == "random") { 453 printf("~~~RANDOMS: %d\n", p["numberOfVerses"]) 454 } 455 } else if (cmd != "list" && cmd != "clean") { 456 print "Unknown cmd specified: " cmd 457 } 458 }