############################################################################
#
#	Name:	 bibleref.icn
#
#	Title:	 Bible Reference Finder
#
#	Author:	 Richard L. Goerwitz
#
#	Version: 1.22
#
############################################################################
#
#  This program helps the user locate and browse passages from the
#  PD-SIG King James or CCAT Revised Standard Version of the Bible.
#  Startup syntax is
#
#      bibleref [-f filename] [-v]
#
#  where filename is the name of the indexed Bible text you wish to
#  peruse.  Because the KJV/RSV filename is hard-coded into the program,
#  you need not supply the -f argument.  It is available, though,
#  just in case you have indexed another biblical file, and wish to
#  use that instead.
#
#  If bibleref is called with a -v argument, it prints the version
#  number and patchlevel, then exits.
#
#  This particular file contains only the basic command loop, some
#  initialization routines, and some basic clearing/prompting/reading
#  utilities.  The other integral file is listutil.icn, which contains
#  all of the basic list and passage display routines.
#
############################################################################
#
#  Requires: UNIX, fully updated & installed Icon Program Library
#
############################################################################
#
#  Links: ./ref2bmap.icn ./name2num.icn ./convertb.icn ./complete.icn
#         ./binsrch.icn ./bmp2text.icn ./initfile.icn ./retrieve.icn
#         ./indexutl.icn ./retrops.icn ./whatnext.icn ./iolib.icn
#         ./iscreen.icn ./listutil.icn ./rewrap.icn ./passutil.icn
#         ./srchutil.icn ./readfile (and probably others I've forgotten)
#
#  Until incorporated into Icon, also link:  ./ipause.icn
#
#  See also: kjv2rtv.icn, makeind.icn, retrieve.icn, iolib.icn
#
############################################################################

global kjv_filename, lists
record lst(l,pos,old_n,s,long)


procedure main(a)

    local option_table, filename, prompt, intext, first, result
    # global lists
    initial {
	lists := []
	checkout_features()
	option_table := getopts(a, "f:v")
	if \option_table["v"] then abort("Bibleref", _version(), 0)
	kjv_filename := \option_table["f"] | "/usr/local/lib/bibleref/kjv.rtv"
	initialize_screen()
	message("Initializing offset file...")
	initfile(kjv_filename) |
	    quit("main","can't locate "||kjv_filename,1)
    }

    # Setup initial prompt.
    prompt := "Enter passage, or f to find a word (q to quit):  "

    # Read user input.
    while intext := snarf_input(prompt) do {

	trim(intext,'\t ') ? {

	    # See if the user has just input a passage reference.
	    # If so, then display it...
	    if display_passage(intext) then
		result := "yes"

	    # ...otherwise, see if his/her input matches any of the
	    # following commands:
	    else {
		first := move(1) | "c"
		case first of {
		    "!" : push_shell() & initialize_screen()
		    "c" : initialize_screen()        # c = clear
		    "d" : display_list()             # d = display (a list)
		    "f" : {			     # f = find a word
			if search_database() # insert new list into "lists"
			then display_list()  # stores it as a record (lst)
		    }
		    "l" : show_lists()		     # l = list all lists
		    "q" : {			     # q = quit program
			if pos(0) & "y" == snarf_input("Really quit? (y/n)  ")
			then break
		    }
		    "r" : readfile() & display_list()# r = read file from disk
		    default : {			     # input error
			err_message("Unrecognized passage or command.")
			next
		    }
		}
	    }
	    # If we have any tangible search results, or else have viewed
	    # a passage, then alter the prompt to reflect the full range
	    # of options.
	    \result | *\lists > 0 &
		prompt := "Enter passage, or !/c/d/f/l/q/r:  "
	}
    }

    # Clear, say goodbye, and exit with zero status.
    initialize_screen()
    message("Thanks for using Bibleref.")
    write(); exit(0)

end


procedure initialize_screen()

    #
    # Initialize screen
    #
    local msg, short_message

    pos(0) | {
	err_message("Garbage characters after \"c\" command.")
	fail
    }

    msg := "\"Bibleref\" - a Bible browser by Richard Goerwitz"
    short_message := "\"Bibleref,\" by RG"

    clear()
    status_line(msg, short_message, "c") &
    return

end


procedure snarf_input(prompt)

    #
    # Read user input after displaying a prompt.
    #
    local command
    # global commands

    /prompt := "Please input:  "
    message(prompt)
    return read() | ""

end


procedure err_message(msg)

    #
    #  Display error message for 1 second; erase.
    #
    /msg := "Error."
    message(msg)
    ipause(700)		# until Icon gets a sleep function
    message("")
    return

end
    

procedure status_message(msg)

    #
    #  Display some status message on the highlighted status line.
    #
    status_line(msg) &
    return

end
    

procedure checkout_features()

    #
    # Check to see if we have the necessary terminal & OS features.
    #
    local capname

    every capname := ("li","co","ce") do {
	getval(capname) | {
	    quit("check_features",
		 "terminal lacks "||capname||" capability", 2)
	}
    }
    find("UNIX",&features) |
	quit("check_features", "OS unsupported", 1)
    return

end


procedure quit(s1, s2, i)
    
    #
    # Move cursor to bottom screen line & abort, sending the message
    # s1: s2 to the user, and exiting with status i.
    #
    iputs(igoto(getval("cm"), 1, getval("li")))
    iputs(getval("ce"))
    abort(s1, s2, i)

end


procedure getopts(arg,optstring)

    #
    # Get opts.  Based on Bob Alexander & Gregg Townsend's IPL
    # options procedure.
    #
    local x,i,c,otab,flist,o,p

    /optstring := string(&letters)
    otab := table()
    flist := []
    while x := get(arg) do {
	x ? {
	    if ="-" & not pos(0) then {
		if ="-" & pos(0) then break
		while c := move(1) do
		    if i := find(c,optstring) + 1 then
		    otab[c] :=
		    if any(':+.',o := optstring[i]) then {
                        p := "" ~== tab(0) | get(arg) |
			    quit("getopts", "No parameter following -"||c, 1)
                        case o of {
			    ":": p
			    "+": integer(p) |
				quit("getopts", "-"||c||" needs numeric", 1)
			    ".": real(p) |
				quit("getopts", "-"||c||" needs numeric", 1)
			}
		    }
		    else 1
		    else quit("getopts","Unrecognized option: -"||c, 1)
	    }
	    else put(flist,x)
	}
    }
    while push(arg,pull(flist))
    return otab

end
