/*++

Copyright (c) 1995-2001  Microsoft Corporation

Module Name:

    range.c

Abstract:

    This module contains the API routines that operate directly on ranges.

          CM_Add_Range
          CM_Create_Range_List
          CM_Delete_Range
          CM_Dup_Range_List
          CM_Find_Range
          CM_First_Range
          CM_Free_Range_List
          CM_Intersect_Range_List
          CM_Invert_Range_List
          CM_Merge_Range_List
          CM_Next_Range
          CM_Test_Range_Available

Author:

    Paula Tomlinson (paulat) 10-17-1995

Environment:

    User mode only.

Revision History:

    17-Oct-1995     paulat

        Creation and initial implementation.

--*/


//
// includes
//
#include "precomp.h"
#include "cfgi.h"
#include "setupapi.h"
#include "spapip.h"


//
// Private prototypes
//
BOOL
IsValidRangeList(
    IN RANGE_LIST rlh
    );

CONFIGRET
AddRange(
    IN PRange_Element  pParentElement,
    IN DWORDLONG       ullStartValue,
    IN DWORDLONG       ullEndValue,
    IN ULONG           ulFlags
    );

CONFIGRET
InsertRange(
    IN PRange_Element  pParentElement,
    IN DWORDLONG       ullStartValue,
    IN DWORDLONG       ullEndValue
    );

CONFIGRET
DeleteRange(
    IN PRange_Element  pParentElement
    );

CONFIGRET
JoinRange(
    IN PRange_Element  pParentElement,
    IN DWORDLONG       ullStartValue,
    IN DWORDLONG       ullEndValue
    );

CONFIGRET
CopyRanges(
    IN PRange_Element  pFromRange,
    IN PRange_Element  pToRange
    );

CONFIGRET
ClearRanges(
    IN PRange_Element  pRange
    );

CONFIGRET
TestRange(
    IN  PRange_Element   rlh,
    IN  DWORDLONG        ullStartValue,
    IN  DWORDLONG        ullEndValue,
    OUT PRange_Element   *pConflictingRange
    );


//
// global data
//





