Пример #1
0
VOID
PrintStringList (
    IN STRING_LIST       *StringList
)
/*++

Routine Description:

  Prints out the string list

Arguments:

  StringList        The string list to print

Returns:

  EFI_STATUS

--*/
{
    CHAR8* String;
    String = StringListToString (StringList);
    if (String != NULL) {
        printf ("%s", String);
        free (String);
    }
}
////////////////////////////////////////////
// OnExecute
// Demonstrate:
// IDirectorySearch::ExecuteSearch
// IDirectorySearch::GetNextRow
// IDirectorySearch::GetColumn
// IDirectorySearch::SetSearchPreference
//
/////////////////////////////////////////////
void CDlgIDirectorySearch::OnExecute() 
{
	ASSERT( m_pSearch );
	CWaitCursor wait;
	
	UpdateData(TRUE); // Get data from the Dialog Box
	HRESULT hr;
	ADS_SEARCH_HANDLE hSearch;
	ADS_SEARCH_COLUMN col;
	CString s;
	int idx=0;
	int nCount;
	LPWSTR *pszAttr=NULL;
	POSITION pos;
	USES_CONVERSION;


	


	/////////////////////////////////
	// Reset the Total Number
	//////////////////////////////////
	SetDlgItemText( IDC_TOTAL, _T(""));


	/////////////////////////////////////////////
	// Get the attribute list, and preparing..
	///////////////////////////////////////////
	CStringList sAttrList;
	m_cListView.DeleteAllItems(); // Reset the UI

    while( m_cListView.DeleteColumn(0))
	{
		;
	}

	//////////////////////////////////////////////////
	// Preparing for attribute list
	// and columns to display
	CString sTemp;
	m_cAttrList.GetWindowText(s);

	// we need to add adspath, so that we can refer to this object later when user dblclk the item
	if ( !s.IsEmpty() )
	{
		sTemp = s;
		sTemp.MakeLower();
		if ( s.Find(_T("adspath"),0) == -1 )
		{
			s += _T(",ADsPath");
		}
	}

	// convert to string list for easy manipulation
	StringToStringList( s, sAttrList );



	nCount = sAttrList.GetCount();
	idx=0;
	if ( nCount )
	{
		
		pszAttr = (LPWSTR*) AllocADsMem( nCount * sizeof(LPWSTR));
	
		pos = sAttrList.GetHeadPosition();
		while ( pos != NULL )
		{
			s = sAttrList.GetAt(pos);
			pszAttr[idx] = T2OLE(s);
			sAttrList.GetNext(pos );
			idx++;
		}
	}
	else
	{
		nCount = -1;
	}






	/////////////////////////////////////////
	// BEGIN  Set the preferences
	///////////////////////////////////////
	DWORD dwCountPref = 0;
	ADS_SEARCHPREF_INFO prefInfo[ MAX_SEARCH_PREF ];
	ADS_SORTKEY *pSortKey = NULL;

	if ( m_bEnableFilter == FALSE )
	{
		// Reset the preference
		m_pSearch->SetSearchPreference( prefInfo, dwCountPref );
	}
	else // Preferences are specified
	{
		////////////////////////
		// Timeout Pref
		////////////////////////////
		if ( m_nTimeOut != 0 )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_TIMEOUT;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			prefInfo[dwCountPref].vValue.Integer = m_nTimeOut;
			dwCountPref++;
		}

		//////////////////////////////
		// Search Scope
		/////////////////////////////
		idx = m_CADsSearchScope.GetCurSel();
		if ( idx != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			prefInfo[dwCountPref].vValue.Integer = idx;
			dwCountPref++;
		}



		///////////////////////////////////////////////////
		// Cache Result. The default is to cache the result
		/////////////////////////////////////////////////
		if ( !m_bCacheResult )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
			prefInfo[dwCountPref].vValue.Boolean = FALSE;
			dwCountPref++;
		}

		//////////////////////////////////////////////////
		// Page Size
		///////////////////////////////////////////////////
		if ( m_nPageSize > 0 )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;;
			prefInfo[dwCountPref].vValue.Integer = m_nPageSize;
			dwCountPref++;
		}


		////////////////////////////////////////////////
		// Chase Referrals
		///////////////////////////////////////////////
		idx = m_cChaseReferrals.GetCurSel();
		if ( idx != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_CHASE_REFERRALS;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
			switch( idx )
			{
			case 0:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_NEVER; 
				 break;
			case 1:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_SUBORDINATE;
				 break;
			case 2:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
				 break;
			default:
				 prefInfo[dwCountPref].vValue.Integer = ADS_CHASE_REFERRALS_EXTERNAL;
				 
			}
			
			dwCountPref++;
		}


		///////////////////////////////////////////////
		// Sort On
		////////////////////////////////////////////////
		if ( !m_sSortOn.IsEmpty() )
		{
			CStringList sList;
			UINT nCount;
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SORT_ON;
			prefInfo[dwCountPref].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
  			StringToStringList( m_sSortOn, sList );

			nCount = sList.GetCount();
			if ( nCount >  0 )
			{
				POSITION pos;
				pos= sList.GetHeadPosition();
				pSortKey = (ADS_SORTKEY *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(ADS_SORTKEY) * nCount );
				idx = 0;
				while( pos != NULL )
				{
					pSortKey[idx].pszAttrType = T2OLE(sList.GetAt(pos));
					pSortKey[idx].pszReserved = NULL;
					pSortKey[idx].fReverseorder =0;

					// Next
					idx++;
					sList.GetNext( pos );
				}
				
				prefInfo[dwCountPref].vValue.ProviderSpecific.dwLength = sizeof(ADS_SORTKEY) * nCount;
				prefInfo[dwCountPref].vValue.ProviderSpecific.lpValue = (LPBYTE) pSortKey;
				dwCountPref++;
			}

		}

		//////////////////////////////////////////////
		// Size Limit
		//////////////////////////////////////////////
		if ( m_nSizeLimit > 0 )
		{
            prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_SIZE_LIMIT;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
            prefInfo[dwCountPref].vValue.Integer = m_nSizeLimit;
			dwCountPref++;
		}


		//////////////////////////////////////////////////
		// A Synchronous
		///////////////////////////////////////////////////
		if ( m_bAsynch )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
            prefInfo[dwCountPref].vValue.Integer = TRUE;
			dwCountPref++;

		}

		/////////////////////////////////////////////////////
		//  Attribute Type Only
		//////////////////////////////////////////////////////
		if ( m_bAttrib )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_ATTRIBTYPES_ONLY;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_BOOLEAN;
            prefInfo[dwCountPref].vValue.Integer = TRUE;
			dwCountPref++;

		}


		/////////////////////////////////////////////////////
		//  Derefence Alias
		//////////////////////////////////////////////////////
		if ( m_nDeref != CB_ERR )
		{
			prefInfo[dwCountPref].dwSearchPref = ADS_SEARCHPREF_DEREF_ALIASES;
            prefInfo[dwCountPref].vValue.dwType = ADSTYPE_INTEGER;
            prefInfo[dwCountPref].vValue.Integer = m_nDeref;
			dwCountPref++;


		}



		///////////////////////////////////////////////
		// Now Set the selected preferences
		//////////////////////////////////////////////
		hr = m_pSearch->SetSearchPreference( prefInfo, dwCountPref );


		
	}

	/////////////////////////////////////////
	// END  Set the preferences
	///////////////////////////////////////





	////////////////////////////////////////
	// Execute the Search
	//////////////////////////////////////
	DWORD dwCount=0;

	hr = m_pSearch->ExecuteSearch(T2OLE(m_sFilter), pszAttr, nCount, &hSearch );


	////////////////////////////////
	//// cleanup
	////////////////////////////////
	if ( pszAttr ) 
	{
  		FreeADsMem( pszAttr );
	}
	
	if ( pSortKey )
	{
		LocalFree( pSortKey );
	}




	if ( !SUCCEEDED(hr) )
	{
		AfxMessageBox(GetErrorMessage(hr));
		return;
	}

	////////////////////////////////////////////////////////
	// Enumerate the rows
	////////////////////////////////////////////////////////

	sAttrList.RemoveAll();

	

	
	/////////////////////////////////////////////////////////
	// Retrieve the column names returned from the server
	///////////////////////////////////////////////////////////
	LPWSTR pszColumn;
	hr = m_pSearch->GetFirstRow( hSearch );

	if ( !SUCCEEDED(hr) )
	{
		return;
	}
	
	

	idx=0;
	while( (hr=m_pSearch->GetNextColumnName( hSearch, &pszColumn )) != S_ADS_NOMORE_COLUMNS )
	{
		s = OLE2T( pszColumn );
		m_cListView.InsertColumn(idx, s, LVCFMT_LEFT, 150 ); // adding columns to the UI	
		sAttrList.AddTail(s);
		FreeADsMem( pszColumn );
		idx++;
	}



	/////////////////////////////////////////////
	// Start iterating the result set
	////////////////////////////////////////////
	int nCol;
	CStringList sValueList;

    do 
	{
		nCol=0;
		pos = sAttrList.GetHeadPosition();

		while( pos != NULL )
		{
		
		    s = sAttrList.GetAt(pos); //column name

			// Get the Name and display it in the list 
			hr = m_pSearch->GetColumn( hSearch, T2OLE(s), &col );
			if ( SUCCEEDED(hr) )
			{
				s =_T("");
				
				if ( col.dwADsType != ADSTYPE_INVALID ) // if we request for attrib only, no value will be returned
				{
					ADsToStringList(col.pADsValues, col.dwNumValues, sValueList );
					StringListToString( sValueList, s );
				}
	
				if ( nCol )
				{
					m_cListView.SetItemText(0,nCol, s);
				}
				else
				{
				   m_cListView.InsertItem(0, s);
				}
				
				m_pSearch->FreeColumn( &col );
			}


			

			nCol++;
			sAttrList.GetNext(pos);

		}
		dwCount++;
		/////////////////////////////
		//Display the total so far
		////////////////////////////////
		s.Format("%ld object(s)", dwCount );
		SetDlgItemText( IDC_TOTAL, s );
	
	} 
	while( (hr=m_pSearch->GetNextRow( hSearch)) != S_ADS_NOMORE_ROWS );	 

	

	m_pSearch->CloseSearchHandle( hSearch ); 



	


}
void    getdefaults(SWISH * sw, char *conffile, int *hasdir, int *hasindex, int hasverbose)
{
    int     i,
            gotdir,
            gotindex;
    char   *line = NULL;
    FILE   *fp;
    int     linenumber = 0;
    int     baddirective = 0;
    StringList *sl;
    IndexFILE *indexf = NULL;
    unsigned char *StringValue = NULL;
    struct swline *tmplist;
    char   *w0;

    gotdir = gotindex = 0;

    if ((fp = fopen(conffile, F_READ_TEXT)) == NULL || !isfile(conffile))
        progerrno("Couldn't open the configuration file '%s': ", conffile);

    if ( sw->verbose >= 2 )
        printf("Parsing config file '%s'\n", conffile );


    /* Init default index file */
    addindexfile(sw, INDEXFILE);
    indexf = sw->indexlist;



    sl = NULL;

    while ( !feof( fp ) )
    {
        /* Free previous line */
        if ( line )
            efree( line );

        /* Read a line */
        line = read_line_from_file( &linenumber, fp );

        if ( sl )
            freeStringList(sl);

        /* Parse line */
        if (!(sl = parse_line(line)))
            continue;

        if (!sl->n)
            continue;

        w0 = sl->word[0];       /* Config Direct. = 1. word */

        if (w0[0] == '#')
            continue;           /* comment */



        if (strcasecmp(w0, "IndexDir") == 0)
        {
            if (sl->n > 1)
            {
                if (!*hasdir)
                {
                    gotdir = 1;
                    grabCmdOptions(sl, 1, &sw->dirlist);
                }
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        if (strcasecmp(w0, "IncludeConfigFile") == 0)
        {
            if (sl->n == 2)
            {
                normalize_path( sl->word[1] );
                getdefaults(sw, sl->word[1], hasdir, hasindex, hasverbose);
            }
            else
                progerr("%s: requires one value", w0);

            continue;
        }


        if (strcasecmp(w0, "NoContents") == 0)
        {
            if (sl->n > 1)
            {
                grabCmdOptions(sl, 1, &sw->nocontentslist);
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexFile") == 0)
        {
            if (!(*hasindex))
            {
                if (sl->n == 2)
                {
                    gotindex = 1;
                    if (indexf->line)
                        efree(indexf->line);
                    indexf->line = estrdup(sl->word[1]);
                    normalize_path( indexf->line );
                }
                else
                    progerr("%s: requires one value", w0);
            }

            continue;
        }


        if (strcasecmp(w0, "IndexReport") == 0)
        {
            if (sl->n == 2)
            {
                if (!hasverbose)
                    sw->verbose =  read_integer( sl->word[1], w0, 0, 4 );
            }
            else
                progerr("%s: requires one value", w0);
            continue;
        }

        if (strcasecmp(w0, "ParserWarnLevel") == 0)
        {
            if (sl->n == 2)
                sw->parser_warn_level = read_integer( sl->word[1], w0, 0, 9 );
            else
                progerr("%s: requires one value", w0);
            continue;
        }


        if (strcasecmp(w0, "obeyRobotsNoIndex") == 0)
        {
            sw->obeyRobotsNoIndex = getYesNoOrAbort(sl, 1, 1);
            continue;
        }


        if (strcasecmp(w0, "AbsoluteLinks") == 0)
        {
            sw->AbsoluteLinks = getYesNoOrAbort(sl, 1, 1);
            continue;
        }




        if (strcasecmp(w0, "MinWordLimit") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.minwordlimit = read_integer( sl->word[1], w0, 0, INT_MAX );
            }
            else
                progerr("%s: requires one value", w0);
            continue;
        }

        if (strcasecmp(w0, "MaxWordLimit") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.maxwordlimit = read_integer( sl->word[1], w0, 0, INT_MAX );
            }
            else
                progerr("%s: requires one value", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexComments") == 0)
        {
            sw->indexComments = getYesNoOrAbort(sl, 1, 1);
            continue;
        }


        if (strcasecmp(w0, "IgnoreNumberChars") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.numberchars = SafeStrCopy(indexf->header.numberchars, sl->word[1], &indexf->header.lennumberchars);
                sortstring(indexf->header.numberchars);
                makelookuptable(indexf->header.numberchars, indexf->header.numbercharslookuptable);
                indexf->header.numberchars_used_flag = 1;  /* Flag that it is used */
            }
            else
                progerr("%s: requires one value (a set of characters)", w0);

            continue;
        }


        if (strcasecmp(w0, "WordCharacters") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.wordchars = SafeStrCopy(indexf->header.wordchars, sl->word[1], &indexf->header.lenwordchars);
                sortstring(indexf->header.wordchars);
                makelookuptable(indexf->header.wordchars, indexf->header.wordcharslookuptable);
            }
            else
                progerr("%s: requires one value", w0);

            continue;
        }


        if (strcasecmp(w0, "BeginCharacters") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.beginchars = SafeStrCopy(indexf->header.beginchars, sl->word[1], &indexf->header.lenbeginchars);
                sortstring(indexf->header.beginchars);
                makelookuptable(indexf->header.beginchars, indexf->header.begincharslookuptable);
            }
            else
                progerr("%s: requires one value", w0);
            continue;
        }

        if (strcasecmp(w0, "EndCharacters") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.endchars = SafeStrCopy(indexf->header.endchars, sl->word[1], &indexf->header.lenendchars);
                sortstring(indexf->header.endchars);
                makelookuptable(indexf->header.endchars, indexf->header.endcharslookuptable);
            }
            else
                progerr("%s: requires one value", w0);

            continue;
        }


        if (strcasecmp(w0, "IgnoreLastChar") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.ignorelastchar = SafeStrCopy(indexf->header.ignorelastchar, sl->word[1], &indexf->header.lenignorelastchar);
                sortstring(indexf->header.ignorelastchar);
                makelookuptable(indexf->header.ignorelastchar, indexf->header.ignorelastcharlookuptable);
            }                   /* Do nothing */
            /* else progerr("%s: requires one value",w0); */

            continue;
        }

        if (strcasecmp(w0, "IgnoreFirstChar") == 0)
        {
            if (sl->n == 2)
            {
                indexf->header.ignorefirstchar = SafeStrCopy(indexf->header.ignorefirstchar, sl->word[1], &indexf->header.lenignorefirstchar);
                sortstring(indexf->header.ignorefirstchar);
                makelookuptable(indexf->header.ignorefirstchar, indexf->header.ignorefirstcharlookuptable);
            }                   /* Do nothing */
            /*  else progerr("%s: requires one value",w0); */

            continue;
        }


        if (strcasecmp(w0, "ReplaceRules") == 0)
        {
            if (sl->n > 2)
                Build_ReplaceRules( w0, sl->word, &sw->replaceRegexps );
            else
                progerr("%s: requires at least two values", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexName") == 0)
        {
            if (sl->n > 1)
            {
                StringValue = StringListToString(sl, 1);
                indexf->header.indexn = SafeStrCopy(indexf->header.indexn, (char *)StringValue, &indexf->header.lenindexn);
                efree(StringValue);
            }
            else
                progerr("%s: requires a value", w0);
            continue;
        }


        if (strcasecmp(w0, "IndexDescription") == 0)
        {
            if (sl->n > 1)
            {
                StringValue = StringListToString(sl, 1);
                indexf->header.indexd = SafeStrCopy(indexf->header.indexd, (char *)StringValue, &indexf->header.lenindexd);
                efree(StringValue);
            }
            else
                progerr("%s: requires a value", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexPointer") == 0)
        {
            if (sl->n > 1)
            {
                StringValue = StringListToString(sl, 1);
                indexf->header.indexp = SafeStrCopy(indexf->header.indexp, (char *)StringValue, &indexf->header.lenindexp);
                efree(StringValue);
            }
            else
                progerr("%s: requires a value", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexAdmin") == 0)
        {
            if (sl->n > 1)
            {
                StringValue = StringListToString(sl, 1);
                indexf->header.indexa = SafeStrCopy(indexf->header.indexa, (char *)StringValue, &indexf->header.lenindexa);
                efree(StringValue);
            }
            else
                progerr("%s: requires one value", w0);

            continue;
        }


        if (strcasecmp(w0, "UseStemming") == 0)
        {
            progwarn("UseStemming is deprecated.  See FuzzyIndexingMode in the docs");
            if ( getYesNoOrAbort(sl, 1, 1) )
                fuzzy_or_die( indexf, "Stemming_en" );

            continue;
        }

        if (strcasecmp(w0, "UseSoundex") == 0)
        {
            if ( getYesNoOrAbort(sl, 1, 1) )
                fuzzy_or_die( indexf, "Soundex" );

            continue;
        }


        if (strcasecmp(w0, "FuzzyIndexingMode") == 0)
        {
            if (sl->n != 2)
                progerr("%s: requires one value", w0);

            fuzzy_or_die( indexf, sl->word[1] );
            continue;
        }



        if (strcasecmp(w0, "IgnoreTotalWordCountWhenRanking") == 0)
        {
            indexf->header.ignoreTotalWordCountWhenRanking = getYesNoOrAbort(sl, 1, 1);
            continue;
        }



        if (strcasecmp(w0, "TranslateCharacters") == 0)
        {
            if (sl->n >= 2)
            {
                if (!BuildTranslateChars(indexf->header.translatecharslookuptable, (unsigned char *)sl->word[1], (unsigned char *)sl->word[2]))
                {
                    progerr("%s: requires two values (same length) or one translation rule", w0);
                }
            }
            continue;
        }


        if (strcasecmp(w0, "ExtractPath") == 0)
        {
            struct metaEntry *m;
            char **words;

            if (sl->n < 4)
                progerr("%s: requires at least three values: metaname expression type and a expression/strings", w0);

            if ( !( m = getMetaNameByName( &indexf->header, sl->word[1])) )
                m = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0);

            words = sl->word;
            words++;  /* past metaname */
            add_ExtractPath( w0, sw, m, words );

            continue;
        }

        if (strcasecmp(w0, "ExtractPathDefault") == 0)
        {
            struct metaEntry *m;

            if (sl->n != 3)
                progerr("%s: requires two values: metaname default_value", w0);

            if ( !( m = getMetaNameByName( &indexf->header, sl->word[1])) )
                m = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0);

            if ( m->extractpath_default )
                progerr("%s already defined for meta '%s' as '%s'", w0, m->metaName, m->extractpath_default );

            m->extractpath_default = estrdup( sl->word[2] );

            continue;
        }




        if (strcasecmp(w0, "MetaNames") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( getMetaNameByName( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a MetaName", w0, sl->word[i] );

                addMetaEntry(&indexf->header, sl->word[i], META_INDEX, 0);
            }

            continue;
        }



        if (strcasecmp(w0, "MetaNameAlias") == 0)
        {
            struct metaEntry *meta_entry;
            struct metaEntry *new_meta;

            if (sl->n < 3)
                progerr("%s: requires at least two values", w0);


            /* Make sure first entry is not an alias */
            /* Lookup entry, and do not follow alias */
            if ( !(meta_entry = getMetaNameByNameNoAlias( &indexf->header, sl->word[1]) ) )
                progerr("%s - name '%s' not a MetaName", w0, sl->word[1] );


            if ( meta_entry->alias )
                progerr("%s - name '%s' must not be an alias", w0, sl->word[1] );


            for (i = 2; i < sl->n; i++)
            {
                if ( getMetaNameByNameNoAlias( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a MetaName or MetaNameAlias", w0, sl->word[i] );

                new_meta = addMetaEntry(&indexf->header, sl->word[i], meta_entry->metaType, 0);
                new_meta->alias = meta_entry->metaID;
            }

            continue;
        }


        /* Allow setting a bias on MetaNames */

        if (strcasecmp(w0, "MetaNamesRank") == 0)
        {
            struct metaEntry *meta_entry;
            int               rank = 0;

            if (sl->n < 3)
                progerr("%s: requires only two or more values, a rank (integer) and a list of property names", w0);


            rank = read_integer( sl->word[1], w0, -RANK_BIAS_RANGE, RANK_BIAS_RANGE  );  // NOTE: if this is changed db.c must match


            for (i = 2; i < sl->n; i++)
            {
                /* already exists? */
                if ( (meta_entry = getMetaNameByNameNoAlias( &indexf->header, sl->word[i])) )
                {
                    if ( meta_entry->alias )
                        progerr("Can't assign a rank to metaname '%s': it is an alias", meta_entry->metaName );

                    if ( meta_entry->rank_bias )
                        progwarn("Why are you redefining the rank of metaname '%s'?", meta_entry->metaName );
                }
                else
                    meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_INDEX, 0);


                meta_entry->rank_bias = rank;
            }

            continue;
        }





        /* Meta name to extract out <a href> links */
        if (strcasecmp(w0, "HTMLLinksMetaName") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires one value", w0);

            if ( !( sw->links_meta = getMetaNameByName( &indexf->header, sl->word[1]) ))
                sw->links_meta = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0);

            continue;
        }


        /* What to do with IMG ATL tags? */
        if (strcasecmp(w0, "IndexAltTagMetaName") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires one value", w0);

            if ( strcasecmp( sl->word[1], "as-text" ) == 0)
            {
                sw->IndexAltTag = 1;
                if ( sw->IndexAltTagMeta )
                {
                    efree( sw->IndexAltTagMeta );
                    sw->IndexAltTagMeta = NULL;
                }
            }
            else
            {
                sw->IndexAltTag = 1;
                if ( sw->IndexAltTagMeta )
                {
                    efree( sw->IndexAltTagMeta );
                    sw->IndexAltTagMeta = NULL;
                }
                sw->IndexAltTagMeta = estrdup( sl->word[1] );
            }
            continue;
        }




        /* Meta name to extract out <img src> links */
        if (strcasecmp(w0, "ImageLinksMetaName") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires one value", w0);

            if ( !( sw->images_meta = getMetaNameByName( &indexf->header, sl->word[1]) ))
                sw->images_meta = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0);

            continue;
        }





        if (strcasecmp(w0, "PropCompressionLevel") == 0)
        {

#ifdef HAVE_ZLIB
            if (sl->n == 2)
            {
                sw->PropCompressionLevel = read_integer( sl->word[1], w0, 0, 9 );
            }
            else
                progerr("%s: requires one value", w0);
#else
            progwarn("%s: Swish not built with zlib support -- cannot compress", w0);
#endif
            continue;
        }




        if (strcasecmp(w0, "PropertyNames") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( getPropNameByName( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] );

                addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0);
            }

            continue;
        }


        if (strcasecmp(w0, "PropertyNamesIgnoreCase") == 0)
        {
            struct metaEntry *m;

            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) )
                    addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0);
                else
                {
                    if ( !is_meta_string( m ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );

                    m->metaType |= META_IGNORE_CASE;
                }
            }

            continue;
        }



        if (strcasecmp(w0, "PropertyNamesCompareCase") == 0)
        {
            struct metaEntry *m;

            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) )
                    addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0);
                else
                {

                    if ( !is_meta_string( m ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );

                    m->metaType &= ~META_IGNORE_CASE;
                }
            }

            continue;
        }

        /* --- this is duplicating.. */

        if (strcasecmp(w0, "PropertyNamesNoStripChars") == 0)
        {
            struct metaEntry *m;

            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) )
                    addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE|META_NOSTRIP, 0);
                else
                {
                    if ( !is_meta_string( m ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );

                    m->metaType |= META_NOSTRIP;
                }
            }

            continue;
        }



        if (strcasecmp(w0, "PropertyNamesStripChars") == 0)
        {
            struct metaEntry *m;

            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) )
                    addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0);
                else
                {

                    if ( !is_meta_string( m ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );

                    m->metaType &= ~META_NOSTRIP;
                }
            }

            continue;
        }



        if (strcasecmp(w0, "PropertyNamesNumeric") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( getPropNameByName( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] );

                addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_NUMBER, 0);
            }

            continue;
        }
        if (strcasecmp(w0, "PropertyNamesDate") == 0)
        {
            if (sl->n <= 1)
                progerr("%s: requires at least one value", w0);

            for (i = 1; i < sl->n; i++)
            {
                if ( getPropNameByName( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] );

                addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_DATE, 0);
            }

            continue;
        }


        if (strcasecmp(w0, "PropertyNameAlias") == 0)
        {
            struct metaEntry *meta_entry;
            struct metaEntry *new_meta;

            if (sl->n < 3)
                progerr("%s: requires at least two values", w0);


            /* Make sure first entry is not an alias */
            /* Lookup entry, and do not follow alias */
            if ( !(meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[1]) ) )
                progerr("%s - name '%s' not a PropertyName", w0, sl->word[1] );


            if ( meta_entry->alias )
                progerr("%s - name '%s' must not be an alias", w0, sl->word[1] );


            for (i = 2; i < sl->n; i++)
            {
                if ( getPropNameByNameNoAlias( &indexf->header, sl->word[i]) )
                    progerr("%s - name '%s' is already a PropertyName or PropertyNameAlias", w0, sl->word[i] );

                new_meta = addMetaEntry(&indexf->header, sl->word[i], meta_entry->metaType, 0);
                new_meta->alias = meta_entry->metaID;
            }

            continue;
        }


        /* This allows setting a limit on a property's string length */
        // One question would be if this should set the length on the alias, or the real property. */
        // If on the alias then you could really fine tune:
        //    PropertyNames description
        //    PropertyNameAlias description td h1 h2 h3
        //    PropertyNameMaxLength 5000 description
        //    PropertyNameMaxLength 100 td
        //    PropertyNameMaxLength 10 h1 h2 h3
        // then the total length would be 5000, but each one would be limited, too.  I find that hard to imagine
        // it would be useful.  So the current design is you can only assign to a non-alias.


        if (strcasecmp(w0, "PropertyNamesMaxLength") == 0)
        {
            struct metaEntry *meta_entry;
            int               max_length = 0;

            if (sl->n < 3)
                progerr("%s: requires only two or more values, a length and a list of property names", w0);


            max_length = read_integer( sl->word[1], w0, 0, INT_MAX );


            for (i = 2; i < sl->n; i++)
            {
                /* already exists? */
                if ( (meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[i])) )
                {
                    if ( meta_entry->alias )
                        progerr("Can't assign a length to property '%s': it is an alias", meta_entry->metaName );

                    if ( meta_entry->max_len )
                        progwarn("Why are you redefining the max length of property '%s'?", meta_entry->metaName );

                    if ( !is_meta_string( meta_entry ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );
                }
                else
                    meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0);


                meta_entry->max_len = max_length;
            }

            continue;
        }

        /* Set the sort length */

        if (strcasecmp(w0, "PropertyNamesSortKeyLength") == 0)
        {
            struct metaEntry *meta_entry;
            int               max_length = 0;

            if (sl->n < 3)
                progerr("%s: requires only two or more values, a length and a list of property names", w0);


            max_length = read_integer( sl->word[1], w0, 1, INT_MAX );


            for (i = 2; i < sl->n; i++)
            {
                /* already exists? */
                if ( (meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[i])) )
                {
                    if ( meta_entry->alias )
                        progerr("Can't assign a length to property '%s': it is an alias", meta_entry->metaName );

                    if ( meta_entry->max_len )
                        progwarn("Why are you redefining the max sort key length of property '%s'?", meta_entry->metaName );

                    if ( !is_meta_string( meta_entry ) )
                        progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] );
                }
                else
                    meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0);


                meta_entry->sort_len = max_length;
            }

            continue;
        }



        /* Hashed word lists */

        if ( !strcasecmp(w0, "IgnoreWords") || !strcasecmp(w0, "StopWords"))
        {
            word_hash_config( sl, &indexf->header.hashstoplist );
            continue;
        }

        if (strcasecmp(w0, "BuzzWords") == 0)  /* 2001-04-24 moseley */
        {
            word_hash_config( sl, &indexf->header.hashbuzzwordlist );
            continue;
        }

        if (strcasecmp(w0, "UseWords") == 0)
        {
            word_hash_config( sl, &indexf->header.hashuselist );
            continue;
        }



        /* IndexVerbose is supported for backwards compatibility */
        if (strcasecmp(w0, "IndexVerbose") == 0)
        {
            sw->verbose = getYesNoOrAbort(sl, 1, 1);
            if (sw->verbose)
                sw->verbose = 3;

            continue;
        }


        if (strcasecmp(w0, "IndexOnly") == 0)
        {
            if (sl->n > 1)
            {
                grabCmdOptions(sl, 1, &sw->suffixlist);
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        if (strcasecmp(w0, "IndexContents") == 0)
        {
            if (sl->n > 2)
            {
                struct IndexContents *ic = (struct IndexContents *) emalloc(sizeof(struct IndexContents));

                ic->DocType = getDocTypeOrAbort(sl, 1);
                ic->patt = NULL;

                for (i = 2; i < sl->n; i++)
                    ic->patt = addswline(ic->patt, sl->word[i]);

                if (sw->indexcontents)
                    ic->next = sw->indexcontents;
                else
                    ic->next = NULL;

                sw->indexcontents = ic;
            }
            else
                progerr("%s: requires at least two values", w0);

            continue;
        }


        /* $$$ this needs fixing */
        if (strcasecmp(w0, "StoreDescription") == 0)
        {
            if (sl->n == 3 || sl->n == 4)
            {
                struct StoreDescription *sd = (struct StoreDescription *) emalloc(sizeof(struct StoreDescription));

                sd->DocType = getDocTypeOrAbort(sl, 1);
                sd->size = 0;
                sd->field = NULL;
                i = 2;

                if (sl->word[i][0] == '<' && sl->word[i][strlen(sl->word[i]) - 1] == '>')
                {
                    sl->word[i][strlen(sl->word[i]) - 1] = '\0';
                    sd->field = estrdup(sl->word[i] + 1);
                    i++;
                }

                if (i < sl->n && isnumstring(  (unsigned char *)sl->word[i] ))
                {
                    sd->size = read_integer( sl->word[i], w0, 0, INT_MAX );
                }
                if (sl->n == 3 && !sd->field && !sd->size)
                    progerr("%s: second parameter must be <fieldname> or a number", w0);
                if (sl->n == 4 && sd->field && !sd->size)
                    progerr("%s: third parameter must be empty or a number", w0);
                if (sw->storedescription)
                    sd->next = sw->storedescription;
                else
                    sd->next = NULL;

                sw->storedescription = sd;

                /* Make sure there's a property name */
                if ( !getPropNameByName( &indexf->header, AUTOPROPERTY_SUMMARY) )
                    addMetaEntry(&indexf->header, AUTOPROPERTY_SUMMARY, META_PROP|META_STRING, 0);
            }
            else
                progerr("%s: requires two or three values", w0);

            continue;
        }


        if (strcasecmp(w0, "DefaultContents") == 0)
        {
            if (sl->n == 2 )
            {
                sw->DefaultDocType = getDocTypeOrAbort(sl, 1);
            }
            else
                progerr("%s: requires one value -- a parser type", w0);

            continue;
        }


        if (strcasecmp(w0, "BumpPositionCounterCharacters") == 0)
        {
            if (sl->n > 1)
            {
                indexf->header.bumpposchars = SafeStrCopy(indexf->header.bumpposchars, sl->word[1], &indexf->header.lenbumpposchars);
                sortstring(indexf->header.bumpposchars);
                makelookuptable(indexf->header.bumpposchars, indexf->header.bumpposcharslookuptable);
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        /* #### Added UndefinedMetaTags as defined by Bill Moseley */
        if (strcasecmp(w0, "UndefinedMetaTags") == 0)
        {
            get_undefined_meta_flags( w0, sl, &sw->UndefinedMetaTags );
            if ( !sw->UndefinedMetaTags )
                progerr("%s: possible values are error, ignore, index or auto", w0);

            continue;
        }


        if (strcasecmp(w0, "UndefinedXMLAttributes") == 0)
        {
            get_undefined_meta_flags( w0, sl, &sw->UndefinedXMLAttributes );
            continue;
        }



        if (strcasecmp(w0, "IgnoreMetaTags") == 0)
        {
            if (sl->n > 1)
            {
                grabCmdOptions(sl, 1, &sw->ignoremetalist);
                /* Go lowercase */
                for (tmplist = sw->ignoremetalist; tmplist; tmplist = tmplist->next)
                    (void)strtolower(tmplist->line);
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        if (strcasecmp(w0, "XMLClassAttributes") == 0)
        {
            if (sl->n > 1)
            {
                grabCmdOptions(sl, 1, &sw->XMLClassAttributes);
                /* Go lowercase */
                for (tmplist = sw->XMLClassAttributes; tmplist; tmplist = tmplist->next)
                    (void)strtolower(tmplist->line);
            }
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }


        if (strcasecmp(w0, "DontBumpPositionOnStartTags") == 0)
        {
            if (sl->n > 1)
                grabCmdOptions(sl, 1, &sw->dontbumpstarttagslist);
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }

        if (strcasecmp(w0, "DontBumpPositionOnEndTags") == 0)
        {
            if (sl->n > 1)
                grabCmdOptions(sl, 1, &sw->dontbumpendtagslist);
            else
                progerr("%s: requires at least one value", w0);

            continue;
        }

        if (strcasecmp(w0, "TruncateDocSize") == 0)
        {   /* rasc 2001-03 */
            if (sl->n == 2 && isnumstring( (unsigned char *)sl->word[1] ))
                sw->truncateDocSize = atol(sl->word[1]);
            else
                progerr("%s: requires size parameter in bytes", w0);

            continue;
        }

        if (strcasecmp(w0, "CompressPositions") == 0)
        {
            sw->compressPositions = getYesNoOrAbort(sl, 1, 1);
            continue;
        }


        else if (configModule_Entities(sw, sl));
        else if (configModule_Filter(sw, sl)); /* rasc */
        else if (configModule_ResultOutput(sw, sl)); /* rasc */
        else if (configModule_ResultSort(sw, sl)); /* jmruiz */
        else if (configModule_Index(sw, sl)); /* jmruiz */
        else if (configModule_Prog(sw, sl));
        else if (!parseconfline(sw, sl))
        {
            printf("Bad directive on line #%d of file %s: %s\n", linenumber, conffile, line);
            if ( ++baddirective > 30 )
                progerr("Too many errors.  Can not continue.");
        }

    }

    freeStringList(sl);

    fclose(fp);

    if (baddirective)
        exit(1);
    if (gotdir && !(*hasdir))
        *hasdir = 1;
    if (gotindex && !(*hasindex))
        *hasindex = 1;
}