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