CONFIGRET
CM_Add_Range(
    IN DWORDLONG  ullStartValue,
    IN DWORDLONG  ullEndValue,
    IN RANGE_LIST rlh,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine adds a memory range to a range list.

Parameters:

   ullStartValue  Low end of the range.

   ullEndValue    High end of the range.

   rlh            Handle of a range list.

   ulFlags        Supplies flags specifying options for ranges that conflict
                  with ranges alread in the list.  May be one of the
                  following values:

                  CM_ADD_RANGE_ADDIFCONFLICT New range is merged with the
                                             ranges it conflicts with.
                  CM_ADD_RANGE_DONOTADDIFCONFLICT Returns CR_FAILURE if there
                                             is a conflict.

Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_FAILURE,
         CR_INVALID_FLAG,
         CR_INVALID_RANGE,
         CR_INVALID_RANGE_LIST, or
         CR_OUT_OF_MEMORY.
--*/

{
    CONFIGRET    Status = CR_SUCCESS;
    BOOL         bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, CM_ADD_RANGE_BITS)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        if (ullStartValue > ullEndValue) {
            Status = CR_INVALID_RANGE;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        Status = AddRange((PRange_Element)rlh, ullStartValue,
                          ullEndValue, ulFlags);

    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_Add_Range



CONFIGRET
CM_Create_Range_List(
    OUT PRANGE_LIST prlh,
    IN  ULONG  ulFlags
    )

/*++

Routine Description:

   This routine creates a list of ranges.

Parameters:

   prlh     Supplies the address of the variable that receives a
            handle to the new range list.

   ulFlags  Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_POINTER, or
         CR_OUT_OF_MEMORY.

--*/

{
    CONFIGRET         Status = CR_SUCCESS;
    PRange_List_Hdr   pRangeHdr = NULL;


    try {
        //
        // validate parameters
        //
        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        if (prlh == NULL) {
            Status = CR_INVALID_POINTER;
            goto Clean0;
        }

        //
        // allocate a buffer for the range list header struct
        //
        pRangeHdr = pSetupMalloc(sizeof(Range_List_Hdr));

        if (pRangeHdr == NULL) {
            Status = CR_OUT_OF_MEMORY;
            goto Clean0;
        }

        //
        // initialize the range list header buffer
        //
        pRangeHdr->RLH_Head = 0;
        pRangeHdr->RLH_Header = (ULONG_PTR)pRangeHdr;
        pRangeHdr->RLH_Signature = Range_List_Signature;

        //
        // initialize the private resource lock
        //
        InitPrivateResource(&(pRangeHdr->RLH_Lock));

        //
        // return a pointer to range list buffer to the caller
        //
        *prlh = (RANGE_LIST)pRangeHdr;


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        Status = CR_FAILURE;
    }

    return Status;

} // CM_Create_Range_List



CONFIGRET
CM_Delete_Range(
    IN DWORDLONG  ullStartValue,
    IN DWORDLONG  ullEndValue,
    IN RANGE_LIST rlh,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine deletes a range from a range list. If ullStartValue
   and ullEndValue are set to 0 and DWORD_MAX, this API carries out
   a special case, quickly emptying the lower 4 Gigabytes of the range.
   If ullEndValue is instead DWORDLONG_MAX, the entire range list is
   cleared, without having to process each element.

Parameters:

   ullStartValue  Low end of the range.

   ullEndValue    High end of the range.

   rlh            Handle of a range list.

   ulFlags        Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_FAILURE,
         CR_INVALID_FLAG,
         CR_INVALID_RANGE,
         CR_INVALID_RANGE_LIST, or
         CR_OUT_OF_MEMORY.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRange = NULL, pPrevious = NULL, pCurrent = NULL;
    BOOL           bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        if (ullStartValue > ullEndValue) {
            Status = CR_INVALID_RANGE;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        pPrevious = (PRange_Element)rlh;


        //-------------------------------------------------------------
        // first check the special case range values
        //-------------------------------------------------------------

        if (ullStartValue == 0) {

            if (ullEndValue == DWORDLONG_MAX) {
                //
                // quick clear of all ranges
                //
                ClearRanges(pPrevious);
            }

            else if (ullEndValue == DWORD_MAX) {
                //
                // quick clear of lower 4 GB ranges
                //
                while (pPrevious->RL_Next != 0) {
                    pCurrent = (PRange_Element)pPrevious->RL_Next;

                    if (pCurrent->RL_Start >= DWORD_MAX) {
                        goto Clean0;   // done
                    }

                    if (pCurrent->RL_End >= DWORD_MAX) {
                        pCurrent->RL_Start = DWORD_MAX;
                        goto Clean0;   // done
                    }

                    DeleteRange(pPrevious);    // pass the parent
                }
                goto Clean0;
            }
        }


        //-------------------------------------------------------------
        // search through each range in this list, if any part of the
        // specified range is contained in this range list, remove the
        // intersections
        //-------------------------------------------------------------

        while (pPrevious->RL_Next != 0) {
            pRange = (PRange_Element)pPrevious->RL_Next;

            //
            // if this range is completely before the current range, then
            // we can stop
            //
            if (ullEndValue < pRange->RL_Start) {
                break;
            }

            //
            // if this range is completely after the current range, then
            // skip to the next range
            //
            if (ullStartValue > pRange->RL_End) {
                goto NextRange;
            }

            //
            // if the range is completely contained, then delete the whole
            // thing
            //
            if (ullStartValue <= pRange->RL_Start  &&
                ullEndValue >= pRange->RL_End) {

                DeleteRange(pPrevious);    // pass the parent range

                //
                // don't goto next range because that would increment the
                // pPrevious counter. Since the current range was just deleted,
                // we need to process the current spot still.
                //
                continue;
            }

            //
            // if the start of the specified range intersects the current range,
            // adjust the current range to exclude it
            //
            if (ullStartValue > pRange->RL_Start  &&
                ullStartValue <= pRange->RL_End) {
                //
                // if the specified range is in the middle of this range, then
                // in addition to shrinking the first part of the range, I'll
                // have to create a range for the second part
                //       |  |<-- delete --->|  |
                //
                if (ullEndValue < pRange->RL_End) {
                    AddRange(pRange, ullEndValue+1, pRange->RL_End,
                             CM_ADD_RANGE_ADDIFCONFLICT);
                }

                pRange->RL_End = ullStartValue-1;

                //
                // reset the delete range for further processing
                //
                if (ullEndValue > pRange->RL_End) {
                    ullStartValue = pRange->RL_End+1;
                }
            }

            //
            // if the end of the specified range intersects the current range,
            // adjust the current range to exclude it
            //
            if (ullEndValue >= pRange->RL_Start  &&
                ullEndValue <= pRange->RL_End) {

                pRange->RL_Start = ullEndValue+1;

                //
                // reset the delete range for further processing
                //
                if (ullEndValue > pRange->RL_End) {
                    ullStartValue = pRange->RL_End+1;
                }
            }


            NextRange:

            pPrevious = (PRange_Element)pPrevious->RL_Next;
        }


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_Delete_Range



CONFIGRET
CM_Dup_Range_List(
    IN RANGE_LIST rlhOld,
    IN RANGE_LIST rlhNew,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine copies a range list.

Parameters:

   rlhOld   Supplies the handle of the range list to copy.

   rlhNew   Supplies the handle of a valid range list into which rlhOld
            is copied.  Anything contained in the rlhNew range list is
            removed by the copy operation.

   ulFlags  Must be zero.

Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_RANGE_LIST, or
         CR_OUT_OF_MEMORY

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRangeNew = NULL, pRangeOld = NULL;
    BOOL           bLockOld = FALSE, bLockNew = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlhOld)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhNew)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
        bLockOld = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
        bLockNew = TRUE;

        pRangeNew = (PRange_Element)rlhNew;
        pRangeOld = (PRange_Element)rlhOld;

        //
        // If the new range list is not empty, then delete ranges
        //
        if (pRangeNew->RL_Next != 0) {
            ClearRanges(pRangeNew);
        }

        Status = CR_SUCCESS;    // reset status flag to okay


        //
        // duplicate each of the old ranges
        //
        pRangeOld = (PRange_Element)pRangeOld->RL_Next;
        CopyRanges(pRangeOld, pRangeNew);


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLockOld = bLockOld;    // needed to prevent optimizing this flag away
        bLockNew = bLockNew;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }


    if (bLockOld) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
    }
    if (bLockNew) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
    }

    return Status;

} // CM_Dup_Range_List



