anchor.diff:    IndexIndex: longint;
     IndexEntry: string;
     IndexEntryWord: string;
  -  Topic: TTopic;
  +  tmpTopic: TTopic;
     IndexEntryWordIndex: longint;
     WordRelevance: longint;
     IndexEntryWordRelevance: longint;
  -begin
  -  for IndexIndex:= 0 to HelpFile.Index.Count - 1 do
  -  begin
  -    Topic:= HelpFile.Index.Objects[ IndexIndex ] as TTopic;
  -    IndexEntry:= HelpFile.Index[ IndexIndex ];
  +  tmpIndexWords : TStringList;
  +  i : integer;
  +begin
  +  tmpIndexWords := TStringList.Create;
  +
  +  for IndexIndex := 0 to HelpFile.Index.Count - 1 do
  +  begin
  +    IndexEntry := HelpFile.Index.GetLabels.ValuePtrs[IndexIndex];
       IndexEntryWordIndex := 0;
  -    while IndexEntry <> '' do
  +
  +    tmpIndexWords.Clear;
  +    StrExtractStringsQuoted(tmpIndexWords, IndexEntry);
  +
  +    for i := 0 to tmpIndexWords.count-1 do
       begin
  -      IndexEntryWord:= ExtractNextValue( IndexEntry, ' ' );
  +      IndexEntryWord := tmpIndexWords[i];
  +
         WordRelevance := CompareWord( SearchWord, IndexEntryWord );
         if WordRelevance > 0 then
         begin
           if IndexEntryWordIndex = 0 then
  +        begin
             // matching the first word is best
  -          IndexEntryWordRelevance := mwFirstIndexWord * WordRelevance
  +          if i = tmpIndexWords.count-1 then
  +          begin
  +            // in fact it's the only word
  +            IndexEntryWordRelevance := mwOnlyIndexWord * WordRelevance
  +          end
  +          else
  +            IndexEntryWordRelevance := mwFirstIndexWord * WordRelevance
  +        end
           else
  +        begin
             IndexEntryWordRelevance := mwIndexWord * WordRelevance;
  -        inc( Results^[ Topic.Index ], IndexEntryWordRelevance );
  +        end;
  +        tmpTopic := HelpFile.Index.getTopic(IndexIndex);
  +        inc( Results^[ tmpTopic.Index ], IndexEntryWordRelevance );
         end;
         inc( IndexEntryWordIndex );
       end;
     end;
  -end;
  -
  -// Utility function used in decompression of search table.
  -// Updates the appropriate entry in Results array.
  -// The word being matched is given in DictIndex and is
  -// used to count the actual occurrences of the word
  -// within the topic
  -{procedure AddTopicFoundInTopicText( TopicIndex: int16;
  -                                    Results: Int32ArrayPointer;
  -                                     DictIndex: longint;
  -                                              WordRelevance: longint );
  -var
  -  Topic: TTopic;
  -  Relevance: longint;
  -begin
  -  Topic:= _Topics[ TopicIndex ];
  -  Relevance := mwTopicTextWord
  -            * Topic.CountWord( DictIndex )
  -            * WordRelevance;
  -  inc( Results^[ TopicIndex ], Relevance );
  -
  -end;}
  +
  +  tmpIndexWords.Free;
  +end;
   
   // ------------------------------------------------------
   
  
