module index (* System: ??? File: index.tm Author: Claudia Niederee Date : 07-JUN-1994 Purpose: preparation of a latex index file *) import reader :Reader string :StringOp print :Print char :CharOp iter :Iter varList :VarList writer :Writer fmt :Fmt export Let Rec Entry <:Ok= Tuple sortKey :String entry :String pages: varList.T(Int) subEntries :varList.T(Entry) end let pageNumber(var entry :String) :Int = begin let entrySize = string.size(entry) let var rIndex = 0 let var c = string.get(entry entrySize) let var value = 0 let var factor = 1 while char.isDigit(c) do value := value + {factor*{char.ord(c) - char.ord('0')}} factor:= factor*10 rIndex := rIndex + 1 c := string.get(entry entrySize-rIndex) end entry:= string.sub(entry 1 entrySize-{rIndex+2}) value end let includesChar(s :String c :Char) :Bool = iter.some(string.elements(s) fun(c1 :Char) char.equal(c c1)) let newEntry(sortKey, entry :String page :Int) :Entry = tuple let sortKey = sortKey let entry = entry let pages = varList.create(iter.singleton(:Int page)) let subEntries = varList.new(:Entry) end let newEntryNN(s :String) :Entry = tuple let sortKey = s let entry = s let pages = varList.new(:Int) let subEntries = varList.new(:Entry) end let getEntry(entries :varList.T(Entry) s :String ) :Entry = iter.any(varList.elements(entries) fun(e :Entry) string.equal(e.entry s)) let pnExists(pns :varList.T(Int) p :Int) :Bool = if varList.empty(pns) then false else iter.some(varList.elements(pns) fun(i :Int) i ==p) end let entryExists(entries :varList.T(Entry) s :String) :Bool = if varList.empty(entries) then false else iter.some(varList.elements(entries) fun(e :Entry) string.equal(e.entry s)) end let insertPage(pns :varList.T(Int) p :Int) :Ok = (******* Sorted Insert of page numbers *********************) begin let size = varList.size(pns) if size == 0 then varList.insert(pns p) else let var i = 1 varList.goto(pns i) while {varList.get(pns) < p} /\ {i < size} do varList.gotoNext(pns) i:=i+1 end if varList.get(pns) > p then varList.insertBefore(pns p) else varList.insert(pns p) end end end (* let innerLower(s :String) :Bool = begin let var i = string.position(" " s 1) while char.equal(string.get(s i) ' ')/\ {i< string.size(s)} do i:= i+1 end char.isLower(string.get(s i)) end *) let innerUpper(s :String) :Bool = begin let size = string.size(s) if size == 0 then false elsif includesChar(s ' ') then let var i = string.position(" " s 1) while char.equal(string.get(s i) ' ')/\ {i< size} do i:= i+1 end char.isUpper(string.get(s i)) else false end end let isKey(s :String) :Bool = if string.size(s) == 0 then false else char.equal(string.get(s 1) '{') end let insertSpEntry(entries :varList.T(Entry) e :Entry) :Ok = begin let size = varList.size(entries) if size == 0 then varList.insert(entries e) else varList.goto(entries size) varList.insert(entries e) end end let insertKeyEntry(entries :varList.T(Entry) e :Entry) :Ok = begin let size = varList.size(entries) if size == 0 then varList.insert(entries e) else let var i =1 varList.goto(entries 1) let var current = varList.get(entries) while string.less(current.sortKey e.sortKey) /\ {i < size} do varList.gotoNext(entries) i:=i+1 current:= varList.get(entries) end if string.greater(current.sortKey e.sortKey) then varList.insertBefore(entries e) elsif string.equal(current.sortKey e.sortKey) then if i < size then varList.gotoNext(entries) let var next = varList.get(entries) let var j = i + 1 while string.equal(next.sortKey e.sortKey) /\ {j <= size} do current := next i:= i + 1 if j< size then j := j+1 varList.gotoNext(entries) next := varList.get(entries) end (* if *) end (* while *) end (* if i < size *) varList.goto(entries i) if isKey(current.entry) /\ innerUpper(e.entry) then varList.insertBefore(entries e) else varList.insert(entries e) end else (* end of list *) varList.insert(entries e) end (* if string .. *) end (* if size == 0 *) end (* begin *) let insertEntry(entries :varList.T(Entry) e :Entry) :Ok = (* Sorted insert of Entry *) begin let size = varList.size(entries) if size == 0 then varList.insert(entries e) else (* if char.isAlpha(string.get(e.sortKey 1)) then *) let var i = 1 varList.goto(entries i) let var current = varList.get(entries) while string.less(current.sortKey e.sortKey) /\ {i < size} do varList.gotoNext(entries) i:=i+1 current := varList.get(entries) end if string.equal(current.sortKey e.sortKey) then if isKey(current.entry) then varList.insertBefore(entries e) elsif char.isLower(string.get(e.entry 1)) then varList.insert(entries e) else varList.insertBefore(entries e) end elsif string.greater(current.sortKey e.sortKey) then varList.insertBefore(entries e) else (* end of list reached *) varList.insert(entries e) end (* else varList.goto(entries size) varList.insert(entries e) *) end end (****************************************************************) let mainEntry(entries : varList.T(Entry) s :String page: Int) :Ok = if not(entryExists(entries s)) then (* if char.isUpper(string.get(s 1)) then *) let entry = string.copy(s) let size = string.size(s) let var i = 1 while i <= size do if char.isUpper(string.get(s i)) then string.set(entry i char.lower(string.get(s i))) end i:= i+1 end insertEntry(entries newEntry(entry s page)) else let temp = getEntry(entries s) if not(pnExists(temp.pages page)) then insertPage(temp.pages page) end end let specialEntry(entries : varList.T(Entry) s :String page :Int) :Ok = if not(entryExists(entries s)) then if char.equal(string.get(s 1) '{') then let var i =1 while not(char.equal(string.get(s i) ' ')) do i:= i+1 end while char.equal(string.get(s i) ' ') do i :=i+1 end let sortKey = string.sub(s i string.size(s)-i) if char.isUpper(string.get(sortKey 1)) then string.set(sortKey 1 char.lower(string.get(sortKey 1))) end insertKeyEntry(entries newEntry(sortKey s page)) else insertSpEntry(entries newEntry("|" s page)) end else let temp = getEntry(entries s) if not(pnExists(temp.pages page)) then insertPage(temp.pages page) end end let subEntry(entries :varList.T(Entry) s :String page :Int) :Ok = begin let var i = string.position("," s 1) let size = string.size(s) let part1 = string.sub(s 1 i-1) i:=i+1 while char.equal(string.get(s i) ' ') do i :=i+1 end let part2 = string.sub(s i size-i+1) let size2 = string.size(part2) let subEntry = if includesChar(part2 '~') then let i = string.position("~" part2 1) tuple let entry = string.sub(part2 1 i-1) <> "$\\sim$" <> string.sub(part2 i+1 size2-i) let sortKey = string.sub(part2 1 i-1) <> part1 <> string.sub(part2 i+1 size2-i) end else tuple let entry = part2 let sortKey = part2 end end if entryExists(entries part1) then let item = getEntry(entries part1) if entryExists(item.subEntries subEntry.entry) then let subitem = getEntry(item.subEntries subEntry.entry) if not(pnExists(subitem.pages page)) then insertPage(subitem.pages page) end else insertEntry(item.subEntries newEntry(subEntry.sortKey subEntry.entry page)) end else let item = newEntryNN(part1) insertEntry(entries item) insertEntry(item.subEntries newEntry(subEntry.sortKey subEntry.entry page)) end end (*****************************************************************) let inEntries(source :reader.T) :varList.T(Entry) = begin let start = string.size(" indexentry{") + 1 let latexInput = reader.getLines(source) let entries = varList.new(:Entry) iter.forEach(latexInput fun(line :String) begin if string.size(line) > 0 then if char.equal(string.get(line 1) '\\') then let var entry = string.sub(line start string.size(line)-start) let page = pageNumber(entry) print.string(entry) print.ln() if includesChar(entry ',') then subEntry(entries entry page) elsif not(char.isAlpha(string.get(entry 1))) then specialEntry(entries entry page) else mainEntry(entries entry page) end else ok end else ok end end) entries end (****************************OUTPUT *****************************) let makePages(pages :varList.T(Int)) :String = if not(varList.empty(pages)) then let size = varList.size(pages) varList.goto(pages 1) let var pageStr = " " <> fmt.int(varList.get(pages)) while varList.pos(pages) < size do varList.gotoNext(pages) pageStr := pageStr <> ", " <> fmt.int(varList.get(pages)) end pageStr else string.nil() end let makeItem(s :String pages: varList.T(Int)) :String = "\\item " <> s <> makePages(pages) let makeSubItem(s :String pages: varList.T(Int)) :String = "\\subitem " <> s <> makePages(pages) let makeSpace() :String = "\\indexspace" let makeNewLetter(c :Char) :String = "\\item $" <> fmt.char(char.upper(c)) <>"$" let putSubItems(out :writer.T subItems :varList.T(Entry)) = iter.forEach(varList.elements(subItems) fun(e :Entry) writer.putLine(out makeSubItem(e.entry e.pages))) let putItems(target :writer.T entries :varList.T(Entry)) :Ok = begin writer.putLine(target "\\begin{theindex}") let var previous = ' ' varList.goto(entries 1) iter.forEach(varList.elements(entries) fun(e :Entry) begin let frstChar = string.get(e.sortKey 1) if char.notEqual(frstChar previous) then writer.putLine(target makeSpace()) if char.isAlpha(frstChar) then writer.putLine(target makeNewLetter(frstChar)) elsif char.equal(frstChar '|') then writer.putLine(target "\\item $Others$") end end writer.putLine(target makeItem(e.entry e.pages)) if not(varList.empty(e.subEntries)) then putSubItems(target e.subEntries) end previous := string.get(e.sortKey 1) end) writer.putLine(target "\\end{theindex}") end (*****************************Main ********************************) let create(sourceFile, targetFile :String) :Ok = begin let source = reader.file(sourceFile) let entries = inEntries(source) (* print.string("inEntries fertig ") print.ln() *) let target = writer.file(targetFile) putItems(target entries) writer.close(target) end end;