CONFIGRET
CM_Find_Range(
    OUT PDWORDLONG pullStart,
    IN  DWORDLONG  ullStart,
    IN  ULONG      ulLength,
    IN  DWORDLONG  ullAlignment,
    IN  DWORDLONG  ullEnd,
    IN  RANGE_LIST rlh,
    IN  ULONG      ulFlags
    )

/*++

Routine Description:

  This routine attempts to find a range in the supplied range list that
  will accommodate the range requirements specified.  [TBD:  Verify
  that this description is correct.]

Parameters:

   pullStart   Supplies the address of a variable that receives the
               starting value of the allocated range.

   ullStart    Supplies the starting address that the range can have.

   ulLength    Supplies the length needed for the allocated range.

   ullAlignment   Supplies the alignment bitmask that specifies where the
               allocated range can start. [TBD:  verify that this is indeed
               a bitmask]

   ullEnd      Supplies the ending address of the area from which the range
               may be allocated.

   rlh         Supplies a handle to a range list in which the specified
               range is to be found.

   ulFlags     TBD


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_POINTER,
         CR_FAILURE

--*/

{
    CONFIGRET         Status = CR_SUCCESS;
    PRange_Element    pRange = NULL;
    DWORDLONG         ullNewEnd;
    BOOL              bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (pullStart == NULL) {
            Status = CR_INVALID_POINTER;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        //
        // Normalize aligment. Alignments are now like 0x00000FFF.
        //
        ullAlignment =~ ullAlignment;

        //
        // Test for impossible alignments (-1, not a power of 2 or start is
        // less than alignment away from wrapping). Also test for invalid
        // length.
        //
        if ((ullAlignment == DWORD_MAX) |
            (ulLength == 0) |
            ((ullAlignment & (ullAlignment + 1)) != 0) |
            (ullStart + ullAlignment < ullStart)) {

            Status = CR_FAILURE;
            goto Clean0;
        }

        //
        // Align the base.
        //
        ullStart += ullAlignment;
        ullStart &= ~ullAlignment;

        //
        // Compute the new end.
        //
        ullNewEnd = ullStart + ulLength - 1;

        //
        // Make sure we do have space.
        //
        if ((ullNewEnd < ullStart) || (ullNewEnd > ullEnd)) {
            Status = CR_FAILURE;
            goto Clean0;
        }

        //
        // Check if that range fits
        //
        if (TestRange((PRange_Element)rlh, ullStart, ullStart + ulLength - 1,
                      &pRange) == CR_SUCCESS) {
            //
            // We got it then, on the first try.
            //
            *pullStart = ullStart;
            goto Clean0;
        }

        //
        // Search for a spot where this range will fit.
        //
        while (TRUE) {
            //
            // Start at the end of the conflicting range.
            //
            ullStart = pRange->RL_End + 1;

            //
            // Check for wrapping.
            //
            if (!ullStart) {
                Status = CR_FAILURE;
                goto Clean0;
            }

            //
            // Make sure the alignment adjustment won't wrap.
            //
            if (ullStart + ullAlignment < ullStart) {
                Status = CR_FAILURE;
                goto Clean0;
            }

            //
            // Adjust the alignment.
            //
            ullStart += ullAlignment;
            ullStart &= ~ullAlignment;

            //
            // Compute the new end.
            //
            ullNewEnd = ullStart + ulLength - 1;

            //
            // Make sure the new end does not wrap and is still valid.
            //
            if ((ullNewEnd < ullStart) | (ullStart + ulLength - 1 > ullEnd))  {
                Status = CR_FAILURE;
                goto Clean0;
            }

            //
            // Skip any prls which existed only below our new range
            // (because we moved ulStart upward of them).
            //
            while ((pRange = (PRange_Element)pRange->RL_Next) != NULL &&
                   ullStart > pRange->RL_End) {
            }

            //
            // If we don't have a prl or it's begining is after our end
            //
            if (pRange == NULL || ullNewEnd < pRange->RL_Start) {
                *pullStart = ullStart;
                goto Clean0;
            }

            //
            // Otherwise try with the new prl.
            //
        }


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_Find_Range



CONFIGRET
CM_First_Range(
    IN  RANGE_LIST     rlh,
    OUT PDWORDLONG     pullStart,
    OUT PDWORDLONG     pullEnd,
    OUT PRANGE_ELEMENT preElement,
    IN  ULONG          ulFlags
    )

/*++

Routine Description:

   This routine retrieves the first range element in a range list.

Parameters:

   rlh         Supplies the handle of a range list.

   pullStart   Supplies the address of a variable that receives the
               starting value of the first range element.

   pullEnd     Supplies the address of a variable that receives the
               ending value of the first range element.

   preElement  Supplies the address of a variable that receives the
               handle of the next range element.

   ulFlags     Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_FAILURE,
         CR_INVALID_FLAG,
         CR_INVALID_POINTER, or
         CR_INVALID_RANGE_LIST.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRange = NULL;
    BOOL           bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (pullEnd == NULL  ||  pullStart == NULL  ||  preElement == NULL) {
            Status = CR_INVALID_POINTER;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        pRange = (PRange_Element)rlh;

        //
        // is the range list empty?
        //
        if (pRange->RL_Next == 0) {
            Status = CR_FAILURE;
            goto Clean0;
        }

        //
        // skip over the header to the first element
        //
        pRange = (PRange_Element)pRange->RL_Next;

        *pullStart = pRange->RL_Start;
        *pullEnd = pRange->RL_End;
        *preElement = (RANGE_ELEMENT)pRange->RL_Next;

    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }


    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_First_Range



CONFIGRET
CM_Free_Range_List(
    IN RANGE_LIST rlh,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine frees the specified range list and the memory allocated
   for it.

Parameters:

   rlh      Supplies the handle of the range list to be freed.

   ulFlags  Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_RANGE_LIST.

--*/

{
    CONFIGRET      Status = CR_SUCCESS, Status1 = CR_SUCCESS;
    BOOL           bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        while (Status1 == CR_SUCCESS) {
            //
            // keep deleting the first range after the header (pass parent
            // of range to delete)
            //
            Status1 = DeleteRange((PRange_Element)rlh);
        }

        //
        // destroy the private resource lock
        //
        DestroyPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);

        //
        // delete the range header
        //
        ((PRange_List_Hdr)rlh)->RLH_Signature = 0;
        pSetupFree((PRange_Element)rlh);
        bLock = FALSE;


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_Free_Range_List




CONFIGRET
CM_Intersect_Range_List(
    IN RANGE_LIST rlhOld1,
    IN RANGE_LIST rlhOld2,
    IN RANGE_LIST rlhNew,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine creates a range list from the intersection of two specified
   range lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle
   of a valid but empty range list.

Parameters:

   rlhOld1  Supplies the handle of a range list to be used as part of the
            intersection.

   rlhOld2  Supplies the handle of a range list to be used as part of the
            intersection.

   rlhNew   Supplies the handle of the range list that receives the
            intersection of rlhOld1 and rlhOld2.  Anything previously contained
            in the rlhNew ragne list is removed by this operation.

   ulFlags  Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_RANGE_LIST, or
         CR_OUT_OF_MEMORY.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    DWORDLONG      ulStart = 0, ulEnd = 0;
    PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
    BOOL           bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlhOld1)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhOld2)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhNew)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
        bLock1 = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
        bLock2 = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
        bLockNew = TRUE;

        pRangeNew = (PRange_Element)rlhNew;
        pRangeOld1 = (PRange_Element)rlhOld1;
        pRangeOld2 = (PRange_Element)rlhOld2;

        //
        // If the new range list is not empty, then delete ranges
        //
        if (pRangeNew->RL_Next != 0) {
            ClearRanges(pRangeNew);
        }

        //
        // Special case: if either range is empty then there is no
        // intersection by definition
        //
        if (pRangeOld1->RL_Next == 0  || pRangeOld2->RL_Next == 0) {
            goto Clean0;
        }


        pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
        pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;

        while (TRUE) {
            //
            // skip over Old2 ranges until intersects with or exceeds
            // current Old1 range (or no more Old2 ranges left)
            //
            while (pRangeOld2->RL_End < pRangeOld1->RL_Start) {

                if (pRangeOld2->RL_Next == 0) {
                    goto Clean0;      // Old2 exhausted, we're done
                }
                pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
            }

            //
            // if this Old2 range exceeds Old1 range, then go to the
            // next Old1 range and go through the main loop again
            //
            if (pRangeOld2->RL_Start > pRangeOld1->RL_End) {

                if (pRangeOld1->RL_Next == 0) {
                    goto Clean0;      // Old1 exhausted, we're done
                }
                pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
                continue;
            }

            //
            // if we got here there must be an intersection so add
            // the intersected range to New
            //
            ulStart = max(pRangeOld1->RL_Start, pRangeOld2->RL_Start);
            ulEnd   = min(pRangeOld1->RL_End, pRangeOld2->RL_End);

            Status = InsertRange(pRangeNew, ulStart, ulEnd);
            if (Status != CR_SUCCESS) {
                goto Clean0;
            }
            pRangeNew = (PRange_Element)pRangeNew->RL_Next;

            //
            // after handling the intersection, skip to next ranges in
            // Old1 and Old2 as appropriate
            //
            if (pRangeOld1->RL_End <= ulEnd) {
                if (pRangeOld1->RL_Next == 0) {
                    goto Clean0;         // Old1 exhausted, we're done
                }
                pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
            }

            if (pRangeOld2->RL_End <= ulEnd) {
                if (pRangeOld2->RL_Next == 0) {
                    goto Clean0;         // Old1 exhausted, we're done
                }
                pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
            }
        }


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock1 = bLock1;     // needed to prevent optimizing this flag away
        bLock2 = bLock2;     // needed to prevent optimizing this flag away
        bLockNew = bLockNew; // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }


    if (bLock1) {
         UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
    }
    if (bLock2) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
    }
    if (bLockNew) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
    }

    return Status;

} // CM_Intersect_Range_List