positive.code: procedure SearchHelpFile( HelpFile: THelpFile;
                            Query: TTextSearchQuery;
                            Results: TList;
                            HighlightWords: UInt32ArrayPointer );
  var
    Topic: TTopic;
    TopicIndex: longint;
    TermIndex: longint;
    Term: TSearchTerm;
    TopicMatches: UInt32ArrayPointer;
    TopicRelevancesForTerm: UInt32ArrayPointer;
    TopicMatchedTerm: boolean;
  
    WordRelevance: longint;
    DictionaryRelevances: UInt32ArrayPointer;
    DictIndex: longint;
    TopicRelevanceForTerm: longint;
    TopicWordCount: longint;
  begin
    // Reset flags per topic
    for TopicIndex := 0 to HelpFile.TopicCount - 1 do
    begin
      Topic := HelpFile.Topics[ TopicIndex ];
      Topic.FoundInSearch := false;
      Topic.ExcludedInSearch := false;
      Topic.SearchRelevance := 0;
    end;
  
    if HighlightWords <> nil then
      // Clear the highlightwords array
      FillUInt32Array( HighlightWords, HelpFile.DictionaryCount, 0 );
  
    // Get memory for dictionary/topic relevance arrays
    GetMem( DictionaryRelevances, HelpFile.DictionaryCount * sizeof( longint ) );
    GetMem( TopicMatches, HelpFile.TopicCount * sizeof( longint ) );
    GetMem( TopicRelevancesForTerm, HelpFile.TopicCount * sizeof( longint ) );
  
    for TermIndex := 0 to Query.TermCount - 1 do
    begin
      Term := Query.Term[ TermIndex ];
  
      FillUInt32Array( TopicRelevancesForTerm, HelpFile.TopicCount, 0 );
  
      // Search the dictionary for matches.
      SearchDictionary( HelpFile, Term.Text, DictionaryRelevances );
  
      // Update the highlight words array.
      // (effectively an OR)
      if HighlightWords <> nil then
      begin
        if Term.CombineMethod in [ cmAnd, cmOr ] then
        begin
          for DictIndex := 0 to HelpFile.DictionaryCount - 1 do
            inc( HighlightWords^[ DictIndex ],  DictionaryRelevances^[ DictIndex ] );
        end;
      end;
  
      // For each word in the dictionary that matches
      // this search word, search topics/titles/index
      for DictIndex := 0 to HelpFile.DictionaryCount - 1 do
      begin
        WordRelevance := DictionaryRelevances^[ DictIndex ];
        if WordRelevance > 0 then
        begin
          // Search for occurrences of this word
          // within the text of topics
          HelpFile.SearchTable.Search( DictIndex, TopicMatches );
  
          // Work out total relevance for each topic found:
          for TopicIndex := 0 to HelpFile.TopicCount - 1 do
          begin
            if TopicMatches^[ TopicIndex ] > 0 then
            begin
              // Search table indicates word occurs in
              // this topic, so count number of
              // occurrences to get relevance
              Topic := HelpFile.Topics[ TopicIndex ];
  
              TopicWordCount := Topic.CountWord( DictIndex );
              TopicRelevancesForTerm^[ TopicIndex ] := TopicWordCount * WordRelevance;
            end;
          end;
        end;
      end;
  
      // Search titles and index
      SearchTopicTitles( HelpFile, Term.Text, TopicRelevancesForTerm );
      SearchIndex( HelpFile, Term.Text, TopicRelevancesForTerm );
  
      // Set match flags for each topic, marking
      // as found or excluded depending on combine
      // method
      for TopicIndex := 0 to HelpFile.TopicCount - 1 do
      begin
        Topic := HelpFile.Topics[ TopicIndex ];
        TopicRelevanceForTerm := TopicRelevancesForTerm^[ TopicIndex ];
        TopicMatchedTerm := TopicRelevanceForTerm > 0;
        case Term.CombineMethod of
         cmAnd:
           if not TopicMatchedTerm then
             Topic.ExcludedInSearch := true
           else
             Topic.FoundInSearch := true;
  
         cmNot:
           if TopicMatchedTerm then
             Topic.ExcludedInSearch := true;
  
         cmOr:
           if TopicMatchedTerm then
             Topic.FoundInSearch := true;
        end;
        if TopicMatchedTerm then
          inc( Topic.SearchRelevance, TopicRelevanceForTerm );
      end;
  
      // loop for next word...
    end;
  
    // Now find topics that DID have a match
    // and did NOT have an exclusion match
    // ... add the topic to result list
    for TopicIndex := 0 to HelpFile.TopicCount - 1 do
    begin
      Topic := HelpFile.Topics[ TopicIndex ];
      if Topic.FoundInSearch
         and ( not Topic.ExcludedInSearch ) then
      begin
        Results.Add( Topic );
      end;
    end;
  
    FreeMem( TopicRelevancesForTerm, HelpFile.TopicCount * sizeof( longint ) );
    FreeMem( TopicMatches, HelpFile.TopicCount * sizeof( longint ) );
    FreeMem( DictionaryRelevances, HelpFile.DictionaryCount * sizeof( longint ) );
  end;
  
  function ExtractNextIPFWordPart( var Word: string ): string;
  var
    CharIndex: longint;
  begin
    assert( Length( Word ) > 0 );
    CharIndex := 2;
    if IsDigit( Word[ 1 ] ) then
    begin
      // extract string of digits
      while CharIndex <= Length( Word ) do
      begin
        if not IsDigit( Word[ CharIndex ] ) then
          break;
        inc( CharIndex );
      end;
    end
    else if IsAlpha( Word[ 1 ] ) then
    begin
      // extract string of letters
      while CharIndex <= Length( Word ) do
      begin
        if not IsAlpha( Word[ CharIndex ] ) then
          break;
        inc( CharIndex );
      end;
    end
    else
    begin
      // extract single non-alphanumeric symbol
    end;
    assert( CharIndex > 1 );
    Result := Copy(Word, 0, CharIndex-1);
  //  Result := StrLeft( Word, CharIndex - 1 );
    Delete( Word, 1, CharIndex - 1 )
  end;
  
  Initialization
  End.
  
negative.code: {$mode objfpc}{$H+}
  
  // NewView - a new OS/2 Help Viewer
  // Copyright 2003 Aaron Lawrence (aaronl at consultant dot com)
  // This software is released under the Gnu Public License - see readme.txt
  
  Interface
  