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

  1. Newsgroups: comp.sources.misc
  2. From: goer@midway.uchicago.edu (Richard L. Goerwitz)
  3. Subject:  v23i071:  quranref - Holy Qur'an word and passage based retrievals, Part05/08
  4. Message-ID: <1991Oct19.022316.12990@sparky.imd.sterling.com>
  5. X-Md4-Signature: 4dbe78443e8af50cea3a89f1ce65eaf6
  6. Date: Sat, 19 Oct 1991 02:23:16 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 71
  11. Archive-name: quranref/part05
  12. Environment: Icon
  13.  
  14. ---- Cut Here and feed the following to sh ----
  15. #!/bin/sh
  16. # this is quranref.05 (part 5 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file indexutl.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" != 5; 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 indexutl.icn'
  34. else
  35. echo 'x - continuing file indexutl.icn'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'indexutl.icn' &&
  37. X        no -:= 1
  38. X        tab(upto(&digits))
  39. X        bitmap +:= ishift(field, no * IS.len)
  40. X        }
  41. X    }
  42. X    # If we're not at the end of the line, then we've got a
  43. X    # a problem with the portion of the input file passed
  44. X    # to digits_2_bitmap as s (arg1).
  45. X    pos(0) | abort("digits_2_bitmap",
  46. X               "malformed position marker:  "||s,
  47. X               11)
  48. X    }
  49. X
  50. X    # If the current no is not -1, then we have either too
  51. X    # many or too few fields, i.e. someone wrote, say, 01:02:03 in
  52. X    # a text which he or she declared as having four fields.
  53. X    no = 0 | abort("digits_2_bitmap",
  54. X    no || " fields in "||s||" (expected "||IS.no||")",
  55. X    12)
  56. X    # write(&errout,"bitmap = ",radcon(bitmap,10,2))  # for debugging
  57. X    return bitmap
  58. X
  59. Xend
  60. SHAR_EOF
  61. echo 'File indexutl.icn is complete' &&
  62. true || echo 'restore of indexutl.icn failed'
  63. rm -f _shar_wnt_.tmp
  64. fi
  65. # ============= retrops.icn ==============
  66. if test -f 'retrops.icn' -a X"$1" != X"-c"; then
  67.     echo 'x - skipping retrops.icn (File already exists)'
  68.     rm -f _shar_wnt_.tmp
  69. else
  70. > _shar_wnt_.tmp
  71. echo 'x - extracting retrops.icn (Text)'
  72. sed 's/^X//' << 'SHAR_EOF' > 'retrops.icn' &&
  73. X############################################################################
  74. X#
  75. X#    Name:     retrops.icn
  76. X#
  77. X#    Title:     logical operations for retrievals
  78. X#
  79. X#    Author:     Richard L. Goerwitz
  80. X#
  81. X#    Version: 1.17
  82. X#
  83. X############################################################################
  84. X#
  85. X#  The following collection of procedures implements logical
  86. X#  and/or/and_not operations for the retrieve text-retrieval package.
  87. X#  Their general form is
  88. X#
  89. X#      r_op(set1, set2, filename, field, range)
  90. X#
  91. X#  where op = one of either and, or, or and_not.  The field and range
  92. X#  arguments are optional.
  93. X#
  94. X#  To illustrate how these operations are performed, let me explain
  95. X#  how one of the procedures below, r_and(), works.  Let us assume we
  96. X#  have retrieve()d bitmap sets for two patterns in a single indexed
  97. X#  file.  Call the sets set1 and set2.  Call the file filename.  These
  98. X#  two sets are passed to r_and() as arguments one and two.  R_and()
  99. X#  takes the intersection of these two sets.  The result is a
  100. X#  collection of all bitmaps pointing to blocks in filename containing
  101. X#  words matching *both* of the two patterns used to generate set1 and
  102. X#  set2.  R_and() returns this result to the calling procedure.
  103. X#
  104. X#  Note that, by default, r_and() retrieves co-ocurrences of patterns
  105. X#  within a single block.  If the programmer wishes to find
  106. X#  co-ocurrences within larger units, he or she may supply a field
  107. X#  argument.  Fields are fixed width bit-fields into which location
  108. X#  markers for filename are divided, numbered from the largest and
  109. X#  most general to the smallest and most specific.  See the file
  110. X#  makeind for a discussion of how they are handled.  A range
  111. X#  parameter may also be specified, which makes it possible to look
  112. X#  for coocurrences in collections of more than one unit of the type
  113. X#  specified in the field argument.
  114. X#
  115. X############################################################################
  116. X#
  117. X#  Links: none
  118. X#
  119. X#  See also: retrieve.icn, makeind.icn
  120. X#
  121. X############################################################################
  122. X
  123. X# The following globals contain stats for current file (here, arg 3).
  124. X# global filestats    # declared in initfile.icn
  125. X# global IS           # declared in indexutl.icn
  126. X
  127. Xprocedure r_or(set1, set2, filename, field, range)
  128. X
  129. X    # Check for sloppy programming.
  130. X    /filename & abort("apply_op", "you gotta call me with a filename", 43)
  131. X    type(set1) == ("list"|"set") |
  132. X    abort("apply_op","arg 1 must be a list/set",45)
  133. X    type(set2) == ("list"|"set") |
  134. X    abort("apply_op","arg 2 must be a list/set",46)
  135. X
  136. X    # Be sure to convert lists to sets.  Personally, I think list -> set
  137. X    # conversions should be as automatic in Icon as their string -> cset
  138. X    # correspondents.
  139. X    type(set1) == "set" | (set1 := set(set1))
  140. X    type(set2) == "set" | (set2 := set(set2))
  141. X
  142. X    # No need to initialize variables.  Field and range are
  143. X    # meaningless for this op.
  144. X    return set1 ++ set2
  145. X
  146. Xend
  147. X
  148. Xprocedure r_and(set1, set2, filename, field, range)
  149. X    # set intersection
  150. X    return apply_op("**", set1, set2, filename, field, range)
  151. Xend
  152. X
  153. Xprocedure r_and_not(set1, set2, filename, field, range)
  154. X    # simpler way of saying X and not Y, or Y and not X
  155. X    return apply_op("--", set1, set2, filename, field, range)
  156. Xend
  157. X
  158. X
  159. Xprocedure apply_op(op, set1, set2, filename, field, range)
  160. X
  161. X    local r_shift, tbl, elem, set1a, set2a, set3, set4, shifted_elem, elem2
  162. X
  163. X    # globals:
  164. X    #
  165. X    # IS is a global record in which will be stored important stats for
  166. X    # the file named in arg 4 (filename).  We will be using two of IS's
  167. X    # fields:
  168. X    #
  169. X    # IS.len   = the number of bits needed to hold an integer
  170. X    #             representation of a single field in filename
  171. X    # IS.no    = number of fields for filename
  172. X    #
  173. X    # Filestats is a global table which contains various important stats
  174. X    # for every file that's been accessed.  These stats are kept in a
  175. X    # record of type Fs
  176. X    #  
  177. X    #     record Fs(ind_filename, bmp_filename, lim_filename, unt_filename
  178. X    #               IS, ofs_table)
  179. X    #
  180. X    # Fs is declared in initfile.icn; here all we need is Fs.IS,
  181. X    # which we access via filestats[filename].IS.  Initfile() sets up
  182. X    # filestats for filename, but we shouldn't call it here.  It has
  183. X    # (or should already have) been called by retrieve().
  184. X    #
  185. X
  186. X    # Check for sloppy programming.
  187. X    /filename & abort("apply_op", "you gotta call me with a filename", 43)
  188. X    type(set1) == ("list"|"set") |
  189. X    abort("apply_op","arg 1 must be a list/set",47)
  190. X    type(set2) == ("list"|"set") |
  191. X    abort("apply_op","arg 2 must be a list/set",48)
  192. X
  193. X    # Initialize important variables.
  194. X    #
  195. X    if /filestats | /filestats[filename]
  196. X    then abort("apply_op", "can't apply_op before retrieve()ing", 44)
  197. X    IS := filestats[filename].IS      # re-initialize IS for current file
  198. X
  199. X    /field := IS.no; field := IS.no - field
  200. X    (/range := 0) | (range := abs(range))
  201. X    IS.no >= field >= 0 | abort("apply_op", "field out of range", 40)
  202. X    range >= 0 | abort("apply_op", "no negative ranges, please!", 41)
  203. X
  204. X    if field = range = 0 then {
  205. X    type(set1) ~== "set" & set1 := set(set1)
  206. X    type(set2) ~== "set" & set2 := set(set2)
  207. X    # no need to shift anything around
  208. X    return op(set1, set2)
  209. X    } else {
  210. X    set1a := set()
  211. X    if field = 0 then {
  212. X        # Great, no need to shift out any fields.
  213. X        every elem := !set1 do {
  214. X        if abs(elem - !set2) <= range then
  215. X            insert(set1a, elem)
  216. X        }
  217. X        if op == "**"
  218. X        then return set1a
  219. X        else {
  220. X        # op == "--"
  221. X        (type(set1) == "set") | (set1 := set(set1))
  222. X        return (set1 -- set1a)
  223. X        }
  224. X    }
  225. X    # Uh oh, we need to knock out some fields!
  226. X    else {
  227. X        tbl := table()
  228. X        set1a := set(); set2a := set()
  229. X        r_shift := -(field * IS.len)
  230. X        every elem := !set1 do {
  231. X        shifted_elem := ishift(elem, r_shift)
  232. X        /tbl[shifted_elem] := set()
  233. X        insert(tbl[shifted_elem], elem)
  234. X        insert(set1a, shifted_elem)
  235. X        }
  236. X        every elem := !set2 do {
  237. X        shifted_elem := ishift(elem, r_shift)
  238. X        op == "**" & {
  239. X            /tbl[shifted_elem] := set()
  240. X            insert(tbl[shifted_elem], elem)
  241. X        }
  242. X        insert(set2a, shifted_elem)
  243. X        }
  244. X        set4 := set()
  245. X        if range = 0 then {
  246. X        set3 := op(set1a, set2a)
  247. X        every insert(set4, !tbl[!set3])
  248. X                return set4
  249. X        }
  250. X        # Difficult stuff, field ~= verse, range ~= 0.
  251. X        else {
  252. X        if op == "**" then {
  253. X            every elem := !set1a do {
  254. X                # Range is always positive (see above; range
  255. X                # := abs(range)).
  256. X            if abs(elem - (elem2 := !set2a)) <= range then
  257. X                every insert(set4, !tbl[elem|elem2])
  258. X            }
  259. X            return set4
  260. X        }
  261. X        # else if op == "--"
  262. X        else {
  263. X            set3 := set()
  264. X            every elem := !set1a do {
  265. X            if abs(elem - !set2a) <= range then {
  266. X                insert(set3, elem)
  267. X            }
  268. X            }
  269. X            every insert(set4, !tbl[!(set1a -- set3)])
  270. X            return set4
  271. X        }
  272. X        }
  273. X    }
  274. X    }
  275. X
  276. Xend
  277. SHAR_EOF
  278. true || echo 'restore of retrops.icn failed'
  279. rm -f _shar_wnt_.tmp
  280. fi
  281. # ============= whatnext.icn ==============
  282. if test -f 'whatnext.icn' -a X"$1" != X"-c"; then
  283.     echo 'x - skipping whatnext.icn (File already exists)'
  284.     rm -f _shar_wnt_.tmp
  285. else
  286. > _shar_wnt_.tmp
  287. echo 'x - extracting whatnext.icn (Text)'
  288. sed 's/^X//' << 'SHAR_EOF' > 'whatnext.icn' &&
  289. X###########################################################################
  290. X#
  291. X#    Name:     whatnext.icn
  292. X#
  293. X#    Title:     return next/previous bitmap in filename
  294. X#
  295. X#    Author:     Richard L. Goerwitz
  296. X#
  297. X#    Version: 1.8
  298. X#
  299. X###########################################################################
  300. X#
  301. X#  Given a bitmap and a filename, NextBitmap() and PrevBitmap() return
  302. X#  either the next or previous bitmap in filename.  Fail if there is no
  303. X#  next or previous bitmap.  Syntax:
  304. X#
  305. X#      {Next,Prev}Bitmap(bitmap, filename, start_no)
  306. X#
  307. X#  start_no specifies the lowest possible field value.  If null, defaults
  308. X#  to 1.  Normally start_no will be either 1 or 0.
  309. X#
  310. X############################################################################
  311. X#
  312. X#  links:  ./indexutl.icn ./initfile.icn
  313. X#
  314. X############################################################################
  315. X
  316. X# For error messages, debugging.
  317. Xlink radcon
  318. X
  319. X# Declared in indexutl.icn.
  320. X# record is(FS, s_len, len, no, is_case_sensitive)
  321. X# global IS
  322. X
  323. X# Declared in initfile.icn.
  324. X# global filestats
  325. X# record Fs(ind_filename, bmp_filename, lim_filename, unt_filename,
  326. X#           IS, ofs_table)
  327. X
  328. X# Used here to store limits data in the static table limits_tbl.
  329. Xrecord ldata(limitslst, limitsset)
  330. X
  331. X
  332. Xprocedure PrevBitmap(bitmap, filename, start_no)
  333. X    return PrevNextBitmap(bitmap, filename, "p", start_no)
  334. Xend
  335. X
  336. Xprocedure NextBitmap(bitmap, filename, start_no)
  337. X    return PrevNextBitmap(bitmap, filename, "n", start_no)
  338. Xend
  339. X
  340. X
  341. Xprocedure PrevNextBitmap(bitmap, filename, direction, start_no)
  342. X
  343. X    local limits_file, limit, bitmap_length, limitslst,
  344. X    limitsset, field_mask, shift_bits_out, lowlimit, shift_back, 
  345. X    i, j, newbitmap
  346. X    static limits_tbl
  347. X    initial limits_tbl := table()
  348. X
  349. X    # These verses are missing from the standard Hebrew Bible.  For
  350. X    # English, we can safely ignore them.  See below ("return newbitmap")
  351. X    # for an explanation of how to use a weirdos set.
  352. X    # weirdos := set(["josh 14:8","deut 23:12"])
  353. X
  354. X    # Check for sloppy programming.
  355. X    /filename & abort("PrevNextBitmap", "you called me without a filename",54)
  356. X    /start_no := 1        # default low value for fields is 1
  357. X
  358. X    # If necessary, initialize limits stats for the current file.
  359. X    #
  360. X    if /limits_tbl[filename] then {
  361. X    if /filestats | /filestats[filename] then
  362. X        initfile(filename)           # see initfile.icn
  363. X    limits_file := open(filestats[filename].lim_filename) |
  364. X        abort("PrevBitmap","can't open "||
  365. X          filestats[filename].lim_filename ||
  366. X          ", index with the -l [int] option", 60)
  367. X    IS := filestats[filename].IS
  368. X    # Figure out how many bits we need (has to be divisible by 8).
  369. X    bitmap_length := ((IS.len * IS.no) <= seq(0,8))
  370. X    limitslst := list(); limitsset := set()
  371. X    shift_bits_out := -(((IS.no-IS.r_field)+ 1) * IS.len)
  372. X    while limit := read_int(limits_file, bitmap_length) do {
  373. X        lowlimit :=    ishift(limit, shift_bits_out)
  374. X        # Shift back, filling remaining fields with start_no (usu. 1).
  375. X        # Note that if IS.no - IS.r_field is 0, nothing will happen!
  376. X        every shift_back := IS.len * (1 to (IS.no-IS.r_field)+ 1) do {
  377. X        lowlimit := ior(ishift(lowlimit, shift_back), start_no)
  378. X        }
  379. X        every put(limitslst, lowlimit | limit)
  380. X        insert(limitsset, limit)
  381. X    }
  382. X    close(limits_file)
  383. X    insert(limits_tbl, filename, ldata(limitslst, limitsset))
  384. X    }
  385. X
  386. X    IS := filestats[filename].IS
  387. X    limitslst := limits_tbl[filename].limitslst
  388. X    limitsset := limits_tbl[filename].limitsset
  389. X    #
  390. X    # Used to mask off the least significant field of bitmap.
  391. X    field_mask := 2^(IS.len)-1
  392. X    #
  393. X    # How many bits should we shift to the right?  E.g. in biblical
  394. X    # texts with morphological tags, we want to shift out the morpheme
  395. X    # field, and deal only with book chapter:verse.  The rollover
  396. X    # field (IS.r_field) is the field on which the limits file is
  397. X    # based.  Subtract it from the total number of fields (IS.no), and
  398. X    # then multiply it by the field width in bits (IS.len) and we get
  399. X    # the amount to shift out in order to leave us with the rollover
  400. X    # field in the least position.
  401. X    #
  402. X    shift_bits_out := -((IS.no-IS.r_field) * IS.len)
  403. X
  404. X    if direction == "p" then {
  405. X    #
  406. X    # See if the rollover field has its lowest possible value.  If
  407. X    # so, then use the limits list to get a bitmap for the
  408. X    # preceding section in filename.
  409. X    #
  410. X    if iand(ishift(bitmap, shift_bits_out), field_mask) = start_no then {
  411. X        bitmap = limitslst[j := 1 to *limitslst] | fail
  412. X        newbitmap := limitslst[j - 1] | fail
  413. X    }
  414. X    #
  415. X    # If the rollover field doesn't have its lowest possible
  416. X    # value, then it can simply be decremented; then the remaining
  417. X    # fields must be reset to start_no.
  418. X    #
  419. X    else {
  420. X        # Decrement appropriate field by one; direction is "p".
  421. X        newbitmap := ishift(bitmap, shift_bits_out) - 1
  422. X        # Shift back, filling remaining fields with start_no (usu. 1).
  423. X        # Note that if IS.no - IS.r_field is 0, nothing will happen!
  424. X        every shift_back := IS.len * (1 to (IS.no-IS.r_field)) do {
  425. X        newbitmap := ior(ishift(newbitmap, shift_back), start_no)
  426. X        }
  427. X    }
  428. X    return newbitmap
  429. X        # This is how we'd handle things if we needed a weirdos set
  430. X        # (needed, e.g., for the Hebrew Bible).
  431. X        # if member(weirdos, newbitmap)
  432. X        # then return WhatsNextPrevious(
  433. X    #    newbitmap, filename, direction, start_no)
  434. X        # else return newbitmap
  435. X    }
  436. X    else if direction == "n" then {
  437. X    #
  438. X    # See if the field after the rollover field has its highest
  439. X    # possible value.  We can determine this by checking to see if
  440. X    # bitmap is a member of the limits set.  If so, then use the
  441. X    # limits *list* to get a bitmap for the next section in filename.
  442. X    #
  443. X    if member(limitsset,bitmap) then {
  444. X        bitmap = limitslst[i := 1 to *limitslst] | fail
  445. X        newbitmap := limitslst[i + 1] | fail
  446. X    }
  447. X    #
  448. X    # If the rollover field doesn't have its highest possible
  449. X    # value, then it can simply be incremented; then the remaining
  450. X    # fields must be reset to start_no.
  451. X    #
  452. X    else {
  453. X        # Increment appropriate field by one; direction is "n".
  454. X        newbitmap := ishift(bitmap, shift_bits_out) + 1
  455. X        # Shift back, filling remaining fields with start_no (usu. 1).
  456. X        every shift_back := IS.len * (1 to (IS.no-IS.r_field)) do {
  457. X        newbitmap := ior(ishift(newbitmap, shift_back), start_no)
  458. X        }
  459. X    }
  460. X    return newbitmap
  461. X        # if member(weirdos, newbitmap)
  462. X        # then return WhatsNextPrevious(
  463. X    #    newbitmap, filename, direction, start_no)
  464. X        # else return newbitmap
  465. X    }
  466. X
  467. X    # If we get to here, we've fed this procedure a bad bitmap, or have
  468. X    # used the wrong filename argument.
  469. X    abort("NextPrevBitmap", "Bad argument: 2r"||exbase10(bitmap,2), 63)
  470. X    fail
  471. X    
  472. Xend
  473. SHAR_EOF
  474. true || echo 'restore of whatnext.icn failed'
  475. rm -f _shar_wnt_.tmp
  476. fi
  477. # ============= iolib.icn ==============
  478. if test -f 'iolib.icn' -a X"$1" != X"-c"; then
  479.     echo 'x - skipping iolib.icn (File already exists)'
  480.     rm -f _shar_wnt_.tmp
  481. else
  482. > _shar_wnt_.tmp
  483. echo 'x - extracting iolib.icn (Text)'
  484. sed 's/^X//' << 'SHAR_EOF' > 'iolib.icn' &&
  485. X########################################################################
  486. X#    
  487. X#    Name:    iolib.icn
  488. X#    
  489. X#    Title:    Icon termlib-type tools for MS-DOS and UNIX
  490. X#    
  491. X#    Author:    Richard L. Goerwitz (with help from Norman Azadian)
  492. X#
  493. X#    Version: 1.13
  494. X#
  495. X#########################################################################
  496. X#
  497. X#  The authors place this and future versions of iolib in the public
  498. X#  domain.
  499. X#
  500. X#########################################################################
  501. X#
  502. X#  The following library represents a series of rough functional
  503. X#  equivalents to the standard Unix low-level termcap routines.  It is
  504. X#  not meant as an exact termlib clone.  Nor is it enhanced to take
  505. X#  care of magic cookie terminals, terminals that use \D in their
  506. X#  termcap entries, or archaic terminals that require padding.  This
  507. X#  library is geared mainly for use with ANSI and VT-100 devices.
  508. X#  Note that this file may, in most instances, be used in place of the
  509. X#  older UNIX-only itlib.icn file.  It essentially replaces the DOS-
  510. X#  only itlibdos routines.  For DOS users not familiar with the whole
  511. X#  notion of generalized screen I/O, I've included extra documentation
  512. X#  below.  Please read it.
  513. X#
  514. X#  The sole disadvantage of this over the old itlib routines is that
  515. X#  iolib.icn cannot deal with archaic or arcane UNIX terminals and/or
  516. X#  odd system file arrangements.  Note that because these routines
  517. X#  ignore padding, they can (unlike itlib.icn) be run on the NeXT and
  518. X#  other systems which fail to implement the -g option of the stty
  519. X#  command.  Iolib.icn is also simpler and faster than itlib.icn.
  520. X#
  521. X#  I want to thank Norman Azadian for suggesting the whole idea of
  522. X#  combining itlib.icn and itlibdos.icn into one distribution, for
  523. X#  suggesting things like letting drive specifications appear in DOS
  524. X#  TERMCAP environment variables, and for finding several bugs (e.g.
  525. X#  the lack of support for %2 and %3 in cm).  Although he is loathe
  526. X#  to accept this credit, I think he deserves it.
  527. X#
  528. X#########################################################################
  529. X#
  530. X#  Contents:
  531. X#
  532. X#  setname(term)
  533. X#    Use only if you wish to initialize itermlib for a terminal
  534. X#  other than what your current environment specifies.  "Term" is the
  535. X#  name of the termcap entry to use.  Normally this initialization is
  536. X#  done automatically, and need not concern the user.
  537. X#
  538. X#  getval(id)
  539. X#    Works something like tgetnum, tgetflag, and tgetstr.  In the
  540. X#  spirit of Icon, all three have been collapsed into one routine.
  541. X#  Integer valued caps are returned as integers, strings as strings,
  542. X#  and flags as records (if a flag is set, then type(flag) will return
  543. X#  "true").  Absence of a given capability is signalled by procedure
  544. X#  failure.
  545. X#
  546. X#  igoto(cm,destcol,destline) - NB:  default 1 offset (*not* zero)!
  547. X#    Analogous to tgoto.  "Cm" is the cursor movement command for
  548. X#  the current terminal, as obtained via getval("cm").  Igoto()
  549. X#  returns a string which, when output via iputs, will cause the
  550. X#  cursor to move to column "destcol" and line "destline."  Column and
  551. X#  line are always calculated using a *one* offset.  This is far more
  552. X#  Iconish than the normal zero offset used by tgoto.  If you want to
  553. X#  go to the first square on your screen, then include in your program
  554. X#  "iputs(igoto(getval("cm"),1,1))."
  555. X#
  556. X#  iputs(cp,affcnt)
  557. X#    Equivalent to tputs.  "Cp" is a string obtained via getval(),
  558. X#  or, in the case of "cm," via igoto(getval("cm"),x,y).  Affcnt is a
  559. X#  count of affected lines.  It is completely irrelevant for most
  560. X#  modern terminals, and is supplied here merely for the sake of
  561. X#  backward compatibility with itlib, a UNIX-only version of these
  562. X#  routines (one which handles padding on archaic terminals).
  563. X#
  564. X##########################################################################
  565. X#
  566. X#  Notes for MS-DOS users:
  567. X#
  568. X#    There are two basic reasons for using the I/O routines
  569. X#  contained in this package.  First, by using a set of generalized
  570. X#  routines, your code will become much more readable.  Secondly, by
  571. X#  using a high level interface, you can avoid the cardinal
  572. X#  programming error of hard coding things like screen length and
  573. X#  escape codes into your programs.
  574. X#
  575. X#    To use this collection of programs, you must do two things.
  576. X#  First, you must add the line "device=ansi.sys" (or the name of some
  577. X#  other driver, like zansi.sys, nansi.sys, or nnansi.sys [=new
  578. X#  nansi.sys]) to your config.sys file.  Secondly, you must add two
  579. X#  lines to your autoexec.bat file: 1) "set TERM=ansi-mono" and 2)
  580. X#  "set TERMCAP=\location\termcap."  The purpose of setting the TERM
  581. X#  variable is to tell this program what driver you are using.  If you
  582. X#  have a color system, you could use "ansi-color" instead of
  583. X#  "ansi-mono," although for compatibility with a broader range of
  584. X#  users, it would perhaps be better to stick with mono.  The purpose
  585. X#  of setting TERMCAP is to make it possible to determine where the
  586. X#  termcap database file is located.  The termcap file (which should
  587. X#  have been packed with this library as termcap.dos) is a short
  588. X#  database of all the escape sequences used by the various terminal
  589. X#  drivers.  Set TERMCAP so that it reflects the location of this file
  590. X#  (which should be renamed as termcap, for the sake of consistency
  591. X#  across UNIX and MS-DOS spectra).  If desired, you can also try
  592. X#  using termcap2.dos.  Certain games work a lot better using this
  593. X#  alternate file.  To try it out, rename it to termcap, and set
  594. X#  the environment variable TERMCAP to its location.
  595. X#
  596. X#    Although the authors make no pretense of providing here a
  597. X#  complete introduction to the format of the termcap database file,
  598. X#  it will be useful, we believe, to explain a few basic facts about
  599. X#  how to use this program in conjunction with it.  If, say, you want
  600. X#  to clear the screen, add the line,
  601. X#
  602. X#    iputs(getval("cl"))
  603. X#
  604. X#  to your program.  The function iputs() outputs screen control
  605. X#  sequences.  Getval retrieves a specific sequence from the termcap
  606. X#  file.  The string "cl" is the symbol used in the termcap file to
  607. X#  mark the code used to clear the screen.  By executing the
  608. X#  expression "iputs(getval("cl"))," you are 1) looking up the "cl"
  609. X#  (clear) code in the termcap database entry for your terminal, and
  610. X#  the 2) outputting that sequence to the screen.
  611. X#
  612. X#    Some other useful termcap symbols are "ce" (clear to end of
  613. X#  line), "ho" (go to the top left square on the screen), "so" (begin
  614. X#  standout mode), and "se" (end standout mode).  To output a
  615. X#  boldfaced string, str, to the screen, you would write -
  616. X#
  617. X#    iputs(getval("so"))
  618. X#    writes(str)
  619. X#    iputs(getval("se"))
  620. X#
  621. X#  You can also write "writes(getval("so") || str || getval("se")),
  622. X#  but this would make reimplementation for UNIX terminals that
  623. X#  require padding rather difficult.
  624. X#
  625. X#    It is also heartily to be recommended that MS-DOS programmers
  626. X#  try not to assume that everyone will be using a 25-line screen.
  627. X#  Most terminals are 24-line.  Some 43.  Some have variable window
  628. X#  sizes.  If you want to put a status line on, say, the 2nd-to-last
  629. X#  line of the screen, then determine what that line is by executing
  630. X#  "getval("li")."  The termcap database holds not only string-valued
  631. X#  sequences, but numeric ones as well.  The value of "li" tells you
  632. X#  how many lines the terminal has (compare "co," which will tell you
  633. X#  how many columns).  To go to the beginning of the second-to-last
  634. X#  line on the screen, type in:
  635. X#
  636. X#    iputs(igoto(getval("cm"), 1, getval("li")-1))
  637. X#
  638. X#  The "cm" capability is a special capability, and needs to be output
  639. X#  via igoto(cm,x,y), where cm is the sequence telling your computer
  640. X#  to move the cursor to a specified spot, x is the column, and y is
  641. X#  the row.  The expression "getval("li")-1" will return the number of
  642. X#  the second-to-last line on your screen.
  643. X#
  644. X##########################################################################
  645. X#
  646. X#  Requires: UNIX or MS-DOS, co-expressions
  647. X#
  648. X#  See also: itlib.icn, iscreen.icn
  649. X#
  650. X##########################################################################
  651. X
  652. X
  653. Xglobal tc_table, isDOS
  654. Xrecord true()
  655. X
  656. X
  657. Xprocedure check_features()
  658. X
  659. X    initial {
  660. X
  661. X    if find("UNIX",&features) then
  662. X        isDOS := &null
  663. X    else if find("MS-DOS", &features) then
  664. X        isDOS := 1
  665. X    else stop("check_features:  OS not (yet?) supported.")
  666. X
  667. X    find("expressi",&features) |
  668. X        er("check_features","co-expressions not implemented - &$#!",1)
  669. X    }
  670. X
  671. X    return
  672. X
  673. Xend
  674. X
  675. X
  676. X
  677. Xprocedure setname(name)
  678. X
  679. X    # Sets current terminal type to "name" and builds a new termcap
  680. X    # capability database (residing in tc_table).  Fails if unable to
  681. X    # find a termcap entry for terminal type "name."  If you want it
  682. X    # to terminate with an error message under these circumstances,
  683. X    # comment out "| fail" below, and uncomment the er() line.
  684. X
  685. X    #tc_table is global
  686. X    
  687. X    check_features()
  688. X
  689. X    tc_table := table()
  690. X    tc_table := maketc_table(getentry(name)) | fail
  691. X    # er("setname","no termcap entry found for "||name,3)
  692. X    return "successfully reset for terminal " || name
  693. X
  694. Xend
  695. X
  696. X
  697. X
  698. Xprocedure getname()
  699. X
  700. X    # Getname() first checks to be sure we're running under DOS or
  701. X    # UNIX, and, if so, tries to figure out what the current terminal
  702. X    # type is, checking successively the value of the environment
  703. X    # variable TERM, and then (under UNIX) the output of "tset -".
  704. X    # Terminates with an error message if the terminal type cannot be
  705. X    # ascertained.  DOS defaults to "mono."
  706. X
  707. X    local term, tset_output
  708. X
  709. X    check_features()
  710. X
  711. X    if \isDOS then {
  712. X        term := getenv("TERM") | "mono"
  713. X    }
  714. X    else {
  715. X    if not (term := getenv("TERM")) then {
  716. X        tset_output := open("/bin/tset -","pr") |
  717. X        er("getname","can't find tset command",1)
  718. X        term := !tset_output
  719. X        close(tset_output)
  720. X    }
  721. X    }
  722. X
  723. X    return \term |
  724. X    er("getname","can't seem to determine your terminal type",1)
  725. X
  726. Xend
  727. X
  728. X
  729. X
  730. Xprocedure er(func,msg,errnum)
  731. X
  732. X    # short error processing utility
  733. X    write(&errout,func,":  ",msg)
  734. X    exit(errnum)
  735. X
  736. Xend
  737. X
  738. X
  739. X
  740. Xprocedure getentry(name, termcap_string)
  741. X
  742. X    # "Name" designates the current terminal type.  Getentry() scans
  743. X    # the current environment for the variable TERMCAP.  If the
  744. X    # TERMCAP string represents a termcap entry for a terminal of type
  745. X    # "name," then getentry() returns the TERMCAP string.  Otherwise,
  746. X    # getentry() will check to see if TERMCAP is a file name.  If so,
  747. X    # getentry() will scan that file for an entry corresponding to
  748. X    # "name."  If the TERMCAP string does not designate a filename,
  749. X    # getentry() will scan the termcap file for the correct entry.
  750. X    # Whatever the input file, if an entry for terminal "name" is
  751. X    # found, getentry() returns that entry.  Otherwise, getentry()
  752. X    # fails.
  753. X
  754. X    local isFILE, f, getline, line, nm, ent1, ent2, entry
  755. X    static slash, termcap_names
  756. X    initial {
  757. X    if \isDOS then {
  758. X        slash := "\\"
  759. X        termcap_names := ["termcap","termcap.dos","termcap2.dos"]
  760. X    }
  761. X    else {
  762. X        slash := "/"
  763. X        termcap_names := ["/etc/termcap"]
  764. X    }
  765. X    }
  766. X
  767. X
  768. X    # You can force getentry() to use a specific termcap file by cal-
  769. X    # ling it with a second argument - the name of the termcap file
  770. X    # to use instead of the regular one, or the one specified in the
  771. X    # termcap environment variable.
  772. X    /termcap_string := getenv("TERMCAP")
  773. X
  774. X    if \isDOS then {
  775. X    if \termcap_string then {
  776. X        if termcap_string ? (
  777. X         not ((tab(any(&letters)), match(":")) | match(slash)),
  778. X         pos(1) | tab(find("|")+1), =name)
  779. X        then {
  780. X        # if entry ends in tc= then add in the named tc entry
  781. X        termcap_string ?:= tab(find("tc=")) ||
  782. X            # Recursively fetch the new termcap entry w/ name trimmed.
  783. X            # Note that on the next time through name won't match the
  784. X            # termcap environment variable, so getentry() will look for
  785. X            # a termcap file.
  786. X            (move(3), getentry(tab(find(":"))) ?
  787. X             (tab(find(":")+1), tab(0)))
  788. X        return termcap_string
  789. X        }
  790. X        else isFILE := 1
  791. X    }
  792. X    }
  793. X    else {
  794. X    if \termcap_string then {
  795. X        if termcap_string ? (
  796. X            not match(slash), pos(1) | tab(find("|")+1), =name)
  797. X        then {
  798. X        # if entry ends in tc= then add in the named tc entry
  799. X        termcap_string ?:= tab(find("tc=")) ||
  800. X            # Recursively fetch the new termcap entry w/ name trimmed.
  801. X            (move(3), getentry(tab(find(":")), "/etc/termcap") ?
  802. X             (tab(find(":")+1), tab(0)))
  803. X        return termcap_string
  804. X        }
  805. X        else isFILE := 1
  806. X    }
  807. X    }
  808. X
  809. X    # The logic here probably isn't clear.  The idea is to try to use
  810. X    # the termcap environment variable successively as 1) a termcap en-
  811. X    # try and then 2) as a termcap file.  If neither works, 3) go to
  812. X    # the /etc/termcap file.  The else clause here does 2 and, if ne-
  813. X    # cessary, 3.  The "\termcap_string ? (not match..." expression
  814. X    # handles 1.
  815. X
  816. X    if \isFILE            # if find(slash, \termcap_string)
  817. X    then f := open(\termcap_string)
  818. X    /f := open(!termcap_names) |
  819. X    er("getentry","I can't access your termcap file.  Read iolib.icn.",1)
  820. X    
  821. X    getline := create read_file(f)
  822. X    
  823. X    while line := @getline do {
  824. X    if line ? (pos(1) | tab(find("|")+1), =name, any(':|')) then {
  825. X        entry := ""
  826. X        while (\line | @getline) ? {
  827. X        if entry ||:= 1(tab(find(":")+1), pos(0))
  828. X        then {
  829. X            close(f)
  830. X            # if entry ends in tc= then add in the named tc entry
  831. X            entry ?:= tab(find("tc=")) ||
  832. X            # recursively fetch the new termcap entry
  833. X            (move(3), getentry(tab(find(":"))) ?
  834. X             # remove the name field from the new entry
  835. X             (tab(find(":")+1), tab(0)))
  836. X            return entry
  837. X        }
  838. X        else {
  839. X            \line := &null # must precede the next line
  840. X            entry ||:= trim(trim(tab(0),'\\'),':')
  841. X        }
  842. X        }
  843. X    }
  844. X    }
  845. X
  846. X    close(f)
  847. X    er("getentry","can't find and/or process your termcap entry",3)
  848. Xend
  849. X
  850. X
  851. X
  852. Xprocedure read_file(f)
  853. X
  854. X    # Suspends all non #-initial lines in the file f.
  855. X    # Removes leading tabs and spaces from lines before suspending
  856. X    # them.
  857. X
  858. X    local line
  859. X
  860. X    \f | er("read_tcap_file","no valid termcap file found",3)
  861. X    while line := read(f) do {
  862. X    match("#",line) & next
  863. X    line ?:= (tab(many('\t ')) | &null, tab(0))
  864. X    suspend line
  865. X    }
  866. X
  867. X    fail
  868. X
  869. Xend
  870. X
  871. X
  872. X
  873. Xprocedure maketc_table(entry)
  874. X
  875. X    # Maketc_table(s) (where s is a valid termcap entry for some
  876. X    # terminal-type): Returns a table in which the keys are termcap
  877. X    # capability designators, and the values are the entries in
  878. X    # "entry" for those designators.
  879. X
  880. X    local k, v, str, decoded_value
  881. X
  882. X    /entry & er("maketc_table","no entry given",8)
  883. X    if entry[-1] ~== ":" then entry ||:= ":"
  884. X    
  885. X    /tc_table := table()
  886. X
  887. X    entry ? {
  888. X
  889. X    tab(find(":")+1)    # tab past initial (name) field
  890. X
  891. X    while tab((find(":")+1) \ 1) ? {
  892. X        &subject == "" & next
  893. X        if k := 1(move(2), ="=") then {
  894. X        # Get rid of null padding information.  Iolib can't
  895. X        # handle it (unlike itlib.icn).  Leave star in.  It
  896. X        # indicates a real dinosaur terminal, and will later
  897. X        # prompt an abort.
  898. X        str := ="*" | ""; tab(many(&digits))
  899. X        decoded_value := Decode(str || tab(find(":")))
  900. X        }
  901. X        else if k := 1(move(2), ="#")
  902. X        then decoded_value := integer(tab(find(":")))
  903. X        else if k := 1(tab(find(":")), pos(-1))
  904. X        then decoded_value := true()
  905. X        else er("maketc_table", "your termcap file has a bad entry",3)
  906. X        /tc_table[k] := decoded_value
  907. X        &null
  908. X    }
  909. X    }
  910. X
  911. X    return tc_table
  912. X
  913. Xend
  914. X
  915. X
  916. X
  917. Xprocedure getval(id)
  918. X
  919. X    /tc_table := maketc_table(getentry(getname())) |
  920. SHAR_EOF
  921. true || echo 'restore of iolib.icn failed'
  922. fi
  923. echo 'End of  part 5'
  924. echo 'File iolib.icn is continued in part 6'
  925. echo 6 > _shar_seq_.tmp
  926. exit 0
  927.  
  928. exit 0 # Just in case...
  929. -- 
  930. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  931. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  932. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  933. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  934.