CONFIGRET
CM_Invert_Range_List(
    IN RANGE_LIST rlhOld,
    IN RANGE_LIST rlhNew,
    IN DWORDLONG  ullMaxValue,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine creates a range list that is the inverse of a specified
   range list; all claimed ranges in the new list are specified as free
   in the old list, and vice-versa. For example, the inversion of
   {[2,4],[6,8]} when the ulMaxValue parameter is 15 is {[0,1],[5,5],[9,15]}.
   If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a valid
   but empty range list.


Parameters:

   rlhOld      Supplies the handle of a range list to be inverted.

   rlhNew      Supplies the handle of the range list that receives the
               inverted copy of rlhOld.  Anything previously contained in
               the rlhNew range list is removed by this operation.

   ullMaxValue Uppermost value of the inverted range list.

   ulFlags     Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_RANGE_LIST,
         CR_OUT_OF_MEMORY.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRangeNew = NULL, pRangeOld = NULL;
    DWORDLONG      ullStart = 0, ullEnd = 0;
    BOOL           bLockOld = FALSE, bLockNew = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlhOld)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhNew)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
        bLockOld = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
        bLockNew = TRUE;

        pRangeNew = (PRange_Element)rlhNew;
        pRangeOld = (PRange_Element)rlhOld;

        //
        // If the new range list is not empty, then delete ranges
        //
        if (pRangeNew->RL_Next != 0) {
            ClearRanges(pRangeNew);
        }

        //
        // special case: if the old range is empty, then the new range
        // is the entire range (up to max)
        //
        if (pRangeOld->RL_Next == 0) {
            Status = InsertRange(pRangeNew, 0, ullMaxValue);
            goto Clean0;
        }


        //
        // invert each of the old ranges
        //
        ullStart = ullEnd = 0;

        while (pRangeOld->RL_Next != 0) {

            pRangeOld = (PRange_Element)pRangeOld->RL_Next;

            //
            // Special start case: if range starts at 0, skip over it
            //
            if (pRangeOld->RL_Start != 0) {

                //
                // Special end case: check if we've hit the max for the new range
                //
                if (pRangeOld->RL_End >= ullMaxValue) {

                    ullEnd = min(ullMaxValue, pRangeOld->RL_Start - 1);
                    Status = InsertRange(pRangeNew, ullStart, ullEnd);
                    goto Clean0;      // we're done
                }

                Status = InsertRange(pRangeNew, ullStart, pRangeOld->RL_Start - 1);
                if (Status != CR_SUCCESS) {
                    goto Clean0;
                }

                pRangeNew = (PRange_Element)pRangeNew->RL_Next;
            }

            ullStart = pRangeOld->RL_End + 1;
        }

        //
        // add the range that incorporates the end of the old range up to
        // the max value specified
        //
        if (ullStart <= ullMaxValue) {
            Status = InsertRange(pRangeNew, ullStart, ullMaxValue);
        }


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLockOld = bLockOld;    // needed to prevent optimizing this flag away
        bLockNew = bLockNew;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }


    if (bLockOld) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhOld)->RLH_Lock);
    }
    if (bLockNew) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
    }

    return Status;

} // CM_Invert_Range_List



