/*++ BUILD Version: 0005 // Increment this if a change has global effects Copyright (c) 1989-1999 Microsoft Corporation Module Name: llsrtl.h Abstract: Include file for NT runtime routines that are callable by both kernel mode code in the executive and user mode code in various NT subsystems. Author: Steve Wood (stevewo) 31-Mar-1989 Environment: These routines are statically linked in the caller's executable and are callable in either kernel mode or user mode. Revision History: --*/ #ifndef _LLSRTL_ #define _LLSRTL_ #if defined (_MSC_VER) #if ( _MSC_VER >= 800 ) #pragma warning(disable:4514) #if _MSC_VER >= 1200 #pragma warning(push) #endif #pragma warning(disable:4001) #pragma warning(disable:4201) #pragma warning(disable:4214) #endif #if (_MSC_VER > 1020) #pragma once #endif #endif // begin_ntddk begin_wdm begin_winnt begin_ntifs begin_nthal // // for move macros // #ifdef _MAC #ifndef _INC_STRING #include #endif /* _INC_STRING */ #else #include #endif // _MAC // end_ntddk end_wdm end_winnt end_ntifs end_nthal #ifdef __cplusplus extern "C" { #endif // begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntndis // // If debugging support enabled, define an ASSERT macro that works. Otherwise // define the ASSERT macro to expand to an empty expression. // #if DBG NTSYSAPI VOID NTAPI RtlAssert( PVOID FailedAssertion, PVOID FileName, ULONG LineNumber, PCHAR Message ); #ifndef ASSERT #define ASSERT( exp ) \ ((!(exp)) ? \ RtlAssert( #exp, __FILE__, __LINE__, NULL ) : \ ((void)0)) #endif #ifndef ASSERTMSG #define ASSERTMSG( msg, exp ) \ ((!(exp)) ? \ RtlAssert( #exp, __FILE__, __LINE__, msg ) : \ ((void)0)) #endif #else #ifndef ASSERT #define ASSERT( exp ) ((void)0) #endif #ifndef ASSERTMSG #define ASSERTMSG( msg, exp ) ((void)0) #endif #endif // DBG // end_ntddk end_wdm end_nthal end_ntifs end_ntndis // begin_ntddk begin_wdm begin_nthal begin_ntifs begin_ntndis // // Doubly-linked list manipulation routines. Implemented as macros // but logically these are procedures. // // // VOID // InitializeListHead( // PLIST_ENTRY ListHead // ); // #define InitializeListHead(ListHead) (\ (ListHead)->Flink = (ListHead)->Blink = (ListHead)) // // BOOLEAN // IsListEmpty( // PLIST_ENTRY ListHead // ); // #define IsListEmpty(ListHead) \ ((ListHead)->Flink == (ListHead)) // // PLIST_ENTRY // RemoveHeadList( // PLIST_ENTRY ListHead // ); // #define RemoveHeadList(ListHead) \ (ListHead)->Flink;\ {RemoveEntryList((ListHead)->Flink)} // // PLIST_ENTRY // RemoveTailList( // PLIST_ENTRY ListHead // ); // #define RemoveTailList(ListHead) \ (ListHead)->Blink;\ {RemoveEntryList((ListHead)->Blink)} // // VOID // RemoveEntryList( // PLIST_ENTRY Entry // ); // #define RemoveEntryList(Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_Flink;\ _EX_Flink = (Entry)->Flink;\ _EX_Blink = (Entry)->Blink;\ _EX_Blink->Flink = _EX_Flink;\ _EX_Flink->Blink = _EX_Blink;\ } // // VOID // InsertTailList( // PLIST_ENTRY ListHead, // PLIST_ENTRY Entry // ); // #define InsertTailList(ListHead,Entry) {\ PLIST_ENTRY _EX_Blink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Blink = _EX_ListHead->Blink;\ (Entry)->Flink = _EX_ListHead;\ (Entry)->Blink = _EX_Blink;\ _EX_Blink->Flink = (Entry);\ _EX_ListHead->Blink = (Entry);\ } // // VOID // InsertHeadList( // PLIST_ENTRY ListHead, // PLIST_ENTRY Entry // ); // #define InsertHeadList(ListHead,Entry) {\ PLIST_ENTRY _EX_Flink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Flink = _EX_ListHead->Flink;\ (Entry)->Flink = _EX_Flink;\ (Entry)->Blink = _EX_ListHead;\ _EX_Flink->Blink = (Entry);\ _EX_ListHead->Flink = (Entry);\ } // // // PSINGLE_LIST_ENTRY // PopEntryList( // PSINGLE_LIST_ENTRY ListHead // ); // #define PopEntryList(ListHead) \ (ListHead)->Next;\ {\ PSINGLE_LIST_ENTRY FirstEntry;\ FirstEntry = (ListHead)->Next;\ if (FirstEntry != NULL) { \ (ListHead)->Next = FirstEntry->Next;\ } \ } // // VOID // PushEntryList( // PSINGLE_LIST_ENTRY ListHead, // PSINGLE_LIST_ENTRY Entry // ); // #define PushEntryList(ListHead,Entry) \ (Entry)->Next = (ListHead)->Next; \ (ListHead)->Next = (Entry) // end_wdm end_nthal end_ntifs end_ntndis // end_ntddk // // Define the generic table package. Note a generic table should really // be an opaque type. We provide routines to manipulate the structure. // // A generic table is package for inserting, deleting, and looking up elements // in a table (e.g., in a symbol table). To use this package the user // defines the structure of the elements stored in the table, provides a // comparison function, a memory allocation function, and a memory // deallocation function. // // Note: the user compare function must impose a complete ordering among // all of the elements, and the table does not allow for duplicate entries. // // // Add an empty typedef so that functions can reference the // a pointer to the generic table struct before it is declared. // struct _LLS_GENERIC_TABLE; // // The results of a compare can be less than, equal, or greater than. // typedef enum _LLS_GENERIC_COMPARE_RESULTS { LLSGenericLessThan, LLSGenericGreaterThan, LLSGenericEqual } LLS_GENERIC_COMPARE_RESULTS; // // The comparison function takes as input pointers to elements containing // user defined structures and returns the results of comparing the two // elements. // typedef LLS_GENERIC_COMPARE_RESULTS (NTAPI *PLLS_GENERIC_COMPARE_ROUTINE) ( struct _LLS_GENERIC_TABLE *Table, PVOID FirstStruct, PVOID SecondStruct ); // // The allocation function is called by the generic table package whenever // it needs to allocate memory for the table. // typedef PVOID (NTAPI *PLLS_GENERIC_ALLOCATE_ROUTINE) ( struct _LLS_GENERIC_TABLE *Table, CLONG ByteSize ); // // The deallocation function is called by the generic table package whenever // it needs to deallocate memory from the table that was allocated by calling // the user supplied allocation function. // typedef VOID (NTAPI *PLLS_GENERIC_FREE_ROUTINE) ( struct _LLS_GENERIC_TABLE *Table, PVOID Buffer ); // // To use the generic table package the user declares a variable of type // GENERIC_TABLE and then uses the routines described below to initialize // the table and to manipulate the table. Note that the generic table // should really be an opaque type. // typedef struct _LLS_GENERIC_TABLE { PRTL_SPLAY_LINKS TableRoot; LIST_ENTRY InsertOrderList; PLIST_ENTRY OrderedPointer; ULONG WhichOrderedElement; ULONG NumberGenericTableElements; PLLS_GENERIC_COMPARE_ROUTINE CompareRoutine; PLLS_GENERIC_ALLOCATE_ROUTINE AllocateRoutine; PLLS_GENERIC_FREE_ROUTINE FreeRoutine; PVOID TableContext; } LLS_GENERIC_TABLE; typedef LLS_GENERIC_TABLE *PLLS_GENERIC_TABLE; // // This enumerated type is used as the function return value of the function // that is used to search the tree for a key. FoundNode indicates that the // function found the key. Insert as left indicates that the key was not found // and the node should be inserted as the left child of the parent. Insert as // right indicates that the key was not found and the node should be inserted // as the right child of the parent. // typedef enum _LLS_TABLE_SEARCH_RESULT{ LLSTableEmptyTree, LLSTableFoundNode, LLSTableInsertAsLeft, LLSTableInsertAsRight } LLS_TABLE_SEARCH_RESULT; // // The procedure InitializeGenericTable takes as input an uninitialized // generic table variable and pointers to the three user supplied routines. // This must be called for every individual generic table variable before // it can be used. // VOID NTAPI LLSInitializeGenericTable ( PLLS_GENERIC_TABLE Table, PLLS_GENERIC_COMPARE_ROUTINE CompareRoutine, PLLS_GENERIC_ALLOCATE_ROUTINE AllocateRoutine, PLLS_GENERIC_FREE_ROUTINE FreeRoutine, PVOID TableContext ); // // The function InsertElementGenericTable will insert a new element // in a table. It does this by allocating space for the new element // (this includes splay links), inserting the element in the table, and // then returning to the user a pointer to the new element. If an element // with the same key already exists in the table the return value is a pointer // to the old element. The optional output parameter NewElement is used // to indicate if the element previously existed in the table. Note: the user // supplied Buffer is only used for searching the table, upon insertion its // contents are copied to the newly created element. This means that // pointer to the input buffer will not point to the new element. // PVOID NTAPI LLSInsertElementGenericTable ( PLLS_GENERIC_TABLE Table, PVOID Buffer, CLONG BufferSize, PBOOLEAN NewElement OPTIONAL ); // // The function InsertElementGenericTableFull will insert a new element // in a table. It does this by allocating space for the new element // (this includes splay links), inserting the element in the table, and // then returning to the user a pointer to the new element. If an element // with the same key already exists in the table the return value is a pointer // to the old element. The optional output parameter NewElement is used // to indicate if the element previously existed in the table. Note: the user // supplied Buffer is only used for searching the table, upon insertion its // contents are copied to the newly created element. This means that // pointer to the input buffer will not point to the new element. // This routine is passed the NodeOrParent and SearchResult from a // previous RtlLookupElementGenericTableFull. // PVOID NTAPI LLSInsertElementGenericTableFull ( PLLS_GENERIC_TABLE Table, PVOID Buffer, CLONG BufferSize, PBOOLEAN NewElement OPTIONAL, PVOID NodeOrParent, LLS_TABLE_SEARCH_RESULT SearchResult ); // // The function DeleteElementGenericTable will find and delete an element // from a generic table. If the element is located and deleted the return // value is TRUE, otherwise if the element is not located the return value // is FALSE. The user supplied input buffer is only used as a key in // locating the element in the table. // BOOLEAN NTAPI LLSDeleteElementGenericTable ( PLLS_GENERIC_TABLE Table, PVOID Buffer ); // // The function LookupElementGenericTable will find an element in a generic // table. If the element is located the return value is a pointer to // the user defined structure associated with the element, otherwise if // the element is not located the return value is NULL. The user supplied // input buffer is only used as a key in locating the element in the table. // PVOID NTAPI LLSLookupElementGenericTable ( PLLS_GENERIC_TABLE Table, PVOID Buffer ); // // The function LookupElementGenericTableFull will find an element in a generic // table. If the element is located the return value is a pointer to // the user defined structure associated with the element. If the element is not // located then a pointer to the parent for the insert location is returned. The // user must look at the SearchResult value to determine which is being returned. // The user can use the SearchResult and parent for a subsequent FullInsertElement // call to optimize the insert. // PVOID NTAPI LLSLookupElementGenericTableFull ( PLLS_GENERIC_TABLE Table, PVOID Buffer, OUT PVOID *NodeOrParent, OUT LLS_TABLE_SEARCH_RESULT *SearchResult ); // // The function EnumerateGenericTable will return to the caller one-by-one // the elements of of a table. The return value is a pointer to the user // defined structure associated with the element. The input parameter // Restart indicates if the enumeration should start from the beginning // or should return the next element. If the are no more new elements to // return the return value is NULL. As an example of its use, to enumerate // all of the elements in a table the user would write: // // for (ptr = EnumerateGenericTable(Table, TRUE); // ptr != NULL; // ptr = EnumerateGenericTable(Table, FALSE)) { // : // } // // // PLEASE NOTE: // // If you enumerate a GenericTable using RtlEnumerateGenericTable, you // will flatten the table, turning it into a sorted linked list. // To enumerate the table without perturbing the splay links, use // RtlEnumerateGenericTableWithoutSplaying PVOID NTAPI LLSEnumerateGenericTable ( PLLS_GENERIC_TABLE Table, BOOLEAN Restart ); // // The function EnumerateGenericTableWithoutSplaying will return to the // caller one-by-one the elements of of a table. The return value is a // pointer to the user defined structure associated with the element. // The input parameter RestartKey indicates if the enumeration should // start from the beginning or should return the next element. If the // are no more new elements to return the return value is NULL. As an // example of its use, to enumerate all of the elements in a table the // user would write: // // RestartKey = NULL; // for (ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey); // ptr != NULL; // ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey)) { // : // } // // If RestartKey is NULL, the package will start from the least entry in the // table, otherwise it will start from the last entry returned. // // // Note that unlike RtlEnumerateGenericTable, this routine will NOT perturb // the splay order of the tree. // PVOID NTAPI LLSEnumerateGenericTableWithoutSplaying ( PLLS_GENERIC_TABLE Table, PVOID *RestartKey ); // // The function GetElementGenericTable will return the i'th element // inserted in the generic table. I = 0 implies the first element, // I = (RtlNumberGenericTableElements(Table)-1) will return the last element // inserted into the generic table. The type of I is ULONG. Values // of I > than (NumberGenericTableElements(Table)-1) will return NULL. If // an arbitrary element is deleted from the generic table it will cause // all elements inserted after the deleted element to "move up". PVOID NTAPI LLSGetElementGenericTable( PLLS_GENERIC_TABLE Table, ULONG I ); // // The function NumberGenericTableElements returns a ULONG value // which is the number of generic table elements currently inserted // in the generic table. ULONG NTAPI LLSNumberGenericTableElements( PLLS_GENERIC_TABLE Table ); // // The function IsGenericTableEmpty will return to the caller TRUE if // the input table is empty (i.e., does not contain any elements) and // FALSE otherwise. // BOOLEAN NTAPI LLSIsGenericTableEmpty ( PLLS_GENERIC_TABLE Table ); // end_ntifs #endif // _LLSRTL_