home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume23 / quranref / part06 < prev    next >
Encoding:
Text File  |  1991-10-19  |  32.2 KB  |  1,074 lines

  1. Newsgroups: comp.sources.misc
  2. From: goer@midway.uchicago.edu (Richard L. Goerwitz)
  3. Subject:  v23i072:  quranref - Holy Qur'an word and passage based retrievals, Part06/08
  4. Message-ID: <1991Oct19.022331.13057@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8fe3852cf0ae92dbb24e3cd376a4b203
  6. Date: Sat, 19 Oct 1991 02:23:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: goer@midway.uchicago.edu (Richard L. Goerwitz)
  10. Posting-number: Volume 23, Issue 72
  11. Archive-name: quranref/part06
  12. Environment: Icon
  13.  
  14. ---- Cut Here and feed the following to sh ----
  15. #!/bin/sh
  16. # this is quranref.06 (part 6 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file iolib.icn continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 6; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping iolib.icn'
  34. else
  35. echo 'x - continuing file iolib.icn'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'iolib.icn' &&
  37. X    er("getval","can't make a table for your terminal",4)
  38. X
  39. X    return \tc_table[id] | fail
  40. X    # er("getval","the current terminal doesn't support "||id,7)
  41. X
  42. Xend
  43. X
  44. X
  45. X
  46. Xprocedure Decode(s)
  47. X
  48. X    # Does things like turn ^ plus a letter into a genuine control
  49. X    # character.
  50. X
  51. X    local new_s, chr, chr2
  52. X
  53. X    new_s := ""
  54. X
  55. X    s ? {
  56. X
  57. X    while new_s ||:= tab(upto('\\^')) do {
  58. X        chr := move(1)
  59. X        if chr == "\\" then {
  60. X        new_s ||:= {
  61. X            case chr2 := move(1) of {
  62. X            "\\" : "\\"
  63. X            "^"  : "^"
  64. X            "E"  : "\e"
  65. X            "b"  : "\b"
  66. X            "f"  : "\f"
  67. X            "n"  : "\n"
  68. X            "r"  : "\r"
  69. X            "t"  : "\t"
  70. X            default : {
  71. X                if any(&digits,chr2) then {
  72. X                char(integer("8r"||chr2||move(2 to 0 by -1))) |
  73. X                    er("Decode","bad termcap entry",3)
  74. X                }
  75. X               else chr2
  76. X            }
  77. X            }
  78. X        }
  79. X        }
  80. X        else new_s ||:= char(ord(map(move(1),&lcase,&ucase)) - 64)
  81. X    }
  82. X    new_s ||:= tab(0)
  83. X    }
  84. X
  85. X    return new_s
  86. X
  87. Xend
  88. X
  89. X
  90. X
  91. Xprocedure igoto(cm,col,line)
  92. X
  93. X    local colline, range, increment, padding, str, outstr, chr, x, y
  94. X
  95. X    if \col > (tc_table["co"]) | \line > (tc_table["li"]) then {
  96. X    colline := string(\col) || "," || string(\line) | string(\col|line)
  97. X    range := "(" || tc_table["co"]-1 || "," || tc_table["li"]-1 || ")"
  98. X    er("igoto",colline || " out of range " || (\range|""),9)
  99. X    } 
  100. X
  101. X    # Use the Iconish 1;1 upper left corner & not the C-ish 0 offsets
  102. X    increment := -1
  103. X    outstr := ""
  104. X    
  105. X    cm ? {
  106. X    while outstr ||:= tab(find("%")) do {
  107. X        tab(match("%"))
  108. X        if padding := integer(tab(any('23')))
  109. X        then chr := (="d" | "d")
  110. X        else chr := move(1)
  111. X        if case \chr of {
  112. X        "." :  outstr ||:= char(line + increment)
  113. X        "+" :  outstr ||:= char(line + ord(move(1)) + increment)
  114. X        "d" :  {
  115. X            str := string(line + increment)
  116. X            outstr ||:= right(str, \padding, "0") | str
  117. X        }
  118. X        }
  119. X        then line :=: col
  120. X        else {
  121. X        case chr of {
  122. X            "n" :  line := ixor(line,96) & col := ixor(col,96)
  123. X            "i" :  increment := 0
  124. X            "r" :  line :=: col
  125. X            "%" :  outstr ||:= "%"
  126. X            "B" :  line := ior(ishift(line / 10, 4), line % 10)
  127. X            ">" :  {
  128. X            x := move(1); y := move(1)
  129. X            line > ord(x) & line +:= ord(y)
  130. X            &null
  131. X            }
  132. X        } | er("goto","bad termcap entry",5)
  133. X        }
  134. X    }
  135. X    return outstr || tab(0)
  136. X    }
  137. X
  138. Xend
  139. X
  140. X
  141. X
  142. Xprocedure iputs(cp, affcnt)
  143. X
  144. X    # Writes cp to the screen.  Use this instead of writes() for
  145. X    # compatibility with itlib (a UNIX-only version which can handle
  146. X    # albeit inelegantly) terminals that need padding.
  147. X
  148. X    static num_chars
  149. X    initial num_chars := &digits ++ '.'
  150. X
  151. X    type(cp) == "string" |
  152. X    er("iputs","you can't iputs() a non-string value!",10)
  153. X
  154. X    cp ? {
  155. X    if tab(many(num_chars)) & ="*" then
  156. X        stop("iputs:  iolib can't use terminals that require padding.")
  157. X    writes(tab(0))
  158. X    }
  159. X
  160. X    return
  161. X
  162. Xend
  163. SHAR_EOF
  164. echo 'File iolib.icn is complete' &&
  165. true || echo 'restore of iolib.icn failed'
  166. rm -f _shar_wnt_.tmp
  167. fi
  168. # ============= iscreen.icn ==============
  169. if test -f 'iscreen.icn' -a X"$1" != X"-c"; then
  170.     echo 'x - skipping iscreen.icn (File already exists)'
  171.     rm -f _shar_wnt_.tmp
  172. else
  173. > _shar_wnt_.tmp
  174. echo 'x - extracting iscreen.icn (Text)'
  175. sed 's/^X//' << 'SHAR_EOF' > 'iscreen.icn' &&
  176. X############################################################################
  177. X#
  178. X#    Name:     iscreen.icn
  179. X#
  180. X#    Title:     Icon screen functions
  181. X#
  182. X#    Author:     Richard L. Goerwitz
  183. X#
  184. X#    Version: 1.26
  185. X#
  186. X############################################################################
  187. X#
  188. X#  This and future version of iscreen are placed in the public domain - RLG
  189. X#
  190. X############################################################################
  191. X#  
  192. X#      This file contains some rudimentary screen functions for use with
  193. X#  itlib.icn (termlib-like routines for Icon).
  194. X#
  195. X#      clear()              - clears the screen (tries several methods)
  196. X#      emphasize()          - initiates emphasized mode
  197. X#      boldface()           - initiates bold mode
  198. X#      blink()              - initiates blinking mode
  199. X#      normal()             - resets to normal mode
  200. X#      message(s)           - displays message s on 2nd-to-last line
  201. X#      underline()          - initiates underline mode
  202. X#      status_line(s,s2,p)  - draws status line s on the 3rd-to-last
  203. X#        screen line; if s is too short for the terminal, s2 is used;
  204. X#        if p is nonnull then it either centers, left-, or right-justi-
  205. X#        fies, depending on the value, "c," "l," or "r."
  206. X#      clear_emphasize()    - horrible way of clearing the screen to all-
  207. X#        emphasize mode; necessary for many terminals
  208. X#
  209. X############################################################################
  210. X#
  211. X#  Requires: UNIX
  212. X#
  213. X#  Links: itlib.icn (or your OS-specific port of itlib)
  214. X#
  215. X#  See also: boldface.icn
  216. X#
  217. X############################################################################
  218. X
  219. X
  220. Xprocedure clear()
  221. X
  222. X    # Clears the screen.  Tries several methods.
  223. X    local i
  224. X
  225. X    normal()
  226. X    if not iputs(getval("cl"))
  227. X    then iputs(igoto(getval("cm"),1,1) | getval("ho"))
  228. X    if not iputs(getval("cd"))
  229. X    then {
  230. X    every i := 1 to getval("li") do {
  231. X        iputs(igoto(getval("cm"),1,i))
  232. X        iputs(getval("ce"))
  233. X    }
  234. X    iputs(igoto(getval("cm"),1,1))
  235. X    }
  236. X    return
  237. X
  238. Xend
  239. X
  240. X
  241. X
  242. Xprocedure boldface()
  243. X    
  244. X    static bold_str, cookie_str
  245. X    initial {
  246. X    if bold_str := getval("md")
  247. X    then cookie_str := repl(getval("le"|"bc") | "\b", getval("mg"))
  248. X    else {
  249. X        # One global procedure value substituted for another.
  250. X        boldface := emphasize
  251. X        return emphasize()
  252. X    }
  253. X    }        
  254. X    normal()
  255. X    iputs(\bold_str)
  256. X    iputs(\cookie_str)
  257. X    return
  258. X
  259. Xend
  260. X
  261. X
  262. X
  263. Xprocedure blink()
  264. X    
  265. X    static blink_str, cookie_str
  266. X    initial {
  267. X    if blink_str := getval("mb")
  268. X    then cookie_str :=
  269. X         repl(getval("le"|"bc") | "\b", getval("mg"))
  270. X    else {
  271. X        # One global procedure value substituted for another.
  272. X        blink := emphasize
  273. X        return emphasize()
  274. X    }
  275. X    }        
  276. X    normal()
  277. X    iputs(\blink_str)
  278. X    iputs(\cookie_str)
  279. X    return
  280. X
  281. Xend
  282. X
  283. X
  284. X
  285. Xprocedure emphasize()
  286. X    
  287. X    static emph_str, cookie_str
  288. X    initial {
  289. X    if emph_str := getval("so")
  290. X    then cookie_str := repl(getval("le"|"bc") | "\b", getval("sg"))
  291. X    else {
  292. X        if emph_str := getval("us")
  293. X        then cookie_str := repl(getval("le"|"bc") | "\b", getval("ug"))
  294. X    }
  295. X    }        
  296. X    normal()
  297. X    iputs(\emph_str)
  298. X    iputs(\cookie_str)
  299. X    return
  300. X
  301. Xend
  302. X
  303. X
  304. X
  305. Xprocedure underline()
  306. X    
  307. X    static underline_str, cookie_str
  308. X    initial {
  309. X    if underline_str := getval("us")
  310. X    then cookie_str := repl(getval("le"|"bc") | "\b", getval("ug"))
  311. X    }
  312. X
  313. X    normal()
  314. X    iputs(\underline_str)
  315. X    iputs(\cookie_str)
  316. X    return
  317. X
  318. Xend
  319. X
  320. X
  321. X
  322. Xprocedure normal(mode)
  323. X
  324. X    static UN_emph_str, emph_cookie_str,
  325. X    UN_underline_str, underline_cookie_str,
  326. X    UN_bold_str, bold_cookie_str
  327. X
  328. X    initial {
  329. X
  330. X    # Find out code to turn off emphasize (reverse video) mode.
  331. X    if UN_emph_str := getval("se") then
  332. X        # Figure out how many backspaces we need to erase cookies.
  333. X        emph_cookie_str := repl(getval("le"|"bc") | "\b", getval("sg"))
  334. X
  335. X    # Finally, figure out how to turn off underline mode.
  336. X    if UN_underline_str := (UN_emph_str ~== getval("ue")) then
  337. X        underline_cookie_str := repl(getval("le"|"bc")|"\b", getval("ug"))
  338. X
  339. X    # Figure out how to turn off boldface mode.
  340. X    if UN_bold_str := 
  341. X        (UN_underline_str ~== (UN_emph_str ~== getval("me"))) then
  342. X        # Figure out how many backspaces we need to erase cookies.
  343. X        bold_cookie_str := repl(getval("le"|"bc") | "\b", getval("mg"))
  344. X
  345. X    }        
  346. X    
  347. X    iputs(\UN_emph_str) &
  348. X    iputs(\emph_cookie_str)
  349. X
  350. X    iputs(\UN_underline_str) &
  351. X    iputs(\underline_cookie_str)
  352. X
  353. X    iputs(\UN_bold_str) &
  354. X    iputs(\bold_cookie_str)
  355. X
  356. X    return
  357. X
  358. Xend
  359. X
  360. X
  361. X
  362. Xprocedure status_line(s,s2,p)
  363. X
  364. X    # Writes a status line on the terminal's third-to-last line
  365. X    # The only necessary argument is s.  S2 (optional) is used
  366. X    # for extra narrow screens.  In other words, by specifying
  367. X    # s2 you give status_line an alternate, shorter status string
  368. X    # to display, in case the terminal isn't wide enough to sup-
  369. X    # port s.  If p is nonnull, then the status line is either
  370. X    # centered (if equal to "c"), left justified ("l"), or right
  371. X    # justified ("r").
  372. X
  373. X    local width
  374. X
  375. X    /s := ""; /s2 := ""; /p := "c"
  376. X    width := getval("co")
  377. X    if *s > width then {
  378. X    (*s2 < width, s := s2) |
  379. X        er("status_line","Your terminal is too narrow.",4)
  380. X    }
  381. X
  382. X    case p of {
  383. X    "c"    : s := center(s,width)
  384. X    "l"    : s := left(s,width)
  385. X    "r"    : s := right(s,width)
  386. X    default: stop("status_line:  Unknown option "||string(p),4)
  387. X    }
  388. X
  389. X    iputs(igoto(getval("cm"), 1, getval("li")-2))
  390. X    emphasize(); writes(s)
  391. X    normal()
  392. X    return
  393. X
  394. Xend
  395. X
  396. X
  397. X
  398. Xprocedure message(s)
  399. X
  400. X    # Display prompt s on the second-to-last line of the screen.
  401. X    # I hate to use the last line, due to all the problems with
  402. X    # automatic scrolling.
  403. X
  404. X    /s := ""
  405. X    normal()
  406. X    iputs(igoto(getval("cm"), 1, getval("li")))
  407. X    iputs(getval("ce"))
  408. X    normal()
  409. X    iputs(igoto(getval("cm"), 1, getval("li")-1))
  410. X    iputs(getval("ce"))
  411. X    writes(s[1:getval("co")] | s)
  412. X    return
  413. X
  414. Xend
  415. X
  416. X
  417. X
  418. Xprocedure clear_underline()
  419. X
  420. X    # Horrible way of clearing the screen to all underline mode, but
  421. X    # the only apparent way we can do it "portably" using the termcap
  422. X    # capability database.
  423. X
  424. X    local i
  425. X
  426. X    underline()
  427. X    iputs(igoto(getval("cm"),1,1))
  428. X    if getval("am") then {
  429. X    underline()
  430. X        every 1 to (getval("li")-1) * getval("co") do
  431. X        writes(" ")
  432. X    }
  433. X    else {
  434. X    every i := 1 to getval("li")-1 do {
  435. X        iputs(igoto(getval("cm"), 1, i))
  436. X        underline()
  437. X        writes(repl(" ",getval("co")))
  438. X    }
  439. X    }
  440. X    iputs(igoto(getval("cm"),1,1))
  441. X
  442. Xend
  443. X
  444. X
  445. X
  446. Xprocedure clear_emphasize()
  447. X
  448. X    # Horrible way of clearing the screen to all reverse-video, but
  449. X    # the only apparent way we can do it "portably" using the termcap
  450. X    # capability database.
  451. X
  452. X    local i
  453. X
  454. X    emphasize()
  455. X    iputs(igoto(getval("cm"),1,1))
  456. X    if getval("am") then {
  457. X    emphasize()
  458. X        every 1 to (getval("li")-1) * getval("co") do
  459. X        writes(" ")
  460. X    }
  461. X    else {
  462. X    every i := 1 to getval("li")-1 do {
  463. X        iputs(igoto(getval("cm"), 1, i))
  464. X        emphasize()
  465. X        writes(repl(" ",getval("co")))
  466. X    }
  467. X    }
  468. X    iputs(igoto(getval("cm"),1,1))
  469. X
  470. Xend
  471. SHAR_EOF
  472. true || echo 'restore of iscreen.icn failed'
  473. rm -f _shar_wnt_.tmp
  474. fi
  475. # ============= qur2rtv.icn ==============
  476. if test -f 'qur2rtv.icn' -a X"$1" != X"-c"; then
  477.     echo 'x - skipping qur2rtv.icn (File already exists)'
  478.     rm -f _shar_wnt_.tmp
  479. else
  480. > _shar_wnt_.tmp
  481. echo 'x - extracting qur2rtv.icn (Text)'
  482. sed 's/^X//' << 'SHAR_EOF' > 'qur2rtv.icn' &&
  483. X############################################################################
  484. X#
  485. X#    Name:     qur2rtv.icn
  486. X#
  487. X#    Title:     qur2rtv  (Quran -> retrieve format converter)
  488. X#
  489. X#    Author:     Richard L. Goerwitz
  490. X#
  491. X#    Version: 1.2
  492. X#
  493. X############################################################################
  494. X#
  495. X#  Program for converting the internet-accessible scan of M. H.
  496. X#  Shakir's Quran translation into retrieve format.  Reads standard
  497. X#  input.  Writes reformatted text to standard output.  Assumes the
  498. X#  sections will come in order (1 before 2; 2 before 3, etc.), but
  499. X#  that they will all be directed into the same input stream.
  500. X#  Naturally, it does not matter whether they have been concatenated
  501. X#  into one, or remain split into several, files.
  502. X#
  503. X############################################################################
  504. X#
  505. X#  Links: none
  506. X#
  507. X############################################################################
  508. X
  509. X
  510. Xprocedure main()
  511. X
  512. X    local line, verse
  513. X    # in case this ever gets encapsulated
  514. X    static section, last_verse, text, skipped, extra_text, seenit
  515. X    initial {
  516. X    last_verse := 1000
  517. X    section := 0
  518. X    extra_text := ""
  519. X    skipped := 1
  520. X    }
  521. X
  522. X    # While you can read lines from stdin...
  523. X    while line := trim(read(),'\t \x0D\x1A')    # trim CR, tab, sp, ^Z
  524. X    do {
  525. X
  526. X    # ...scan them for text numbers, and output these in retrieve
  527. X    # format, along with corresponding text.
  528. X    line ? {
  529. X
  530. X        # Housekeeping.
  531. X        if pos(0) then {
  532. X        skipped := 1    # note that the last line was blank
  533. X        next        # skip past empty lines
  534. X        }
  535. X        tab(many('\t '))    # tab past whitespace (if present)
  536. X
  537. X        # Two cases where extra text has been tacked onto a file
  538. X        # and has to be stripped out.
  539. X        ="THE SPIDER" & {
  540. X        until read(&input) ? (tab(match("\x1A" | "with")), pos(0))
  541. X        next
  542. X        }
  543. X        if section = 65 & verse = 12 & /seenit & {
  544. X        ="In the Name of Allah, the Beneficent, the Merciful."
  545. X        }
  546. X        then {
  547. X        until read(&input) ? tab(match("\x1A" | "and she"))
  548. X        seenit := 1
  549. X        next
  550. X        }
  551. X        # More housekeeping (the text is rife with errors).
  552. X        (=". ", match("2"))
  553. X        ="/ "
  554. X
  555. X        # If the next line begins with a numerical reference, then
  556. X        # write out the text of the preceding text (if in fact
  557. X        # there *was* a preceding text block).  Finally, write out the
  558. X        # section/text reference (in retrieve format).
  559. X
  560. X        if \skipped | any('.?:', \text, -1) &
  561. X        verse := is_it_a_verse()
  562. X        then {
  563. X        write(\text)
  564. X        if -1 <= verse < 2 then {
  565. X            section +:= 1
  566. X#            # For debugging purposes.
  567. X#            write(&errout, "resetting; text = \n", \text)
  568. X#            write(&errout, "section now = ", section)
  569. X#            write(&errout, "last_verse = ", last_verse)
  570. X#            write(&errout, "verse = ", verse)
  571. X        }
  572. X        else if verse ~= (last_verse+1) then {
  573. X            if verse = (last_verse+2) then
  574. X            write(&errout, "LF missing, ",section,":",last_verse)
  575. X            else if not (verse := map(verse, "1", "7")= (last_verse+1))
  576. X            then if verse = 34 & last_verse = 35
  577. X            then verse := 36
  578. X            else if verse = 6 & last_verse = 3 & section = 47
  579. X            then {
  580. X            write(&errout,"extra text, ",section,":",last_verse)
  581. X            until trim(read(&input)) == ""
  582. X            next
  583. X            } else if section = 43 & verse = 29 & last_verse = 30
  584. X            then {
  585. X            find("disbelievers in it", !&input) |
  586. X                stop("parsing error; get help")
  587. X            next
  588. X            }
  589. X            else stop("error, ",section,":",last_verse,"\n",text)
  590. X        }
  591. X        last_verse := verse
  592. X        write("::", section, ":", verse)
  593. X        tab(many(' \t'))
  594. X        text := extra_text || " " || tab(0)
  595. X        extra_text := ""
  596. X        } else {
  597. X        # Dump the (rest of) the line onto text.
  598. X        if /skipped & (extra_text == "") then
  599. X            text ||:= " " || tab(0)
  600. X        else {
  601. X            # if we've had a blank line in this text block, but
  602. X            # no verse number, then concatenate it with any other
  603. X            # text we have after the last blank line
  604. X            extra_text ||:= " " || tab(0)
  605. X        }
  606. X        }
  607. X    }
  608. X    skipped := &null
  609. X    }
  610. X    # Flush the "text" buffer.
  611. X    \text ||:= " " || \extra_text
  612. X    write(\text)
  613. X
  614. X    exit(0)
  615. X    # or fail
  616. X
  617. Xend
  618. X
  619. X
  620. X#
  621. X# From strings.icn in the IPL (written by Ralph Griswold).
  622. X#
  623. Xprocedure REplace(s1,s2,s3)
  624. X
  625. X    local result, i
  626. X    result := ""
  627. X    i := *s2
  628. X
  629. X    s1 ? {
  630. X    while result ||:= tab(find(s2)) do {
  631. X        result ||:= s3
  632. X        move(i)
  633. X    }
  634. X    return result || tab(0)
  635. X    }
  636. X
  637. Xend
  638. X
  639. X
  640. Xprocedure is_it_a_verse()
  641. X
  642. X    local tmp
  643. X
  644. X    #
  645. X    # Can the first bit of text in &subject possible be construed as a
  646. X    # verse reference (with typos)?  Let's see.
  647. X    #
  648. X
  649. X    # I've seen "I 1." for 11.
  650. X    return (="I 1. ", 11) |
  651. X    # I've seen "I." or "l." for "1."
  652. X    (tab(any('lI')), =".", 1) |
  653. X    # I've even seen "S." for "5."
  654. X    (="S", =".", 5) |
  655. X    1(tab(many(&digits)), tab(any('.: '))) | {
  656. X    # If it's none of the above, then as long as it's over two chars,
  657. X    # try lots of mapping.  If I took away the restriction that the
  658. X    # sequence be less than two chars, I'd get lines which begin with
  659. X    # the word "I" (as in "I am").  No go.
  660. X        (tab(find(" ")+1) || tab(upto(&ucase))) \ 1 ? {
  661. X        *(tmp := 1(tab(many(&digits++'IOlS')), tab(any(':., ')))) > 1 &
  662. X            integer(map(tmp, "IOlS", "1015"))
  663. X        }
  664. X    }
  665. X    
  666. Xend
  667. SHAR_EOF
  668. true || echo 'restore of qur2rtv.icn failed'
  669. rm -f _shar_wnt_.tmp
  670. fi
  671. # ============= makeind.icn ==============
  672. if test -f 'makeind.icn' -a X"$1" != X"-c"; then
  673.     echo 'x - skipping makeind.icn (File already exists)'
  674.     rm -f _shar_wnt_.tmp
  675. else
  676. > _shar_wnt_.tmp
  677. echo 'x - extracting makeind.icn (Text)'
  678. sed 's/^X//' << 'SHAR_EOF' > 'makeind.icn' &&
  679. X############################################################################
  680. X#
  681. X#    Name:     makeind.icn
  682. X#
  683. X#    Title:     makeind.icn
  684. X#
  685. X#    Author:     Richard L. Goerwitz
  686. X#
  687. X#    Version: 2.4
  688. X#
  689. X############################################################################
  690. X#
  691. X#  This file, makeind.icn, compiles into an indexing program which
  692. X#  creates a series of files offering the user rapid access to
  693. X#  individual elements (usually words) within a text file.  Access is
  694. X#  gained through a set of basic retrieval utilities contained in the
  695. X#  file retrieve.icn, bmp2text.icn, retrops.icn, and others included
  696. X#  with this package.  In order to be indexable, files must interleave
  697. X#  string coded bitfield-style designators with text in the following
  698. X#  manner:
  699. X#
  700. X#  ::001:001:001
  701. X#  This is text.
  702. X#  ::001:001:002
  703. X#  This is more text.
  704. X#
  705. X#  The lines beginning with :: (a double colon) mark bitfield-style
  706. X#  location-designators.  Location designators are strings with digit
  707. X#  fields of fixed number and length separated either by nothing (as
  708. X#  in, say 001001002), or better yet by non-digits (e.g. 001:001:002).
  709. X#  NOTE WELL: The bitmaps must come in ascending order.  For example,
  710. X#  if we assume three-field bitmaps, 002:001:014 would come before
  711. X#  003:001:013.  If your file is not sorted properly, depending on
  712. X#  the structure of the file, retrieve() may 1) abort, 2) retrieve the
  713. X#  wrong text, or 3) work perfectly fine.  Unless you're absolutely
  714. X#  sure of what you're doing, write a quick sort routine and put the
  715. X#  file in order before invoking makind on it.
  716. X#
  717. X#  usage:  makeind -f filename -m int -n int [-l int] [-s]
  718. X#
  719. X#  When calling makeind, you must specify the filename to be indexed
  720. X#  (-f filename), the maximum field value (-m max-value; e.g. if
  721. X#  fields can go from 0 to 255, then -m 255 would be used), and the
  722. X#  number of fields (-n field-number).  The -s switch directs makeind
  723. X#  to create a case-sensitive index.  The default is case-insensitive.
  724. X#  -l [int] tells makeind to create a .LIM file, which is only needed
  725. X#  if you want to retrieve text by location marker, and not just via
  726. X#  the index (for this, you'll need something to translate human-
  727. X#  readable references into retrieve's native format).
  728. X#
  729. X#  BUGS: This indexing routine is going to eat up a _tremendous_
  730. X#  amount of memory when used on large files, since every token in the
  731. X#  input file gets its own entry in wordtbl, and each entry gets a set
  732. X#  as its corresponding key.  If you don't have the memory, then you
  733. X#  could use strings instead of sets (the insert routines will be just
  734. X#  a tiny bit more complicated).  Intermediate files could also be
  735. X#  used.  Drop me a line if you want help.  Otherwise, make sure you
  736. X#  have at *least* two megabytes core for every megabyte of text in
  737. X#  the file you wish to index (or else a very, very good virtual
  738. X#  memory management system).
  739. X#
  740. X#  NOTE: The -S [field-sep] option is currently disabled because using
  741. X#  it slows things down drastically.  If you want to be able to
  742. X#  specify what separator to use when breaking files down into
  743. X#  individual words, consult ./gettokens.icn.
  744. X#
  745. X#  NOTE ALSO:  Makeind compresses the input file somewhat, and in the
  746. X#  process, backs the old file up.  If you need the old file back again,
  747. X#  look for a file with the extension .BAK (the original name may be
  748. X#  slightly permutated).  Makeind will not overwrite this .BAK file, so
  749. X#  please either erase or move it when you are finished.  If you try to
  750. X#  remake without doing this, makeind (ever cautious) will abort.
  751. X#
  752. X############################################################################
  753. X#
  754. X#  Links: options.icn, codeobj.icn, ./indexutl.icn ./gettokens.icn
  755. X#
  756. X#  See also: retrieve.icn, bmp2text.icn, expandrf.icn
  757. X#
  758. X############################################################################
  759. X
  760. X# IPL files to be linked in at compile time.
  761. Xlink options, codeobj
  762. X
  763. X# Global variable (for OS-dependencies).
  764. X# global IS            # declared in indexutl.icn
  765. X
  766. X# Is is a record containing vital information on an indexed file, such
  767. X# as the field separator, the string-length of fields, etc.  I've re-
  768. X# moved the record declaration from this file, and placed it in index-
  769. X# utl.icn.
  770. X# record is(FS, s_len, len, no, is_case_sensitive, r_field, hufftree)
  771. X
  772. X#
  773. X# Main procedure.
  774. X#
  775. Xprocedure main(a)
  776. X
  777. X    local usage, opt_table, fname, rollover_field, index_fname,
  778. X    bitmap_fname, upto_field, ofs_filename, bitmap_offset_table,
  779. X    out_IS, limits_fname, char_tbl, backup_filename, unt_filename,
  780. X    huffman_table, index_table
  781. X
  782. X    # global IS            # IS contains stats for file being indexed
  783. X
  784. X    #
  785. X    # Initialize global OS-related parameters, such as the directory
  786. X    # separator (_slash) and the maximum permissible filename length
  787. X    # minus four (to make room for extensions makeind tacks on).
  788. X    #
  789. X    initialize_os_params()
  790. X
  791. X    #
  792. X    # Read in and check command argument list.  Insert FS and no
  793. X    # parameters into (global) record IS.  Calculate s_len, len, and
  794. X    # bitmap_length parameters as well.  Returns table of options
  795. X    # (keys are option letters).
  796. X    #
  797. X    usage:= "usage: makeind -f filename -m int -n int [-l int] [-s]"
  798. X    opt_table := initialize_IS(a)
  799. X    fname := \opt_table["f"]                | stop(usage)
  800. X    rollover_field := opt_table["l"]            # (optional)
  801. X
  802. X    #
  803. X    # Begin the process of tokenizing, recording token locations, and
  804. X    # of storing this information in two separate files.
  805. X    #
  806. X    # Read input file, making a table of words and their locations.
  807. X    # While we're at it, build a table of character frequencies for
  808. X    # text (not bitmaps) within the file (char_tbl), and then create
  809. X    # a huffman tree and table out of this character frequency list.
  810. X    #
  811. X    index_table := table(); char_tbl := table()
  812. X    create_index(fname, index_table, char_tbl)
  813. X    # Use the char_tbl to generate a Huffman tree & a code table.
  814. X    IS.hufftree := heap_2_huffman_tree(heap_init(char_tbl))
  815. X    huffman_table := hash_huffcodes(IS.hufftree)
  816. X
  817. X    #
  818. X    # Write keys to one file, with pointers into another file
  819. X    # containing the bitmaps for each key.  Use the index_table
  820. X    # created just above (contains words & their locations).
  821. X    #
  822. X    index_fname  := dir_name(fname)||create_fname(fname, "IND")
  823. X    bitmap_fname := dir_name(fname)||create_fname(fname, "BMP")
  824. X    write_tokens_and_offsets(index_fname, bitmap_fname, index_table)
  825. X
  826. X    #
  827. X    # Backup the original text file.  Prepare to re-use the original
  828. X    # filename to store compressed text.
  829. X    #
  830. X    backup_filename := create_fname(fname,"BAK")
  831. X    backup_filename ?:= (tab(many('x')), tab(0))
  832. X    backup_filename := dir_name(fname)||backup_filename
  833. X    if close(open(backup_filename)) then
  834. X    abort("makeind", "backup filename collision; aborting", 6)
  835. X    rename(fname, backup_filename) |
  836. X    abort("makeind", "cannot back up file to disk; aborting", 7)
  837. X    #
  838. X    # Open backup file (i.e. the original text file), then run through
  839. X    # it, writing the bitmaps directly to a .UNT file (using the
  840. X    # original, human-readable form).  Compress and write the text
  841. X    # associated with those bitmaps to a file having the same name as
  842. X    # the original text file (not the backup name), tacking onto the
  843. X    # bitmaps in the .UNT file their offset within the main text file.
  844. X    # Write the offsets of the major divisions in the .UNT file to the
  845. X    # .OFS file.
  846. X    #
  847. X    upto_field := 1 < (IS.no * 2) / 3 | 1
  848. X    ofs_filename := dir_name(fname)||create_fname(fname, "OFS")
  849. X    unt_filename := dir_name(fname)||create_fname(fname, "UNT")
  850. X    bitmap_offset_table := 
  851. X    store_bitmaps_and_offsets(fname, unt_filename, backup_filename,
  852. X                  upto_field, huffman_table)
  853. X    # Write .OFS file.  The .UNT and main text files have already been
  854. X    # written out by store_bitmaps_and_offsets().  The original main file
  855. X    # name now holds compressed text.
  856. X    write_bitmaps_and_offsets(ofs_filename, bitmap_offset_table, upto_field)
  857. X
  858. X    #
  859. X    # Re-open UNT file.  Read it, find the pre-rollover bitmaps, and
  860. X    # store them in the .LIM file.  Obviously this procedure could be
  861. X    # stuffed into another one above (e.g. store_bitmaps_and_offsets()).
  862. X    #
  863. X    if \rollover_field then {
  864. X    #
  865. X    # Let's say we are using the Bible as our text, and we want to
  866. X    # create all the bitmaps for Genesis 1:9-2:10.  We need to know
  867. X    # what verse chapter 1 goes up to.  By supplying makeind
  868. X    # with a "-l 3" argument, you are telling it to store this in-
  869. X    # formation for later use by expandrf().
  870. X    #
  871. X    limits_fname := dir_name(fname)||create_fname(fname, "LIM")
  872. X    write_limits(limits_fname, unt_filename, rollover_field)
  873. X    IS.r_field := rollover_field
  874. X    }
  875. X
  876. X    #
  877. X    # Write IS record to the .IS file.
  878. X    #
  879. X    out_IS := open(dir_name(fname)||create_fname(fname, "IS"), "w") |
  880. X    abort("makeind","can't open .IS file",2)
  881. X    writes(out_IS, encode(IS))
  882. X    close(out_IS)
  883. X
  884. X    # All is well.  Exit with zero status.
  885. X    exit(0)
  886. X
  887. Xend
  888. X
  889. X
  890. X#
  891. X# initialize_IS
  892. X#
  893. X# Sets up main parameters for the current index file, such as the
  894. X# field separator to be used in tokenizing the file, the string and
  895. X# bit lengths of bitmap fields, the number of fields, and the size of
  896. X# the actual bitmaps (in bytes) as written to disk (comes out to the
  897. X# smallest multiple of eight greater than the field length times the
  898. X# field number.  The marker length has to be set in the main
  899. X# procedure, so initialize_IS leaves it null for now.
  900. X#
  901. Xprocedure initialize_IS(a)
  902. X
  903. X    local usage, fname, opt_table
  904. X    # global IS
  905. X
  906. X    usage:="usage: makeind -f filename -m int -n int [-l int] [-s]"
  907. X
  908. X    IS := is()            # set up some IS fields
  909. X    opt_table := options(a, "f:m:n+sS:l+")
  910. X    3 <= *opt_table <= 6            | stop(usage)
  911. X    IS.no := \opt_table["n"]            | stop(usage)
  912. X    IS.FS := \opt_table["S"] | "['.]?[^-0-9A-Za-z']+'?"
  913. X    IS.is_case_sensitive := opt_table["s"]      # normally is &null
  914. X
  915. X    #
  916. X    # Calculate string representation length for fields, as well as
  917. X    # the number of bits required for their integer representation.
  918. X    # I.e. if the opt_table["m"] value is 99, this will take two chars to
  919. X    # represent as a string ("99"), but 7 binary "digits" to represent
  920. X    # internally as a base-two integer.
  921. X    #
  922. X    IS.s_len := *string(opt_table["m"])
  923. X    IS.len := *exbase10(opt_table["m"], 2)
  924. X
  925. X    return opt_table
  926. X
  927. Xend
  928. X
  929. X
  930. X#
  931. X# create_index
  932. X#
  933. X# (A better name would be fill_out_index_and_char_frequency_table.)
  934. X#
  935. X# Places tokens in fname (the full text file) in a table (supplied as
  936. X# arg 2), with the set of each token's locations recorded as values
  937. X# for those tokens.  IS.FS is not used.  IS.s_len is the location
  938. X# marker string-representation field length.  IS.len is the number of
  939. X# binary digits needed for an integer representation of a given field.
  940. X# IS.no is the number of fields.  While creating a table for tokens in
  941. X# fname, create_index ALSO fills out a table of character frequencies
  942. X# in the entries (i.e. it doesn't count frequencies of chars used in
  943. X# the bitmaps).
  944. X# 
  945. Xprocedure create_index(fname, wordtbl, char_tbl)
  946. X
  947. X    local intext, line, bitmap, token, value
  948. X
  949. X    intext := open(fname) |
  950. X    abort("create_index","can't open index file, "||fname, 9)
  951. X    # Dummy key to hold all bitmaps in the text.
  952. X    insert(wordtbl, "", set())
  953. X
  954. X    # Seek past any garbage.  Take first :: initial line.
  955. X    match("::", line := !intext)
  956. X    repeat {
  957. X    line ? {
  958. X
  959. X        if ="::" then {
  960. X        bitmap := digits_2_bitmap(tab(0))
  961. X        # Insert every bitmap into the dummy entry for "".
  962. X        insert(wordtbl[""], bitmap)
  963. X        line := read(intext)
  964. X        } else {
  965. X
  966. X        value := line || "\n"
  967. X        # Concatenate every line in this entry into a single value.
  968. X        while line := read(intext) do {
  969. X            line ? {
  970. X            match("::") & break
  971. X            value ||:= line || "\n"
  972. X            }
  973. X        }
  974. X
  975. X        value := trim(value, '\n')
  976. X        # Maintain character frequency table (arg 3 above).
  977. X        count_chars("" ~== value, char_tbl)
  978. X        # Build a table of tokens. NB gettokens() resides
  979. X        # in a separate file.  The table is arg 2.
  980. X        value ? {
  981. X            every token := gettokens(IS.is_case_sensitive) do {
  982. X            /wordtbl[token] := set()
  983. X            insert(wordtbl[token], \bitmap)
  984. X            }
  985. X        }
  986. X
  987. X        # If :: doesn't appear first on line, we're at EOF.  If
  988. X        # line == &subject, then to prevent an infinite loop, we
  989. X        # break.
  990. X        line == &subject & break
  991. X        match("::", line) | break
  992. X        }
  993. X    }
  994. X    }
  995. X
  996. X    \line | abort("create_index", "empty input file, "||fname, 8)
  997. X    close(intext)
  998. X    return "tokenized " || *wordtbl || " words; filled out char_tbl"
  999. X
  1000. Xend
  1001. X
  1002. X
  1003. X#
  1004. X# write_tokens_and_offsets
  1005. X#
  1006. X# Writes to one file (the .IND file) a list of all tokens collected
  1007. X# from the input file, one to a line, followed by a tab, and then a
  1008. X# byte offset into another file (the .BMP file) where the bitmaps for
  1009. X# that token are kept.
  1010. X#
  1011. X#     token tab offset
  1012. X#
  1013. X# A seek to "offset" in the .BMP file will put you at the start of a
  1014. X# block of bitmaps.
  1015. X#
  1016. Xprocedure write_tokens_and_offsets(index_fname, bitmap_fname, t)
  1017. X
  1018. X    local outtokens, outbitmaps, index_lst, i, bitmap_length,
  1019. X    how_many_bitmaps, bits_needed, inverse_signal, inverse_set
  1020. X
  1021. X    outtokens := open(index_fname, "w") |
  1022. X    abort("write_tokens_and_offsets","can't open "||index_fname,6)
  1023. X    outbitmaps := open(bitmap_fname, "w") |
  1024. X    abort("write_tokens_and_offsets","can't open "||bitmap_fname,5)
  1025. X    # Calculate the length of bitmaps (must be the smallest multiple of
  1026. X    # 8 >= (IS.len * IS.no)).
  1027. X    bitmap_length := ((IS.len * IS.no) <= seq(0,8))
  1028. X    index_lst := sort(t, 3)
  1029. X    bits_needed := 24        # bytes needed to hold no of bitmaps for keys
  1030. X    inverse_signal := 8388608    # 24th bit, which signals inverse storage
  1031. X
  1032. X    every i := 1 to *index_lst-1 by 2 do {
  1033. X
  1034. X    # Write token to index file with the offset of that token's
  1035. X    # bitmaps in the bitmap file.
  1036. X    write(outtokens, index_lst[i], "\t", where(outbitmaps))
  1037. X
  1038. X    # Now write the bitmaps for the above token to the bitmap file.
  1039. X    # First write out the number of bitmaps in this block.  4 bytes
  1040. X    # are allotted to hold this count (23 bits).  If the number of
  1041. X    # bitmaps for the current token exceeds 3/5 of the total number
  1042. X    # of bitmaps for the entire file, then add bits_needed-1 to the
  1043. X    # number.  That is, set the highest bit to 1.
  1044. X    how_many_bitmaps := *index_lst[i+1]
  1045. X    if how_many_bitmaps > (inverse_signal-1) then {        # just in case
  1046. X        abort("write_tokens_and_offsets",
  1047. X          "too many bitmaps for"||index_lst[i], bits_needed)
  1048. X    }
  1049. X    # "" is a dummy key containing all the bitmaps in the text.
  1050. X    # If the number of bitmaps for any key other than "" exceeds
  1051. X    # 3/5 that of "", then store those bitmaps where the key does
  1052. X    # NOT occur, and set the inverse_signal bit...
  1053. X    if index_lst[i] ~== "" &
  1054. X        how_many_bitmaps >= integer(*t[""] * 0.60)
  1055. X    then {
  1056. X        inverse_set := (index_lst[2] -- index_lst[i+1])
  1057. SHAR_EOF
  1058. true || echo 'restore of makeind.icn failed'
  1059. fi
  1060. echo 'End of  part 6'
  1061. echo 'File makeind.icn is continued in part 7'
  1062. echo 7 > _shar_seq_.tmp
  1063. exit 0
  1064.  
  1065. exit 0 # Just in case...
  1066. -- 
  1067. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1068. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1069. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1070. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1071.