CONFIGRET
CM_Merge_Range_List(
    IN RANGE_LIST rlhOld1,
    IN RANGE_LIST rlhOld2,
    IN RANGE_LIST rlhNew,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine creates a range list from the union of two specified range
   lists. If this API returns CR_OUT_OF_MEMORY, rlhNew is the handle of a
   valid but empty range list.

Parameters:

   rlhOld1  Supplies the handle of a range list to be used as part of the
            union.

   rlhOld2  Supplies the handle of a range list to be used as part of the
            union.

   rlhNew   Supplies the handle of the range list that receives the union
            of rlhOld1 and rlhOld2.  Anything previously contained in the
            rlhNew range list is removed by this operation.

   ulFlags  Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_INVALID_FLAG,
         CR_INVALID_RANGE_LIST, or
         CR_OUT_OF_MEMORY.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    DWORDLONG      ullStart = 0, ullEnd = 0;
    BOOL           bOld1Empty = FALSE, bOld2Empty = FALSE;
    PRange_Element pRangeNew = NULL, pRangeOld1 = NULL, pRangeOld2 = NULL;
    BOOL           bLock1 = FALSE, bLock2 = FALSE, bLockNew = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlhOld1)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhOld2)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (!IsValidRangeList(rlhNew)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
        bLock1 = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
        bLock2 = TRUE;

        LockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
        bLockNew = TRUE;

        pRangeNew = (PRange_Element)rlhNew;
        pRangeOld1 = (PRange_Element)rlhOld1;
        pRangeOld2 = (PRange_Element)rlhOld2;

        //
        // If the new range list is not empty, then clear it
        //
        if (pRangeNew->RL_Next != 0) {
            ClearRanges(pRangeNew);
        }

        //
        // Special case: if both ranges are empty then there is no
        // union by definition
        //
        if (pRangeOld1->RL_Next == 0  &&  pRangeOld2->RL_Next == 0) {
            goto Clean0;
        }

        //
        // Special case: if one range is empty, then the union is just the other
        //
        if (pRangeOld1->RL_Next == 0) {
            pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
            CopyRanges(pRangeOld2, pRangeNew);     // from -> to
            goto Clean0;
        }

        if (pRangeOld2->RL_Next == 0) {
            pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
            CopyRanges(pRangeOld1, pRangeNew);     // from -> to
            goto Clean0;
        }


        pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
        pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;


        while (TRUE) {
            //
            // Pick whichever range comes first between current Old1 range
            // and current Old2 range
            //
            if (pRangeOld1->RL_Start <= pRangeOld2->RL_Start) {

                ullStart = pRangeOld1->RL_Start;
                ullEnd   = pRangeOld1->RL_End;

                if (pRangeOld1->RL_Next == 0) {
                    bOld1Empty = TRUE;
                } else {
                    pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
                }

            } else {

                ullStart = pRangeOld2->RL_Start;
                ullEnd   = pRangeOld2->RL_End;

                if (pRangeOld2->RL_Next == 0) {
                    bOld2Empty = TRUE;
                } else {
                    pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
                }
            }

            //
            // gather any ranges in Old1 that intersect (ullStart,ullEnd)
            //
            while (pRangeOld1->RL_Start <= ullEnd) {

                ullEnd = max(ullEnd, pRangeOld1->RL_End);

                if (pRangeOld1->RL_Next == 0) {
                    bOld1Empty = TRUE;
                    break;
                }
                pRangeOld1 = (PRange_Element)pRangeOld1->RL_Next;
            }

            //
            // gather any ranges in Old2 that intersect (ullStart,ullEnd)
            //
            while (pRangeOld2->RL_Start <= ullEnd) {

                ullEnd = max(ullEnd, pRangeOld2->RL_End);

                if (pRangeOld2->RL_Next == 0) {
                    bOld2Empty = TRUE;
                    break;
                }
                pRangeOld2 = (PRange_Element)pRangeOld2->RL_Next;
            }

            //
            // add (ullStart,ullEnd) to the new range
            //
            Status = InsertRange(pRangeNew, ullStart, ullEnd);
            if (Status != CR_SUCCESS) {
                goto Clean0;
            }
            pRangeNew = (PRange_Element)pRangeNew->RL_Next;

            //
            // As an optimization, if either range is exhausted first,
            // then only need to duplicate the other remaining ranges.
            //
            if (bOld1Empty && bOld2Empty) {
                goto Clean0;   // both exhausted during last pass, we're done
            }

            if (bOld1Empty) {    // Old1 exhausted, copy remaining from Old2
                CopyRanges(pRangeOld2, pRangeNew);
                goto Clean0;
            }

            if (bOld2Empty) {    // Old2 exhausted, copy remaining from Old1
                CopyRanges(pRangeOld1, pRangeNew);
                goto Clean0;
            }
        }


    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock1 = bLock1;     // needed to prevent optimizing this flag away
        bLock2 = bLock2;     // needed to prevent optimizing this flag away
        bLockNew = bLockNew; // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }


    if (bLock1) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhOld1)->RLH_Lock);
    }
    if (bLock2) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhOld2)->RLH_Lock);
    }
    if (bLockNew) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlhNew)->RLH_Lock);
    }

    return Status;

} // CM_Merge_Range_List



