1 /* -*-C-*-
2 *******************************************************************************
3 *
4 * File: brl.c
5 * RCS: $Header: /home/matthew/cvs/bible-kjv-4.10/brl.c,v 2.7 2005/01/23 11:19:58 matthew Exp $
6 * Description: Bible Retrieval Library
7 * Author: Chip Chapin, Hewlett Packard Company
8 * Created: Jan 14 1989, Chip Chapin
9 * Modified: Mon Apr 26 11:11:59 1993 (Chip Chapin) chip@hpclbis
10 * Language: C
11 * Package: Bible Retrieval System
12 * Status: Experimental (Do Not Distribute)
13 *
14 *******************************************************************************
15 *
16 * Revisions:
17 *
18 * Thu Dec 30 1999 (Oliver Elphick) olly@lfix.co.uk
19 * Increase VBSIZE from 512 to 550, because very long verses were
20 * being truncated in pretty printing.
21 * Thu Apr 22 14:39:43 1993 (Chip Chapin) chip@hpclbis
22 * Fix bad return value from brl_printverse when no errors occurred.
23 * Support non-POSIX sprintf.
24 * Tue Jan 5 18:23:41 1993 (Chip Chapin) chip@hpclbis
25 * Change how current context is handled. Now use single var
26 * "brl_cur_vnum", and make our caller responsible for updating it.
27 * brl_getverse is now commented out. Nobody uses it anymore.
28 * Added file parameter to brl_printverse.
29 * Mon Jan 4 10:11:19 1993 (Chip Chapin) chip@hpclbis
30 * Renamed verse_spec() as brl_verse_spec() and exposed it to callers.
31 * Thu Dec 24 11:04:42 1992 (Chip Chapin) chip@hpclbis
32 * Added brl_cur_ref(), and converted all absolute verse refs to use
33 * "ref_t", instead of "int" and "long".
34 * Tue Dec 22 17:11:41 1992 (Chip Chapin) chip@hpclbis
35 * Fix bug parsing "ma.." books.
36 * Added tolower fix submitted by Stephen North, AT&T.
37 * Mon Dec 21 19:13:10 1992 (Chip Chapin) chip@hpclbis
38 * Fixed minor verse ref parsing bugs.
39 * Added brl_num_to_ref to support concordance.
40 *******************************************************************************
41 *
42 * $Log: brl.c,v $
43 * Revision 2.7 2005/01/23 11:19:58 matthew
44 * explicit casts
45 *
46 * Revision 2.6 2005/01/22 17:47:40 matthew
47 * remove improper function declarations
48 *
49 * Revision 2.5 2005/01/22 16:40:34 matthew
50 * cast return value of strlen to signed int
51 *
52 * Revision 2.4 2005/01/21 19:38:25 matthew
53 * Code clean-up - initialise vref, remove unused variable.
54 *
55 * Revision 2.3 2005/01/21 19:07:31 matthew
56 * disambiguate an else
57 *
58 * Revision 2.2 2005/01/21 19:05:51 matthew
59 * Prototype all functions
60 *
61 * Revision 2.1 2003/01/08 15:50:53 matthew
62 * applied debian patch
63 *
64 * Revision 2.0 2003/01/08 15:29:52 matthew
65 * versions collected from the net
66 *
67 * Revision 1.16 93/04/26 11:18:12 11:18:12 chip (Chip Chapin)
68 * Release 4.00
69 * Public release of portable datafile version.
70 *
71 * Revision 1.15 93/04/23 13:08:01 13:08:01 chip (Chip Chapin)
72 * PORTABILITY RELEASE
73 * This version supports portable data files, usable on machines with
74 * differing native byte-orders.
75 * Also, this version compiles and runs on non-HPUX systems. It has been
76 * tested on SunOS 4.? and ULTRIX 4.?, using SPARC and DEC 3100 hardware
77 * respectively. Note that the data file format has rolled again.
78 *
79 * Revision 1.14 93/01/05 19:05:30 19:05:30 chip (Chip Chapin)
80 * Release 3.00: (not for distribution)
81 * Fixed errors (blank lines) in bible.data file. Data file is not compatible
82 * with previous (1.x and 2.x) distributions. Further changes pending.
83 * Rewrote context handling, and added "<" and ">" commands.
84 * Tools for building brl-index are now part of release.
85 *
86 * Revision 1.13 93/01/05 10:49:09 10:49:09 chip (Chip Chapin)
87 * Release 2.2, Added ?w command and line formatting to ?l output.
88 *
89 * Revision 1.12 93/01/04 16:20:57 16:20:57 chip (Chip Chapin)
90 * Release 2.1, implements ?in and ?or commands.
91 *
92 * Revision 1.11 92/12/24 11:09:14 11:09:14 chip (Chip Chapin)
93 * Release 2.04. Include verse ref in prompt line.
94 *
95 * Revision 1.10 92/12/23 14:10:43 14:10:43 chip (Chip Chapin)
96 * Release 2.03: minor tweaks and bug fixes.
97 *
98 * Revision 1.9 92/12/22 18:17:06 18:17:06 chip (Chip Chapin)
99 * Minor tweaks for release 2.02.
100 *
101 * Revision 1.8 92/12/21 20:00:47 20:00:47 chip (Chip Chapin)
102 * Release 2.0. This release adds the concordance, and some small fixes.
103 *
104 * Revision 1.7 89/10/02 22:20:45 22:20:45 chip (Chip Chapin)
105 * Fix bugs: looping when lwidth very small,
106 * and blank-line after verse range not printing verse AFTER the last
107 * verse of the range.
108 *
109 * Revision 1.6 89/09/14 20:33:45 20:33:45 chip (Chip Chapin)
110 * Release 1-2. Supports -f and -l options for formatting the output.
111 * Updates primarily brl.c, bible.c, and bible.1.
112 *
113 * Revision 1.5 89/09/13 21:49:13 21:49:13 chip (Chip Chapin)
114 * Implement -f and -l options for pretty-printing and linewidth limitation.
115 *
116 * Revision 1.4 89/09/08 13:22:47 13:22:47 chip (Chip Chapin)
117 * Better error checking on verse syntax; automatic test suite.
118 *
119 * Revision 1.3 89/09/08 09:01:22 09:01:22 chip (Chip Chapin)
120 * Bug fix and simplification: send whole input lines or arguments to BRL,
121 * and let BRL worry about multiple references. We don't care.
122 *
123 * Revision 1.2 89/09/05 20:22:59 20:22:59 chip (Chip Chapin)
124 * Workaround 6.2 C compiler enum gripes.
125 *
126 * Revision 1.1 89/09/05 17:49:15 17:49:15 chip (Chip Chapin)
127 * Initial revision
128 *
129 *******************************************************************************
130 */
131
132 /*----------------------------------------------------------------------
133 | NAME:
134 | brl.c
135 |
136 | PURPOSE:
137 | Provide a set of routines for retrieving Bible text from
138 | the Text Storage Library (tsl). All of these routines
139 | should take a high-level view of the text itself; they may
140 | know something about the structure of the Bible, but
141 | should *not* depend in any way upon the manner in which
142 | the text is stored. Call on the TSL for that.
143 |
144 | FUNCTIONS:
145 | Grammar Functions: Used within the BRL to parse verse
146 | specifications.
147 | brl_verse_spec (also called from applications)
148 | verse_id
149 | verse_continuation
150 |
151 | Access Functions: Called from application programs to
152 | retrieve Bible text.
153 | brl_getverse
154 | brl_printverse
155 |
156 | Utility Functions: Called from application programs.
157 | brl_init
158 | brl_close
159 | brl_num_to_ref
160 |
161 | HISTORY:
162 | 890114 cc Initial creation.
163 | 890824 cc Improved partitioning between BRL and TSL. Created
164 | brl_getverse to hide brl_verse_spec and verse numbers from
165 | user programs. Fix bug in verse_id parsing "jn".
166 | 921217 cc Added brl_num_to_ref.
167 |
168 \*----------------------------------------------------------------------*/
169
170
171 #include <stdio.h>
172 #include <stdlib.h>
173 #include <ctype.h>
174 #include <string.h>
175 #include "tsl.h"
176 #include "brl.h"
177
178 #define FALSE (0)
179
180 char *booknamestr[] = { "Genesis",
181 "Exodus",
182 "Leviticus",
183 "Numbers",
184 "Deuteronomy",
185 "Joshua",
186 "Judges",
187 "Ruth",
188 "1 Samuel",
189 "2 Samuel",
190 "1 Kings",
191 "2 Kings",
192 "1 Chronicles",
193 "2 Chronicles",
194 "Ezra",
195 "Nehemiah",
196 "Esther",
197 "Job",
198 "Psalms",
199 "Proverbs",
200 "Ecclesiastes",
201 "Song of Solomon",
202 "Isaiah",
203 "Jeremiah",
204 "Lamentations",
205 "Ezekiel",
206 "Daniel",
207 "Hosea",
208 "Joel",
209 "Amos",
210 "Obadiah",
211 "Jonah",
212 "Micah",
213 "Nahum",
214 "Habakkuk",
215 "Zephaniah",
216 "Haggai",
217 "Zechariah",
218 "Malachi",
219 "Matthew",
220 "Mark",
221 "Luke",
222 "John",
223 "Acts",
224 "Romans",
225 "1 Corinthians",
226 "2 Corinthians",
227 "Galatians",
228 "Ephesians",
229 "Philippians",
230 "Colossians",
231 "1 Thessalonians",
232 "2 Thessalonians",
233 "1 Timothy",
234 "2 Timothy",
235 "Titus",
236 "Philemon",
237 "Hebrews",
238 "James",
239 "1 Peter",
240 "2 Peter",
241 "1 John",
242 "2 John",
243 "3 John",
244 "Jude",
245 "Revelation",
246 "BAD"
247 };
248
249 /* Standard abbreviations */
250 char *bookabbrvstr[] = { "Gen",
251 "Ex",
252 "Lev",
253 "Num",
254 "Dt",
255 "Jsh",
256 "Jdg",
257 "Ru",
258 "1Sa",
259 "2Sa",
260 "1Ki",
261 "2Ki",
262 "1Ch",
263 "2Ch",
264 "Ezr",
265 "Ne",
266 "Es",
267 "Job",
268 "Ps",
269 "Pr",
270 "Ec",
271 "SoS",
272 "Is",
273 "Je",
274 "Lam",
275 "Ezk",
276 "Da",
277 "Ho",
278 "Jl",
279 "Am",
280 "Ob",
281 "Jon",
282 "Mi",
283 "Na",
284 "Hab",
285 "Zep",
286 "Hag",
287 "Zec",
288 "Mal",
289 "Mt",
290 "Mk",
291 "Lu",
292 "Jn",
293 "Ac",
294 "Ro",
295 "1Co",
296 "2Co",
297 "Ga",
298 "Ep",
299 "Php",
300 "Co",
301 "1Th",
302 "2Th",
303 "1Ti",
304 "2Ti",
305 "Ti",
306 "Phm",
307 "He",
308 "Ja",
309 "1Pe",
310 "2Pe",
311 "1Jn",
312 "2Jn",
313 "3Jn",
314 "Jde",
315 "Re",
316 "BAD"
317 };
318
319
320 ref_t brl_cur_vnum; /* Current context. */
321
322 /* Name of text. This should really be initialized or provided by tsl */
323 char brl_textname[]="KJV";
324
325
326
327
328 /*----------------------------------------------------------------------
329 |
330 | Verse Specification Grammar
331 |
332 | The following routines implement the grammar by which
333 | verses may be specified.
334 | See each routine, starting with brl_verse_spec, for the grammar.
335 |
336 \*----------------------------------------------------------------------*/
337
338 #define getnum(s,n) n=0; get_nonblank(s); \
339 while (isdigit((int)*s)) n = 10 * n + (*s++ - '0');
340
341
342
get_book(char ** s,int book)343 int get_book(char **s,int book)
344 /*----------------------------------------------------------------------
345 | NAME:
346 | get_book
347 |
348 | ALGORITHM:
349 | Parse a bible book name or abbreviation. Defaults to the
350 | book number passed in "book" if no book is specified.
351 |
352 | Returns the number of the book, 0..65, -1 if an
353 | unrecognizable book name is given, or -2 if no book name
354 | is given (needs a bit of cleanup!).
355 |
356 | HISTORY:
357 | 890902 cc Extracted from verse_id.
358 | 890904 cc Revised to allow non-fatal errors.
359 |
360 \*----------------------------------------------------------------------*/
361 {
362 int c;
363 char *s1;
364
365 book = -2; /* assume no book is given */
366 get_nonblank(*s);
367 s1 = *s;
368 if (*s1 && (isalpha((int)*s1) || isalpha((int)*(s1+1)))) {
369 switch (c = *s1++) {
370 case '1': /* 1Sa, 1Ki, 1Ch, 1Co, 1Th, 1Ti, 1Pe, 1Jn */
371 case '2': /* 2Sa, 2Ki, 2Ch, 2Co, 2Th, 2Ti, 2Pe, 2Jn */
372 case '3': /* 3Jn */
373 get_nonblank(s1);
374 switch (*s1++) {
375 case 'c':
376 if (*s1=='h') book= (int)CHRON1;
377 else if (*s1=='o') book= (int)COR1;
378 else {
379 tsl_error( FALSE, BADBOOK, *s );
380 return -1;
381 }
382 break;
383 case 'j':
384 book= (int)JOHN1;
385 break;
386 case 'k':
387 book= (int)KINGS1;
388 break;
389 case 'p':
390 book= (int)PET1;
391 break;
392 case 's':
393 book= (int)SAM1;
394 break;
395 case 't':
396 if (*s1=='h') book= (int)THESS1;
397 else if (*s1=='i') book= (int)TIM1;
398 else {
399 tsl_error( FALSE, BADBOOK, *s );
400 return -1;
401 }
402 break;
403 default:
404 tsl_error( FALSE, BADBOOK, *s );
405 return -1;
406 }
407 if (c != '1') book++;
408 if (c == '3'){
409 if (book == (int)JOHN2) book++;
410 else {
411 tsl_error( FALSE, BADBOOK, *s );
412 return -1;
413 }
414 }
415 break;
416 case 'a': /* amos, acts */
417 c = *s1++;
418 if (c == 'm') book = (int)AMOS;
419 else if (c == 'c') book = (int)ACTS;
420 else {
421 tsl_error( FALSE, BADBOOK, *s );
422 return -1;
423 }
424 break;
425 case 'c': /* col */
426 book = (int)COLOS;
427 break;
428 case 'd': /* deut, dan */
429 c = *s1++;
430 if (c == 'e' || c == 't') book = (int)DEUT; /* de, dt */
431 else if (c == 'a') book = (int)DANIEL;
432 else {
433 tsl_error( FALSE, BADBOOK, *s );
434 return -1;
435 }
436 break;
437 case 'e': /* exodus, ezra, esther, eccl, ezekiel, eph */
438 c = *s1++;
439 if (c == 'x') book = (int)EXODUS; /* ex */
440 else if (c == 's') book = (int)ESTHER; /* es */
441 else if (c == 'c') book = (int)ECCL; /* ec */
442 else if (c == 'p') book = (int)EPH; /* ep */
443 else {
444 if (c == 'z') c = *s1++;
445 if (c == 'r') book = (int)EZRA; /* ezr, er */
446 else if (c == 'e' || c == 'k')
447 book = (int)EZEKIEL; /* eze,ee,ezk,ek */
448 else {
449 tsl_error( FALSE, BADBOOK, *s );
450 return -1;
451 }
452 }
453 break;
454 case 'g': /* gen, gal */
455 c = *s1++;
456 if (c == 'e' || c == 'n') book = (int)GENESIS;
457 else if (c == 'a' || c == 'l') book = (int)GAL;
458 else {
459 tsl_error( FALSE, BADBOOK, *s );
460 return -1;
461 }
462 break;
463 case 'h': /* hebrews, hosea, habakkuk, haggai */
464 c = *s1++;
465 if (c == 'o') book = (int)HOSEA; /* ho */
466 else if (c == 'e' || c == 'b')
467 book = (int)HEBREWS; /* he, hb (more likely than Hab.) */
468 else {
469 if (c == 'a') c = *s1++;
470 if (c == 'b') book = (int)HABAK; /* hab */
471 else if (c == 'g') book = (int)HAGGAI; /* hag, hg */
472 else {
473 tsl_error( FALSE, BADBOOK, *s );
474 return -1;
475 }
476 }
477 break;
478 case 'i': /* isaiah */
479 book = (int)ISAIAH;
480 break;
481 case 'j': /* josh, judges, job, jer, joel, jonah, john, jam, jude */
482 c = *s1++;
483 if (c == 'a') book = (int)JAMES; /* ja */
484 else if (c == 'e' || c == 'r') book = (int)JEREM; /* je, jr */
485 else if (c == 'b') book = (int)JOB; /* jb */
486 else if (c == 'd') {
487 if ((c = *s1++) == 'g') book = (int)JUDGES; /* jdg */
488 else if (c == 'e') book = (int)JUDE; /* jde */
489 else {
490 tsl_error( FALSE, BADBOOK, *s );
491 return -1;
492 }
493 }
494 else if (c == 'g') book = (int)JUDGES; /* jg */
495 else if (c == 'l') book = (int)JOEL; /* jl */
496 else if (c == 'n') book = (int)JOHN; /* jn */
497 else if (c == 's') {
498 if ((c = *s1++) == 'h') book = (int)JOSHUA; /* jsh */
499 else {
500 tsl_error( FALSE, BADBOOK, *s );
501 return -1;
502 }
503 }
504 else if (c == 'u') {
505 if ((c = *s1++) == 'd') c = *s1++;
506 if (c == 'g') book = (int)JUDGES; /* judg, jug (ha-ha) */
507 else if (c == 'e') book = (int)JUDE; /* jude, jue (ha-ha) */
508 else {
509 tsl_error( FALSE, BADBOOK, *s );
510 return -1;
511 }
512 }
513 else if (c == 'o') {
514 if ((c = *s1++) == 's') book = (int)JOSHUA; /* jos */
515 else if (c == 'b') book = (int)JOB; /* job */
516 else if (c == 'e') book = (int)JOEL; /* joe */
517 else if (c == 'n') book = (int)JONAH; /* jon */
518 else if (c == 'h') book = (int)JOHN; /* joh */
519 else {
520 tsl_error( FALSE, BADBOOK, *s );
521 return -1;
522 }
523 }
524 else {
525 tsl_error( FALSE, BADBOOK, *s );
526 return -1;
527 }
528 break;
529 case 'l': /* lev, lam, luke */
530 c = *s1++;
531 if (c == 'e' || c == 'v') book = (int)LEVIT;
532 else if (c == 'a' || c == 'm') book = (int)LAMENT;
533 else if (c == 'u' || c == 'k') book = (int)LUKE;
534 else {
535 tsl_error( FALSE, BADBOOK, *s );
536 return -1;
537 }
538 break;
539 case 'm': /* micah, malachi, matt, mark */
540 c = *s1++;
541 if (c == 'i' || c == 'c') book = (int)MICAH;
542 else {
543 /* mal, ml, mat, mt, mar, mr, mk (and "mak"!) */
544 if (c == 'a') c = *s1++;
545 if (c == 'l') book = (int)MALACHI;
546 else if (c == 't') book = (int)MATT;
547 else if (c == 'r' || c == 'k') book = (int)MARK;
548 else {
549 tsl_error( FALSE, BADBOOK, *s );
550 return -1;
551 }
552 }
553 break;
554 case 'n': /* num, neh, nahum */
555 c = *s1++;
556 if (c == 'u' || c == 'm') book = (int)NUM;
557 else if (c == 'e') book = (int)NEHEM;
558 else if (c == 'a') book = (int)NAHUM;
559 else {
560 tsl_error( FALSE, BADBOOK, *s );
561 return -1;
562 }
563 break;
564 case 'o': /* obadiah */
565 book = (int)OBADIAH;
566 break;
567 case 'p': /* psalms, proverbs, philippians, philemon */
568 c = *s1++;
569 if (c == 's') book = (int)PSALMS;
570 else if (c == 'r') book = (int)PROV;
571 else {
572 if (c == 'h') c = *s1++;
573 if (c == 'i') c = *s1++;
574 if (c == 'l') c = *s1++;
575 if (c == 'i' || c == 'p' || !isalpha(c)) {
576 /* phili, philp, phil, phi, ph, php, pp, etc. */
577 /* This gives preference to Philippians over Philemon */
578 book = (int)PHILIP;
579 if (!isalpha(c)) s1--; /* point back to the chapter number */
580 } else if (c == 'e' || c == 'm') book = (int)PHILEM;
581 else {
582 tsl_error( FALSE, BADBOOK, *s );
583 return -1;
584 }
585 }
586 break;
587 case 'q': /* Not a book, but it makes typing easier */
588 brl_close();
589 exit( 0 );
590 break;
591 case 'r': /* ruth, romans, revelation */
592 c = *s1++;
593 if (c == 'u' || c == 't') book = (int)RUTH;
594 else if (c == 'o' || c == 'm') book = (int)ROMANS;
595 else if (c == 'e' || c == 'v') book = (int)REV;
596 else {
597 tsl_error( FALSE, BADBOOK, *s );
598 return -1;
599 }
600 break;
601 case 's': /* song */
602 book = (int)SONG;
603 break;
604 case 't': /* titus */
605 book = (int)TITUS;
606 break;
607 case 'z': /* zeph, zech */
608 if ((c = *s1++) == 'e') c = *s1++;
609 if (c == 'p') book = (int)ZEPH;
610 else if (c == 'c') book = (int)ZECH;
611 else {
612 tsl_error( FALSE, BADBOOK, *s );
613 return -1;
614 }
615 break;
616 default:
617 tsl_error( FALSE, BADBOOK, *s );
618 return -1;
619 } /* switch on first letter of book name */
620
621 /* Skip any remaining letters in book name */
622 while (isalpha((int)*s1)) s1++;
623 get_nonblank(s1);
624 }
625 *s = s1;
626 return book;
627 } /* get_book */
628
629
630
verse_continuation(char ** s,int book,int chapter,int verse,ref_t absverse)631 int verse_continuation(char **s,int book,int chapter,int verse,ref_t absverse)
632 /*----------------------------------------------------------------------
633 | NAME:
634 | verse_continuation
635 |
636 | ALGORITHM:
637 | <verse continuation> ::= <null>
638 | ::= - <verse id>
639 |
640 | "s" is pointing to the first char of the <verse
641 | continuation>. If it is a null continuation we leave it
642 | where it is, otherwise on exit we update it to point to
643 | the first non-blank after the continuation.
644 |
645 | book -- Number of the book in which the verse spec began.
646 | chapter -- Number of the chapter ...
647 | absverse -- ABSOLUTE VERSE NUMBER where verse spec began
648 | (this is more useful than the relative num).
649 |
650 | Returns the total number of verses to be fetched, unless
651 | there was a problem. Returns zero if there was a problem.
652 |
653 |
654 | HISTORY:
655 | 890829 cc Initial implementation (formerly always returned 1).
656 | 890908 cc Error return.
657 |
658 \*----------------------------------------------------------------------*/
659 {
660 int n;
661 char *s1;
662
663 s1 = *s; /* For easier handling. Be sure to update it */
664 n = 1; /* Assume NO following verses */
665
666 if (*s1++ == '-') {
667 /* yup, there's a continuation */
668 get_nonblank(s1);
669 if (*s1 == '\0') {
670 /* special case - end of chapter */
671 n = verse_num( book, chapter, 1000);
672 *s = s1;
673 } else {
674 if (verse_id( &s1, &book, &chapter, &verse ) == 0)
675 return 0;
676 *s = s1;
677
678 /* Determine absolute verse number of ending verse */
679 n = verse_num( book, chapter, verse );
680 }
681
682 /* how many verses is that? */
683 n = n - absverse +1;
684 }
685
686 return n;
687 } /* verse_continuation */
688
689
690
verse_id(char ** s,int * bookp,int * chapterp,int * versep)691 ref_t verse_id(char **s,int *bookp,int *chapterp,int *versep )
692 /*----------------------------------------------------------------------
693 | NAME:
694 | verse_id
695 |
696 | ALGORITHM:
697 | <verse id> ::= <book> <chapter> : <verse>
698 | ::= <book> <chapter> # implies vs. 1
699 | ::= <book> # implies 1:1
700 | ::= <chapter> : <verse> # implies current book
701 | ::= <verse> # implies current book/chapter
702 |
703 | "s" is pointing to the first character of the <verse id>.
704 | On exit, we update it to be pointing to the next non-blank
705 | after what we've parsed.
706 |
707 | The values of *bookp, and *chapterp are used as
708 | defaults in case of a partial verse spec. For example,
709 | "15" would mean verse 15 in the default book/chapter.
710 |
711 | We return an absolute verse number (Gen 1:1 == 1) for the
712 | referenced verse. Also update *bookp, *chapterp*, and
713 | *versep with the book, chapter, and verse numbers.
714 |
715 | If a problem occurs, we return 0.
716 |
717 | HISTORY:
718 | 890902 cc Revised to handle incomplete verse specs.
719 | 890908 cc Fix to blank line handling. Revised error return.
720 |
721 \*----------------------------------------------------------------------*/
722 {
723 short book, chapter, verse;
724 int num;
725 ref_t vn;
726 char *s1;
727
728 s1 = *s; /* For easier handling. Be sure to update it */
729 if ((book = get_book( &s1, *bookp )) == -1) return 0;
730 getnum(s1, num);
731 if (num < 1) {
732 /* <verse spec> ::= <book> */
733 if (book < 0) {
734 /* Special case: if this is a blank line, then print
735 the very next verse. But if there's still junk on
736 the line, then what we have here is an error.
737 */
738 if (*s1) {
739 /* Bad news, gang */
740 tsl_error( FALSE, "Extra garbage on line: '%s'", s1 );
741 return 0;
742 }
743
744 /* Get the last verse printed, increment it,
745 and translate that back into book/chapter/verse,
746 while making sure it stays in the proper range.
747 */
748 vn = verse_num( *bookp, *chapterp, *versep );
749 vn++;
750 vn = brl_extract_num( vn, bookp, chapterp, versep );
751 *s = s1;
752 return( vn );
753 } else {
754 chapter = 1;
755 verse = 1;
756 }
757 } else {
758 get_nonblank(s1);
759 if (*s1 != ':') {
760 if (book < 0) {
761 /* <verse spec> ::= <verse> */
762 book = *bookp;
763 chapter = *chapterp;
764 verse = num;
765 } else {
766 /* <verse spec> ::= <book> <chapter> */
767 chapter = num;
768 verse = 1;
769 }
770 } else {
771 /* <verse spec> ::= <book> <chapter> : <verse> */
772 /* <verse spec> ::= <chapter> : <verse> */
773 s1++; /* skip past the ':' */
774 if (book < 0)
775 book = *bookp; /* default book */
776 chapter = num;
777 getnum(s1, verse);
778 if (verse < 1) {
779 tsl_error( FALSE, NO_VERSE, *s );
780 } else {
781 get_nonblank(s1);
782 }
783 }
784 }
785
786 *s = s1; /* Update the pointer we were passed */
787 *bookp = book;
788 *chapterp = chapter;
789 *versep = verse;
790 /* return absolute verse number */
791 return( verse_num( book, chapter, verse ) );
792 } /* verse_id */
793
794
795
brl_extract_num(ref_t absverse,int * bp,int * cp,int * vp)796 ref_t brl_extract_num(ref_t absverse,int *bp,int *cp,int *vp)
797 /*----------------------------------------------------------------------
798 | NAME:
799 | brl_extract_num
800 |
801 | ALGORITHM:
802 | Extract the book, chapter, [relative] verse corresponding
803 | to the absolute verse number passed in "absverse", if
804 | "absverse" is valid. If it is not valid, then coerce it
805 | into something reasonable. Update book, chapter, and
806 | verse through their pointers "bp", "cp", and "vp",
807 | respectively. Return the [possibly changed] value of
808 | absverse.
809 |
810 | HISTORY:
811 | 890904 cc Created (in a hurry)
812 |
813 \*----------------------------------------------------------------------*/
814 {
815 int bk, chp;
816
817 if (absverse < 1)
818 absverse = 1; /* cheap insurance */
819
820 for (bk= (int)GENESIS; bk <= (int)REV; bk++)
821 if (absverse <= start_verse[start_chapter[bk+1]+1])
822 /* we've got the right book */
823 for (chp=start_chapter[bk]+1; chp <= start_chapter[bk+1]; chp++)
824 if (absverse <= start_verse[chp+1]) {
825 /* we've got the right chapter */
826 *bp = bk;
827 *cp = chp - start_chapter[bk];
828 *vp = absverse - start_verse[chp];
829 return absverse;
830 }
831 /* if we got here, then things are messed up.
832 Assume that the verse is off the back.
833 */
834 *bp = (int)REV;
835 *cp = start_chapter[ (int)REV+1 ] - start_chapter[(int)REV];
836 *vp = start_verse[(*cp)+1] - start_verse[*cp];
837 return verse_num( *bp, *cp, *vp );
838 } /* brl_extract_num */
839
840
841
verse_num(int b,int c,int v)842 ref_t verse_num(int b,int c,int v)
843 /*----------------------------------------------------------------------
844 | NAME:
845 | verse_num
846 |
847 | ALGORITHM:
848 | Return the absolute verse number, given the book, chapter
849 | and [relative] verse number.
850 |
851 | Look up the starting absolute verse number of the
852 | specified book/chapter, using the "start_verse" and
853 | "start_chapter" tables, then add the [relative] verse
854 | number.
855 |
856 | Error checking: Ensure chapter is not too big for the
857 | book, and that verse is not too big for the chapter.
858 |
859 | HISTORY:
860 | 890830 cc Created. The original lookup didn't do any
861 | error checking.
862 |
863 \*----------------------------------------------------------------------*/
864 {
865 int abschapter;
866 ref_t absverse;
867
868 /* force book into proper range */
869 if (b < (int)GENESIS) b = (int)GENESIS;
870 else if (b > (int)REV) b = (int)REV;
871
872 if ((abschapter = start_chapter[b] + c) > start_chapter[b+1])
873 abschapter = start_chapter[b+1];
874 if ((absverse = start_verse[abschapter] + v) > start_verse[abschapter+1])
875 absverse = start_verse[abschapter+1];
876 return absverse;
877 } /* verse_num */
878
879
880
brl_verse_spec(char ** s,int * n)881 ref_t brl_verse_spec(char **s,int *n)
882 /*----------------------------------------------------------------------
883 | NAME:
884 | brl_verse_spec
885 |
886 | ALGORITHM:
887 |
888 | <verse spec> ::= <verse id> <verse continuation>
889 |
890 | Translate a <verse specifier> string s into a starting
891 | absolute verse number, returned as the function result,
892 | and a count n of verses to read. Gen. 1:1 == verse 1.
893 |
894 | Returns 0 if something went wrong, leaving n undefined.
895 |
896 | HISTORY:
897 |
898 \*----------------------------------------------------------------------*/
899 {
900 ref_t av;
901 char *s1;
902 int book, chapter, verse;
903
904 /* Munge off leading spaces,
905 convert string to lower case,
906 convert commas into blanks, and
907 dispose of possible yucky '\n'.
908 */
909 get_nonblank(*s);
910 s1 = *s;
911 while (*s1) {
912 if (isupper((int)*s1)) *s1 = tolower((int)*s1);
913 if (*s1 == ',')
914 *s1 = ' ';
915 else if (*s1 == '\n')
916 *s1 = '\0';
917 s1++;
918 }
919
920 brl_cur_vnum = brl_extract_num( brl_cur_vnum, &book, &chapter, &verse );
921 if ((av = verse_id( &(*s), &book, &chapter, &verse )) == 0)
922 return 0;
923 if (**s) {
924 if ((*n = verse_continuation( &(*s), book, chapter, verse, av )) == 0)
925 return 0;
926 } else {
927 *n = 1;
928 }
929 return av;
930 } /* brl_verse_spec */
931
932
933
934 #if 0 /* COMMENTED OUT -- NOT USED ANYMORE */
935 int brl_getverse( vs, vb, vbsize, pretty, lwidth )
936 /*----------------------------------------------------------------------
937 | NAME:
938 | brl_getverse
939 |
940 | ALGORITHM:
941 | Stuff buffer "vb" with text of verses specified by string
942 | "vs", a <verse spec>.
943 |
944 | "pretty" and "lwidth" are formatting options passed to
945 | tsl_gettext. (NOT IMPLEMENTED!)
946 |
947 | HISTORY:
948 | 890824 cc Created to hide internal functions
949 | tsl_gettext and brl_verse_spec from user programs.
950 | 890912 cc Added pretty and lwidth.
951 |
952 \*----------------------------------------------------------------------*/
953
954 char *vs;
955 char *vb;
956 int vbsize;
957 int pretty, lwidth;
958 {
959 ref_t vn;
960 int vc, bytecount;
961
962 bytecount = 0;
963 while (*vs && (vn = brl_verse_spec( &vs, &vc )))
964 bytecount += tsl_gettext( vn, vc, vb, vbsize );
965
966 return bytecount;
967 } /* brl_getverse */
968 #endif
969
970
brl_printverse(char * vs,int pretty,int lwidth,FILE * outf)971 ref_t brl_printverse(char *vs,int pretty,int lwidth,FILE *outf)
972 /*----------------------------------------------------------------------
973 | NAME:
974 | brl_printverse
975 |
976 | ALGORITHM:
977 | Print text to stdout of verses specified by string "vs".
978 |
979 | pretty -- If true, then we want special output formatting.
980 | lwidth -- If non-zero, then insert new-lines if necessary
981 | between words to prevent lines from being longer
982 | than lwidth.
983 | outf -- If non-NULL, then copy output to this file in
984 | addition to stdout.
985 |
986 | Returns absolute verse number of last verse printed.
987 |
988 | HISTORY:
989 | 890902 cc Created as alternative to brl_getverse.
990 | 890912 cc Added pretty and lwidth.
991 | 921221 cc Print bookname with chapter.
992 | 921223 cc Print chapter heading anytime v.1 is printed.
993 | 930105 cc Added outf functionality & return verse number.
994 | 930422 cc Return correct versenum when errors occur.
995 | 991230 oe Increase VBSIZE to avoid verse truncation.
996 |
997 \*----------------------------------------------------------------------*/
998 {
999 ref_t vn, vref=0;
1000 int vc, vcount;
1001 int len, indent;
1002 /* Length of the longest line is 535, so original length of 512 was not enough */
1003 #define VBSIZE 550
1004 char vb1[VBSIZE], vb2[VBSIZE];
1005 char *srcp, *dstp, *endp;
1006 int curbook, curchapter, curverse;
1007 int oldbook, oldchapter, oldverse;
1008
1009 if (pretty || lwidth) {
1010 /* Get current context info to help with pretty printing */
1011 brl_cur_vnum = brl_extract_num( brl_cur_vnum,
1012 &oldbook, &oldchapter, &oldverse );
1013
1014 /* Process all verse specs that we're given */
1015 while (*vs && (vref = brl_verse_spec( &vs, &vcount ))) {
1016 brl_cur_vnum = vref +vcount -1; /* Update context.
1017 Won't be used unless next loop
1018 gets an error. */
1019 for (vc=vcount, vn=vref; vc; vc--) {
1020 /* get text for a single verse */
1021 len=tsl_gettext( vn++, 1, vb1, VBSIZE );
1022 srcp = vb1;
1023 dstp = vb2;
1024 indent = 0;
1025 if (pretty) {
1026 brl_extract_num( vn-1, &curbook, &curchapter, &curverse );
1027 /* print book/chapter heading?? */
1028 if (curbook != oldbook ||
1029 curchapter != oldchapter ||
1030 curverse == 1) {
1031 /* print chapter heading */
1032 sprintf( dstp, "\n%s %d\n\n",
1033 booknamestr[curbook], curchapter );
1034 /* Advance dstp (supports non-POSIX sprintf) */
1035 while (*dstp) dstp++;
1036 }
1037 oldbook = curbook;
1038 oldchapter = curchapter;
1039 oldverse = curverse;
1040
1041 /* advance to the verse number in source */
1042 while (*srcp != ':') srcp++;
1043 srcp++;
1044
1045 /* insert indentation in dest */
1046 indent = 2; /* two for verse */
1047 *dstp++ = ' '; *dstp++ = ' ';
1048 }
1049
1050 if (lwidth) {
1051 /* Line width limitation. */
1052 while ((int)strlen(srcp) > (lwidth-indent)) {
1053 /* split this line. But where? */
1054 endp=srcp+lwidth-indent;
1055 while (*endp!=' ' && endp>srcp) endp--;
1056 if (endp <= srcp) {
1057 /* oops. Not enough room for even one word.
1058 * Print it anyway.
1059 */
1060 endp=srcp+1;
1061 while (*endp!=' ' && *endp!='\n' && *endp) endp++;
1062 }
1063
1064 /* style is to indent only the first line of the
1065 * verse, before the verse number. Subsequent lines
1066 * are *not* indented.
1067 */
1068 indent=0;
1069
1070 len = endp-srcp;
1071 strncpy(dstp, srcp, len);
1072 dstp += len;
1073 *dstp++ = '\n';
1074 srcp = ++endp; /* past the ' ' */
1075 }
1076 /* last line, get the rest */
1077 strcpy(dstp, srcp);
1078 } else {
1079 /* No line length limit.
1080 Just copy the rest of the verse line.
1081 */
1082 strcpy(dstp, srcp);
1083 }
1084 /* now print out the verse */
1085 printf( "%s", vb2 );
1086 if (outf != NULL)
1087 fprintf( outf, "%s", vb2 );
1088 } /* for */
1089 } /* while */
1090 } else {
1091 /* Raw output. Not pretty or line-wrapped */
1092 while (*vs && (vref = brl_verse_spec( &vs, &vcount )))
1093 tsl_printtext( vref, vcount );
1094 }
1095 if (vref) return vref + vcount-1;
1096 else return brl_cur_vnum;
1097 } /* brl_printverse */
1098
1099
1100
brl_num_to_ref(char * vbuf,ref_t * absversep)1101 char* brl_num_to_ref(char *vbuf,ref_t *absversep)
1102 /*----------------------------------------------------------------------
1103 | NAME:
1104 | brl_num_to_ref
1105 |
1106 | ALGORITHM:
1107 | Accepts an absolute verse number and returns
1108 | a string containing a legal verse reference.
1109 |
1110 | This is useful with some concordance functions.
1111 |
1112 | vbuf -- Points to buffer to use for string.
1113 |
1114 | Returns a copy of vbuf pointer.
1115 |
1116 | HISTORY:
1117 | 921217 cc Initial creation.
1118 |
1119 \*----------------------------------------------------------------------*/
1120 {
1121 int bk, chp, v;
1122
1123 *absversep = brl_extract_num( *absversep, &bk, &chp, &v);
1124 sprintf(vbuf, "%s%d:%d", bookabbrvstr[bk], chp, v);
1125 return( vbuf );
1126 } /* brl_num_to_ref */
1127
1128
1129
brl_init(char * dfname,char * dfpath,int memlimit)1130 void brl_init(char *dfname,char *dfpath,int memlimit)
1131 /*----------------------------------------------------------------------
1132 | NAME:
1133 | brl_init
1134 |
1135 | ALGORITHM:
1136 | Initialize the library.
1137 |
1138 | memlimit Limit (in Kbytes) on buffer space used by TSL.
1139 | dfname Name of the data file.
1140 | dfpath List of paths to use in searching for the
1141 | data file.
1142 |
1143 | HISTORY:
1144 | 890830 cc Added memlimit.
1145 | 890905 cc Added filename and paths.
1146 |
1147 \*----------------------------------------------------------------------*/
1148 {
1149 if (dfname == NULL)
1150 dfname = "bible.data";
1151 if (dfpath == NULL)
1152 dfpath = "./ " DESTLIB "/"; /* /usr/lib/; */
1153 tsl_init( dfname, dfpath, memlimit );
1154
1155 /* Set (low) illegal value for current context.
1156 Making it low means that it will be coerced to Gen1:1 if
1157 the user gives a null input.
1158 */
1159 brl_cur_vnum = 0;
1160 } /* brl_init */
1161
1162
brl_close(void)1163 void brl_close(void)
1164 /*----------------------------------------------------------------------
1165 | NAME:
1166 | brl_close
1167 |
1168 | ALGORITHM:
1169 | Close the library.
1170 |
1171 | HISTORY:
1172 |
1173 \*----------------------------------------------------------------------*/
1174 {
1175 tsl_close();
1176 } /* brl_close */
1177
1178
1179