aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/index
diff options
context:
space:
mode:
authorwkj <devnull@localhost>2004-05-17 03:22:35 +0000
committerwkj <devnull@localhost>2004-05-17 03:22:35 +0000
commitaa83d77271f0d2be72067058f78abd1780f3b69e (patch)
tree14a24e73abb43ad0b7340a1623e077a733b0be33 /src/cmd/index
parenta7eb134e8717c2ea831066891314cf74fa4a6ad3 (diff)
downloadplan9port-aa83d77271f0d2be72067058f78abd1780f3b69e.tar.gz
plan9port-aa83d77271f0d2be72067058f78abd1780f3b69e.tar.bz2
plan9port-aa83d77271f0d2be72067058f78abd1780f3b69e.zip
More troff bits; if you want them elsewhere, feel free to repo copy them.
Diffstat (limited to 'src/cmd/index')
-rw-r--r--src/cmd/index/README80
-rw-r--r--src/cmd/index/cleanup3
-rw-r--r--src/cmd/index/deroman18
-rw-r--r--src/cmd/index/doclean27
-rw-r--r--src/cmd/index/final.sort5
-rw-r--r--src/cmd/index/format64
-rw-r--r--src/cmd/index/gen.key57
-rw-r--r--src/cmd/index/hierarchy133
-rw-r--r--src/cmd/index/install3
-rw-r--r--src/cmd/index/ix.macro4
-rw-r--r--src/cmd/index/ix.test17
-rw-r--r--src/cmd/index/make.index23
-rw-r--r--src/cmd/index/num.collapse21
-rw-r--r--src/cmd/index/range.collapse35
-rw-r--r--src/cmd/index/range.prep10
-rw-r--r--src/cmd/index/range.sort5
-rw-r--r--src/cmd/index/reroman23
-rw-r--r--src/cmd/index/rotate31
-rw-r--r--src/cmd/index/see.prep10
-rw-r--r--src/cmd/index/see.terms69
20 files changed, 638 insertions, 0 deletions
diff --git a/src/cmd/index/README b/src/cmd/index/README
new file mode 100644
index 00000000..afd1c379
--- /dev/null
+++ b/src/cmd/index/README
@@ -0,0 +1,80 @@
+
+The indexing programs here are modified from the versions printed in
+Bentley & Kernighan, EP-ODD V1 #1. The programs are also described in
+AT&T Bell Laboratories Computing Science Technical Report No. 128,
+``Tools for Printing Indexes''.
+
+Changes from the published version derive from further experience
+after the paper was frozen, plus some cleanup and corrections by Joe
+Kruskal (to whom many thanks), plus some very local features for
+printing the AMPL book.
+
+
+USING THE PROGRAMS
+
+install
+ makes the appropriate files executable. since this file
+ is not executable, use by typing "sh <install"
+ix.test
+see.terms
+ these two files provide test input. make.index produces
+ standard output and files
+ foo[1-9] foo.regular foo.see foo.hier foo.all
+ from ix.test and see.terms. to make sure things
+ work when you first unbundle this file, type
+ sh <install
+ make.index ix.test >foo.ix
+ troff -ms foo.ix >foo.out
+ and then examine the troff output foo.out
+cleanup
+ removes the garbage files left around for debugging
+
+
+CHANGES FROM THE PAPER
+
+make.index
+ handles "see" file see.terms. A line like
+ algorithms<tab>searching, sorting
+ generates in the final index
+ algorithms see searching, sorting
+ a 3rd field of %also makes it
+ algorithms see also searching, sorting
+doclean
+deroman
+range.prep
+ minor change to defend against bug in some versions of "sort"
+rotate
+ moved here (and changed as necessary) to remove subtle bug.
+ see check.data below
+range.sort
+ -u option on sort removes duplicate entries on same page
+range.collapse
+reroman
+ page number concatenation removed from here ...
+num.collapse
+ and moved to here. also commas between numbers now
+ inserted here (to make see terms easier)
+gen.key
+ literals protected differently in gsub commands.
+ rules for non-alpha index terms slightly richer:
+ purely nonalphabetic lines first
+ lines with leading digits next
+ ordinary lines last
+see.prep
+ changed to match changes above, and to rely on font-changing {}
+final.sort
+ uses -d option for "telephone directory" order.
+hierarchy
+ a rather special purpose version to replace runs of items
+ with a common one or two word prefix and replace them by
+ a head word and indented lines.
+ this also does some rearrangement to bring see terms to the top,
+ and terms with formatting info to the bottom; this is not
+ always the right thing to do.
+format
+ letter changes (.YY) determined by first letter.
+ minor rearrangement of how output line is created.
+ commas no longer added here.
+ [Some systems have a disk-formatting program called format.]
+check.data
+ new program that catches subtle errors in the data
diff --git a/src/cmd/index/cleanup b/src/cmd/index/cleanup
new file mode 100644
index 00000000..cad2edf3
--- /dev/null
+++ b/src/cmd/index/cleanup
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+rm foo[1-9] foo.*
diff --git a/src/cmd/index/deroman b/src/cmd/index/deroman
new file mode 100644
index 00000000..5129e511
--- /dev/null
+++ b/src/cmd/index/deroman
@@ -0,0 +1,18 @@
+awk ' # deroman
+# Input: string (tab) [arab or roman]
+# Output: string (tab) [arab]
+
+# Roman numeral n is replaced by arab n-1000 (e.g., iii -> -997)
+BEGIN { FS = OFS = "\t"
+ # set a["i"] = 1, a["ii"] = 2, ...
+ s = "i ii iii iv v vi vii viii ix x"
+ s = s " xi xii xiii xiv xv xvi xvii xviii xix xx"
+ s = s " xxi xxii xxiii xxiv xxv xxvi xxvii xxviii xxix xxx"
+ n = split(s, b, " ")
+ for (i = 1; i <= n; i++) a[b[i]] = i
+ }
+$2~/^[ivxlc]+$/ { if ($2 in a) $2 = -1000 + a[$2]
+ else print "deroman: bad number: " $0 | "cat 1>&2"
+ }
+ { print }
+' $*
diff --git a/src/cmd/index/doclean b/src/cmd/index/doclean
new file mode 100644
index 00000000..c1763fd9
--- /dev/null
+++ b/src/cmd/index/doclean
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+awk ' # doclean
+
+# Input: "number tab IX string
+# 107 IX self-reference #1186 -
+# 281 TL APPENDIX A AMPL Reference Manual #26 -
+# Output: string (tab) number
+# excess spaces are removed output string
+# note reversal of order; rest of programs expect it
+
+# This contains some special pleading for the AMPL book
+
+BEGIN { FS = OFS = "\t" }
+
+/\t(TL|H1|H2|H3|LASTPAGE)/ { next } # zap expected noise
+
+$0 !~ /[0-9ixv]+\tIX / {
+ print "doclean: non index line: " $0 | "cat 1>&2"; next
+}
+
+{ sub(/IX +/, "", $2) # zap "IX "
+ sub(/ +#[0-9]+ .*$/, "", $2) # zap trailing blanks, slug, file
+ gsub(/ +/, " ", $2) # compress internal blanks
+ print $2, $1 # item (tab) page number
+}
+' $*
diff --git a/src/cmd/index/final.sort b/src/cmd/index/final.sort
new file mode 100644
index 00000000..37c68a24
--- /dev/null
+++ b/src/cmd/index/final.sort
@@ -0,0 +1,5 @@
+# final.sort
+# Input/Output: sort key (tab) string (tab) numlist
+# Sort by $1 (string)
+
+sort -t' ' +0fd -1 +0f -1 $*
diff --git a/src/cmd/index/format b/src/cmd/index/format
new file mode 100644
index 00000000..87e1a385
--- /dev/null
+++ b/src/cmd/index/format
@@ -0,0 +1,64 @@
+awk ' # format
+# Input: sort key (tab) string (tab) numlist
+# Output: troff format, commands interpreted
+
+BEGIN { FS = "\t"
+ s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz "
+ # set upper["a"] = "A"
+ for (i = 1; i <= 27; i++) upper[substr(s,i+27,1)] = substr(s,i,1)
+ # set lower["a"] = lower["A"] ="a"
+ for (i = 1; i <= 27; i++) {
+ lower[substr(s,i,1)] = substr(s,i+27,1)
+ lower[substr(s,i+27,1)] = substr(s,i+27,1)
+ }
+}
+{ # mark change between letters with .YY
+ # find first non-punctuation char
+ for (i = 1; (c = substr($1,i,1)) != ""; i++)
+ if (c ~ /[a-zA-Z0-9 ]/)
+ break
+ this = c
+ if (!(this in lower)) lower[this] = " "
+ this = lower[this]
+ if (this != last) # && this != " ")
+ print ".YY", this, upper[last=this]
+ quoted = 0
+
+ # interpret font change language
+
+ if ($2 ~ /^ /) # different macro, to avoid bad breaks in hier
+ print ".ZZ"
+ else
+ print ".XX"
+ if (NF == 3)
+ $0 = $2 "," " " $3 # discard sort key, leave term .. numlist
+ else
+ $0 = $2
+
+ if ($0 ~ /%/) {
+ quoted = 1
+ gsub(/%%/, "QQ0QQ", $0)
+ gsub(/%\[/, "QQ1QQ", $0)
+ gsub(/%\]/, "QQ2QQ", $0)
+ gsub(/%\{/, "QQ3QQ", $0)
+ gsub(/%\}/, "QQ4QQ", $0)
+ gsub(/%~/, "QQ5QQ", $0)
+ }
+ gsub(/%e/, "\\e", $0) # %e -> \e
+ gsub(/~/, " ", $0) # unpaddable spaces go away at last
+ if (gsub(/\[/, "\\\\&\\f(CW", $0))
+ gsub(/\]/, "\\fP", $0)
+ if (gsub(/\{/, "\\f2", $0))
+ gsub(/\}/, "\\fP", $0)
+ if (quoted) {
+ gsub(/%/, "", $0)
+ gsub(/QQ0QQ/, "%", $0)
+ gsub(/QQ1QQ/, "[", $0)
+ gsub(/QQ2QQ/, "]", $0)
+ gsub(/QQ3QQ/, "{", $0)
+ gsub(/QQ4QQ/, "}", $0)
+ gsub(/QQ5QQ/, "~", $0)
+ }
+ printf "\\&%s\n", $0
+}
+' $*
diff --git a/src/cmd/index/gen.key b/src/cmd/index/gen.key
new file mode 100644
index 00000000..a7922763
--- /dev/null
+++ b/src/cmd/index/gen.key
@@ -0,0 +1,57 @@
+awk ' # gen.key
+# Input: Each input line has one of the following two forms:
+# string (tab) numlist
+# string " %key " sort.key (tab) numlist
+# Output: Each output line has the form:
+# sort.key (tab) string (tab) numlist
+
+BEGIN { FS = OFS = "\t" }
+
+/ %key / { # use sort.key if it is provided
+ i = index($1, " %key ")
+ print substr($1, i+6), substr($1, 1, i-1), $2
+ next
+ }
+
+ { # generate sort.key (in $2, by modifying string) if it is not provided
+ $3 = $2
+ $2 = $1
+
+ #Modify sort.key
+ # Remove some troff commands
+ gsub(/\\f\(..|\\f.|\\s[+-][0-9]|\\s[0-9][0-9]?/, "", $2)
+
+ # underscore -> 0, so "foo_gorp" sorts before "food"
+ gsub(/_/, "0", $2)
+
+ # quote character is %, space character is ~
+ quoted = 0
+ if ($2 ~ /%/) { # hide quoted literals in Q
+ quoted = 1
+ gsub(/%%/, "QQ0QQ", $2)
+ gsub(/%\[/, "QQ1QQ", $2)
+ gsub(/%\]/, "QQ2QQ", $2)
+ gsub(/%\{/, "QQ3QQ", $2)
+ gsub(/%\}/, "QQ4QQ", $2)
+ gsub(/%~/, "QQ5QQ", $2)
+ }
+ gsub(/%e/, "\\", $2) # implement troff escape
+ gsub(/~/, " ", $2) # remove tildes
+ gsub(/[%\[\]\{\}]/, "", $2) # remove % and font-changing []{}
+ if (quoted) { # restore literals but without escape charcter
+ gsub(/QQ0QQ/, "%", $2)
+ gsub(/QQ1QQ/, "[", $2)
+ gsub(/QQ2QQ/, "]", $2)
+ gsub(/QQ3QQ/, "{", $2)
+ gsub(/QQ4QQ/, "}", $2)
+ gsub(/QQ5QQ/, "~", $2)
+ }
+ if ($2 ~ /^[^a-zA-Z]+$/) # purely nonalphabetic lines go first
+ $2 = " " $2
+ else if ($2 ~ /^[0-9]/) # lines with eading digits come next
+ $2 = " " $2
+ # otherwise whatever final.sort does
+}
+
+ { print $2, $1, $3 }
+' $*
diff --git a/src/cmd/index/hierarchy b/src/cmd/index/hierarchy
new file mode 100644
index 00000000..16cda592
--- /dev/null
+++ b/src/cmd/index/hierarchy
@@ -0,0 +1,133 @@
+#!/bin/sh
+
+# input:
+# key (tab) string (tab) page numbers
+# command command 123
+# command, data command, [data] 11
+# command, display command, [display] 11, 54, 63, 75
+# command, model command, [model] 11
+# command, quit command, [quit] 5, 16
+# output:
+# key (tab) string (tab) page numbers
+# key command 123
+# key [data] 11
+# key [display] ...
+# key [model] ...
+# key [quit] ...
+
+awk '
+BEGIN { FS = OFS = "\t" }
+
+{ line[NR] = $0; x[NR] = $2 "\t" $3; y[NR] = $1 }
+
+# find a sequence that have the same prefix
+# dump prefix, then each instance with spaces instead of prefix
+END {
+ for (i = 1; i <= NR; i = j+1) {
+ j = findrun(i) # returns last elem of run
+ if (j > i)
+ printrun(i, j)
+ else
+ print y[i], x[i]
+ }
+}
+
+function findrun(s, j, p, np) { # find y[s],y[s+1]... with same prefix
+ p = prefix(y[s])
+ np = length(p)
+ for (j = s+1; j <= NR; j++) {
+ if (y[j] == p) # same, so include
+ continue
+ if (index(y[j], p) != 1) # no match
+ break
+ c = substr(y[j], np+1, 1)
+ if (c != " " && c != ",") # has to be whole word prefix
+ break
+ }
+ return j-1
+}
+
+function prefix(s, n) { # find 1st word of s: same sort key, minus ,
+ gsub(/,/, "", s)
+ n = index(s, " ")
+ if (n > 0)
+ return substr(s, 1, n-1)
+ else
+ return s
+}
+
+function printrun(s, e, i) { # move [...] to end, "see" to front
+ s1 = 0; e1 = 0; p1 = 0; i1 = 0
+ for (i = s; i <= e; i++) {
+ if (x[i] ~ /{see/) { # see, see also
+ sx[s1] = x[i]
+ sy[s1] = y[i]
+ s1++
+ } else if (x[i] ~ /^\[/) { # prefix word is [...]
+ px[p1] = x[i]
+ py[p1] = y[i]
+ p1++
+ } else if (x[i] ~ /\[.*\]/) { # [...] somewhere else
+ ex[e1] = x[i]
+ ey[e1] = y[i]
+ e1++
+ } else { # none of the above
+ ix[i1] = x[i]
+ iy[i1] = y[i]
+ i1++
+ }
+ }
+ if (e-s+1 != s1 + p1 + i1 + e1) print "oh shit" >"/dev/stderr"
+
+ for (i = 0; i < s1; i++) # "see", one/line
+ print sy[i], sx[i]
+ if (i1 > 1)
+ printgroup(ix,iy,0,i1) # non [...] items
+ else if (i1 == 1)
+ print iy[0], ix[0]
+ if (e1 > 1)
+ printgroup(ex,ey,0,e1) # prefix [...] items
+ else if (e1 == 1)
+ print ey[0], ex[0]
+ # for (i = 0; i < p1; i++) # [prefix] ... items
+ # print py[i], px[i]
+ if (p1 > 1)
+ printgroup(px,py,0,p1) # [prefix] ... items
+ else if (p1 == 1)
+ print py[0], px[0]
+}
+
+function printgroup(x, y, s, e, i, j) {
+ split(x[s], f23)
+ if (split(f23[1], temp, " ") > 1) {
+ pfx = temp[1] " " temp[2] # 2-word prefix
+ for (i = s+1; i < e; i++) {
+ if (index(x[i], pfx) != 1)
+ break
+ c = substr(x[i], length(pfx)+1, 1)
+ if (c != " " && c != ",") # has to be whole word prefix
+ break
+ }
+ if (i == e) {
+ # print "got a run with", pfx
+ sub(/ /, "@", f23[1])
+ for (i = s; i < e; i++)
+ sub(/ /, "@", x[i]) # take @ out later
+ }
+ }
+ n = sub(/,?[ ~]+.*/, "", f23[1]) # zap rest of line
+
+ sub(/,$/, "", f23[1])
+ if (n > 0) { # some change, so not a single word
+ sub(/@/, " ", f23[1])
+ print y[s], f23[1] # print main entry
+ }
+ for (j = s; j < e; j++) {
+ split(x[j], f23)
+ sub(/^[^, ]+[, ]+/, " ", f23[1])
+ sub(/@/, " ", f23[1])
+ print y[s], f23[1], f23[2]
+ }
+}
+
+' $*
diff --git a/src/cmd/index/install b/src/cmd/index/install
new file mode 100644
index 00000000..0cd264f9
--- /dev/null
+++ b/src/cmd/index/install
@@ -0,0 +1,3 @@
+chmod +x check.data cleanup deroman doclean final.sort format \
+ gen.key hierarchy make.index num.collapse range.collapse \
+ range.prep range.sort reroman rotate see.prep
diff --git a/src/cmd/index/ix.macro b/src/cmd/index/ix.macro
new file mode 100644
index 00000000..d8d17d9d
--- /dev/null
+++ b/src/cmd/index/ix.macro
@@ -0,0 +1,4 @@
+.de ix
+.ie '\\n(.z'' .tm ix: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 \\n%
+.el \\!.ix \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
diff --git a/src/cmd/index/ix.test b/src/cmd/index/ix.test
new file mode 100644
index 00000000..41f824ac
--- /dev/null
+++ b/src/cmd/index/ix.test
@@ -0,0 +1,17 @@
+ix: line 1
+ix: line 2
+ix: line 2
+ix: line 3
+ix: %begin line 11
+ix: line 15
+ix: %end line 19
+ix: \f(CWps\fP \f(CW-a\fP 34
+ix: \f(CWps\fP command 34
+ix: \f(CWPS1\fP shell variable 36
+ix: sorting~a book~index 25
+ix: [pr]~[-]{n} command 31
+ix: [%[^]...[%]] regular~expression 32
+ix: [printf] [%%d] specification 35
+ix: T\v'.17m'\h'-.12m'E\h'-.12m'\v'-.17m'X %key TEX 40
+ix: CONTENTS 7 Input and Output
+ix: [%~] tilde 41
diff --git a/src/cmd/index/make.index b/src/cmd/index/make.index
new file mode 100644
index 00000000..aa89993d
--- /dev/null
+++ b/src/cmd/index/make.index
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+#check.data $*
+
+doclean $* >foo1
+deroman foo1 >foo2
+range.prep foo2 >foo3
+rotate foo3 >foo4
+range.sort foo4 >foo5
+range.collapse foo5 >foo6
+reroman foo6 >foo7
+num.collapse foo7 >foo8
+gen.key foo8 >foo9
+see.prep see.terms | gen.key >foo.see
+final.sort foo9 foo.see >foo.regular
+
+hierarchy foo.regular >foo.hier
+
+format foo.hier >foo.all
+
+cat foo.all
+
+#cleanup
diff --git a/src/cmd/index/num.collapse b/src/cmd/index/num.collapse
new file mode 100644
index 00000000..47203f52
--- /dev/null
+++ b/src/cmd/index/num.collapse
@@ -0,0 +1,21 @@
+awk ' # num.collapse
+# Input: lines of form: string (tab) num1 [(space) num2]
+# Output: lines of form: string (tab) fancy.num.list
+#
+# fancy.num.list contains items, separated by ", ", of form: num or num-num
+# Sequence of input lines with same value of string is combined
+# into a single output line. Each input line contributes either
+# num or num-num to output line.
+
+BEGIN { FS = OFS = "\t" }
+
+ { sub(/ /, "\\(en", $2) } # use - if there is no en dash
+
+$1 != p { p = $1
+ if (NR > 1) printf "\n"
+ printf "%s\t%s", $1, $2
+ next
+ }
+ { printf ", %s", $2 }
+END { if (NR > 0) printf "\n" }
+' $*
diff --git a/src/cmd/index/range.collapse b/src/cmd/index/range.collapse
new file mode 100644
index 00000000..9119cea6
--- /dev/null
+++ b/src/cmd/index/range.collapse
@@ -0,0 +1,35 @@
+awk ' # range.collapse
+# Input: lines of form: string (tab) ["b"|"e"|"a"] (tab) number
+# Output: lines of form: string (tab) num [(space) num]
+# In sequence of lines with same value of string:
+# b line and following e line are combined into single line:
+# string (tab) num num
+# a line disappears if between paired b and e
+# a line otherwise becomes single line:
+# string (tab) num
+
+function error(s) {
+ print "range.collapse: " s " near pp " rlo "-" rhi | "cat 1>&2"
+}
+function printoldrange() {
+ if (range == 1) { error("no %end for " term); rhi = "XXX" }
+ if (NR > 1) {
+ if (rlo == rhi)
+ print term, rlo
+ else
+ print term, (rlo " " rhi)
+ }
+ rlo = rhi = $3 # bounds of current range
+}
+
+BEGIN { FS = OFS = "\t" }
+$1 != term { printoldrange(); term = $1; range = 0 }
+$2 == "e" { if (range == 1) { range = 0; rhi = $3 }
+ else { printoldrange(); error("no %begin for " term); rlo = "XXX" }
+ next
+ }
+$3 <= rhi + 1 { rhi = $3}
+$3 > rhi + 1 { if (range == 0) printoldrange() }
+$2 == "b" { if (range == 1) error("multiple %begin for " term); range = 1 }
+END { if (NR == 1) NR = 2; printoldrange() }
+' $*
diff --git a/src/cmd/index/range.prep b/src/cmd/index/range.prep
new file mode 100644
index 00000000..16ae3cc8
--- /dev/null
+++ b/src/cmd/index/range.prep
@@ -0,0 +1,10 @@
+awk ' # range.prep
+# Input: ["%begin"|"%end"|""] string (tab) number
+# Output: string (tab) ["b"|"e"|"a"] (tab) number
+
+BEGIN { FS = OFS = "\t" }
+ { f2 = "a" }
+$1 ~ /^%begin/ { f2 = "b"; sub(/^%begin */, "", $1) }
+$1 ~ /^%end/ { f2 = "e"; sub(/^%end */, "", $1) }
+ { print $1, f2, $2 }
+' $*
diff --git a/src/cmd/index/range.sort b/src/cmd/index/range.sort
new file mode 100644
index 00000000..e2cdd493
--- /dev/null
+++ b/src/cmd/index/range.sort
@@ -0,0 +1,5 @@
+# range.sort
+# Input/Output: string (tab) ["b"|"e"|"a"] (tab) number
+# Sort by $1 (string), $3 (number), then $2 ("b"|"e"|"a")
+
+sort -u '-t ' +0 -1 +2n +1 -2 $*
diff --git a/src/cmd/index/reroman b/src/cmd/index/reroman
new file mode 100644
index 00000000..0d9fa00b
--- /dev/null
+++ b/src/cmd/index/reroman
@@ -0,0 +1,23 @@
+awk ' # reroman
+# Output: string (tab) arab1 [(space) arab2]
+# Input: string (tab) arab1 or roman1 [(space) arab2 or roman2]
+
+BEGIN { FS = OFS = "\t"
+ # set a[1] = "i", a[2] = "ii", ...
+ s = "i ii iii iv v vi vii viii ix x"
+ s = s " xi xii xiii xiv xv xvi xvii xviii xix xx"
+ s = s " xxi xxii xxiii xxiv xxv xxvi xxvii xxviii xxix xxx"
+ split(s, a, " ")
+ }
+$2 < 0 { n = split($2, b, " ")
+ for (i = 1; i <= n; i++) {
+ if (b[i] >= 0) continue
+ j = 1000 + b[i]
+ if (j in a) b[i] = a[j]
+ else print "reroman: bad number: " $0 | "cat 1>&2"
+ }
+ $2 = b[1]
+ if (n > 1) $2 = b[1] " " b[2]
+ }
+ { print }
+' $*
diff --git a/src/cmd/index/rotate b/src/cmd/index/rotate
new file mode 100644
index 00000000..76c0274c
--- /dev/null
+++ b/src/cmd/index/rotate
@@ -0,0 +1,31 @@
+awk ' # rotate
+# Input line: string (tab) ["b"|"e"|"a"] (tab) number
+# Output several lines:
+# string (tab) ["b"|"e"|"a"] (tab) number
+# rotated string (tab) ["b"|"e"|"a"] (tab) number
+# rotated string (tab) ["b"|"e"|"a"] (tab) number
+# ...
+#
+# In the output strings, tildes are replaced by spaces
+
+BEGIN { FS = OFS = "\t" }
+
+/ %key / { # if explicit sort.key is provided, do not rotate
+ print $0
+ next
+ }
+
+ {
+ t1 = $1 #t1 will be $1 with tildes changed to spaces
+ gsub(/%~/, "QQ5QQ", t1) #hide real tildes
+ gsub(/~/, " ", t1) #change tildes to spaces
+ gsub(/QQ5QQ/, "%~", t1) #restore real tildes
+ print t1, $2, $3
+ i = 1
+ while ((j = index(substr($1, i+1), " ")) > 0) {
+ i += j
+ printf("%s, %s\t%s\t%s\n", \
+ substr(t1, i+1), substr(t1, 1, i-1), $2, $3)
+ }
+ }
+' $*
diff --git a/src/cmd/index/see.prep b/src/cmd/index/see.prep
new file mode 100644
index 00000000..33d4c2df
--- /dev/null
+++ b/src/cmd/index/see.prep
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+awk ' # see.prep
+# Input: string "\t" string
+# Output: string "\t{see [also]} " string
+
+BEGIN { FS = "\t" }
+$3 ~ /%also/ { print $1 "\t{see also} " $2; next }
+ { print $1 "\t{see} " $2 }
+' $*
diff --git a/src/cmd/index/see.terms b/src/cmd/index/see.terms
new file mode 100644
index 00000000..8a8aa6b7
--- /dev/null
+++ b/src/cmd/index/see.terms
@@ -0,0 +1,69 @@
+soft constraints penalty function
+[>>> <<<] error messages
+omitted data value default symbol
+data value, omitted default symbol
+["].\|.\|.["], ['].\|.\|.['] quotes
+[..] arithmetic progression
+[=] attribute defined variables
+[.body] constraint body
+built-in function function
+Cartesian product cross product
+conditional expression logical expression, [if]-[then]-[else]
+conditional declaration [if] indexing expression
+[.dat] file file
+[.dual] dual value
+Lagrange multiplier dual variables
+index dummy index
+iterated operator operator
+comparison operators relational operators
+[maximize] objective declaration
+[minimize] objective declaration
+model file file
+[.mod] file file
+price, shadow dual value
+problem model %also
+[.rc] reduced cost
+data reset [reset] [data] command
+scaling along arc loss in network flow
+scope dummy index %also
+set of sets indexed collection
+shadow price dual value
+marginal~value dual value
+simplification of expression presolve %also
+starting guess initial values of variables
+[subject] [to] constraint declaration
+[s.t.] constraint declaration
+symmetric difference [symdiff]
+set difference [diff], [symdiff]
+syntax error error messages
+messages error messages
+space requirement memory use
+viewing data [display] command
+[;] semicolon statement terminator
+array one-dimensional set, parameter
+vector one-dimensional set, parameter
+matrix two-dimensional set, parameter
+command mode model mode
+[>], [>>] output to file
+redirection output to file
+qualified name [.] suffix
+member, dummy dummy index
+membership test [in], [within]
+subset test [in], [within]
+such-that condition logical condition
+set intersection [inter]
+intersection, set [inter]
+slope piecewise-linear expression
+breakpoint piecewise-linear expression
+command statement %also
+statement command, declaration %also
+declaration statement %also
+traffic flow maximum flow model
+flow network flow
+roll trim problem cutting-stock problem
+argument command-line argument
+zero-one programming integer programming
+reading files [model], [data]
+file inclusion [model], [data]
+[include] [model], [data] %also
+transposition table transposition