CONFIGRET
CM_Next_Range(
    IN OUT PRANGE_ELEMENT preElement,
    OUT PDWORDLONG        pullStart,
    OUT PDWORDLONG        pullEnd,
    IN  ULONG             ulFlags
    )

/*++

Routine Description:

    This routine returns the next range element in a range list. This
    API returns CR_FAILURE if there are no more elements in the range
    list.

Parameters:

   preElement  Supplies the address of the handle for the current range
               element.  Upon return, this variable receives the handle
               of the next range element.

   pullStart   Supplies the address of the variable that receives the
               starting value of the next range.

   pullEnd     Supplies the address of the variable that receives the
               ending value of the next range.

   ulFlags     Must be zero.


Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_FAILURE,
         CR_INVALID_FLAG,
         CR_INVALID_POINTER, or
         CR_INVALID_RANGE.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRange = NULL;
    BOOL           bLock = FALSE;
    PRange_List_Hdr prlh = NULL;


    try {
        //
        // validate parameters
        //
        if (preElement == NULL  ||  *preElement == 0) {
            Status = CR_FAILURE;
            goto Clean0;
        }

        if (pullEnd == NULL  ||  pullStart == NULL) {
            Status = CR_INVALID_POINTER;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        prlh = (PRange_List_Hdr)((PRange_Element)(*preElement))->RL_Header;
        LockPrivateResource(&(prlh->RLH_Lock));
        bLock = TRUE;

        pRange = (PRange_Element)(*preElement);

        *pullStart = pRange->RL_Start;
        *pullEnd = pRange->RL_End;
        *preElement = (RANGE_ELEMENT)pRange->RL_Next;

    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&(prlh->RLH_Lock));
    }

    return Status;

} // CM_Next_Range



CONFIGRET
CM_Test_Range_Available(
    IN DWORDLONG  ullStartValue,
    IN DWORDLONG  ullEndValue,
    IN RANGE_LIST rlh,
    IN ULONG      ulFlags
    )

/*++

Routine Description:

   This routine checks a range against a range list to ensure that no
   conflicts exist.

Parameters:

   ullStartValue  Supplies the low end of the range.

   ullEndValue    Supplies the high end of the range.

   rlh            Supplies the handle to a range list.

   ulFlags        Must be zero.

Return Value:

   If the function succeeds, the return value is CR_SUCCESS.
   If the function fails, the return value is one of the following:
         CR_FAILURE,
         CR_INVALID_FLAG,
         CR_INVALID_RANGE, or
         CR_INVALID_RANGE_LIST.

--*/

