885 lines
25 KiB
C
885 lines
25 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-91 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
listfunc.c
|
||
|
||
Abstract:
|
||
|
||
This module contains functions which canonicalize and traverse lists.
|
||
The following functions are defined:
|
||
|
||
NetpwListCanonicalize
|
||
NetpwListTraverse
|
||
(FixupAPIListElement)
|
||
|
||
Author:
|
||
|
||
Danny Glasser (dannygl) 14 June 1989
|
||
|
||
Notes:
|
||
|
||
There are currently four types of lists supported by these
|
||
functions:
|
||
|
||
UI/Service input list - Leading and trailing delimiters
|
||
are allowed, multiple delimiters are allowed between
|
||
elements, and the full set of delimiter characters is
|
||
allowed (space, tab, comma, and semicolon). Note that
|
||
elements which contain a delimiter character must be
|
||
quoted. Unless explicitly specified otherwise, all UIs
|
||
and services must accept all input lists in this format.
|
||
|
||
API list - Leading and trailing delimiters are not allowed,
|
||
multiple delimiters are not allowed between elements,
|
||
and there is only one delimiter character (space). Elements
|
||
which contain a delimiter character must be quoted.
|
||
Unless explicitly specified otherwise, all lists provided
|
||
as input to API functions must be in this format, and all
|
||
lists generated as output by API functions will be in this
|
||
format.
|
||
|
||
Search-path list - The same format as an API list, except that
|
||
the delimiter is a semicolon. This list is designed as
|
||
input to the DosSearchPath API.
|
||
|
||
Null-null list - Each element is terminated by a null
|
||
byte and the list is terminated by a null string
|
||
(that is, a null byte immediately following the null
|
||
byte which terminates the last element). Clearly,
|
||
multiple, leading, and trailing delimiters are not
|
||
supported. Elements do not need to be quoted. An empty
|
||
null-null list is simply a null string. This list format
|
||
is designed for internal use.
|
||
|
||
NetpListCanonicalize() accepts all UI/Service, API, and null-null
|
||
lists on input and produces API, search-path, and null-null lists
|
||
on output. NetpListTraverse() supports null-null lists only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "nticanon.h"
|
||
|
||
//
|
||
// prototypes
|
||
//
|
||
|
||
STATIC
|
||
DWORD
|
||
FixupAPIListElement(
|
||
IN LPTSTR Element,
|
||
IN LPTSTR* pElementTerm,
|
||
IN LPTSTR BufferEnd,
|
||
IN TCHAR cDelimiter
|
||
);
|
||
|
||
//
|
||
// routines
|
||
//
|
||
|
||
|
||
NET_API_STATUS
|
||
NetpwListCanonicalize(
|
||
IN LPTSTR List,
|
||
IN LPTSTR Delimiters OPTIONAL,
|
||
OUT LPTSTR Outbuf,
|
||
IN DWORD OutbufLen,
|
||
OUT LPDWORD OutCount,
|
||
OUT LPDWORD PathTypes,
|
||
IN DWORD PathTypesLen,
|
||
IN DWORD Flags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
NetpListCanonicalize produces the specified canonical version of
|
||
the list, validating and/or canonicalizing the individual list
|
||
elements as specified by <Flags>.
|
||
|
||
Arguments:
|
||
|
||
List - The list to canonicalize.
|
||
|
||
Delimiters - A string of valid delimiters for the input list.
|
||
A null pointer or null string indicates that the
|
||
input list is in null-null format.
|
||
|
||
Outbuf - The place to store the canonicalized version of the list.
|
||
|
||
OutbufLen - The size, in bytes, of <Outbuf>.
|
||
|
||
OutCount - The place to store the number of elements in the
|
||
canonicalized list.
|
||
|
||
PathTypes - The array in which to store the types of each of the paths
|
||
in the canonicalized list. This parameter is only used if
|
||
the NAMETYPE portion of the flags parameter is set to
|
||
NAMETYPE_PATH.
|
||
|
||
PathTypesLen- The number of elements in <pflPathTypes>.
|
||
|
||
Flags - Flags to determine operation. Currently defined values are:
|
||
|
||
rrrrrrrrrrrrrrrrrrrrmcootttttttt
|
||
|
||
where:
|
||
|
||
r = Reserved. MBZ.
|
||
|
||
m = If set, multiple, leading, and trailing delimiters are
|
||
allowed in the input list.
|
||
|
||
c = If set, each of the individual list elements are
|
||
validated and canonicalized. If not set, each of the
|
||
individual list elements are validated only. This
|
||
bit is ignored if the NAMETYPE portion of the flags is
|
||
set to NAMETYPE_COPYONLY.
|
||
|
||
o = Type of output list. Currently defined types are
|
||
API, search-path, and null-null.
|
||
|
||
t = The type of the objects in the list, for use in
|
||
canonicalization or validation. If this value is
|
||
NAMETYPE_COPYONLY, type is irrelevant; a canonical list
|
||
is generated but no interpretation of the list elements
|
||
is done. If this value is NAMETYPE_PATH, the list
|
||
elements are assumed to be pathnames; NetpPathType is
|
||
run on each element, the results are stored in
|
||
<pflPathTypes>, and NetpPathCanonicalize is run on
|
||
each element (if appropriate). Any other values for
|
||
this is considered to be the type of the list elements
|
||
and is passed to NetpName{Validate,Canonicalize} as
|
||
appropriate.
|
||
|
||
Manifest values for these flags are defined in NET\H\ICANON.H.
|
||
|
||
Return Value:
|
||
|
||
0 if successful.
|
||
The error number (> 0) if unsuccessful.
|
||
|
||
Possible error returns include:
|
||
|
||
ERROR_INVALID_PARAMETER
|
||
NERR_TooManyEntries
|
||
NERR_BufTooSmall
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS rc = 0;
|
||
BOOL NullInputDelimiter;
|
||
LPTSTR next_string;
|
||
DWORD len;
|
||
DWORD list_len = 0; // cumulative input buffer length
|
||
LPTSTR Input;
|
||
LPTSTR OutPtr;
|
||
LPTSTR OutbufEnd;
|
||
DWORD OutElementCount;
|
||
DWORD DelimiterLen;
|
||
LPTSTR NextQuote;
|
||
LPTSTR ElementBegin;
|
||
LPTSTR ElementEnd;
|
||
TCHAR cElementEndBackup;
|
||
LPTSTR OutElementEnd;
|
||
BOOL DelimiterInElement;
|
||
DWORD OutListType;
|
||
TCHAR OutListDelimiter;
|
||
|
||
|
||
#ifdef CANONDBG
|
||
DbgPrint("NetpwListCanonicalize\n");
|
||
#endif
|
||
|
||
if (Flags & INLC_FLAGS_MASK_RESERVED) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Determine if our input list is in null-null format. We do
|
||
// this first because we need to use it to do proper GP-fault probing
|
||
// on <List>.
|
||
//
|
||
|
||
NullInputDelimiter = !ARGUMENT_PRESENT(Delimiters) || (*Delimiters == TCHAR_EOS);
|
||
|
||
//
|
||
// Validate address parameters (i.e. GP-fault tests) and accumulate string
|
||
// lengths (accumulate: now there's a word from a past I'd rather forget)
|
||
//
|
||
|
||
list_len = STRLEN(List) + 1;
|
||
|
||
if (NullInputDelimiter) {
|
||
|
||
//
|
||
// This is a null-null list; stop when we find a null string.
|
||
//
|
||
|
||
next_string = List + list_len;
|
||
do {
|
||
|
||
//
|
||
// Q: Is the compiler smart enough to do the right thing with
|
||
// these +1s?
|
||
//
|
||
|
||
len = STRLEN(next_string);
|
||
list_len += len + 1;
|
||
next_string += len + 1;
|
||
} while (len);
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(Delimiters)) {
|
||
STRLEN(Delimiters);
|
||
}
|
||
|
||
if ((Flags & INLC_FLAGS_MASK_NAMETYPE) == NAMETYPE_PATH && PathTypesLen > 0) {
|
||
PathTypes[0] = PathTypes[PathTypesLen - 1] = 0;
|
||
}
|
||
|
||
*OutCount = 0;
|
||
|
||
//
|
||
// Initialize variables
|
||
//
|
||
|
||
Input = List;
|
||
OutPtr = Outbuf;
|
||
OutbufEnd = Outbuf + OutbufLen;
|
||
OutElementCount = 0;
|
||
|
||
NullInputDelimiter = !ARGUMENT_PRESENT(Delimiters) || (*Delimiters == TCHAR_EOS);
|
||
OutListType = Flags & INLC_FLAGS_MASK_OUTLIST_TYPE;
|
||
|
||
//
|
||
// Skip leading delimiters
|
||
//
|
||
// NOTE: We don't have to both to do this for a null-null list,
|
||
// because if it has a leading delimiter then it's an
|
||
// empty list.
|
||
//
|
||
|
||
if (!NullInputDelimiter) {
|
||
DelimiterLen = STRSPN(Input, Delimiters);
|
||
|
||
if (DelimiterLen > 0 && !(Flags & INLC_FLAGS_MULTIPLE_DELIMITERS)) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
Input += DelimiterLen;
|
||
}
|
||
|
||
//
|
||
// We validate the output list type here are store the delimiter
|
||
// character.
|
||
//
|
||
// NOTE: Later on, we rely on the fact that the delimiter character
|
||
// is not zero if the output list is either API or search-path.
|
||
//
|
||
|
||
if (OutListType == OUTLIST_TYPE_API) {
|
||
OutListDelimiter = LIST_DELIMITER_CHAR_API;
|
||
} else if (OutListType == OUTLIST_TYPE_SEARCHPATH) {
|
||
OutListDelimiter = LIST_DELIMITER_CHAR_SEARCHPATH;
|
||
} else if (OutListType == OUTLIST_TYPE_NULL_NULL) {
|
||
OutListDelimiter = TCHAR_EOS;
|
||
} else {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Loop until we've reached the end of the input list
|
||
// OR until we encounter an error
|
||
//
|
||
|
||
while (*Input != TCHAR_EOS) {
|
||
|
||
//
|
||
// Find the beginning and ending characters of the list element
|
||
//
|
||
|
||
//
|
||
// Handle quoted strings separately
|
||
//
|
||
|
||
if (!NullInputDelimiter && *Input == LIST_QUOTE_CHAR) {
|
||
|
||
//
|
||
// Find the next quote; return an error if there is none
|
||
// or if it's the next character.
|
||
//
|
||
|
||
NextQuote = STRCHR(Input + 1, LIST_QUOTE_CHAR);
|
||
|
||
if (NextQuote == NULL || NextQuote == Input + 1) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
ElementBegin = Input + 1;
|
||
ElementEnd = NextQuote;
|
||
} else {
|
||
ElementBegin = Input;
|
||
ElementEnd = Input
|
||
+ (NullInputDelimiter
|
||
? STRLEN(Input)
|
||
: STRCSPN(Input, Delimiters)
|
||
);
|
||
}
|
||
|
||
//
|
||
// Set the end character to null so that we can treat the list
|
||
// element as a string, saving its real value for later.
|
||
//
|
||
// WARNING: Once we have done this, we should not return from
|
||
// this function until we've restored this character,
|
||
// since we don't want to trash the string the caller
|
||
// passed us. If we are above the label
|
||
// <INLC_RestoreEndChar> and we encounter an error
|
||
// we should set <rc> to the error code and jump
|
||
// to that label (which will restore the character and
|
||
// return if the error is non-zero).
|
||
//
|
||
|
||
cElementEndBackup = *ElementEnd;
|
||
*ElementEnd = TCHAR_EOS;
|
||
|
||
//
|
||
// Copy the list element to the output buffer, validating its
|
||
// name or canonicalizing it as specified by the user.
|
||
//
|
||
|
||
switch(Flags & INLC_FLAGS_MASK_NAMETYPE) {
|
||
case NAMETYPE_PATH:
|
||
|
||
//
|
||
// Make sure that that the <PathTypes> array is big enough
|
||
//
|
||
|
||
if (OutElementCount >= PathTypesLen) {
|
||
rc = NERR_TooManyEntries;
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
|
||
//
|
||
// Determine if we only want to validate or if we also
|
||
// want to canonicalize.
|
||
//
|
||
|
||
if (Flags & INLC_FLAGS_CANONICALIZE) {
|
||
|
||
//
|
||
// We need to set the type to 0 before calling
|
||
// NetpwPathCanonicalize.
|
||
//
|
||
|
||
PathTypes[OutElementCount] = 0;
|
||
|
||
//
|
||
// Call NetICanonicalize and abort if it fails
|
||
//
|
||
|
||
rc = NetpwPathCanonicalize(
|
||
ElementBegin,
|
||
OutPtr,
|
||
(DWORD)(OutbufEnd - OutPtr),
|
||
NULL,
|
||
&PathTypes[OutElementCount],
|
||
0L
|
||
);
|
||
} else {
|
||
|
||
//
|
||
// Just validate the name and determine its type
|
||
//
|
||
|
||
rc = NetpwPathType(
|
||
ElementBegin,
|
||
&PathTypes[OutElementCount],
|
||
0L
|
||
);
|
||
|
||
//
|
||
// If this succeeded, attempt to copy it into the buffer
|
||
//
|
||
|
||
if (rc == 0) {
|
||
if (OutbufEnd - OutPtr < ElementEnd - ElementBegin + 1) {
|
||
rc = NERR_BufTooSmall;
|
||
} else {
|
||
STRCPY(OutPtr, ElementBegin);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (rc) {
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
|
||
//
|
||
// Determine the end of the element (for use below)
|
||
//
|
||
|
||
OutElementEnd = STRCHR(OutPtr, TCHAR_EOS);
|
||
|
||
//
|
||
// Do fix-ups for API list format (enclose element in
|
||
// quotes, if necessary, and replace terminating null
|
||
// with the list delimiter).
|
||
//
|
||
|
||
if (OutListDelimiter != TCHAR_EOS) {
|
||
rc = FixupAPIListElement(
|
||
OutPtr,
|
||
&OutElementEnd,
|
||
OutbufEnd,
|
||
OutListDelimiter
|
||
);
|
||
if (rc) {
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case NAMETYPE_COPYONLY:
|
||
|
||
//
|
||
// Determine if this element needs to be quoted
|
||
//
|
||
|
||
DelimiterInElement = (OutListDelimiter != TCHAR_EOS)
|
||
&& (STRCHR(ElementBegin, OutListDelimiter) != NULL);
|
||
|
||
//
|
||
// See if there's enough room in the output buffer for
|
||
// this element; abort if there isn't.
|
||
//
|
||
// (ElementEnd - ElementBegin) is the number of bytes
|
||
// in the element. We add 1 for the element separator and
|
||
// an additional 2 if we need to enclose the element in quotes.
|
||
//
|
||
|
||
if (OutbufEnd - OutPtr < ElementEnd - ElementBegin + 1 + DelimiterInElement * 2) {
|
||
rc = NERR_BufTooSmall;
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
|
||
//
|
||
// Start the copying; set pointer to output string
|
||
//
|
||
|
||
OutElementEnd = OutPtr;
|
||
|
||
//
|
||
// Put in leading quote, if appropriate
|
||
//
|
||
|
||
if (DelimiterInElement) {
|
||
*OutElementEnd++ = LIST_QUOTE_CHAR;
|
||
}
|
||
|
||
//
|
||
// Copy input to output and advance end pointer
|
||
//
|
||
|
||
STRCPY(OutElementEnd, ElementBegin);
|
||
OutElementEnd += ElementEnd - ElementBegin;
|
||
|
||
//
|
||
// Put in trailing quote, if appropriate
|
||
//
|
||
|
||
if (DelimiterInElement) {
|
||
*OutElementEnd++ = LIST_QUOTE_CHAR;
|
||
}
|
||
|
||
//
|
||
// Store delimiter
|
||
//
|
||
|
||
*OutElementEnd = OutListDelimiter;
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// If this isn't one of the special types, we assume that it's
|
||
// a type with meaning to NetpwNameValidate and
|
||
// NetpwNameCanonicalize. We call the appropriate one of these
|
||
// functions and let it validate the name type and the name,
|
||
// passing back any error it returns.
|
||
//
|
||
|
||
//
|
||
// Determine if we only want to validate or if we also
|
||
// want to canonicalize.
|
||
//
|
||
|
||
if (Flags & INLC_FLAGS_CANONICALIZE) {
|
||
rc = NetpwNameCanonicalize(
|
||
ElementBegin,
|
||
OutPtr,
|
||
(DWORD)(OutbufEnd - OutPtr),
|
||
Flags & INLC_FLAGS_MASK_NAMETYPE,
|
||
0L
|
||
);
|
||
} else {
|
||
rc = NetpwNameValidate(
|
||
ElementBegin,
|
||
Flags & INLC_FLAGS_MASK_NAMETYPE,
|
||
0L
|
||
);
|
||
|
||
//
|
||
// If this succeeded, attempt to copy it into the buffer
|
||
//
|
||
|
||
if (rc == 0) {
|
||
if (OutbufEnd - OutPtr < ElementEnd - ElementBegin + 1) {
|
||
rc = NERR_BufTooSmall;
|
||
} else {
|
||
STRCPY(OutPtr, ElementBegin);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (rc) {
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
|
||
//
|
||
// Determine the end of the element (for use below)
|
||
//
|
||
|
||
OutElementEnd = STRCHR(OutPtr, TCHAR_EOS);
|
||
|
||
//
|
||
// Do fix-ups for API list format (enclose element in
|
||
// quotes, if necessary, and replace terminating null
|
||
// with the list delimiter).
|
||
//
|
||
|
||
if (OutListDelimiter != TCHAR_EOS) {
|
||
rc = FixupAPIListElement(
|
||
OutPtr,
|
||
&OutElementEnd,
|
||
OutbufEnd,
|
||
OutListDelimiter
|
||
);
|
||
if (rc) {
|
||
goto INLC_RestoreEndChar;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
//
|
||
// End of switch statement
|
||
//
|
||
|
||
INLC_RestoreEndChar:
|
||
|
||
//
|
||
// Restore the character at <ElementEnd>; return if one of the
|
||
// above tasks failed.
|
||
//
|
||
|
||
*ElementEnd = cElementEndBackup;
|
||
|
||
if (rc) {
|
||
return rc;
|
||
}
|
||
|
||
//
|
||
// Skip past the last input character if it's a quote character
|
||
//
|
||
|
||
if (*ElementEnd == LIST_QUOTE_CHAR) {
|
||
ElementEnd++;
|
||
}
|
||
|
||
//
|
||
// Skip delimiter(s)
|
||
//
|
||
|
||
if (!NullInputDelimiter) {
|
||
|
||
//
|
||
// Determine the number of delimiters and set the input
|
||
// pointer to point past them.
|
||
//
|
||
|
||
DelimiterLen = STRSPN(ElementEnd, Delimiters);
|
||
Input = ElementEnd + DelimiterLen;
|
||
|
||
//
|
||
// Return an error if:
|
||
//
|
||
// - there are multiple delimiters and the multiple delimiters
|
||
// flag isn't set
|
||
// - we aren't at the end of the list and there are no
|
||
// delimiters
|
||
// - we are at the end of the list, there is a delimiter
|
||
// and the multiple delimiters flag isn't set
|
||
//
|
||
|
||
if (DelimiterLen > 1 && !(Flags & INLC_FLAGS_MULTIPLE_DELIMITERS)) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
if (*Input != TCHAR_EOS && DelimiterLen == 0) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
if (*Input == TCHAR_EOS && DelimiterLen > 0 && !(Flags & INLC_FLAGS_MULTIPLE_DELIMITERS)) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Since this is a null-null list, we know we've already
|
||
// found at least one delimiter. We don't have to worry about
|
||
// multiple delimiters, because a second delimiter indicates
|
||
// the end of the list.
|
||
//
|
||
|
||
Input = ElementEnd + 1;
|
||
}
|
||
|
||
//
|
||
// Update output list pointer and output list count
|
||
//
|
||
|
||
OutPtr = OutElementEnd + 1;
|
||
OutElementCount++;
|
||
}
|
||
|
||
//
|
||
// End of while loop
|
||
//
|
||
|
||
|
||
//
|
||
// If the input list was empty, set the output buffer to be a null
|
||
// string. Otherwise, stick the list terminator at the end of the
|
||
// output buffer.
|
||
//
|
||
|
||
if (OutElementCount == 0) {
|
||
if (OutbufLen < 1) {
|
||
return NERR_BufTooSmall;
|
||
}
|
||
*Outbuf = TCHAR_EOS;
|
||
} else {
|
||
if (OutListType == OUTLIST_TYPE_NULL_NULL) {
|
||
|
||
//
|
||
// Make sure there's room for one more byte
|
||
//
|
||
|
||
if (OutPtr >= OutbufEnd) {
|
||
return NERR_BufTooSmall;
|
||
}
|
||
*OutPtr = TCHAR_EOS;
|
||
} else {
|
||
|
||
//
|
||
// NOTE: It's OK to move backwards in the string here because
|
||
// we know then OutPtr points one byte past the
|
||
// delimiter which follows the last element in the list.
|
||
// This does not violate DBCS as long as the delimiter
|
||
// is a single-byte character.
|
||
//
|
||
|
||
*(OutPtr - 1) = TCHAR_EOS;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the count of elements in the list
|
||
//
|
||
|
||
*OutCount = OutElementCount;
|
||
|
||
//
|
||
// We're done; return with success
|
||
//
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
LPTSTR
|
||
NetpwListTraverse(
|
||
IN LPTSTR Reserved OPTIONAL,
|
||
IN LPTSTR* pList,
|
||
IN DWORD Flags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Traverse a list which has been converted to null-null form by
|
||
NetpwListCanonicalize. NetpwListTraverse returns a pointer to the first
|
||
element in the list, and modifies the list pointer parameter to point to the
|
||
next element of the list.
|
||
|
||
Arguments:
|
||
|
||
Reserved- A reserved far pointer. Must be NULL.
|
||
|
||
pList - A pointer to the pointer to the beginning of the list. On return
|
||
this will point to the next element in the list or NULL if we
|
||
have reached the end
|
||
|
||
Flags - Flags to determine operation. Currently MBZ.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the first element in the list, or NULL if the list
|
||
is empty.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPTSTR FirstElement;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
UNREFERENCED_PARAMETER(Flags);
|
||
|
||
//
|
||
// Produce an assertion error if the reserved parameter is not NULL
|
||
// or the flags parameter is no zero.
|
||
//
|
||
|
||
//
|
||
// KEEP - This code is ifdef'd out because NETAPI.DLL won't build
|
||
// with the standard C version of assert(). This code
|
||
// should either be replaced or the #if 0 should be removed
|
||
// when we get a standard Net assert function.
|
||
//
|
||
|
||
#ifdef CANONDBG
|
||
NetpAssert((Reserved == NULL) && (Flags == 0));
|
||
#endif
|
||
|
||
//
|
||
// Return immediately if the pointer to the list pointer is NULL,
|
||
// if the list pointer itself is NULL, or if the list is a null
|
||
// string (which marks the end of the null-null list).
|
||
//
|
||
|
||
if (pList == NULL || *pList == NULL || **pList == TCHAR_EOS) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Save a pointer to the first element
|
||
//
|
||
|
||
FirstElement = *pList;
|
||
|
||
//
|
||
// Update the list pointer to point to the next element
|
||
//
|
||
|
||
// *pList += STRLEN(FirstElement) + 1;
|
||
*pList = STRCHR(FirstElement, TCHAR_EOS) + 1;
|
||
|
||
//
|
||
// Return the pointer to the first element
|
||
//
|
||
|
||
return FirstElement;
|
||
}
|
||
|
||
|
||
STATIC
|
||
DWORD
|
||
FixupAPIListElement(
|
||
IN LPTSTR Element,
|
||
IN LPTSTR* pElementTerm,
|
||
IN LPTSTR BufferEnd,
|
||
IN TCHAR DelimiterChar
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
FixupAPIListElement Fixes-up a list element which has been copied into the
|
||
output buffer so that it conforms to API list format.
|
||
|
||
FixupAPIListElement takes an unquoted, null-terminated list element
|
||
(normally, which has been copied into the output buffer by strcpy() or by
|
||
Netpw{Name,Path}Canonicalize) and translates it into the format expected by
|
||
API and search-path lists. Specifically, it surrounds the element with quote
|
||
characters if it contains a list delimiter character, and it replaces the
|
||
null terminator with the API list delimiter.
|
||
|
||
Arguments:
|
||
Element - A pointer to the beginning of the null-terminated element.
|
||
|
||
pElementTerm- A pointer to the pointer to the element's (null) terminator.
|
||
|
||
BufferEnd - A pointer to the end of the output buffer (actually, one byte
|
||
past the end of the buffer).
|
||
|
||
DelimiterChar- The list delimiter character.
|
||
|
||
Return Value:
|
||
|
||
0 if successful.
|
||
|
||
NERR_BufTooSmall if the buffer doesn't have room for the additional
|
||
quote characters.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// See if the element contains a delimiter; if it does, it needs to
|
||
// be quoted.
|
||
//
|
||
|
||
if (STRCHR(Element, DelimiterChar) != NULL) {
|
||
|
||
//
|
||
// Make sure that the output buffer has room for two more
|
||
// characters (the quotes).
|
||
//
|
||
|
||
if (BufferEnd - *pElementTerm <= 2 * sizeof(*BufferEnd)) {
|
||
return NERR_BufTooSmall;
|
||
}
|
||
|
||
//
|
||
// Shift the string one byte to the right, stick quotes on either
|
||
// side, and update the end pointer. The element itself with be
|
||
// stored in the range [Element + 1, *pElementTerm].
|
||
//
|
||
|
||
MEMMOVE(Element + sizeof(*Element), Element, (int)(*pElementTerm - Element));
|
||
*Element = LIST_QUOTE_CHAR;
|
||
*(*pElementTerm + 1) = LIST_QUOTE_CHAR;
|
||
*pElementTerm += 2;
|
||
}
|
||
|
||
//
|
||
// Put a delimiter at the end of the element
|
||
//
|
||
|
||
**pElementTerm = DelimiterChar;
|
||
|
||
//
|
||
// Return with success
|
||
//
|
||
|
||
return 0;
|
||
}
|