home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
3
/
3001
/
gettext.icn
< prev
next >
Wrap
Text File
|
1991-03-06
|
6KB
|
206 lines
############################################################################
#
# Name: gettext.icn
#
# Title: gettext (simple text-base routines)
#
# Author: Richard L. Goerwitz
#
# Version: 1.14
#
############################################################################
#
# 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.icn
#
# Requires: UNIX (maybe MS-DOS; untested)
#
############################################################################
global _slash, _baselen
procedure gettext(KEY,FNAME)
local line, value
static last_FNAME, intext, inidx
initial {
if find("UNIX", &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))
}
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 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