{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pRange = NULL;
    BOOL           bLock = FALSE;

    try {
        //
        // validate parameters
        //
        if (!IsValidRangeList(rlh)) {
            Status = CR_INVALID_RANGE_LIST;
            goto Clean0;
        }

        if (INVALID_FLAGS(ulFlags, 0)) {
            Status = CR_INVALID_FLAG;
            goto Clean0;
        }

        if (ullEndValue < ullStartValue) {
            Status = CR_INVALID_RANGE;
            goto Clean0;
        }

        LockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
        bLock = TRUE;

        pRange = (PRange_Element)rlh;

        //
        // check each range for a conflict
        //
        while (pRange->RL_Next != 0) {

            pRange = (PRange_Element)pRange->RL_Next;

            //
            // If I've already passed the test range, then it's available
            //
            if (ullEndValue < pRange->RL_Start) {
                goto Clean0;
            }

            //
            // check if the start of the test range intersects the current range
            //
            if (ullStartValue >= pRange->RL_Start &&
                ullStartValue <= pRange->RL_End) {

                Status = CR_FAILURE;
                goto Clean0;
            }

            //
            // check if the end of the test range intersects the current range
            //
            if (ullEndValue >= pRange->RL_Start &&
               ullEndValue <= pRange->RL_End) {

                Status = CR_FAILURE;
                goto Clean0;
            }

            //
            // check if it's a complete overlap
            //
            if (ullStartValue <= pRange->RL_Start &&
               ullEndValue >= pRange->RL_End) {

                Status = CR_FAILURE;
                goto Clean0;
            }
        }

        //
        // if we got this far, then we made it through the range list
        // without hitting a conflict
        //

    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        bLock = bLock;    // needed to prevent optimizing this flag away
        Status = CR_FAILURE;
    }

    if (bLock) {
        UnlockPrivateResource(&((PRange_List_Hdr)rlh)->RLH_Lock);
    }

    return Status;

} // CM_Test_Range_Available




//------------------------------------------------------------------------
// Private Utility Functions
//------------------------------------------------------------------------


BOOL
IsValidRangeList(
    IN RANGE_LIST rlh
    )
{
   BOOL             Status = TRUE;
   PRange_List_Hdr  pRangeHdr = NULL;

    try {

        if (rlh == 0  || rlh == (DWORD)-1) {
            return FALSE;
        }

        pRangeHdr = (PRange_List_Hdr)rlh;

        if (pRangeHdr->RLH_Signature != Range_List_Signature) {
            Status = FALSE;
        }

    } except(EXCEPTION_EXECUTE_HANDLER) {
        Status = FALSE;
    }

    return Status;

} // IsValidRangeList




CONFIGRET
AddRange(
    IN PRange_Element   prlh,
    IN DWORDLONG        ullStartValue,
    IN DWORDLONG        ullEndValue,
    IN ULONG            ulFlags
    )
{
    CONFIGRET      Status = CR_SUCCESS;
    PRange_Element pPrevious = NULL, pCurrent = NULL;


    try {

        pPrevious = prlh;

        if (pPrevious->RL_Next == 0) {
            //
            // the range is empty
            //
            Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
            goto Clean0;
        }


        while (pPrevious->RL_Next != 0) {

            pCurrent = (PRange_Element)pPrevious->RL_Next;


            if (ullStartValue < pCurrent->RL_Start) {

                if (ullEndValue < pCurrent->RL_Start) {
                    //
                    // new range completely contained before this one,
                    // add new range between previous and current range
                    //
                    Status = InsertRange(pPrevious, ullStartValue, ullEndValue);
                    goto Clean0;
                }

                if (ullEndValue <= pCurrent->RL_End) {
                    //
                    // new range intersects current range, on the low side,
                    // enlarge this range to include the new range
                    //
                    if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                        Status = CR_FAILURE;
                        goto Clean0;
                    }

                    pCurrent->RL_Start = ullStartValue;
                    goto Clean0;
                }

                if ((pCurrent->RL_Next == 0)  ||
                    (ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
                    //
                    // new range intersects current range on high and low
                    // side, extent range to include the new range
                    //
                    if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                        Status = CR_FAILURE;
                        goto Clean0;
                    }

                    pCurrent->RL_Start = ullStartValue;
                    pCurrent->RL_End = ullEndValue;
                    goto Clean0;
                }

                //
                // new range intersects more than one range, needs to be
                // merged
                //
                if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                    Status = CR_FAILURE;
                    goto Clean0;
                }

                Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
                goto Clean0;
            }


            if (ullStartValue <= pCurrent->RL_End+1) {

                if (ullEndValue <= pCurrent->RL_End) {
                    //
                    // new range is completely contained inside the current
                    // range so nothing to do
                    //
                    if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                        Status = CR_FAILURE;
                        goto Clean0;
                    }

                    goto Clean0;
                }

                if ((pCurrent->RL_Next == 0)  ||
                    (ullEndValue < ((PRange_Element)(pCurrent->RL_Next))->RL_Start)) {
                    //
                    // new range intersects current range on high end only,
                    // extend range to include the new range
                    //
                    if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                        Status = CR_FAILURE;
                        goto Clean0;
                    }

                    pCurrent->RL_End = ullEndValue;
                    goto Clean0;
                }

                //
                // new range intersects more than one range, needs to be
                // merged
                //
                if (ulFlags == CM_ADD_RANGE_DONOTADDIFCONFLICT) {
                    Status = CR_FAILURE;
                    goto Clean0;
                }

                Status = JoinRange(pPrevious, ullStartValue, ullEndValue);
                goto Clean0;
            }

            //
            // step to the next range
            //
            pPrevious = pCurrent;
            pCurrent = (PRange_Element)pCurrent->RL_Next;
        }

        //
        // if we got here then we need to just insert this range to the end
        // of the range list
        //
        Status = InsertRange(pPrevious, ullStartValue, ullEndValue);

    Clean0:
        NOTHING;

    } except(EXCEPTION_EXECUTE_HANDLER) {
        Status = 0;
    }

    return Status;

} // AddRange



