home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / OUT18.ZIP / INDEXLIB.INC < prev    next >
Encoding:
Text File  |  1986-04-13  |  9.2 KB  |  333 lines

  1.  
  2. (*
  3.  * indexlib.inc - library for document indexing
  4.  *
  5.  * Author: S.H.Smith, 11-Apr-86
  6.  *
  7.  *)
  8.  
  9.  
  10. (*
  11.  * Package specification
  12.  *
  13.  *)
  14.  
  15. {----------------------------------------------------
  16.  --                                                --
  17.  --            Index package data                  --
  18.  --                                                --
  19.  ----------------------------------------------------}
  20.  
  21. type phrase_ptr = ^phrase_string;
  22.      phrase_string = string[45];    {longest phrase that can be indexed}
  23.  
  24. type page_number = 0..255;          {legal page numbers}
  25.  
  26. const max_pages = 20;               {number of pages on which a phrase
  27.                                      can be used}
  28.  
  29. type page_list_index = 0..max_pages;
  30. type page_list = array [page_list_index] of page_number;
  31.  
  32. type index_node = ^index_node_rec;
  33.      index_node_rec = record
  34.         word:    phrase_ptr;        {pointer to the word or phrase}
  35.         count:   page_list_index;   {number of pages where word is used}
  36.         pages:   page_list;         {list of pages where word is used}
  37.         higher:  index_node;        {all higher sort order words}
  38.         lower:   index_node;        {all lower sort order words}
  39.      end;
  40.  
  41.  
  42. var index_root: index_node;         {the root of the index}
  43.  
  44. var longest_word: integer;          {the longest word in the index}
  45.  
  46.  
  47.  
  48. {----------------------------------------------------
  49.  --                                                --
  50.  --        Index creation and disposal             --
  51.  --                                                --
  52.  ----------------------------------------------------}
  53.  
  54. procedure init_index;
  55.    {-- initialize index for operation}
  56.    forward;
  57.  
  58. procedure dispose_index;
  59.    {-- dispose of the current index data and release the memory
  60.     -- used by it}
  61.    forward;
  62.  
  63.  
  64.  
  65. {----------------------------------------------------
  66.  --                                                --
  67.  --        Index building and output               --
  68.  --                                                --
  69.  ----------------------------------------------------}
  70.  
  71. procedure index_word(word: phrase_string; on_page: page_number);
  72.    {-- associate a word or phrase with a page number}
  73.    forward;
  74.  
  75. procedure output_index(var tofile: textfile);
  76.    {-- prepare and output the index to a text file}
  77.    forward;
  78.  
  79.  
  80.  
  81. (****************************************************
  82.  *
  83.  * End of package specification
  84.  *
  85.  * Start of package body
  86.  *
  87.  *)
  88.  
  89.  
  90. {----------------------------------------------------
  91.  --                                                --
  92.  --        Private internal procedures             --
  93.  --                                                --
  94.  ----------------------------------------------------}
  95.  
  96. function string_save (word: phrase_string): phrase_ptr;
  97.    {-- allocate space for a phrase on the heap and
  98.     -- return a pointer to it.  allocates only enough
  99.     -- space as is needed.}
  100. var
  101.    buf:  phrase_ptr;
  102. begin
  103.  
  104.    if length(word) > longest_word then
  105.       longest_word := length(word);
  106.  
  107.    getmem(buf,length(word)+1);
  108.    buf^ := word;
  109.    string_save := buf;
  110. end;
  111.  
  112.  
  113.  
  114. {----------------------------------------------------
  115.  --                                                --
  116.  --        Index creation and disposal             --
  117.  --                                                --
  118.  ----------------------------------------------------}
  119.  
  120. procedure init_index;
  121.    {-- initialize index for operation}
  122. begin
  123.    new(index_root);
  124.  
  125.    with index_root^ do
  126.    begin
  127.       word := string_save('Root');
  128.       count := 0;
  129.       pages[0] := 0;
  130.       higher := nil;
  131.       lower := nil;
  132.    end;
  133.  
  134.    longest_word := 0;
  135. end;
  136.  
  137.  
  138. procedure dispose_index;
  139.    {-- dispose of the current index data and release the memory
  140.     -- used by it}
  141.  
  142.    procedure dispose_node(var node: index_node);
  143.       {-- dispose of an index node and all of the
  144.        -- subordinate nodes; sets the node to nil}
  145.    begin
  146.       if node <> nil then
  147.       begin
  148.          dispose_node(node^.higher);
  149.          dispose_node(node^.lower);
  150.          freemem(node^.word,length(node^.word^)+1);
  151.          dispose(node);
  152.          node := nil;
  153.       end;
  154.    end;
  155.  
  156. begin
  157.    dispose_node(index_root);
  158. end;
  159.  
  160.  
  161.  
  162. {----------------------------------------------------
  163.  --                                                --
  164.  --        Index building                          --
  165.  --                                                --
  166.  ----------------------------------------------------}
  167.  
  168. procedure index_word {(word: phrase_string; on_page: page_number)};
  169.    {-- associate a word or phrase with a page number}
  170.  
  171.    procedure index_node (var node: index_node);
  172.       {-- search for and update the proper node}
  173.  
  174.    begin
  175.       if node = nil then           {create a new node, if needed}
  176.       begin
  177.          new(node);
  178.          node^.word := string_save(word);
  179.          node^.count := 1;
  180.          node^.pages[1] := on_page;
  181.          node^.higher := nil;
  182.          node^.lower := nil;
  183.       end
  184.       else
  185.  
  186.       if word = node^.word^ then   {if the phrase has been found, update its
  187.                                     page list with on_page and exit}
  188.       begin
  189.          if (node^.pages[node^.count] <> on_page) then
  190.             if node^.count < max_pages then
  191.                node^.count := node^.count + 1
  192.             else
  193.                on_page := 255;     {too many page references}
  194.  
  195.          node^.pages[node^.count] := on_page;
  196.       end
  197.       else
  198.  
  199.       if word > node^.word^ then
  200.          index_node(node^.higher)    {search up the higher branch}
  201.       else
  202.          index_node(node^.lower);    {search down the lower branch}
  203.    end;
  204.  
  205. begin
  206.    word[1] := upcase(word[1]);    {force first word of all index entries
  207.                                    to be upper case}
  208.  
  209.    index_node(index_root);        {search for and update a node, starting
  210.                                    at the root of the index}
  211. end;
  212.  
  213.  
  214.  
  215.  
  216. {----------------------------------------------------
  217.  --                                                --
  218.  --        Index output formatting                 --
  219.  --                                                --
  220.  ----------------------------------------------------}
  221.  
  222. procedure output_index {(var tofile: textfile)};
  223.    {-- prepare and output the index to a text file}
  224.  
  225. var
  226.    outpos:  integer;
  227.    pletter: char;
  228.  
  229.  
  230.    procedure output_node (node: index_node);
  231.       {-- format and output a node in the index; recursively
  232.        -- outputs all higher and lower branching nodes}
  233.  
  234.       procedure output_number(n: page_number);
  235.          {-- output a single page number and adjust output position}
  236.       begin
  237.          case n of
  238.             0..9:   outpos := outpos + 1;
  239.             10..99: outpos := outpos + 2;
  240.             else    outpos := outpos + 3;
  241.          end;
  242.          write(tofile, n);
  243.       end;
  244.  
  245.       procedure output_node_page_list;
  246.          {-- output the page list for a single node}
  247.       var
  248.          i:       page_list_index;
  249.          prev:    page_list_index;
  250.  
  251.       begin
  252.          prev := 0;
  253.          i := 1;
  254.  
  255.          with node^ do
  256.          while i <= count do
  257.          begin
  258.             prev := i;         {locate page number ranges}
  259.  
  260.             while (i < count) and (pages[i]+1 = pages[i+1]) do
  261.                i := i + 1;
  262.  
  263.             if prev = i then       {output single page number}
  264.                output_number(pages[i])
  265.             else
  266.             begin                  {output a range of page numbers}
  267.                output_number(pages[prev]);
  268.                write(tofile,'-');
  269.                outpos := outpos + 1;
  270.                output_number(pages[i]);
  271.             end;
  272.  
  273.             if i < node^.count then
  274.             begin                 {insert , delimiter if needed}
  275.                write(tofile,', ');
  276.                outpos := outpos + 2;
  277.  
  278.                if (outpos > 70) then
  279.                begin              {start a new line if needed}
  280.                   writeln(tofile);
  281.                   write(tofile,'':longest_word+8);
  282.                   outpos := longest_word+8;
  283.                end;
  284.             end;
  285.  
  286.             i := i + 1;
  287.          end;
  288.  
  289.          writeln(tofile);
  290.       end;
  291.  
  292.  
  293.    begin   {output_node}
  294.  
  295.       if node <> nil then
  296.       begin
  297.          output_node(node^.lower);      {output all lower words}
  298.  
  299.          if node^.count > 0 then
  300.          begin
  301.             if pletter <> node^.word^[1] then
  302.             begin                       {start new section for each letter}
  303.                pletter := node^.word^[1];
  304.                writeln(tofile);
  305.                writeln(tofile,pletter);
  306.             end;
  307.  
  308.             write(tofile,'   ',node^.word^);
  309.             outpos := 3 + length(node^.word^);
  310.  
  311.             for outpos := outpos+1 to longest_word+8 do
  312.                if odd(outpos) then      {output the word and ...s}
  313.                   write(tofile,'.')
  314.                else
  315.                   write(tofile,' ');
  316.  
  317.             output_node_page_list;
  318.          end;
  319.  
  320.          output_node(node^.higher);     {output all higher words}
  321.       end;
  322.    end;
  323.  
  324. begin
  325.    pletter := #0;
  326.    if odd(longest_word) then
  327.       longest_word := longest_word + 1;
  328.  
  329.    output_node(index_root);
  330. end;
  331.  
  332.  
  333.