summaryrefslogtreecommitdiffstats
path: root/private/os2/ssrtl/consys.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/os2/ssrtl/consys.c966
1 files changed, 966 insertions, 0 deletions
diff --git a/private/os2/ssrtl/consys.c b/private/os2/ssrtl/consys.c
new file mode 100644
index 000000000..fabc68d51
--- /dev/null
+++ b/private/os2/ssrtl/consys.c
@@ -0,0 +1,966 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ consys.c
+
+Abstract:
+
+ This module contains CONFIG.SYS related parsing routines.
+
+Author:
+
+ Ofer Porat (oferp) 8-Nov-1992
+
+Environment:
+
+ User Mode Only
+
+Revision History:
+
+--*/
+
+#include "os2ssrtl.h"
+
+
+#define WBLANK(ch) ((ch) == L' ' || (ch) == L'\t')
+
+
+typedef struct _INDEX_T {
+
+ UNICODE_STRING Src;
+ UNICODE_STRING Dest;
+
+} INDEX_T, *PINDEX_T;
+
+
+
+//
+// This routine skips over white space in a unicode string
+// either forward or backward.
+// Str -- address of pointer to string.
+// Direction -- either FWD or BWD.
+//
+
+VOID
+Or2SkipWWS(
+ IN OUT PWSTR *Str,
+ IN LONG Direction
+ )
+{
+ PWSTR q = *Str;
+
+ while (WBLANK(*q)) {
+ q += Direction;
+ }
+ *Str = q;
+}
+
+
+//
+// This routine converts a null terminated unicode string to upper case.
+// It is similar to wcsupr(). It exists because I'm not sure wcsupr()
+// actually uses the Unicode convention.
+//
+// Str -- string to convert.
+//
+
+VOID
+Or2UnicodeStrupr(
+ IN OUT PWSTR Str
+ )
+{
+ while (*Str != UNICODE_NULL) {
+ *Str = RtlUpcaseUnicodeChar(*Str);
+ Str++;
+ }
+}
+
+
+//
+// This routine compares 2 null-terminated unicode strings. The comparison
+// has a count limiting the number of chars compared, and the comparison is
+// case insensitive. It is similar to wcsnicmp(). It exists because I'm not
+// sure wcsnicmp() actually uses the Unicode convention.
+//
+// Str1, Str2 -- strings to compare.
+// Count -- max # of chars to compare.
+// return value -- TRUE if they're equal to within Count characters. FALSE otherwise.
+//
+
+BOOLEAN
+Or2UnicodeEqualCI(
+ IN PWSTR Str1,
+ IN PWSTR Str2,
+ IN ULONG Count
+ )
+{
+ while (Count != 0) {
+
+ if (*Str1 == UNICODE_NULL) {
+
+ if (*Str2 == UNICODE_NULL) {
+ return(TRUE);
+ }
+
+ return(FALSE);
+ }
+
+ if (RtlUpcaseUnicodeChar(*Str1) != RtlUpcaseUnicodeChar(*Str2)) {
+
+ return(FALSE);
+ }
+
+ Str1++; Str2++; Count--;
+ }
+ return(TRUE);
+}
+
+
+//
+// This routine appends a source path list to a destination path list. multiple occurences
+// of the same path are removed.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string. It must be in uppercase for elimination of
+// multiple paths to occur. This path list is appended to DestPath.
+// DestPath -- an already existing counted unicode string containing the path list to be appended
+// to. The case is unimportant. The result is stored back in this string.
+// ExpandIt -- Should be TRUE in DestPath contains unexpanded %...% type strings. FALSE otherwise.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// can't expand the
+// DestPath Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// append Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2AppendPathToPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath,
+ IN BOOLEAN ExpandIt
+ )
+{
+ WCHAR wch;
+ WCHAR wch1;
+ WCHAR wch2;
+ PWSTR p;
+ PWSTR q;
+ PWSTR r;
+ PWSTR t;
+ USHORT l;
+ USHORT addsemi;
+ UNICODE_STRING Expanded;
+ UNICODE_STRING Tmp;
+ BOOLEAN Found;
+ NTSTATUS Status;
+
+ Expanded.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Expanded.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathPath: can't allocate Expanded from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Expanded.MaximumLength = DestPath->MaximumLength;
+
+ if (ExpandIt) {
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ DestPath,
+ &Expanded,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(FALSE);
+ }
+
+ } else {
+
+ RtlCopyUnicodeString(&Expanded, DestPath);
+ }
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ Or2UnicodeStrupr(Expanded.Buffer);
+
+ addsemi = 2;
+
+ if (Expanded.Length == 0 ||
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR) - 1] == L';') {
+
+ addsemi = 0;
+ }
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ l = q - SrcPath + 1;
+
+ wch = *(q+1);
+ *(q+1) = UNICODE_NULL;
+ t = Expanded.Buffer;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ r = wcsstr(t, SrcPath);
+
+ if (r == NULL) {
+ break;
+ }
+
+ if (r == Expanded.Buffer) {
+ wch1 = L';';
+ } else {
+ wch1 = *(r-1);
+ }
+
+ wch2 = r[l];
+
+ if ((wch1 == L';' || WBLANK(wch1)) &&
+ (wch2 == L';' || WBLANK(wch2) || wch2 == UNICODE_NULL)) {
+
+ Found = TRUE;
+ break;
+ }
+
+ t = r + l;
+ }
+
+ *(q+1) = wch;
+
+ if (Found) {
+ SrcPath = p;
+ continue;
+ }
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = l * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ if (Expanded.Length + addsemi + Tmp.Length > Expanded.MaximumLength ||
+ DestPath->Length + addsemi + Tmp.Length > DestPath->MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2AppendPathToPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Expanded, L";");
+ RtlAppendUnicodeToString(DestPath, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Expanded, &Tmp);
+ RtlAppendUnicodeStringToString(DestPath, &Tmp);
+
+ Expanded.Buffer[Expanded.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ SrcPath = p;
+ }
+
+ DestPath->Buffer[DestPath->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Expanded.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine takes a counted unicode string containing a path-list with %...% type strings in it.
+// It prepares a pool of characters containing the expansions of paths with %...% strings in them.
+// Also prepared is an index table. Each entry in the index table contains a counted string pointing
+// to the point in DestPath where the unexpanded path is, and a counted string pointing to the the pool
+// where the expanded path is.
+//
+// SrcPath -- a counted unicode string containing the path-list to generate an index for.
+// Pool -- a buffer containing space for SrcPath.MaximumLength wide characters. This is where
+// the expanded strings will be stored.
+// Ind -- a buffer containing enough space to allocate as many index entries as necessary to index
+// the path list. One way to know how many may be necessary is to count the # of semicolons in
+// SrcPath.
+// IndSize -- will contain the number of entries placed in Ind on exit.
+//
+// Possible Errors Effect
+// =============== ======
+// SrcPath.MaximumLength
+// characters are not
+// enough to store the
+// pool of expanded env
+// strings. Stops after the last expanded env string that fits in the pool.
+//
+
+static
+VOID
+Or2IndexPath(
+ IN PUNICODE_STRING SrcPath,
+ OUT PWSTR Pool,
+ OUT PINDEX_T Ind,
+ OUT PULONG IndSize
+ )
+{
+ PWSTR CurPool = Pool;
+ USHORT PoolQuota = SrcPath->MaximumLength;
+ ULONG IndEx = 0;
+ PWCHAR wp = SrcPath->Buffer;
+ PWCHAR wq, wr;
+ BOOLEAN HasPercent;
+ NTSTATUS Status;
+
+ for (; ; ) {
+
+ Or2SkipWWS(&wp, FWD);
+
+ if (*wp == UNICODE_NULL) {
+ break;
+ }
+
+ HasPercent = FALSE;
+
+ wq = wp;
+
+ while (*wq != L';' && *wq != UNICODE_NULL) {
+ if (*wq == L'%') {
+ HasPercent = TRUE;
+ }
+ wq++;
+ }
+
+ if (*wq == L';') {
+ wr = wq + 1;
+ } else {
+ wr = wq;
+ }
+
+ if (!HasPercent) {
+ wp = wr;
+ continue;
+ }
+
+ wq--;
+
+ Or2SkipWWS(&wq, BWD);
+
+ Ind[IndEx].Dest.Buffer = wp;
+ Ind[IndEx].Dest.Length = (wq - wp + 1) * sizeof(WCHAR);
+ Ind[IndEx].Dest.MaximumLength = Ind[IndEx].Dest.Length;
+
+ wp = wr;
+
+ Ind[IndEx].Src.Buffer = CurPool;
+ Ind[IndEx].Src.MaximumLength = PoolQuota;
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &Ind[IndEx].Dest,
+ &Ind[IndEx].Src,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2IndexPath: can't expand environment strings, rc = %lx\n", Status));
+ }
+#endif
+ break;
+ }
+
+ PoolQuota -= Ind[IndEx].Src.Length;
+ CurPool += Ind[IndEx].Src.Length / sizeof(WCHAR);
+
+ Ind[IndEx].Src.MaximumLength = Ind[IndEx].Src.Length;
+
+ IndEx++;
+ }
+
+ *IndSize = IndEx;
+}
+
+
+//
+// This routine takes a destination path-list and a source path list. The destination path-list
+// is completely replaced with the source path list. The destination list may contain %...% strings.
+// The source list is not expected to contain %...% strings. While the replacement is done, any
+// paths in the source which already exist in the destination in a form containing %...% strings, are
+// retained with their original %...% form.
+//
+// HeapHandle -- a handle to a heap for temporary allocations
+// SrcPath -- a null terminated unicode string containing the replacing path-list.
+// DestPath -- an already existing counted unicode string containing the path list to be replaced
+// to. The result is stored back in this string.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Does nothing, return value FALSE
+// DestPath MaxLen
+// exceeded during
+// replace Stop on the last path that fits, return value TRUE
+//
+
+BOOLEAN
+Or2ReplacePathByPath(
+ IN PVOID HeapHandle,
+ IN PWSTR SrcPath,
+ IN OUT PUNICODE_STRING DestPath
+ )
+{
+ PINDEX_T Ind;
+ PWSTR Pool;
+ PWSTR p;
+ PWSTR q;
+ WCHAR wch;
+ ULONG IndSize;
+ ULONG SemiCount;
+ ULONG i;
+ USHORT addsemi;
+ UNICODE_STRING Target;
+ UNICODE_STRING Tmp;
+
+ Target.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, DestPath->MaximumLength + sizeof(WCHAR));
+
+ if (Target.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Target from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ Target.MaximumLength = DestPath->MaximumLength;
+ Target.Length = 0;
+
+ Pool = (PWSTR) RtlAllocateHeap(HeapHandle, 0, (ULONG) DestPath->MaximumLength);
+
+ if (Pool == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Pool from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ SemiCount = 1;
+
+ for (i = 0; i < DestPath->Length/sizeof(WCHAR); i++) {
+ if (DestPath->Buffer[i] == L';') {
+ SemiCount++;
+ }
+ }
+
+ Ind = (PINDEX_T) RtlAllocateHeap(HeapHandle, 0, SemiCount * sizeof(INDEX_T));
+
+ if (Ind == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: can't allocate Ind from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(FALSE);
+ }
+
+ Or2IndexPath(DestPath, Pool, Ind, &IndSize);
+
+ addsemi = 0;
+
+ while (TRUE) {
+
+ Or2SkipWWS(&SrcPath, FWD);
+
+ wch = *SrcPath;
+
+ if (wch == UNICODE_NULL) {
+ break;
+ }
+
+ if (wch == L';') {
+ SrcPath++;
+ continue;
+ }
+
+ p = wcschr(SrcPath, L';');
+
+ if (p == NULL) {
+
+ p = SrcPath + wcslen(SrcPath);
+ q = p - 1;
+
+ } else {
+
+ q = p - 1;
+ p++;
+ }
+
+ Or2SkipWWS(&q, BWD);
+
+ Tmp.Buffer = SrcPath;
+ Tmp.Length = (q - SrcPath + 1) * sizeof(WCHAR);
+ Tmp.MaximumLength = Tmp.Length;
+
+ for (i = 0; i < IndSize; i++) {
+
+ if (RtlEqualUnicodeString(&Tmp, &Ind[i].Src, TRUE)) {
+
+ Tmp = Ind[i].Dest;
+ break;
+ }
+ }
+
+ if (Target.Length + addsemi + Tmp.Length > Target.MaximumLength) {
+
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2ReplacePathByPath: Path buffer overflow\n"));
+ }
+#endif
+ break; // out of string space, terminate processing.
+ }
+
+ if (addsemi) {
+
+ RtlAppendUnicodeToString(&Target, L";");
+
+ } else {
+
+ addsemi = 2;
+ }
+
+ RtlAppendUnicodeStringToString(&Target, &Tmp);
+
+ SrcPath = p;
+ }
+
+ RtlCopyUnicodeString(DestPath, &Target);
+
+ DestPath->Buffer[DestPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ RtlFreeHeap(HeapHandle, 0, Ind);
+ RtlFreeHeap(HeapHandle, 0, Pool);
+ RtlFreeHeap(HeapHandle, 0, Target.Buffer);
+ return(TRUE);
+}
+
+
+//
+// This routine appends a terminating semicolon to a path list, if that path list
+// does not have a semicolon in it (in other words, if the path list contains only
+// one path).
+//
+// Str - The string to do semicolon processing on.
+//
+
+VOID
+Or2CheckSemicolon(
+ IN OUT PUNICODE_STRING Str
+ )
+{
+ USHORT i;
+ BOOLEAN flag;
+
+ if (Str->Length == 0 || Str->Length >= Str->MaximumLength) {
+ return;
+ }
+
+ flag = FALSE;
+
+ for(i = 0; i < Str->Length/ (USHORT) sizeof(WCHAR); i++) {
+ if (Str->Buffer[i] == L';') {
+ flag = TRUE;
+ break;
+ }
+ }
+
+ if (!flag) {
+ Str->Buffer[i++] = L';';
+ Str->Buffer[i] = UNICODE_NULL;
+ Str->Length += sizeof(WCHAR);
+ }
+}
+
+
+//
+// This routine fetches a path-list type environment variable from the registry.
+//
+// Data - an unallocated counted unicode string to hold the result.
+// HeapHandle -- a handle to a heap where we allocate from.
+// MaxSiz -- The MaximumLength Data should be given.
+// EnvKey -- a handle to the registry key in which the environment to be searched is.
+// ValueName -- a null-terminated unicode name of the registry value to fetch.
+// ExpandIt -- If TRUE, the registry value is expanded for %..% type strings before returning it.
+// return value -- TRUE on success, FALSE otherwise.
+//
+// Possible Errors Effect
+// =============== ======
+// allocation failure Data.Buffer = NULL, return value FALSE
+// requested env variable
+// doesn't exist, or
+// can't query its value Data is allocated and given 0 length, return value TRUE
+// can't expand the
+// env variable Data is allocated and given 0 length, return value TRUE
+//
+
+BOOLEAN
+Or2GetEnvPath(
+ OUT PUNICODE_STRING Data,
+ IN PVOID HeapHandle,
+ IN USHORT MaxSiz,
+ IN HANDLE EnvKey,
+ IN PWSTR ValueName,
+ IN BOOLEAN ExpandIt
+ )
+{
+ PKEY_VALUE_PARTIAL_INFORMATION Buf;
+ UNICODE_STRING ExpBuf;
+ UNICODE_STRING ValueName_U;
+ UNICODE_STRING tmp;
+ ULONG ResultLength;
+ ULONG l1, l2;
+ NTSTATUS Status;
+
+ Data->Buffer = NULL;
+
+ l1 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
+
+ Buf = (PKEY_VALUE_PARTIAL_INFORMATION) RtlAllocateHeap(HeapHandle, 0, l1);
+
+ if (Buf == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate Buf from heap\n"));
+ }
+#endif
+ return(FALSE);
+ }
+
+ if (ExpandIt) {
+
+ l2 = ((ULONG) MaxSiz + 1) * sizeof(WCHAR);
+
+ ExpBuf.Buffer = (PWSTR) RtlAllocateHeap(HeapHandle, 0, l2);
+
+ if (ExpBuf.Buffer == NULL) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("Or2GetEnvPath: can't allocate ExpBuf from heap\n"));
+ }
+#endif
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ return(FALSE);
+ }
+
+ ExpBuf.MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ RtlInitUnicodeString(&ValueName_U, ValueName);
+ Status = NtQueryValueKey(EnvKey,
+ &ValueName_U,
+ KeyValuePartialInformation,
+ Buf,
+ l1,
+ &ResultLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - NtQueryValueKey %lx\n", Status));
+ }
+#endif
+ if (ExpandIt) {
+ RtlFreeHeap(HeapHandle, 0, Buf);
+ ExpBuf.Length = 0;
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ *Data = ExpBuf;
+ } else {
+ *((PWSTR) Buf) = UNICODE_NULL;
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = 0;
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+ }
+
+ if (ExpandIt) {
+ RtlInitUnicodeString(&tmp, (PWSTR) Buf->Data);
+
+ Status = RtlExpandEnvironmentStrings_U(NULL,
+ &tmp,
+ &ExpBuf,
+ NULL);
+
+ RtlFreeHeap(HeapHandle, 0, Buf);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OD2_DEBUG( INIT ) {
+ KdPrint(("OS2SSRTL(Or2GetEnvPath): FAILED - RtlExpandEnvironmentStrings_U %lx\n", Status));
+ }
+#endif
+ ExpBuf.Buffer[0] = UNICODE_NULL;
+ ExpBuf.Length = 0;
+ *Data = ExpBuf;
+ return(TRUE);
+ }
+
+ ExpBuf.Buffer[ExpBuf.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ *Data = ExpBuf;
+
+ } else {
+
+ l2 = Buf->DataLength;
+ RtlMoveMemory(Buf, Buf->Data, l2);
+ Data->Buffer = (PWSTR) Buf;
+ Data->Length = (USHORT) (l2 - sizeof(WCHAR));
+ Data->MaximumLength = MaxSiz * sizeof(WCHAR);
+ }
+
+ return(TRUE);
+}
+
+
+//
+// This is a general routine to parse an environment. It loops over the lines in the environment, and
+// identifies the variable in each line. For each variable, it searches a user dispatch table, and if
+// that dispatch table contains an entry for this variable, it calls the user supplied routine with the
+// name and value of the variable.
+//
+// Environment -- The environment to process. This is either in multi-string format, or a
+// (null|^Z)-terminated string consisting of lines separated by crlfs.
+// DispatchTable -- A dispatch table used to process the environment.
+// NumberOfDispatchItems -- Contains the number of entries in DispatchTable.
+// DelimOption -- specifies whether Environment is a multi-string (NULL_DELIM) or a string of crlf
+// separated lines (CRLF_DELIM).
+//
+// Description of the DispatchTable:
+// This is an array of structures of type ENVIRONMENT_DISPATCH_TABLE_ENTRY.
+// Each entry specifies a particular variable which should be handled.
+// an entry contains:
+// -- the name of the variable to operate on (this is case-insensitive).
+// -- a string of possible characters that serve as delimiters for the variable name (e.g. =, space, tab).
+// -- a DispatchFunction. This function is dispatched with 6 parameters:
+// -- the index in the dispatch table which triggered this call.
+// -- a user defined pointer, see below.
+// -- a pointer to the variable name in the environment.
+// -- length of the variable name (in chars).
+// -- a pointer to the variable value in the environment.
+// -- length of the variable value (in chars).
+// -- a user defined pointer that is passed to the dispatch function.
+//
+// The dispatch function may do anything it likes with the information it gets, and it
+// is not expected to return any value.
+//
+// A special value of "*" in the variable name field of an entry indicates that any variable name
+// is to be processed by the DispatchFunction. The DispatchFunction can figure out the name of
+// the variable it was called for by examining its parameters. If this option is used together
+// with a Delimeters value of NULL, no delimiter will be searched for, the line will be passed
+// as is with Name and Value both pointing to the beginning of the line (and ValueLen containing
+// its length)
+//
+
+VOID
+Or2IterateEnvironment(
+ IN PWSTR Environment,
+ IN ENVIRONMENT_DISPATCH_TABLE DispatchTable,
+ IN ULONG NumberOfDispatchItems,
+ IN ULONG DelimOption
+ )
+{
+ PWSTR Src;
+ PWSTR Tmp;
+ PWSTR Eol;
+ PWSTR NextLine;
+ ULONG i, m;
+ LONG l;
+ BOOLEAN Flag;
+
+ if (NumberOfDispatchItems == 0 || Environment == NULL || DispatchTable == NULL) {
+ return;
+ }
+
+ Src = Environment;
+ while (*Src != UNICODE_NULL) {
+ Or2SkipWWS(&Src, FWD);
+
+ if (DelimOption == CRLF_DELIM &&
+ *Src == L'\32') { // ^Z terminates file on CRLF delim texts
+ break;
+ }
+
+ for (i = 0; i < NumberOfDispatchItems; i++) {
+
+ if (DispatchTable[i].VarName[0] == L'*') {
+
+ if (DispatchTable[i].Delimiters == NULL) {
+
+ //
+ // No delimeter required. If the line is empty
+ // we don't process it.
+ //
+
+ if (*Src == UNICODE_NULL) {
+ continue;
+ }
+
+ if (DelimOption == CRLF_DELIM &&
+ (*Src == L'\r' || *Src == L'\n')) {
+ continue;
+ }
+
+ l = -1; // process the line from start
+ break;
+ }
+
+ Tmp = Src;
+ l = 0;
+ while (TRUE) {
+ if (*Tmp == UNICODE_NULL ||
+ (DelimOption == CRLF_DELIM && (*Tmp == L'\r' || *Tmp == L'\n' || *Tmp == L'\32'))) {
+ Flag = FALSE;
+ break;
+ }
+ if (wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(*Tmp)) != NULL) {
+ Flag = TRUE;
+ break;
+ }
+ Tmp++;
+ l++;
+ }
+
+ if (Flag) {
+ break;
+ }
+ continue;
+ }
+
+ l = wcslen(DispatchTable[i].VarName);
+
+ if (Or2UnicodeEqualCI(Src, DispatchTable[i].VarName, (ULONG)l) &&
+ Src[l] != UNICODE_NULL &&
+ wcschr(DispatchTable[i].Delimiters, RtlUpcaseUnicodeChar(Src[l])) != NULL) {
+ break;
+ }
+ }
+
+ if (DelimOption == NULL_DELIM) {
+ Eol = Src + wcslen(Src);
+ NextLine = Eol + 1;
+ } else {
+ Eol = wcspbrk(Src, L"\r\n\32");
+ if (Eol == NULL) {
+ NextLine = Eol = Src + wcslen(Src);
+ } else {
+ NextLine = Eol;
+ if (*Eol != L'\32') {
+ while (*NextLine == L'\r' || *NextLine == L'\n') {
+ NextLine++;
+ }
+ }
+ }
+ }
+
+ if (i == NumberOfDispatchItems || DispatchTable[i].DispatchFunction == NULL) {
+ Src = NextLine;
+ continue;
+ }
+
+ Tmp = Src + l + 1;
+ Or2SkipWWS(&Tmp, FWD);
+ if (Eol != Tmp) {
+ Eol--;
+ Or2SkipWWS(&Eol, BWD);
+ m = (Eol - Tmp) + 1;
+ } else {
+ m = 0;
+ }
+
+ DispatchTable[i].DispatchFunction(i, DispatchTable[i].UserParameter, Src, l, Tmp, m);
+
+ Src = NextLine;
+ }
+}
+
+
+//
+// Following is useful Dispatch Function for use with Or2IterateEnvironment.
+// It copies the parameters passed to it into a structure of type
+// ENVIRONMENT_SEARCH_RECORD. A pointer to the structure to fill must be
+// passed through the UserParameter in the Dispatch Table.
+//
+
+VOID
+Or2FillInSearchRecordDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+{
+ PENVIRONMENT_SEARCH_RECORD p = (PENVIRONMENT_SEARCH_RECORD) UserParameter;
+
+ p->DispatchTableIndex = DispatchTableIndex;
+ p->Name = Name;
+ p->NameLen = NameLen;
+ p->Value = Value;
+ p->ValueLen = ValueLen;
+}
+