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

  1. Newsgroups: comp.sources.misc
  2. From: goer@midway.uchicago.edu (Richard L. Goerwitz)
  3. Subject:  v23i068:  quranref - Holy Qur'an word and passage based retrievals, Part02/08
  4. Message-ID: <1991Oct19.022225.12778@sparky.imd.sterling.com>
  5. X-Md4-Signature: 6092c0a6f024eb5140db5e6976730af1
  6. Date: Sat, 19 Oct 1991 02:22:25 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 68
  11. Archive-name: quranref/part02
  12. Environment: Icon
  13.  
  14. ---- Cut Here and feed the following to sh ----
  15. #!/bin/sh
  16. # this is quranref.02 (part 2 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file listutil.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" != 2; 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 listutil.icn'
  34. else
  35. echo 'x - continuing file listutil.icn'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'listutil.icn' &&
  37. X    # then clear lines until we reach it...
  38. X    if i-1 ~= lines+1 then {
  39. X        every j := i to lines do {
  40. X        iputs(igoto(getval("cm"), 1, j))
  41. X        normal(); iputs(getval("ce"))
  42. X        }
  43. X    }
  44. X    # Display message on status line.
  45. X    status_line("-- " || \msg || " --" | "", "", "c")
  46. X
  47. X    # If we're to the end of the screen, and there's still more to
  48. X    # display, then...
  49. X    if *l > lines-1 & (offset+i) ~= (*l+1) then {
  50. X        rsp := snarf_input("Press !/b/c/m/v (q = quit viewing):  ")
  51. X        case map(rsp) of {
  52. X        ""     : offset := (*l > (offset+1))
  53. X        "!"    : push_shell()
  54. X        "b"    : offset := (0 < offset-lines+1) | 0
  55. X        "c"    : next            
  56. X        "m"    : (offset := (*l > (offset+i-1)))
  57. X        "q"    : break
  58. X        "v"    : {
  59. X            rsp2 := snarf_input("View which list:  ")
  60. X            rsp2 == "q" & next
  61. X            rsp2 == ""  & rsp2 := \last_viewed
  62. X            if last_viewed := integer(rsp2) then {
  63. X            if 0 < last_viewed <= *l
  64. X            then return last_viewed
  65. X            else err_message("Out of range.")
  66. X            }
  67. X            else err_message("Invalid list number.")
  68. X        }
  69. X        default : {
  70. X            err_message("Command invalid in this context.")
  71. X        }
  72. X        }
  73. X    }
  74. X    # ...otherwise, we've displayed everything.
  75. X    else {
  76. X        prompt := "c/v (q to go to previous menu):  "
  77. X        if *l <= lines
  78. X        then rsp:= snarf_input("Press !/" || prompt) | next
  79. X        else rsp :=    snarf_input("Press !/b/" || prompt) | next
  80. X        case map(rsp) of {
  81. X        "!"    : push_shell()
  82. X        "b"    : offset := (0 < offset-lines+1) | 0
  83. X        "c"|"" : next
  84. X        "m"    : next    # no more to display; just stay were we are
  85. X        "q"    : break
  86. X        "v"    : {
  87. X            rsp2 := snarf_input("View which list:  ")
  88. X            rsp2 == "q" & next
  89. X            rsp2 == ""  & rsp2 := \last_viewed
  90. X            if last_viewed := integer(rsp2) then {
  91. X            if 0 < last_viewed <= *l
  92. X            then return last_viewed
  93. X            else err_message("Out of range.")
  94. X            }
  95. X            else err_message("Invalid list number.")
  96. X        }
  97. X        default : {
  98. X            err_message("Command invalid in this context.")
  99. X        }
  100. X        }
  101. X    }
  102. X    }
  103. X    return
  104. X
  105. Xend
  106. X
  107. X
  108. X
  109. Xprocedure search_list(lst_rec, direction, lines)
  110. X
  111. X    local resp, subscript, ltrs, last_ltrs
  112. X    # global _subscripts
  113. X
  114. X    direction == ("?"|"/") | fail
  115. X
  116. X    if pos(0) then {
  117. X    resp := snarf_input("Enter pattern (q to abort):  ")
  118. X    resp == (""|"q") & fail
  119. X    }
  120. X    else resp := tab(0)
  121. X
  122. X    if direction == "/"
  123. X    then _subscripts := create { lst_rec.pos+2 to *lst_rec.l }
  124. X    else _subscripts := create { lst_rec.pos to 1 by -1 }
  125. X
  126. X    message("Searching...")
  127. X
  128. X#  A probably futile attempt at optimization....
  129. X#    last_ltrs := {
  130. X#    if resp ? (tab(any(&digits)) | &null, tab(many(&letters)), pos(0))
  131. X#    then "" else &null
  132. X#    }
  133. X
  134. X    while subscript := @_subscripts do {
  135. X#  See above on futile attempts....
  136. X#    if \last_ltrs then {
  137. X#        convertb(lst_rec.l[subscript],kjv_filename) ?
  138. X#        ltrs := (tab(any(&digits)) | "") || tab(many(&letters))
  139. X#        (last_ltrs ~==:= ltrs) | next
  140. X#    }
  141. X    if findre(resp, convertb(lst_rec.l[subscript],kjv_filename)) then {
  142. X        message("Done.")
  143. X        return subscript-1
  144. X    }
  145. X    }
  146. X    err_message("Pattern not found.")
  147. X    return lst_rec.pos
  148. X
  149. Xend
  150. SHAR_EOF
  151. echo 'File listutil.icn is complete' &&
  152. true || echo 'restore of listutil.icn failed'
  153. rm -f _shar_wnt_.tmp
  154. fi
  155. # ============= passutil.icn ==============
  156. if test -f 'passutil.icn' -a X"$1" != X"-c"; then
  157.     echo 'x - skipping passutil.icn (File already exists)'
  158.     rm -f _shar_wnt_.tmp
  159. else
  160. > _shar_wnt_.tmp
  161. echo 'x - extracting passutil.icn (Text)'
  162. sed 's/^X//' << 'SHAR_EOF' > 'passutil.icn' &&
  163. X############################################################################
  164. X#
  165. X#    Name:     1.20
  166. X#
  167. X#    Title:     utilities for displaying passages
  168. X#
  169. X#    Author:     Richard L. Goerwitz
  170. X#
  171. X#    Version: passutil.icn
  172. X#
  173. X############################################################################
  174. X#
  175. X#  Contains:
  176. X#
  177. X#      display_passage(ref), which displays ref, but fails if ref
  178. X#          either can't be converted to a bitmap or else can, but
  179. X#          doesn't correspond to any text in the main file
  180. X#
  181. X#      listpassage(l, msg, width), which displays the lines contained
  182. X#          in list l, truncating them to width, and displaying msg
  183. X#          both near the top of the screen and on the status line
  184. X#
  185. X#      writepassage(l, msg, switch), which writes list l to a file
  186. X#          (the name of which it prompts the user to enter); if switch
  187. X#          is nonnull, then it appends l to the file the user enters,
  188. X#          rather then overwriting it
  189. X#
  190. X#      get_{next,prev}_passage(), which generates the bitmap for the
  191. X#          next/previous reference in the KJV file
  192. X#
  193. X#      push_shell(), which suspends bibleref, and starts up either
  194. X#          /bin/sh, or the program named in the SHELL environment
  195. X#          variable.
  196. X#
  197. X############################################################################
  198. X#
  199. X#  Links: ./rewrap.icn
  200. X#
  201. X#  See also: ./bibleref.icn
  202. X#
  203. X############################################################################
  204. X
  205. X
  206. Xprocedure display_passage(passage_ref)
  207. X
  208. X    local msg, d_list, bitmap, text
  209. X    static width
  210. X    # global kjv_filename
  211. X    initial {
  212. X    # decide how long to make lines.  The display procedures
  213. X    # listpassage leaves a margin on the left (8 spaces).  On
  214. X    # a typical display, it looks nice to leave about nine
  215. X    # spaces on the other side.  This leaves getval("co")-17
  216. X    # spaces left for text in between.  The space left for
  217. X    # text here is stored in the static variable "width."
  218. X    width := (18 < getval("co")-17) |
  219. X        quit("display_passage","your terminal is too narrow",98)
  220. X    }
  221. X
  222. X    # Try to convert passage_ref to a retrieve-format bitmap.
  223. X    if type(passage_ref) == "string" then {
  224. X    *passage_ref > 0 | fail
  225. X    bitmap := ref_2_bitmap(passage_ref, kjv_filename) | fail
  226. X    }
  227. X    # If the passage_ref is not a string, the it's probably already
  228. X    # been converted; try to use it as-is.
  229. X    else bitmap := passage_ref
  230. X
  231. X    repeat {
  232. X
  233. X    message("Locating text in main file...")
  234. X        # Now check to see if the passage is present in the indexed text.
  235. X    text := bitmap_2_text(bitmap, kjv_filename) | {
  236. X        err_message("No such passage in " || kjv_filename || ".")
  237. X        fail
  238. X    }
  239. X        # Rewrap passage to width characters per line; put them into a list.
  240. X    d_list := []
  241. X    every put(d_list, rewrap(text, width-1))
  242. X    put(d_list, rewrap(&null, width-1))
  243. X
  244. X        # Get the name of the current passage, using standard abbrevs.
  245. X    msg := convertb(bitmap, kjv_filename)
  246. X
  247. X        # Display passage.
  248. X    bitmap := listpassage(bitmap, d_list, msg, width) | fail
  249. X    # If bitmap ends up null, then return.
  250. X    if /bitmap then return
  251. X
  252. X    }
  253. X
  254. Xend
  255. X
  256. X
  257. X
  258. Xprocedure listpassage(bitmap, l, msg, width)
  259. X
  260. X    local offset, ss, done, i, j, n, rsp, result, prompt
  261. X    static lines, top_margin
  262. X    initial {
  263. X    (lines := getval("li")-4) > 6 |
  264. X        quit("listpassage", "your terminal isn't tall enough", 96)
  265. X    top_margin := 3
  266. X    }
  267. X
  268. X    # "l" is a list of lines to print
  269. X    # "msg" is the message to put on the status line
  270. X    # "width" gives the length to which lines in l are truncated
  271. X
  272. X    offset := 0
  273. X    repeat {
  274. X
  275. X    # Set up top margin.
  276. X    every j := 1 to top_margin do {
  277. X        iputs(igoto(getval("cm"), 1, j))
  278. X        if j = 2 then {
  279. X        writes(repl(" ",3))
  280. X        underline()
  281. X        writes(msg)
  282. X        }
  283. X        normal(); iputs(getval("ce"))
  284. X    }
  285. X
  286. X    i := 0
  287. X    while *l >= (ss := offset + (lines > (i +:= 1))) do {
  288. X        iputs(igoto(getval("cm"), 1, i+top_margin))
  289. X        normal(); iputs(getval("ce"))
  290. X        writes(repl(" ", 8), l[ss][1:\width|0])
  291. X    }
  292. X
  293. X    # If we haven't reached the end of the displayable screen,
  294. X    # then clear lines until we reach it...
  295. X    if i-1 ~= lines then {
  296. X        every j := (i+top_margin) to lines+1 do {
  297. X        iputs(igoto(getval("cm"), 1, j))
  298. X        normal(); iputs(getval("ce"))
  299. X        }
  300. X    }
  301. X    status_line("** " || \msg || " **" | "", "", "c")
  302. X
  303. X    # If there's more to do, but we're at the end of the display,
  304. X    # then...
  305. X    if *l > lines-1 & (offset+i) ~= (*l+1) then {
  306. X        rsp := snarf_input("Enter passage or !/a/b/c/m/w/+/- _
  307. X        (q to quit viewing):  ")
  308. X        if result := display_passage(rsp) then {
  309. X        return result
  310. X        } else {
  311. X        case map(rsp) of {
  312. X            ""     : offset := (*l > (offset+1))
  313. X            "!"    : push_shell()
  314. X            "a"    : write_passage(l, msg, "append")
  315. X            "b"    : offset := (0 < offset-lines+1) | 0
  316. X            "c"    : next
  317. X            "m"    : offset := (*l > (offset+i-1))
  318. X            "+"    : return get_next_bitmap(bitmap)
  319. X            "-"    : return get_prev_bitmap(bitmap)
  320. X            "q"    : return
  321. X            "w"    : write_passage(l, msg)
  322. X            default : err_message("Command invalid in this context.")
  323. X        }
  324. X        }
  325. X    }
  326. X    # ...otherwise, we've displayed everything.
  327. X    else {
  328. X        prompt := "c/w/+/- (q to go to previous menu):  "
  329. X        if *l <= lines
  330. X        then rsp:= snarf_input("Enter passage or !/a/" || prompt) | next
  331. X        else rsp :=    snarf_input("Enter passage or !/a/b/" || prompt) | next
  332. X        if result := display_passage(rsp) then {
  333. X        return result
  334. X        } else {
  335. X        case map(rsp) of {
  336. X            "!"    : push_shell()
  337. X            "a"    : write_passage(l, msg, "append")
  338. X            "b"    : offset := (0 < offset-lines+1) | 0
  339. X            "c"|"" : next
  340. X            "m"    : next
  341. X            "+"    : return get_next_bitmap(bitmap)
  342. X            "-"    : return get_prev_bitmap(bitmap)
  343. X            "q"    : return
  344. X            "w"    : write_passage(l, msg)
  345. X            default : err_message("Command invalid in this context.")
  346. X        }
  347. X        }
  348. X    }
  349. X    }
  350. X
  351. Xend
  352. X
  353. X
  354. X
  355. Xprocedure write_passage(passage_list, msg, switch)
  356. X
  357. X    local fname, outtext, firstchar
  358. X
  359. X    # Get straight whether we are appending or clobbering.
  360. X    (/switch := "w") | (switch := "a")
  361. X
  362. X    until \outtext do {
  363. X    fname := snarf_input("Enter filename (! for shell; q to quit):  ")
  364. X    fname ? {
  365. X        firstchar := move(1) | ""
  366. X        case firstchar of {
  367. X        ""   : fail
  368. X        "!"  : push_shell() & initialize_screen()
  369. X        "q"  : pos(0) & fail
  370. X        default : {
  371. X            outtext := open(fname, switch) | {
  372. X            case switch of {
  373. X                "a" : err_message("Can't append to "|| fname||".")
  374. X                "w" : err_message("Cannot write to "|| fname||".")
  375. X                default : quit("write_passage","internal error",80)
  376. X            }
  377. X            }
  378. X        }
  379. X        }
  380. X    }
  381. X    }
  382. X    message("Writing.")
  383. X    write(outtext, "::", msg)
  384. X    every write(outtext,!passage_list)
  385. X    close(outtext)
  386. X    message("Done.")
  387. X    return
  388. X
  389. Xend
  390. X
  391. X
  392. X
  393. Xprocedure get_next_bitmap(lastone)
  394. X
  395. X    local next_bitmap
  396. X    initial message("Reading limits file...")
  397. X
  398. X    next_bitmap := NextBitmap(lastone, kjv_filename) | {
  399. X    err_message(convertb(lastone, kjv_filename) || " has no successor.")
  400. X    return lastone
  401. X    }
  402. X    return next_bitmap
  403. X
  404. Xend
  405. X
  406. X
  407. X
  408. Xprocedure get_prev_bitmap(lastone)
  409. X
  410. X    local prev_bitmap
  411. X    initial message("Reading limits file...")
  412. X
  413. X    prev_bitmap := PrevBitmap(lastone, kjv_filename) | {
  414. X    err_message(convertb(lastone, kjv_filename) || " has no predecessor.")
  415. X    return lastone
  416. X    }
  417. X    return prev_bitmap
  418. X
  419. Xend
  420. X
  421. X
  422. X
  423. Xprocedure push_shell()
  424. X
  425. X    local status
  426. X    static shell
  427. X    initial shell := getenv("SHELL") | "/bin/sh"
  428. X
  429. X    tab(match("!"))
  430. X    clear()
  431. X    if pos(0)
  432. X    then status := system(shell)
  433. X    else {
  434. X    status := system(shell || " -c '" || tab(0) || "'")
  435. X    write("\n\n")
  436. X    message("Please press return to re-enter Bibleref.")
  437. X    read(&input)
  438. X    }
  439. X    clear()
  440. X
  441. X    return status
  442. X
  443. Xend
  444. SHAR_EOF
  445. true || echo 'restore of passutil.icn failed'
  446. rm -f _shar_wnt_.tmp
  447. fi
  448. # ============= readfile.icn ==============
  449. if test -f 'readfile.icn' -a X"$1" != X"-c"; then
  450.     echo 'x - skipping readfile.icn (File already exists)'
  451.     rm -f _shar_wnt_.tmp
  452. else
  453. > _shar_wnt_.tmp
  454. echo 'x - extracting readfile.icn (Text)'
  455. sed 's/^X//' << 'SHAR_EOF' > 'readfile.icn' &&
  456. X############################################################################
  457. X#
  458. X#    Name:     readfile.icn
  459. X#
  460. X#    Title:     read Bibleref files
  461. X#
  462. X#    Author:     Richard L. Goerwitz
  463. X#
  464. X#    Version: 1.3
  465. X#
  466. X############################################################################
  467. X#
  468. X#  Contains readfile(), which reads a file from disk into memory.
  469. X#  Detects automatically whether the file contains passages or only
  470. X#  passage references.  Converts both into Bibleref-format bitmap
  471. X#  lists.  Files may be in one of two formats: 1) ::key + text format
  472. X#  (the format used when you write a passage to disk from within
  473. X#  Bibleref), and 2) a list of references:
  474. X#
  475. X#      1.     Gen 1:3
  476. X#      2.     Exod 2:4
  477. X#      3.     Lev 3:5
  478. X#      etc.
  479. X#
  480. X#  This is the format Bibleref uses when you write one of its
  481. X#  internally generated passage lists to disk.  The numbers+period
  482. X#  are optional.
  483. X#
  484. X############################################################################
  485. X#
  486. X#  Links: ./bibleref.icn ./ref2bmap.icn
  487. X#
  488. X#  See also: 
  489. X#
  490. X############################################################################
  491. X
  492. X
  493. Xprocedure readfile()
  494. X
  495. X    local intext, fname, bitmap_list, firstline, line, firstchar
  496. X
  497. X    until \intext do {
  498. X    fname := snarf_input("Enter filename (! for shell; q to quit):  ")
  499. X    fname ? {
  500. X        firstchar := move(1) | ""
  501. X        case firstchar of {
  502. X        ""   : fail
  503. X        "!"  : push_shell() & initialize_screen()
  504. X        "q"  : pos(0) & fail
  505. X        default : {
  506. X            intext := open(fname) | {
  507. X            err_message("Can't open " || fname || ".")
  508. X            }
  509. X        }
  510. X        }
  511. X    }
  512. X    }
  513. X    message("Reading.")
  514. X
  515. X    bitmap_list := []
  516. X    until firstline := ("" ~== trim(read(intext) | {
  517. X    err_message("Empty file.")
  518. X    fail
  519. X    }))
  520. X    firstline ? {
  521. X    # If the first nonblank line shows the file to be in gettext
  522. X    # format, then it was written by write_passage(), and we need
  523. X    # only read in keys.
  524. X    if ="::" & put(bitmap_list, ref_2_bitmap(tab(0), kjv_filename))
  525. X    then {
  526. X        while line := trim(read(intext)) do {
  527. X        if ="::" then {
  528. X            put(bitmap_list, ref_2_bitmap(tab(0), kjv_filename)) | {
  529. X            err_message("Garbled ::key:  "|| line ||".")
  530. X            fail
  531. X            }
  532. X        } else next
  533. X        }
  534. X    # If the file is not in gettext format, then try reading it in as
  535. X    # a pure list of passages.
  536. X    } else {
  537. X        tab(many(&digits ++ ' ')) & tab(match(".")) & tab(many(' '))
  538. X        if put(bitmap_list, ref_2_bitmap(tab(0), kjv_filename)) then {
  539. X        while line := trim("" ~== !intext) do {
  540. X            line ? {
  541. X            tab(many(&digits ++ ' ')) & ="." & tab(many(' '))
  542. X            put(bitmap_list, ref_2_bitmap(tab(0), kjv_filename)) | {
  543. X                err_message("Garbled line:  "|| line ||".")
  544. X                fail
  545. X            }
  546. X            }
  547. X        }
  548. X        } else {
  549. X        err_message("Unrecognized file format.  Aborting.")
  550. X        fail
  551. X        }
  552. X    }
  553. X    }
  554. X    message("Done.")
  555. X
  556. X    put(lists, lst(bitmap_list, 0, &null, "(read from disk)"))
  557. X    return lists[-1]
  558. X
  559. Xend
  560. SHAR_EOF
  561. true || echo 'restore of readfile.icn failed'
  562. rm -f _shar_wnt_.tmp
  563. fi
  564. # ============= srchutil.icn ==============
  565. if test -f 'srchutil.icn' -a X"$1" != X"-c"; then
  566.     echo 'x - skipping srchutil.icn (File already exists)'
  567.     rm -f _shar_wnt_.tmp
  568. else
  569. > _shar_wnt_.tmp
  570. echo 'x - extracting srchutil.icn (Text)'
  571. sed 's/^X//' << 'SHAR_EOF' > 'srchutil.icn' &&
  572. X############################################################################
  573. X#
  574. X#    Name:     srchutil.icn
  575. X#
  576. X#    Title:     search utilities for bibleref
  577. X#
  578. X#    Author:     Richard L. Goerwitz
  579. X#
  580. X#    Version: 1.14
  581. X#
  582. X############################################################################
  583. X#
  584. X#  Contains:
  585. X#
  586. X#      display_search(), which prompts the user, if necessary, for
  587. X#          search strings and operators, performs the search, and
  588. X#          then puts the results into the global list of lists,
  589. X#
  590. X#      compose_search(), which compiles a little automaton which, when
  591. X#          run via do_search(), returns a list of hits (i.e. retrieve-
  592. X#          format bitmaps),
  593. X#
  594. X#      do_search(), on which see above,
  595. X#
  596. X#      various other utilities (e.g. compose_spaced_search())
  597. X#
  598. X############################################################################
  599. X#
  600. X#  Links:  ./complete.icn ./retrieve.icn, probably others
  601. X#
  602. X#  See also:  bibleref.icn
  603. X#
  604. X############################################################################
  605. X
  606. X# for debugging
  607. X# link ximage
  608. X
  609. Xprocedure search_database()
  610. X
  611. X    #
  612. X    # Search database for word or patterns matching whole words.
  613. X    #
  614. X    local search_machine, result, string_memb, tmp, excl
  615. X
  616. X    search_machine := compose_search() | {
  617. X    err_message("No search performed.  Aborting.")
  618. X    fail
  619. X    }
  620. X
  621. X    # for debugging purposes
  622. X    # write(&errout, ximage(search_machine))
  623. X
  624. X    if *search_machine > 4
  625. X    then message("Executing complex search...")
  626. X    else message("Executing search...")
  627. X    *(result := do_search(search_machine)[1]) > 0 | {
  628. X    err_message("No hits.")
  629. X    fail
  630. X    }
  631. X
  632. X    #
  633. X    # Nasty kludge to see what search strings were incorporated into the
  634. X    # search_machine.    
  635. X    #
  636. X    string_memb := "???"
  637. X    tmp := search_machine[2]
  638. X    excl := (\search_machine[4], "! ") | ""
  639. X    repeat {
  640. X    if type(tmp) == "string" then
  641. X        string_memb := excl || tmp & break
  642. X    else if type(tmp) == "list" then {
  643. X        excl := (\tmp[4], "! ") | ""
  644. X        tmp := tmp[2]
  645. X        }
  646. X    else break
  647. X    }
  648. X    if *search_machine > 4 then string_memb ||:= "..."
  649. X
  650. X    if type(result) == "set" then result := sort(result)
  651. X    put(lists, lst(result, 0, &null, string_memb))
  652. X    message("Done.")
  653. X    return lists[-1]
  654. X
  655. Xend
  656. X    
  657. X
  658. X
  659. Xprocedure compose_search()
  660. X
  661. X    #
  662. X    # Put together a little search machine out of patterns specified by
  663. X    # the user.  Don't execute, though.  Just return a list containing
  664. X    # the user's directions to the calling procedure, and let it handle
  665. X    # execution (via do_search()).
  666. X    #
  667. X
  668. X    local pattern, status, sense_of_search, rsp, result, u, r
  669. X    static blanks
  670. X    initial blanks := ' \t,'
  671. X
  672. X    if pos(0)
  673. X    then rsp := trim(snarf_input("Enter word (q to abort):  "), blanks)
  674. X    else return compose_spaced_search(blanks)
  675. X
  676. X    rsp == (""|"q") & fail
  677. X    if rsp ? (="!", pattern := tab(many(blanks)), tab(0)) then
  678. X    sense_of_search := "inverted"
  679. X    else pattern := rsp
  680. X
  681. X    result := [retrieve, pattern, kjv_filename, sense_of_search]
  682. X    repeat {
  683. X    status := map(snarf_input("f to finish, or a/o/n (q aborts):  "))
  684. X    status == (""|"q") & fail
  685. X    if upto(blanks, rsp) then
  686. X        # And together all words in the input string.
  687. X        return rsp ? compose_spaced_search(blanks)
  688. X    if status == "f" then
  689. X        return result
  690. X    else if status == ("a"|"n"|"o") then {
  691. X        if status ~== "o" then {
  692. X        u := GetUnit() | next
  693. X        r := GetRange() | next
  694. X        }
  695. X        return case status of {
  696. X        "a" : [r_and, result, compose_search(), kjv_filename, u, r]
  697. X        "o" : [r_or, result, compose_search(), kjv_filename, u, r]
  698. X        "n" : [r_and_not, result, compose_search(), kjv_filename, u, r]
  699. X        } | fail
  700. X    }
  701. X    else if status == (""|"q") then fail
  702. X    else err_message("F = finish, a = and, o = or, n = and-not.")
  703. X    }
  704. X
  705. Xend
  706. X
  707. X
  708. X
  709. Xprocedure GetUnit()
  710. X
  711. X    local resp
  712. X
  713. X    if filestats[kjv_filename].IS.no = 3 then
  714. X    repeat {
  715. X        resp := map(snarf_input("Enter unit (b/c/v):  "))
  716. X        case resp of {
  717. X        "b"    : return 1
  718. X        "c"    : return 2
  719. X        "v"    : return 3
  720. X        "q"|"" : fail
  721. X        default : {
  722. X            err_message("Enter b (book), c (chapter), or v (verse).")
  723. X            next
  724. X        }
  725. X        }
  726. X    }
  727. X    else if filestats[kjv_filename].IS.no = 2 then
  728. X    repeat {
  729. X        resp := map(snarf_input("Enter unit (c/v):  "))
  730. X        case resp of {
  731. X        "c"    : return 1
  732. X        "v"    : return 2
  733. X        "q"|"" : fail
  734. X        default : {
  735. X            err_message("Enter c (chapter), or v (verse).")
  736. X            next
  737. X        }
  738. X        }
  739. X    }
  740. X    else abort("GetUnit", "not configured for IS.no not = 2 or 3", 69)
  741. X
  742. Xend
  743. X
  744. X
  745. X
  746. Xprocedure GetRange()
  747. X
  748. X    local resp
  749. X
  750. X    repeat {
  751. X    resp := map(snarf_input("Enter range:  "))
  752. X    if resp := integer(resp) then
  753. X        return resp
  754. X    else {
  755. X        resp == ("q"|"") & fail
  756. X        err_message("Enter an integer (usually 1 or 0).")
  757. X        next
  758. X    }
  759. X    }
  760. X
  761. Xend
  762. X
  763. X
  764. X
  765. Xprocedure do_search(l)
  766. X
  767. X    #
  768. X    # Executes the little machine put together by compose_search().
  769. X    #
  770. X
  771. X    if *l = 0 
  772. X    then return l
  773. X
  774. X    case type(l[1]) of {
  775. X    "list"       : return do_search(l[1]) ||| do_search(l[2:0])
  776. X    "procedure"  : return [l[1]!do_search(l[2:0])] | [[]]
  777. X    default      : return [l[1]] ||| do_search(l[2:0])
  778. X    }
  779. X
  780. Xend
  781. X
  782. X
  783. X
  784. Xprocedure compose_spaced_search(blanks)
  785. X
  786. X    #
  787. X    # Try to turn searches with spaces in them (e.g. "sackcloth and ashes")
  788. X    # into separate searches for each constituent word anded together.
  789. X    # This routine is set up, though, to handle single words or patterns
  790. X    # as well (e.g. "sackcloth").
  791. X    #
  792. X
  793. X    local token, sense_of_search, search_list
  794. X    static wordchars
  795. X    initial wordchars := ~blanks
  796. X
  797. X    #
  798. X    # Whoops, no string.  This shouldn't happen, but just in case I screw
  799. X    # up somewhere in the code, and forget to strip out superfluous blanks
  800. X    # typed in by the user...
  801. X    #
  802. X    tab(upto(wordchars)) | {
  803. X    err_message("No search string.  Aborting.")
  804. X    fail
  805. X    }
  806. X    if ="!" then {
  807. X    sense_of_search := 1
  808. X    tab(upto(wordchars))
  809. X    }
  810. X    token := tab(many(wordchars)) | {
  811. X    err_message("Unexpected end of input.  Aborting")
  812. X    fail
  813. X    }
  814. X
  815. X    #
  816. X    # Make sure tokens aren't just wildcard patterns!  Also, warn the
  817. X    # user about searches containing really common words.
  818. X    #
  819. X    upto(&letters, token) | {
  820. X    err_message("Token "||token||" has no letters in it!")
  821. X    fail
  822. X    }
  823. X
  824. X    #
  825. X    # If we've reached the end of the search string, return what we
  826. X    # have...
  827. X    #
  828. X    search_list := [retrieve, token, kjv_filename, sense_of_search]
  829. X    pos(0) & (return search_list)
  830. X
  831. X    #
  832. X    # ...otherwise and this search string together with the next one,
  833. X    #
  834. X    return [r_and, search_list,
  835. X        compose_spaced_search(blanks),
  836. X        kjv_filename, filestats[kjv_filename].IS.no, 0]
  837. X
  838. Xend
  839. SHAR_EOF
  840. true || echo 'restore of srchutil.icn failed'
  841. rm -f _shar_wnt_.tmp
  842. fi
  843. # ============= version.icn ==============
  844. if test -f 'version.icn' -a X"$1" != X"-c"; then
  845.     echo 'x - skipping version.icn (File already exists)'
  846.     rm -f _shar_wnt_.tmp
  847. else
  848. > _shar_wnt_.tmp
  849. echo 'x - extracting version.icn (Text)'
  850. sed 's/^X//' << 'SHAR_EOF' > 'version.icn' &&
  851. X############################################################################
  852. X#
  853. X#    Name:     version.icn
  854. X#
  855. X#    Title:     return Quranref version number
  856. X#
  857. X#    Author:     Richard L. Goerwitz
  858. X#
  859. X#    Version: 1.3
  860. X#
  861. X############################################################################
  862. X#
  863. X#  See also: ./bibleref.icn
  864. X#
  865. X############################################################################
  866. X
  867. Xprocedure _version()
  868. X    return "Quranref, version 1.0, patchlevel 1"
  869. Xend
  870. SHAR_EOF
  871. true || echo 'restore of version.icn failed'
  872. rm -f _shar_wnt_.tmp
  873. fi
  874. # ============= complete.icn ==============
  875. if test -f 'complete.icn' -a X"$1" != X"-c"; then
  876.     echo 'x - skipping complete.icn (File already exists)'
  877.     rm -f _shar_wnt_.tmp
  878. else
  879. > _shar_wnt_.tmp
  880. echo 'x - extracting complete.icn (Text)'
  881. sed 's/^X//' << 'SHAR_EOF' > 'complete.icn' &&
  882. X############################################################################
  883. X#
  884. X#    Name:     complete.icn
  885. X#
  886. X#    Title:     complete partial input string
  887. X#
  888. X#    Author:     Richard L. Goerwitz
  889. X#
  890. X#    Version: 1.7
  891. X#
  892. X############################################################################
  893. X#
  894. X#  This file contains a single procedure, complete(s,st), which
  895. X#  completes a string (s) relative to a set or list of strings (st).
  896. X#  Put differently, complete() lets you supply a partial string, s,
  897. X#  and get back those strings in st that s is either equal to or a
  898. X#  substring of.
  899. X#
  900. X#  Lots of command interfaces allow completion of partial input.
  901. X#  Complete() simply represents my personal sentiments about how this
  902. X#  might best be done in Icon.  If you strip away the profuse comments
  903. X#  below, you end up with only about thirty lines of actual source
  904. X#  code.
  905. X#
  906. X#  I have arranged things so that only that portion of an automaton
  907. X#  which is needed to complete a given string is actually created and
  908. X#  stored.  Storing automata for later use naturally makes complete()
  909. X#  eat up more memory.  The performance gains can make it worth the
  910. X#  trouble, though.  If, for some reason, there comes a time when it
  911. X#  is advisable to reclaim the space occupied by complete's static
  912. X#  structures, you can just call it without arguments.  This
  913. X#  "resets" complete() and forces an immediate garbage collection.
  914. X#  
  915. X# Example code:
  916. X#
  917. X#      commands := ["run","stop","quit","save","load","continue"]
  918. X#      while line := read(&input) do {
  919. X#          cmds := list()
  920. X#          every put(cmds, complete(line, commands))
  921. X#          case *cmds of {
  922. X#              0 : input_error(line)
  923. X#              1 : do_command(cmds[1])
  924. X#              default : display_possible_completions(cmds)
  925. X#          }
  926. X#          etc...
  927. X#
  928. X#  More Iconish methods might include displaying successive
  929. X#  alternatives each time the user presses the tab key (this would,
  930. X#  however, require using the nonportable getch() routine).  Another
  931. X#  method might be to use the first string suspended by complete().
  932. X#
  933. X#  NOTE: This entire shebang could be replaced with a slightly slower
  934. X#  and much smaller program suggested to me by Jerry Nowlin and Bob
  935. X#  Alexander.
  936. X#
  937. X#      procedure terscompl(s, st)
  938. X#          suspend match(s, p := !st) & p
  939. X#      end
  940. X#
  941. X#  This program will work fine for lists with just a few members, and
  942. X#  also for cases where s is fairly large.  It will also use much less
  943. X#  memory.
  944. X#
  945. X############################################################################
  946. X#
  947. X#  Links: none
  948. X#
  949. X############################################################################
  950. X
  951. X
  952. X
  953. Xprocedure complete(s,st)
  954. X
  955. X    local dfstn, c, l, old_chr, chr, newtbl, str, strset
  956. X    static t
  957. X    initial t := table()
  958. X
  959. X    # No-arg invocation wipes out static structures & causes an
  960. X    # immediate garbage collection.
  961. X    if /s & /st then {
  962. X    t := table()
  963. X    collect()        # do it NOW
  964. X    fail
  965. X    }
  966. X    type(st) == ("list"|"set") |
  967. X    stop("error (complete):  list or set expected for arg2")
  968. X
  969. X    # Seriously, all that's being done here is that possible states
  970. X    # are being represented by sets containing possible completions of
  971. X    # s relative to st.  Each time a character is snarfed from s, we
  972. X    # check to see what strings in st might represent possible
  973. X    # completions, and store these in yet another set.  At some
  974. X    # point, we either run into a character in s that makes comple-
  975. X    # tion impossible (fail), or we run out of characters in s (in
  976. X    # which case we succeed, & suspend each of the possible
  977. X    # completions).
  978. X
  979. X    # Store any sets we have to create in a static structure for later
  980. X    # re-use.
  981. X    /t[st] := table()
  982. X
  983. X    # We'll call the table entry for the current set dfstn.  (It really
  984. X    # does enable us to do things deterministically.)
  985. X    dfstn := t[st]
  986. X
  987. X    # Snarf one character at a time from s.
  988. X    every c := !s do {
  989. X
  990. X    # The state we're in is represented by the set of all possible
  991. X    # completions before c was read.  If we haven't yet seen char
  992. X    # c in this state, run through the current-possible-completion
  993. X    # set, popping off the first character of each possible
  994. X    # completion, and then construct a table which uses these
  995. X    # initial chars as keys, and makes the completions that are
  996. X    # possible for each of these characters into the values for
  997. X    # those keys.
  998. X    if /dfstn[st] then {
  999. X
  1000. X        # To get strings that start with the same char together,
  1001. X        # sort the current string set (st).
  1002. X        l := sort(st)
  1003. X        newtbl := table()
  1004. X        old_chr := ""
  1005. X        # Now pop off each member of the sorted string set.  Use
  1006. X        # first characters as keys, and then divvy up the full strings
  1007. X        # into sets of strings having the same initial letter.
  1008. X        every str := !l do {
  1009. X        str ? { chr := move(1) | next; str := tab(0) }
  1010. X        if old_chr ~==:= chr then {
  1011. X            strset := set([str])
  1012. X            insert(newtbl, chr, strset)
  1013. X        }
  1014. X        else insert(strset, str)
  1015. X        }
  1016. X        insert(dfstn, st, newtbl)
  1017. X    }
  1018. X
  1019. X    # What we've done essentially is to create a table in which
  1020. X    # the keys represent labeled arcs out of the current state,
  1021. X    # and the values represent possible completion sets for those
  1022. X    # paths.  What we need to do now is store that table in dfstn
  1023. X    # as the value of the current state-set (i.e. the current
  1024. X    # range of possible completions).  Once stored, we can then
  1025. X    # see if there is any arc from the current state (dfstn[st])
  1026. X    # with the label c (dfstn[st][c]).  If so, its value becomes
  1027. X    # the new current state (st), and we cycle around again for
  1028. X    # yet another c.
  1029. X    st := \dfstn[st][c] | fail
  1030. X    if *st = 1 & match(s,!st)
  1031. X    then break
  1032. X    }
  1033. X
  1034. X    # Eventually we run out of characters in c.  The current state
  1035. X    # (i.e. the set of possible completions) can simply be suspended
  1036. X    # one element at a time, with s prefixed to each element.  If, for
  1037. X    # instance, st had contained ["hello","help","hear"] at the outset
  1038. X    # and s was equal to "hel", we would now be suspending "hel" ||
  1039. X    # !set(["lo","p"]).
  1040. X    suspend s || !st
  1041. X
  1042. Xend
  1043. SHAR_EOF
  1044. true || echo 'restore of complete.icn failed'
  1045. rm -f _shar_wnt_.tmp
  1046. fi
  1047. # ============= ipause.icn ==============
  1048. if test -f 'ipause.icn' -a X"$1" != X"-c"; then
  1049.     echo 'x - skipping ipause.icn (File already exists)'
  1050.     rm -f _shar_wnt_.tmp
  1051. else
  1052. > _shar_wnt_.tmp
  1053. echo 'x - extracting ipause.icn (Text)'
  1054. sed 's/^X//' << 'SHAR_EOF' > 'ipause.icn' &&
  1055. X############################################################################
  1056. X#
  1057. X#    Name:     ipause.icn
  1058. X#
  1059. X#    Title:     pause within an Icon program
  1060. X#
  1061. X#    Author:     Richard L. Goerwitz
  1062. X#
  1063. X#    Version: 1.2
  1064. X#
  1065. X############################################################################
  1066. X#
  1067. X#  Ipause(i) - pause i milliseconds (accuracy depends on the resolution
  1068. X#  of the system clock).  Would be nice if Icon had a nap() function, so
  1069. X#  that we didn't just have to loop.  Of course, for operating systems
  1070. X#  that don't support all this multitasking nonsense, ipause() will do
  1071. X#  just fine.
  1072. X#
  1073. X############################################################################
  1074. X
  1075. X
  1076. Xprocedure ipause(i)
  1077. X
  1078. X    local T
  1079. X    T := &time
  1080. X    until &time >= (T + i)
  1081. X    return
  1082. X
  1083. Xend
  1084. SHAR_EOF
  1085. true || echo 'restore of ipause.icn failed'
  1086. rm -f _shar_wnt_.tmp
  1087. fi
  1088. # ============= inbits.icn ==============
  1089. if test -f 'inbits.icn' -a X"$1" != X"-c"; then
  1090.     echo 'x - skipping inbits.icn (File already exists)'
  1091.     rm -f _shar_wnt_.tmp
  1092. else
  1093. > _shar_wnt_.tmp
  1094. echo 'x - extracting inbits.icn (Text)'
  1095. sed 's/^X//' << 'SHAR_EOF' > 'inbits.icn' &&
  1096. X############################################################################
  1097. X#
  1098. X#    Name:     inbits.icn
  1099. X#
  1100. X#    Title:     read in variable length characters from a file
  1101. X#
  1102. X#    Author:     Richard L. Goerwitz
  1103. X#
  1104. X#    Version: 1.2
  1105. X#
  1106. X############################################################################
  1107. X#  
  1108. X#  This procedure, inbits(), re-imports data converted into writable
  1109. X#  form by outbits().  See the file outbits.icn for all the whys and
  1110. X#  hows.
  1111. X#
  1112. X############################################################################
  1113. X#
  1114. X#  Links: none
  1115. X#
  1116. X#  See also: outbits.icn
  1117. X#
  1118. X############################################################################
  1119. X
  1120. X
  1121. Xprocedure inbits(f, len)
  1122. X
  1123. X    local i, byte, old_byte_mask
  1124. X    static old_byte, old_len, byte_length
  1125. X    initial {
  1126. X    old_byte := old_len := 0
  1127. SHAR_EOF
  1128. true || echo 'restore of inbits.icn failed'
  1129. fi
  1130. echo 'End of  part 2'
  1131. echo 'File inbits.icn is continued in part 3'
  1132. echo 3 > _shar_seq_.tmp
  1133. exit 0
  1134.  
  1135. exit 0 # Just in case...
  1136. -- 
  1137. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1138. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1139. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1140. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1141.