/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    config.c

Abstract:

    This module implements the code to find an ARC configuration tree
    entry as constructed by the OS Loader.

Author:

    David N. Cutler (davec) 9-Sep-1991

Environment:

    User mode only.

Revision History:

--*/

#include "ki.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,KeFindConfigurationEntry)
#pragma alloc_text(INIT,KeFindConfigurationNextEntry)
#endif

PCONFIGURATION_COMPONENT_DATA
KeFindConfigurationEntry (
    IN PCONFIGURATION_COMPONENT_DATA Child,
    IN CONFIGURATION_CLASS Class,
    IN CONFIGURATION_TYPE Type,
    IN PULONG Key OPTIONAL
    )
/*++

Routine Description:

    This function search the specified configuration tree and returns a
    pointer to an entry that matches the specified class, type, and key
    parameters.

    This routine is the same as KeFindConfurationEntryNext expect
    that the search is performed from the first entry

    N.B. This routine can only be called during system initialization.

--*/
{
    PCONFIGURATION_COMPONENT_DATA Resume;

    Resume = NULL;
    return KeFindConfigurationNextEntry (Child, Class, Type, Key, &Resume);
}

PCONFIGURATION_COMPONENT_DATA
KeFindConfigurationNextEntry (
    IN PCONFIGURATION_COMPONENT_DATA Child,
    IN CONFIGURATION_CLASS Class,
    IN CONFIGURATION_TYPE Type,
    IN PULONG Key OPTIONAL,
    IN PCONFIGURATION_COMPONENT_DATA *Resume
    )

/*++

Routine Description:

    This function search the specified configuration tree and returns a
    pointer to an entry that matches the specified class, type, and key
    parameters.

    N.B. This routine can only be called during system initialization.

Arguments:

    Child - Supplies an optional pointer to an NT configuration component.

    Class - Supplies the configuration class of the entry to locate.

    Type - Supplies the configuration type of the entry to locate.

    Key - Supplies a pointer to an optional key value to use in locating
        the specified entry.

    Resume - Supplies the last returned entry for which the search
        should resume from.

Return Value:

    If the specified entry is located, then a pointer to the configuration
    entry is returned as the function value. Otherwise, NULL is returned.

--*/

{

    PCONFIGURATION_COMPONENT_DATA Entry;
    ULONG MatchKey;
    ULONG MatchMask;
    PCONFIGURATION_COMPONENT_DATA Sibling;

    //
    // Initialize the match key and mask based on whether the optional key
    // value is specified.
    //

    if (ARGUMENT_PRESENT(Key)) {
        MatchMask = 0xffffffff;
        MatchKey = *Key;

    } else {
        MatchMask = 0;
        MatchKey = 0;
    }

    //
    // Search specified configuration tree for an entry that matches the
    // the specified class, type, and key.
    //

    while (Child != NULL) {
        if (*Resume) {
            //
            // If resume location found, clear resume location and continue
            // search with next entry
            //

            if (Child == *Resume) {
                *Resume = NULL;
            }
        } else {

            //
            // If the class, type, and key match, then return a pointer to
            // the child entry.
            //

            if ((Child->ComponentEntry.Class == Class) &&
                (Child->ComponentEntry.Type == Type) &&
                ((Child->ComponentEntry.Key & MatchMask) == MatchKey)) {
                return Child;
            }
        }

        //
        // If the child has a sibling list, then search the sibling list
        // for an entry that matches the specified class, type, and key.
        //

        Sibling = Child->Sibling;
        while (Sibling != NULL) {
            if (*Resume) {
                //
                // If resume location found, clear resume location and continue
                // search with next entry
                //

                if (Sibling == *Resume) {
                    *Resume = NULL;
                }
            } else {

                //
                // If the class, type, and key match, then return a pointer to
                // the child entry.
                //

                if ((Sibling->ComponentEntry.Class == Class) &&
                    (Sibling->ComponentEntry.Type == Type) &&
                    ((Sibling->ComponentEntry.Key & MatchMask) == MatchKey)) {
                    return Sibling;
                }
            }

            //
            // If the sibling has a child tree, then search the child tree
            // for an entry that matches the specified class, type, and key.
            //

            if (Sibling->Child != NULL) {
               Entry = KeFindConfigurationNextEntry (
                                Sibling->Child,
                                Class,
                                Type,
                                Key,
                                Resume
                                );

               if (Entry != NULL) {
                   return Entry;
               }
            }

            Sibling = Sibling->Sibling;
        }

        Child = Child->Child;
    }

    return NULL;
}