CONFIGRET
InsertRange(
    IN PRange_Element pParentElement,
    IN DWORDLONG      ullStartValue,
    IN DWORDLONG      ullEndValue)
{
    PRange_Element  pNewElement = NULL;


    pNewElement = (PRange_Element)pSetupMalloc(sizeof(Range_Element));

    if (pNewElement == NULL) {
        return CR_OUT_OF_MEMORY;
    }

    pNewElement->RL_Next   = pParentElement->RL_Next;   // rejoin the link
    pNewElement->RL_Start  = ullStartValue;
    pNewElement->RL_End    = ullEndValue;
    pNewElement->RL_Header = pParentElement->RL_Header;
    pParentElement->RL_Next = (ULONG_PTR)pNewElement;

    return CR_SUCCESS;

} // InsertRange



CONFIGRET
DeleteRange(
    IN PRange_Element  pParentElement
    )
{
    PRange_Element pTemp = NULL;

    //
    // must pass a valid parent of the range to delete (in otherwords,
    // can't pass the last range)
    //

    if (pParentElement == 0) {
        return CR_FAILURE;
    }

    pTemp = (PRange_Element)(pParentElement->RL_Next);
    if (pTemp == 0) {
        return CR_FAILURE;
    }

    pParentElement->RL_Next =
                ((PRange_Element)(pParentElement->RL_Next))->RL_Next;

    pSetupFree(pTemp);

    return CR_SUCCESS;

} // DeleteRange



CONFIGRET
JoinRange(
    IN PRange_Element  pParentElement,
    IN DWORDLONG       ullStartValue,
    IN DWORDLONG       ullEndValue
    )
{
    CONFIGRET       Status = CR_SUCCESS;
    PRange_Element  pCurrent = NULL, pNext = NULL;


    if (pParentElement->RL_Next == 0) {
        return CR_SUCCESS;      // at the end, nothing to join
    }

    //
    // pCurrent is the starting range of intersecting ranges that need
    // to be joined
    //
    pCurrent = (PRange_Element)pParentElement->RL_Next;

    //
    // set start of joined range
    //
    if (ullStartValue < pCurrent->RL_Start) {
        pCurrent->RL_Start = ullStartValue;
    }

    //
    // find the end of the joined range
    //
    while (pCurrent->RL_Next != 0) {
        pNext = (PRange_Element)pCurrent->RL_Next;

        //
        // I know this next range needs to be absorbed in all cases so
        // reset the end point to at least include the next range
        //
        pCurrent->RL_End = pNext->RL_End;

        if (ullEndValue <= pNext->RL_End) {
            DeleteRange(pCurrent);     // delete the range following current
            break;   // we're done
        }

        if ((pNext->RL_Next == 0)  ||
            (ullEndValue < ((PRange_Element)(pNext->RL_Next))->RL_Start)) {
            //
            // adjust the end point of the newly joined range and then we're done
            //
            pCurrent->RL_End = ullEndValue;
            DeleteRange(pCurrent);     // delete the range following current
            break;
        }

        DeleteRange(pCurrent);     // delete the range following current

        // if we got here, there are more ranges to join
    }

    return Status;

} // JoinRange



CONFIGRET
CopyRanges(
    IN PRange_Element  pFromRange,
    IN PRange_Element  pToRange
    )
{
    CONFIGRET       Status = CR_SUCCESS;

    //
    // copy each range in pFromRange to pToRange
    //
    while (TRUE) {

        Status = AddRange(pToRange,
                          pFromRange->RL_Start,
                          pFromRange->RL_End,
                          CM_ADD_RANGE_ADDIFCONFLICT);

        if (Status != CR_SUCCESS) {
            break;
        }

        pToRange = (PRange_Element)pToRange->RL_Next;

        if (pFromRange->RL_Next == 0) {
            break;
        }

        pFromRange = (PRange_Element)pFromRange->RL_Next;
    }

    return Status;

} // CopyRanges



CONFIGRET
ClearRanges(
    IN PRange_Element  pRange
    )
{
    CONFIGRET       Status = CR_SUCCESS;

    //
    // If the range list is not empty, then delete ranges
    //
    if (pRange->RL_Next != 0) {

        while (Status == CR_SUCCESS) {
            //
            // keep deleting the first range after the header (pass parent
            // of range to delete)
            //
            Status = DeleteRange(pRange);
        }
    }

    return CR_SUCCESS;  // Status is set to end deleting ranges, don't return it

} // ClearRanges



CONFIGRET
TestRange(
    IN  PRange_Element   rlh,
    IN  DWORDLONG        ullStartValue,
    IN  DWORDLONG        ullEndValue,
    OUT PRange_Element   *pConflictingRange
    )

{
    PRange_Element    pRange = (PRange_Element)rlh;

    //
    // check each range for a conflict
    //
    while (pRange->RL_Next != 0) {

        pRange = (PRange_Element)pRange->RL_Next;

        if (pRange->RL_Start > ullEndValue) {
            //
            // We've gone past the range in question so no conflict
            //
            return CR_SUCCESS;
        }

        if (pRange->RL_End < ullStartValue) {
            //
            // this range is still below the range in question, skip to next range
            //
            continue;
        }

        //
        // otherwise there's a conflict
        //
        *pConflictingRange = pRange;
        return CR_FAILURE;
    }

    return CR_SUCCESS;

} // TestRange