home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: gettext.icn
- #
- # Subject: Procedures for gettext (simple text-base routines)
- #
- # Author: Richard L. Goerwitz
- #
- # Date: July 9, 1991
- #
- ###########################################################################
- #
- # Version: 1.18
- #
- ###########################################################################
- #
- # Gettext() and associated routines allow the user to maintain a file
- # of KEY/value combinations such that a call to gettext(KEY, FNAME)
- # will produce value. Gettext() fails if no such KEY exists.
- # Returns an empty string if the key exists, but has no associated
- # value in the file, FNAME.
- #
- # The file format is simple. Keys belong on separate lines, marked
- # as such by an initial colon+colon (::). Values begin on the line
- # following their respective keys, and extend up to the next
- # colon+colon-initial line or EOF. E.g.
- #
- # ::sample.1
- # Notice how the key above, sample.1, has :: prepended to mark it
- # out as a key. The text you are now reading represents that key's
- # value. To retrieve this text, you would call gettext() with the
- # name of the key passed as its first argument, and the name of the
- # file in which this text is stored as its second argument (as in
- # gettext("sample.1","tmp.idx")).
- # ::next.key
- # etc...
- #
- # For faster access, an indexing utility is included, idxtext. Idxtext
- # creates a separate index for a given text-base file. If an index file
- # exists in the same directory as FNAME, gettext() will make use of it.
- # The index becomes worthwhile (at least on my system) after the text-
- # base file becomes longer than 5 kilobytes.
- #
- # Donts:
- # 1) Don't nest gettext text-base files.
- # 2) Don't use spaces and/or tabs in key names.
- # 3) Don't modify indexed files in any way other than to append
- # additional keys/values (unless you want to re-index).
- #
- # This program is intended for situations where keys tend to have
- # very large values, and use of an Icon table structure would be
- # unweildy.
- #
- # BUGS: Gettext() relies on the Icon runtime system and the OS to
- # make sure the last text/index file it opens gets closed.
- #
- # Note: This program is NOT YET TESTED UNDER DOS. In particular,
- # I have no idea whether the indexing mechanism will work, due to
- # translation that has to be done on MS-DOS text files.
- #
- ############################################################################
- #
- # Links: adjuncts
- #
- # Requires: UNIX (maybe MS-DOS; untested)
- #
- ############################################################################
-
- # declared in adjuncts.icn
- # global _slash, _baselen
-
- procedure gettext(KEY,FNAME)
-
- local line, value
- static last_FNAME, intext, inidx
- initial {
- if find("UNIX"|"Amiga", &features) then {
- _slash := "/"
- _baselen := 10
- }
- else if find("MS-DOS", &features) then {
- _slash := "\\"
- _baselen := 8
- }
- else stop("gettext: OS not supported")
- }
-
- (/KEY | /FNAME) & stop("error (gettext): null argument")
-
- if FNAME == \last_FNAME then {
- seek(intext, 1)
- seek(\inidx, 1)
- }
- else {
- # We've got a new text-base file. Close the old one.
- every close(\intext | \inidx)
- # Try to open named text-base file.
- intext := open(FNAME) | stop("gettext: ",FNAME," not found")
- # Try to open index file.
- inidx := open(Pathname(FNAME) || getidxname(FNAME)) | &null
- }
- last_FNAME := FNAME
-
- # Find offsets for key KEY in index file. If inidx (the index
- # file) is null (which happens when none was found), get_offsets()
- # defaults to 1. Otherwise it returns the offset for KEY in the
- # index file, and then returns the last indexed byte of the file.
- # Returning the last indexed byte lets us seek to the end and do a
- # sequential search of any key/value entries that have been added
- # since the last time idxtext was run.
-
- seek(intext, get_offsets(KEY, inidx))
-
- # Find key. Should be right there, unless the user has appended
- # key/value pairs to the end without re-indexing, or else has not
- # bothered to index in the first place. In this case we're
- # supposed to start a sequential search for KEY upto EOF.
-
- while line := (read(intext) | fail) do {
- line ? {
- if (="::", =KEY, pos(0))
- then break
- }
- }
-
- # Collect all text upto the next colon+colon-initial line (::)
- # or EOF.
- value := ""
- while line := read(intext) do {
- match("::",line) & break
- value ||:= line || "\n"
- }
-
- # Note that a key with an empty value returns an empty string.
- return trim(value, '\n')
-
- end
-
-
-
- procedure get_offsets(KEY, inidx)
-
- local incr, bottom, top, loc, firstpart, offset
- # Use these to store values likely to be reused.
- static old_inidx, firstline, SOF, EOF
-
- # If there's no index file, then just return an offset of 1.
- if /inidx then
- return 1
-
- # First line contains offset of last indexed byte in the main
- # text file. We need this later. Save it. Start the binary
- # search routine at the next byte after this line.
- seek(inidx, 1)
- if not (inidx === \old_inidx) then {
-
- # Get first line.
- firstline := !inidx
- # Set "bottom."
- 1 = (SOF := where(inidx)-1) &
- stop("get_offsets: corrupt .IDX file; reindex")
- # How big is this file?
- seek(inidx, 0)
- EOF := where(inidx)
-
- old_inidx := inidx
- }
- # SOF, EOF constant for a given inidx file.
- bottom := SOF; top := EOF
-
- # If bottom gets bigger than top, there's no such key.
- until bottom > top do {
-
- loc := (top+bottom) / 2
- seek(inidx, loc)
-
- # Move past next newline. If at EOF, break.
- incr := 1
- until reads(inidx) == "\n" do
- incr +:= 1
- if loc+incr = EOF then {
- top := loc-1
- next
- }
-
- # Check to see if the current line contains KEY.
- read(inidx) ? {
-
- # .IDX file line format is KEY\toffset
- firstpart := tab(find("\t"))
- if KEY == firstpart then {
- # return offset
- return (move(1), tab(0))
- }
- # Ah, this is what all binary searches do.
- else {
- if KEY << firstpart
- then top := loc-1
- else bottom := loc + incr + *&subject
- }
- }
- }
-
- # First line of the index file contains offset of last indexed
- # byte + 1. Might be the only line in the file (if it had no
- # keys when it was indexed).
- return firstline
-
- end
-