summaryrefslogtreecommitdiffstats
path: root/private/windows/prsinf
diff options
context:
space:
mode:
Diffstat (limited to 'private/windows/prsinf')
-rw-r--r--private/windows/prsinf/makefile6
-rw-r--r--private/windows/prsinf/prsinf.c953
-rw-r--r--private/windows/prsinf/prsinf.h347
-rw-r--r--private/windows/prsinf/sources43
-rw-r--r--private/windows/prsinf/spinf.c1760
-rw-r--r--private/windows/prsinf/spinf.h104
-rw-r--r--private/windows/prsinf/test.c125
7 files changed, 3338 insertions, 0 deletions
diff --git a/private/windows/prsinf/makefile b/private/windows/prsinf/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/windows/prsinf/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/windows/prsinf/prsinf.c b/private/windows/prsinf/prsinf.c
new file mode 100644
index 000000000..5dfe1ad03
--- /dev/null
+++ b/private/windows/prsinf/prsinf.c
@@ -0,0 +1,953 @@
+
+//
+// changes some definitions in spinf
+//
+
+#include <windows.h>
+#include <string.h>
+#include "prsinf.h"
+#include "spinf.h"
+#include <stdio.h>
+
+#define CBMAXSECTION 256
+#define SZLANGSECTION "OptionsText"
+
+//
+// BUGBUG I don't know what is supposed to happen with this.
+//
+#define DWLANGMAX 4
+PCHAR rgszLangs[DWLANGMAX] = {"ENG", "GER", "FREN", "SPAN"};
+
+#define ENGLISH 0
+#define GERMAN 1
+#define FRENCH 2
+#define SPANISH 3
+
+PCHAR GetKeyOrValue( HANDLE, PCHAR, ULONG );
+
+//
+// Device Type to INF filename mapping in the system directory
+//
+
+typedef struct _DeviceTypeToInf {
+ PCHAR szDeviceType;
+ PCHAR szSystemInf;
+ PCHAR szOemInfPrefix;
+ } DEVICETYPETOINF, *pDEVICETYPETOINF;
+
+DEVICETYPETOINF DeviceTypeToInfList[] = {
+ { "Computer" , "COMPUTER.INF" , "OEMCPT" },
+ { "Video" , "VIDEO.INF" , "OEMVIO" },
+ { "Pointer" , "POINTER.INF" , "OEMPTR" },
+ { "Keyboard" , "KEYBOARD.INF" , "OEMKBD" },
+ { "Layout" , "LAYOUT.INF" , "OEMLAY" },
+ { "Language" , "LANGUAGE.INF" , "OEMLNG" },
+ { "Printer" , "PRINTER.INF" , "OEMPRN" },
+ { "Scsi" , "SCSI.INF" , "OEMSCS" },
+ { "Tape" , "TAPE.INF" , "OEMTAP" },
+ { "Sound" , "SOUND.INF" , "OEMSND" },
+ { "Driver" , "DRIVER.INF" , "OEMDRV" },
+ { NULL , NULL , NULL }
+ };
+
+BOOLEAN
+GetFullInfName(
+
+ IN PCHAR szInfName,
+ IN ULONG cb,
+ OUT PCHAR pszFullInfName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes non-qualified inf file name and inserts
+ the directory where inf files are kept in front.
+
+Arguments:
+
+
+ szInfName - Unqualified inf file name
+ cb - number of bytes in Full Inf name buffer
+ pszFullInfName - Pointer to buffer to hold name
+
+Return Value:
+
+ True of name could fit and there is a location for inf files
+
+--*/
+
+{
+ ULONG cbFullName;
+
+ //
+ // Currently all inf's are stored in system directory
+ //
+ cbFullName = GetSystemDirectory(pszFullInfName, cb);
+ if (cbFullName == 0) {
+
+ return( FALSE );
+ }
+
+ if ((cbFullName + strlen( szInfName) + 0) > cb) {
+
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return( FALSE );
+ }
+ strcat(pszFullInfName, szInfName);
+ return( TRUE );
+
+}
+
+PCHAR
+GetInfFileList ( )
+
+/*++
+
+Routine Description:
+
+ Locates all OEM INF files in the system directory.
+
+ This function fills a string buffer with a double 0 terminated
+ list of filenames. Each filename in the buffer is separated from
+ the next by a single 0 termination char. Each filename is relative
+ to the directory where OEM inf files are stored.
+
+Arguments:
+
+ szInfType - String to match in Identification section.
+
+Return Value:
+
+ A NULL is returned on error or no files found. Use GetLastError to
+ determine exact error.
+
+ NOTE: The returned buffer is allocated with LocalAlloc. It MUST be
+ freed with LocalFree by the caller.
+
+--*/
+
+{
+
+ PCHAR psz, pszT;
+ ULONG obBuff, cbBuffMax;
+ ULONG cbPath;
+ HANDLE hndFind;
+ CHAR szSearchPath[MAX_PATH];
+ WIN32_FIND_DATA ffd;
+
+ //
+ // Fully Qualify the file masm first.
+ //
+ if (!GetFullInfName( "\\*.inf",MAX_PATH, szSearchPath)) {
+
+ return( NULL );
+ }
+
+ hndFind = FindFirstFile(szSearchPath, &ffd);
+ if (hndFind == BADHANDLE) {
+
+ return( NULL );
+
+ }
+
+ //
+ // Use an initial guess to start out buffer
+ //
+ cbBuffMax = 12 * MAX_PATH;
+ if ((psz = LocalAlloc(LPTR, cbBuffMax)) == NULL) {
+
+ return( NULL );
+
+ }
+
+ strcpy(psz, ffd.cFileName);
+ obBuff = strlen(psz) + 1;
+ //
+ // Locate all inf files and see if they are of the correct type.
+ //
+ //
+ while ( FindNextFile(hndFind, &ffd) ) {
+
+ cbPath = strlen( ffd.cFileName );
+ //
+ // compute spaced needed plus 2 for string and buffer terminatation
+ //
+ if (cbBuffMax <= (cbPath + obBuff + 2)) {
+
+ cbBuffMax += cbPath + MAX_PATH;
+ pszT = LocalReAlloc(psz, cbBuffMax, LMEM_ZEROINIT | LMEM_MOVEABLE);
+ if (pszT == NULL) {
+
+ LocalFree( psz );
+ return( NULL );
+
+ }
+
+ psz = pszT;
+
+ }
+
+ strcpy(psz + obBuff, ffd.cFileName);
+ obBuff += cbPath + 1;
+ }
+
+ //
+ // Terminate buffer
+ //
+ psz[obBuff] = 0;
+
+ //
+ // realloc down to exact size. plus buffer for terminator
+ //
+ LocalReAlloc(psz, obBuff + 1, LMEM_ZEROINIT);
+ return( psz );
+}
+
+HANDLE
+OpenInfFile (
+
+ IN PCHAR szFileName,
+ IN PCHAR szInfType
+ )
+
+/*++
+
+Routine Description:
+
+ Opens an INF file of the specified type and returns an open handle
+ to it.
+
+ szInfType should match the string in the OptionType value in the
+ Identification section of the INF file.
+
+ if szFileName is a simple filename with no path information the directory
+ where all OEM files are kept is prepended. If szFileName contains any
+ path information it should contain a full path.
+
+Arguments:
+
+ szFileName - File name to locate.
+ szInfType - String to match in Identification section.
+
+Return Value:
+
+ Returns a Bad handle (-1) if szInfType does not match or the file could
+ not be opened.
+
+--*/
+
+{
+
+ CHAR szPath[MAX_PATH];
+ PCHAR szTypeCur;
+ ULONG cbPath;
+ HANDLE hndInf;
+
+
+ //
+ // Check to see if file name has any path characters.
+ // If not then get the standard location for all OEM
+ // files. If it does then assume a full path name.
+ //
+ szPath[0] = 0;
+ cbPath = 0;
+
+ if (!strpbrk( szFileName, "\\:") ) {
+
+ //
+ // This can only fail if buffer too small, but a path cannot
+ // be greater then MAX_PATH.
+ //
+ cbPath = GetSystemDirectory(szPath, MAX_PATH);
+ strcat(szPath, "\\");
+ }
+
+ if ((cbPath + strlen(szFileName)) < MAX_PATH - 2) {
+
+ strcat(szPath, szFileName);
+
+ } else {
+
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return( BADHANDLE );
+ }
+ //
+ // Open the file, load and parse it
+ //
+ hndInf = SpInitINFBuffer(szPath);
+ if (hndInf == BADHANDLE) {
+
+ return( BADHANDLE);
+
+ }
+
+ //
+ // [Identification]
+ // OptionType = <option text> (i.e. match szTypeCur)
+ //
+ szTypeCur = SpGetSectionKeyIndex(hndInf,"Identification","OptionType", 0);
+
+ if (szTypeCur == NULL) {
+
+ //
+ // Could not find Identification section
+ //
+ CloseInfFile( hndInf );
+ SetLastError( ERROR_INF_TYPE_MISMATCH );
+ return( BADHANDLE );
+
+ }
+
+ if (_strcmpi(szTypeCur, szInfType)) {
+
+ //
+ // File is not correct type
+ //
+ // LocalFree( szTypeCur );
+ CloseInfFile( hndInf );
+ SetLastError( ERROR_INF_TYPE_MISMATCH );
+ return( BADHANDLE );
+
+ }
+
+
+ // LocalFree( szTypeCur );
+ return(hndInf);
+
+}
+
+
+
+VOID
+CloseInfFile (
+
+ IN HANDLE hInf
+ )
+
+/*++
+
+Routine Description:
+
+ Free Resources
+
+Arguments:
+
+ hInf - Handle to OEM INF file.
+
+Return Value:
+
+--*/
+
+{
+
+ SpFreeINFBuffer( hInf );
+
+
+}
+
+PCHAR
+GetTokenElementList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szSectionName,
+ IN PCHAR szKey
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a buffer of tokens seperated by comma
+ found in the specificied section with the specified key.
+
+Arguments:
+
+
+Return Value:
+
+ *psz - Pointer to array of elements
+
+--*/
+
+{
+ ULONG irgsz;
+ PCHAR psz;
+ PCHAR szTokenCur;
+ ULONG obBuff, cbBuffMax;
+ ULONG cbToken;
+
+
+ if (!SpGetSectionKeyExists(hndInf, szSectionName, szKey)) {
+
+ SetLastError(ERROR_SECTION_NOT_FOUND);
+ return( NULL );
+
+ }
+
+ //
+ // Allocate space to hold elements from the inf file
+ // Use an initial guess of 256 to start out buffer
+ //
+ cbBuffMax = 256;
+ obBuff = 0;
+ if ((psz = LocalAlloc(LPTR, cbBuffMax)) == NULL) {
+
+ return( NULL );
+
+ }
+
+ //
+ // Loop through inf key value reading in elements
+ // Stop when run out of lines.
+ //
+ for (irgsz = 0;
+ szTokenCur = SpGetSectionKeyIndex(hndInf, szSectionName, szKey, irgsz);
+ irgsz++) {
+
+ cbToken = strlen( szTokenCur );
+ if (cbBuffMax <= (cbToken + obBuff + 2)) {
+
+ cbBuffMax += cbToken + 256;
+ psz = LocalReAlloc(psz, cbBuffMax ,LMEM_ZEROINIT | LMEM_MOVEABLE);
+ if (psz == NULL) {
+
+ LocalFree( psz );
+ // LocalFree(szTokenCur);
+ return( NULL );
+
+ }
+ }
+
+ strcpy(psz + obBuff, szTokenCur);
+ obBuff += cbToken ;
+ psz[obBuff++] = ',';
+ // LocalFree(szTokenCur);
+
+ }
+
+ //
+ // realloc down to exact size plus buffer terminator
+ //
+ LocalReAlloc(psz, obBuff + 1, LMEM_ZEROINIT);
+ //
+ // remove the comma for the last element and terminate buffer
+ //
+ psz[--obBuff] = 0;
+ psz[obBuff] = 0;
+
+ return( psz );
+
+}
+
+
+PCHAR
+GetSectionElementList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szSectionName
+ )
+/*++
+
+Routine Description:
+
+ This routine build buffer of zero terminated strings out of the elements
+ in the specified section of the specified inf file.
+
+Arguments:
+
+ hndInf - Path to OS NAMES file.
+ szSectionName - Section name for to search.
+ idxElement - index within a line to element
+
+Return Value:
+
+ *psz - Pointer to array of elements
+
+--*/
+
+{
+ ULONG irgsz;
+ PCHAR psz;
+ PCHAR szElementCur;
+ ULONG obBuff, cbBuffMax;
+ ULONG cbElement;
+
+
+ if (!SpSearchINFSection(hndInf, szSectionName)) {
+
+ SetLastError( ERROR_SECTION_NOT_FOUND );
+ return( NULL );
+
+ }
+
+ //
+ // Allocate space to hold elements from the inf file
+ // Use an initial guess of 256 to start out buffer
+ //
+ cbBuffMax = 256;
+ obBuff = 0;
+ if ((psz = LocalAlloc(LPTR, cbBuffMax)) == NULL) {
+
+ return( NULL );
+
+ }
+
+ //
+ // Loop through inf section reading in elements
+ // Stop when run out of lines.
+ //
+
+ for (irgsz = 0;
+ szElementCur = GetKeyOrValue(hndInf, szSectionName, irgsz);
+ irgsz++ ) {
+
+ cbElement = strlen( szElementCur );
+ if (cbBuffMax <= (cbElement + obBuff + 2)) {
+
+ cbBuffMax += cbElement + 256;
+ psz = LocalReAlloc(psz, cbBuffMax ,LMEM_ZEROINIT | LMEM_MOVEABLE);
+ if (psz == NULL) {
+
+ LocalFree( psz );
+ // LocalFree(szElementCur);
+ return( NULL );
+
+ }
+ }
+
+ strcpy(psz + obBuff, szElementCur);
+ obBuff += cbElement + 1;
+ // LocalFree(szElementCur);
+
+ }
+
+ //
+ // realloc down to exact size plus buffer terminator
+ //
+ LocalReAlloc(psz, obBuff + 1, LMEM_ZEROINIT);
+
+ //
+ // Terminate entire buffer
+ //
+ psz[obBuff] = 0;
+ return( psz );
+
+}
+
+PCHAR
+GetKeyOrValue(
+
+ IN HANDLE hndInf,
+ IN PCHAR szSectionName,
+ IN ULONG idxLine
+ )
+
+{
+
+ PCHAR szElementCur;
+
+ szElementCur = SpGetKeyName(hndInf, szSectionName, idxLine);
+ if (szElementCur == NULL) {
+
+ szElementCur = SpGetSectionLineIndex(hndInf,
+ szSectionName,
+ idxLine,
+ 0);
+
+ }
+
+ return( szElementCur );
+
+}
+
+PCHAR
+GetOptionList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szOptionSection
+
+ )
+
+/*++
+
+Routine Description:
+
+ This function fills a string buffer with a double 0 terminated
+ list of options from the specified options section. Each option
+ in the buffer is separated from the next option by a single 0
+ termination char. CharNext() and CharPrev() apis should be used
+ to move thru the buffer.
+
+ A NULL szOptionSection will use the default option section name.
+
+Arguments:
+
+ hndInf - Handle to open INF file
+ szOptionSection - section name containing options
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ HANDLE is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+ ERROR_FILE_NOT_FOUND
+
+
+--*/
+
+{
+
+ return( GetSectionElementList(hndInf,szOptionSection) );
+
+}
+
+
+PCHAR
+GetOptionText (
+
+ HANDLE hndInf,
+ PCHAR szOption,
+ DWORD dwLang
+
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the UserInterface display string associated with
+ the option in the desired language.
+
+ Every INF file will have at least one language for option
+ text display. If the desired language is not present then
+ the first listed language text should be returned.
+
+ If the option does not exist or the language does not exist then a
+ pointer to a NULL is returned.
+
+ dwLang should be one of the already defined NLS values
+
+Arguments:
+
+ hInf - Handle to open INF file
+ szOption - Option to match
+ language - Language to match
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ PCHAR is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+
+--*/
+
+{
+
+ CHAR szLangSection[CBMAXSECTION];
+ PCHAR pszOptionText;
+
+ if (dwLang >= DWLANGMAX) {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return( NULL );
+
+ }
+
+ strcpy( szLangSection, SZLANGSECTION );
+ strcat(szLangSection, rgszLangs[dwLang]);
+ pszOptionText = GetTokenElementList(hndInf, szLangSection, szOption);
+ return( pszOptionText );
+}
+
+
+PCHAR
+GetAllOptionsText(
+ IN PCHAR szInfType,
+ IN DWORD dwLang
+ )
+
+/*++
+
+Routine Description:
+
+ Fills the string buffer szBuffer with a set of triplets
+ consisting of File Name, Option, Option Text. All 0 terminated
+ with a double 0 termination for buffer. This used where infType
+ is to span multiple inf files.
+
+ dwLang should be one of the already defined NLS values
+
+Arguments:
+
+ szInfFile - Identificaton section to match
+ szLang - Language to match
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ PCHAR is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+
+
+--*/
+
+{
+
+
+ HANDLE hndInf;
+ PCHAR pszOptions, pszOptionsOrg;
+ PCHAR pszOptionText;
+ PCHAR pszFiles, pszFilesOrg;
+ PCHAR pszBuff;
+ ULONG cbBuff, cbBuffMax;
+ ULONG obBuff;
+
+ pDEVICETYPETOINF pDeviceTypeToInf = DeviceTypeToInfList;
+ PCHAR szSystemInf = NULL;
+ PCHAR szOemInfPrefix = NULL;
+ ULONG cbOemInfPrefix = 0;
+
+ //
+ // Get the list of all infs in the system directory
+ //
+
+ pszFilesOrg = pszFiles = GetInfFileList( );
+ if (pszFiles == NULL) {
+
+ return( NULL );
+
+ }
+
+ //
+ // Find out the infs we will look for in this list
+ //
+ while( pDeviceTypeToInf->szDeviceType != NULL ) {
+ if( !_strcmpi(pDeviceTypeToInf->szDeviceType, szInfType)) {
+ szSystemInf = pDeviceTypeToInf->szSystemInf;
+ szOemInfPrefix = pDeviceTypeToInf->szOemInfPrefix;
+ cbOemInfPrefix = lstrlen( szOemInfPrefix );
+ break;
+ }
+ pDeviceTypeToInf++;
+ }
+
+ if( szSystemInf == NULL || szOemInfPrefix == NULL ) {
+ return( NULL );
+ }
+
+ //
+ // Allocate space to hold elements from the inf file
+ // Use an initial guess to start out buffer
+ //
+ cbBuffMax = 1024;
+ obBuff = 0;
+ if ((pszBuff = LocalAlloc(LPTR, cbBuffMax)) == NULL) {
+
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ LocalFree( pszFiles );
+ return( NULL );
+
+ }
+
+ //
+ // Loop through the inf files looking for one that
+ // matches the szInfType. Once found fetch the correct
+ // text section based upon language id.
+ //
+ for( ; *pszFiles; pszFiles += strlen(pszFiles) + 1) {
+
+ if ( _strcmpi(pszFiles, szSystemInf) &&
+ _strnicmp(pszFiles, szOemInfPrefix, cbOemInfPrefix)) {
+
+ continue;
+ }
+
+ hndInf = OpenInfFile( pszFiles, szInfType );
+
+ if (hndInf == BADHANDLE) {
+
+ //
+ // Check if the problem was just the wrong type of
+ // inf file.
+ //
+ if (GetLastError() != ERROR_INF_TYPE_MISMATCH) {
+
+ return( NULL );
+
+ } else {
+
+ continue;
+
+ }
+
+ }
+
+ //
+ // Get the list of options and fetch the correct text
+ //
+ pszOptionsOrg = pszOptions = GetOptionList(hndInf, "OPTIONS");
+ if (pszOptions == NULL) {
+
+ CloseInfFile( hndInf );
+ LocalFree( pszFilesOrg );
+ return( NULL );
+
+ }
+
+ while (*pszOptions) {
+
+ pszOptionText = GetOptionText(hndInf, pszOptions, dwLang);
+ if (pszOptionText == NULL) {
+
+ CloseInfFile( hndInf );
+ LocalFree( pszFilesOrg );
+ LocalFree( pszOptionsOrg );
+ return( NULL );
+ }
+
+ //
+ // Compute buffer size and add in enough 0's and 1 for termination
+ //
+ cbBuff = strlen(pszOptions) + strlen(pszOptionText) + strlen(pszFiles);
+
+ if (cbBuffMax <= (cbBuff + obBuff + 4)) {
+
+ cbBuffMax += cbBuff + 1024;
+ pszBuff = LocalReAlloc(pszBuff, cbBuffMax ,LMEM_ZEROINIT | LMEM_MOVEABLE);
+ if (pszBuff == NULL) {
+
+ LocalFree( pszBuff );
+ CloseInfFile( hndInf );
+ LocalFree( pszFilesOrg );
+ LocalFree( pszOptionsOrg );
+ return( NULL );
+
+ }
+ }
+
+ strcpy(pszBuff + obBuff, pszOptions);
+ obBuff += strlen(pszOptions) + 1;
+ strcpy(pszBuff + obBuff, pszOptionText);
+ obBuff += strlen(pszOptionText) + 1;
+ strcpy(pszBuff + obBuff, pszFiles);
+ obBuff += strlen(pszFiles) + 1;
+
+ // LocalFree( pszOptionText );
+ pszOptions += strlen(pszOptions) + 1;
+
+ }
+
+ LocalFree( pszOptionsOrg );
+
+ CloseInfFile( hndInf );
+ //
+ // terminate entire buffer
+ //
+ pszBuff[obBuff] = 0;
+ }
+
+ LocalFree( pszFilesOrg );
+
+ //
+ // realloc down to exact size. plus buffer terminator
+ //
+ LocalReAlloc(pszBuff, obBuff + 1, LMEM_ZEROINIT);
+
+ return( pszBuff );
+
+}
+
+#if 0
+BOOLEAN
+GetOemInfFile (
+
+ IN PCHAR szInfType
+
+ )
+
+/*++
+
+Routine Description:
+
+ Prompts user to provide a path to or insert a disk with new
+ options. This routine reads and copies the .INF file to
+ the local system directory using whatever naming convention
+ we think up.
+
+Arguments:
+
+ szInfType - Identification to match
+
+Return Value:
+
+ Returns TRUE if new .INF file chosen by user has options of
+ type szInfType.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( szInfType );
+
+ return( FALSE );
+
+}
+
+
+BOOLEAN
+InstallInfOption (
+
+ IN PCHAR szInfFile,
+ IN PCHAR szOption,
+ IN PCHAR szAction
+ )
+
+/*++
+
+Routine Description:
+
+ Invokes SETUP with proper set of command line arguments, waits for
+ process completion and returns status to calling application.
+
+Arguments:
+
+ szInfType - Identification to match
+ szOption - Option to Install.
+ szAction - Section to execute (usually this is "Install")
+
+Return Value:
+
+ Returns TRUE on successful option installation, FALSE otherwise.
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( szInfFile );
+ UNREFERENCED_PARAMETER( szOption );
+ UNREFERENCED_PARAMETER( szAction );
+ return( FALSE );
+
+}
+
+#endif
diff --git a/private/windows/prsinf/prsinf.h b/private/windows/prsinf/prsinf.h
new file mode 100644
index 000000000..92fce6ab8
--- /dev/null
+++ b/private/windows/prsinf/prsinf.h
@@ -0,0 +1,347 @@
+typedef ULONG ARC_STATUS;
+#define BADHANDLE (HANDLE)-1
+
+//
+// Define Error codes
+//
+#define ERROR_PRSINF_FIRST 0xFF00
+#define ERROR_INF_TYPE_MISMATCH ERROR_PRSINF_FIRST + 0
+#define ERROR_EXPECTED_LBRACE ERROR_PRSINF_FIRST + 1
+#define ERROR_EXPECTED_STRING ERROR_PRSINF_FIRST + 2
+#define ERROR_EXPECTED_RBRACE ERROR_PRSINF_FIRST + 3
+#define ERROR_EXPECTED_EOL ERROR_PRSINF_FIRST + 4
+#define ERROR_EXPECTED_SECTION_LINE ERROR_PRSINF_FIRST + 5
+#define ERROR_EXPECTED_BAD_LINE ERROR_PRSINF_FIRST + 6
+#define ERROR_EXPECTED_COMMA_ANOTHER_STRING ERROR_PRSINF_FIRST + 7
+#define ERROR_EXPECTED_EQUAL_ANOTHER_STRING ERROR_PRSINF_FIRST + 8
+#define ERROR_EXPECTED_EQUAL_STRING_COMMA ERROR_PRSINF_FIRST + 9
+#define ERROR_EXPECTED_EQUAL_VALUE_RECIEVED ERROR_PRSINF_FIRST + 10
+#define ERROR_BAD_ID_SECTION ERROR_PRSINF_FIRST + 11
+#define ERROR_UNKOWN_STATE ERROR_PRSINF_FIRST + 12
+#define ERROR_SECTION_NOT_FOUND ERROR_PRSINF_FIRST + 13
+
+/*
+
+ This module support access to a subset of the GUI Toolkit INF
+ file language. The intent of the module is to return the list of
+ options, options text and associated file names for OEM inf files
+ of a particular type.
+
+ The OEM INF file must have the following sections in the following
+ format. (items within <> are optional or change with the INF file,
+ they are not part of the
+
+ [Identification]
+
+ OptionType = <option type desired>
+
+ [OPTIONS]
+
+ <option1>
+ <option2>
+ ...
+
+ [OptionText<lang>]
+
+ <option1> = <"option1 text">
+ <option2> = <"option2 text">
+
+
+*/
+
+
+BOOLEAN
+GetFullInfName(
+ IN PCHAR szInfName,
+ IN ULONG cb,
+ IN PCHAR pszFullInfName
+ );
+
+/*++
+
+Routine Description:
+
+ This routine takes non-qualified inf file name and inserts
+ the directory where inf files are kept in front.
+
+Arguments:
+
+
+ szInfName - Unqualified inf file name
+ cb - number of bytes in Full Inf name buffer
+ pszFullInfName - Pointer to buffer to hold name
+
+Return Value:
+
+ True of name could fit and there is a location for inf files
+
+--*/
+
+
+PCHAR
+GetInfFileList ( );
+
+/*++
+
+Routine Description:
+
+ Locates all OEM INF files in the system directory.
+
+ This function fills a string buffer with a double 0 terminated
+ list of filenames. Each filename in the buffer is separated from
+ the next by a single 0 termination char. Each filename is relative
+ to the directory where OEM inf files are stored.
+
+Arguments:
+
+ szInfType - String to match in Identification section.
+
+Return Value:
+
+ A NULL is returned on error or no files found. Use GetLastError to
+ determine exact error.
+
+ NOTE: The returned buffer is allocated with LocalAlloc. It MUST be
+ freed with LocalFree by the caller.
+
+--*/
+
+
+HANDLE
+OpenInfFile (
+
+ IN PCHAR szFileName,
+ IN PCHAR szInfType
+ );
+
+/*++
+
+Routine Description:
+
+ Opens an INF file of the specified type and returns an open handle
+ to it.
+
+ szInfType should match the string in the OptionType value in the
+ Identification section of the INF file.
+
+ if szFileName is a simple filename with no path information the directory
+ where all OEM files are kept is prepended. If szFileName contains any
+ path information it should contain a full path.
+
+Arguments:
+
+ szFileName - File name to locate.
+ szInfType - String to match in Identification section.
+
+Return Value:
+
+ Returns a Bad handle (-1) if szInfType does not match or the file could
+ not be opened.
+
+--*/
+
+
+
+
+VOID
+CloseInfFile (
+
+ IN HANDLE hInf
+ );
+
+/*++
+
+Routine Description:
+
+ Free Resources
+
+Arguments:
+
+ hInf - Handle to OEM INF file.
+
+Return Value:
+
+--*/
+
+
+PCHAR
+GetTokenElementList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szSectionName,
+ IN PCHAR szKey
+ );
+/*++
+
+Routine Description:
+
+ This routine returns a buffer of tokens seperated by comma
+ found in the specificied section with the specified key.
+
+Arguments:
+
+
+Return Value:
+
+ *psz - Pointer to array of elements
+
+--*/
+
+
+
+
+PCHAR
+GetSectionElementList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szSectionName
+ );
+/*++
+
+Routine Description:
+
+ This routine build buffer of zero terminated strings out of the elements
+ in the specified section of the specified inf file.
+
+Arguments:
+
+ hndInf - Path to OS NAMES file.
+ szSectionName - Section name for to search.
+ idxElement - index within a line to element
+
+Return Value:
+
+ *psz - Pointer to array of elements
+
+--*/
+
+
+PCHAR
+GetOptionList (
+
+ IN HANDLE hndInf,
+ IN PCHAR szOptionSection
+
+ );
+
+/*++
+
+Routine Description:
+
+ This function fills a string buffer with a double 0 terminated
+ list of options from the specified options section. Each option
+ in the buffer is separated from the next option by a single 0
+ termination char. CharNext() and CharPrev() apis should be used
+ to move thru the buffer.
+
+ A NULL szOptionSection will use the default option section name.
+
+Arguments:
+
+ hndInf - Handle to open INF file
+ szOptionSection - section name containing options
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ HANDLE is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+ ERROR_FILE_NOT_FOUND
+
+
+--*/
+
+
+
+
+PCHAR
+GetOptionText (
+
+ HANDLE hndInf,
+ PCHAR szOption,
+ DWORD dwLang
+
+ );
+
+/*++
+
+Routine Description:
+
+ Returns the UserInterface display string associated with
+ the option in the desired language.
+
+ Every INF file will have at least one language for option
+ text display. If the desired language is not present then
+ the first listed language text should be returned.
+
+ If the option does not exist or the language does not exist then a
+ pointer to a NULL is returned.
+
+ dwLang should be one of the already defined NLS values
+
+Arguments:
+
+ hInf - Handle to open INF file
+ szOption - Option to match
+ language - Language to match
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ PCHAR is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+
+--*/
+
+
+PCHAR
+GetAllOptionsText(
+ IN PCHAR szInfType,
+ IN DWORD dwLang
+ );
+
+/*++
+
+Routine Description:
+
+ Fills the string buffer szBuffer with a set of triplets
+ consisting of Option, Option Text. File Name. All 0 terminated
+ with a double 0 termination for buffer. This used where infType
+ is to span multiple inf files.
+
+ dwLang should be one of the already defined NLS values
+
+Arguments:
+
+ szInfFile - Identificaton section to match
+ szLang - Language to match
+
+Return Value:
+
+ A NULL is returned on failure to allocate. A pointer to an empty
+ buffer (buffer with 2 0's) is returned for empty option list.
+
+ PCHAR is allocated as fixed memory and can be referenced directory after
+ a cast. The buffer should be freed with LocalFree
+
+ Error return codes returned GetLastError()
+
+ ERROR_INVALID_PARAMETER
+ ERROR_NOT_ENOUGH_MEMORY
+
+
+--*/
diff --git a/private/windows/prsinf/sources b/private/windows/prsinf/sources
new file mode 100644
index 000000000..20f3e261b
--- /dev/null
+++ b/private/windows/prsinf/sources
@@ -0,0 +1,43 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=windows
+MINORCOMP=prsinf
+
+NTPROFILEINPUT=yes
+
+
+TARGETNAME=prsinf
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc;
+
+SOURCES=prsinf.c \
+ spinf.c \
+ test.c
+
+UMTYPE=console
+UMTEST=test
+UMLIBS=obj\*\prsinf.lib
diff --git a/private/windows/prsinf/spinf.c b/private/windows/prsinf/spinf.c
new file mode 100644
index 000000000..bed58562d
--- /dev/null
+++ b/private/windows/prsinf/spinf.c
@@ -0,0 +1,1760 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ alinf.c
+
+Abstract:
+
+ This module implements functions to _access the parsed INF.
+
+Author:
+
+ Sunil Pai (sunilp) 13-Nov-1991
+
+Revision History:
+
+--*/
+
+//
+// changes some definitions in spinf
+//
+
+#define _CTYPE_DISABLE_MACROS
+#include <windows.h>
+#include "prsinf.h"
+#include "spinf.h"
+#include <stdio.h>
+
+#define SpFree(x) LocalFree(x);(x)=NULL
+#define SpMalloc(x) LocalAlloc(LPTR,x)
+#define SetMemoryError() GetLastError()
+#define SpSetLastError( x ) SetLastError( x )
+
+// #define DEBUG 1
+
+#include <string.h>
+#include <ctype.h>
+
+
+
+// what follows was alpar.h
+
+//
+// EXPORTED BY THE PARSER AND USED BY BOTH THE PARSER AND
+// THE INF HANDLING COMPONENTS
+//
+
+// typedefs exported
+//
+
+typedef struct _value {
+ struct _value *pNext;
+ PCHAR pName;
+ } INFVALUE, *PINFVALUE;
+
+typedef struct _line {
+ struct _line *pNext;
+ PCHAR pName;
+ PINFVALUE pValue;
+ } LINE, *PLINE;
+
+typedef struct _section {
+ struct _section *pNext;
+ PCHAR pName;
+ PLINE pLine;
+ } SECTION, *PSECTION;
+
+typedef struct _inf {
+ PSECTION pSection;
+ } INF, *PINF;
+
+//
+// Routines exported
+//
+
+PVOID
+ParseInfBuffer(
+ PCHAR Buffer,
+ ULONG Size
+ );
+
+
+//
+// DEFINES USED FOR THE PARSER INTERNALLY
+//
+//
+// typedefs used
+//
+
+typedef enum _tokentype {
+ TOK_EOF,
+ TOK_EOL,
+ TOK_LBRACE,
+ TOK_RBRACE,
+ TOK_STRING,
+ TOK_EQUAL,
+ TOK_COMMA,
+ TOK_ERRPARSE,
+ TOK_ERRNOMEM
+ } TOKENTYPE, *PTOKENTTYPE;
+
+
+typedef struct _token {
+ TOKENTYPE Type;
+ PCHAR pValue;
+ } TOKEN, *PTOKEN;
+
+
+//
+// Routine defines
+//
+
+ARC_STATUS
+SpAppendSection(
+ IN PCHAR pSectionName
+ );
+
+ARC_STATUS
+SpAppendLine(
+ IN PCHAR pLineKey
+ );
+
+ARC_STATUS
+SpAppendValue(
+ IN PCHAR pValueString
+ );
+
+TOKEN
+SpGetToken(
+ IN OUT PCHAR *Stream,
+ IN PCHAR MaxStream,
+ IN PCHAR pszStrTerms,
+ IN PCHAR pszQStrTerms,
+ IN PCHAR pszCBrStrTerms
+ );
+
+BOOLEAN
+IsStringTerminator(
+ IN CHAR ch,
+ IN PCHAR pszStrTerm
+ );
+
+BOOLEAN
+IsQStringTerminator(
+ IN CHAR ch,
+ IN PCHAR pszStrTerm
+ );
+
+// what follows was alinf.c
+
+//
+// Internal Routine Declarations for freeing inf structure members
+//
+
+VOID
+FreeSectionList (
+ IN PSECTION pSection
+ );
+
+VOID
+FreeLineList (
+ IN PLINE pLine
+ );
+
+VOID
+FreeValueList (
+ IN PINFVALUE pValue
+ );
+
+
+//
+// Internal Routine declarations for searching in the INF structures
+//
+
+
+PINFVALUE
+SearchValueInLine(
+ IN PLINE pLine,
+ IN ULONG ValueIndex
+ );
+
+PLINE
+SearchLineInSectionByKey(
+ IN PSECTION pSection,
+ IN PCHAR Key
+ );
+
+PLINE
+SearchLineInSectionByIndex(
+ IN PSECTION pSection,
+ IN ULONG LineIndex
+ );
+
+PSECTION
+SearchSectionByName(
+ IN PINF pINF,
+ IN PCHAR SectionName
+ );
+
+//
+// ROUTINE DEFINITIONS
+//
+
+//
+// returns a handle to use for further inf parsing
+//
+
+HANDLE
+SpInitINFBuffer (
+ IN PCHAR szInfFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ ARC_STATUS Status;
+ OFSTRUCT ofFile;
+ PCHAR szBuffer;
+ HANDLE hndFile;
+ HANDLE hndMappedFile;
+ ULONG cbFile;
+ HANDLE hndInf;
+
+
+ //
+ // Open the file
+ //
+ hndFile = (HANDLE)OpenFile( szInfFile, &ofFile, OF_READ );
+ if (hndFile == BADHANDLE) {
+
+ return( BADHANDLE );
+
+ }
+
+
+ //
+ // Map the file
+ //
+ hndMappedFile = CreateFileMapping( hndFile, NULL, PAGE_READONLY, 0, 0, NULL );
+ if (hndMappedFile == BADHANDLE) {
+
+ CloseHandle(hndFile);
+ return( BADHANDLE );
+ }
+ szBuffer = MapViewOfFile( hndMappedFile, FILE_MAP_READ,0,0,0);
+ if (szBuffer == NULL) {
+ Status = GetLastError();
+ CloseHandle(hndFile);
+ SpSetLastError(Status);
+ return( BADHANDLE );
+
+ }
+
+ cbFile = GetFileSize(hndFile, NULL);
+
+ //
+ // Get the size of the file
+ //
+ hndInf = (HANDLE) ParseInfBuffer(szBuffer, cbFile);
+
+ //
+ // Clean up and return
+ //
+ CloseHandle(hndFile);
+ return( hndInf );
+
+}
+
+
+VOID
+SpFreeINFBuffer (
+ IN PVOID INFHandle
+ )
+{
+ if(INFHandle) {
+ FreeSectionList(((PINF)INFHandle)->pSection);
+ SpFree(INFHandle);
+ }
+}
+
+
+VOID
+FreeSectionList (
+ IN PSECTION pSection
+ )
+{
+ PSECTION pNext;
+
+ while(pSection) {
+
+ pNext = pSection->pNext;
+
+ FreeLineList(pSection->pLine);
+ SpFree(pSection->pName);
+ SpFree(pSection);
+
+ pSection = pNext;
+ }
+}
+
+
+VOID
+FreeLineList (
+ IN PLINE pLine
+ )
+{
+ PLINE pNext;
+
+ while(pLine) {
+
+ pNext = pLine->pNext;
+
+ FreeValueList(pLine->pValue);
+ if(pLine->pName) {
+ SpFree(pLine->pName);
+ }
+ SpFree(pLine);
+
+ pLine = pNext;
+ }
+}
+
+VOID
+FreeValueList (
+ IN PINFVALUE pValue
+ )
+{
+ PINFVALUE pNext;
+
+ while(pValue) {
+
+ pNext = pValue->pNext;
+
+ if(pValue->pName) {
+ SpFree(pValue->pName);
+ }
+ SpFree(pValue);
+
+ pValue = pNext;
+ }
+}
+
+
+//
+// searches for the existance of a particular section
+//
+BOOLEAN
+SpSearchINFSection (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ //
+ // if search for section fails return false
+ //
+
+ if ((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ )) == (PSECTION)NULL) {
+ return( FALSE );
+ }
+
+ //
+ // else return true
+ //
+ return( TRUE );
+
+}
+
+
+
+
+//
+// given section name, line number and index return the value.
+//
+PCHAR
+SpGetSectionLineIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+ PLINE pLine;
+ PINFVALUE pValue;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL)
+ return((PCHAR)NULL);
+
+ if((pLine = SearchLineInSectionByIndex(
+ pSection,
+ LineIndex
+ ))
+ == (PLINE)NULL)
+ return((PCHAR)NULL);
+
+ if((pValue = SearchValueInLine(
+ pLine,
+ ValueIndex
+ ))
+ == (PINFVALUE)NULL)
+ return((PCHAR)NULL);
+
+ return (pValue->pName);
+
+}
+
+
+BOOLEAN
+SpGetSectionKeyExists (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL) {
+ return( FALSE );
+ }
+
+ if (SearchLineInSectionByKey(pSection, Key) == (PLINE)NULL) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+PCHAR
+SpGetKeyName(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex
+ )
+{
+ PSECTION pSection;
+ PLINE pLine;
+
+ pSection = SearchSectionByName((PINF)INFHandle,SectionName);
+ if(pSection == NULL) {
+ return(NULL);
+ }
+
+ pLine = SearchLineInSectionByIndex(pSection,LineIndex);
+ if(pLine == NULL) {
+ return(NULL);
+ }
+
+ return(pLine->pName);
+}
+
+
+
+//
+// given section name, key and index return the value
+//
+PCHAR
+SpGetSectionKeyIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+ PLINE pLine;
+ PINFVALUE pValue;
+
+ if((pSection = SearchSectionByName(
+ (PINF)INFHandle,
+ SectionName
+ ))
+ == (PSECTION)NULL)
+ return((PCHAR)NULL);
+
+ if((pLine = SearchLineInSectionByKey(
+ pSection,
+ Key
+ ))
+ == (PLINE)NULL)
+ return((PCHAR)NULL);
+
+ if((pValue = SearchValueInLine(
+ pLine,
+ ValueIndex
+ ))
+ == (PINFVALUE)NULL)
+ return((PCHAR)NULL);
+
+ return (pValue->pName);
+
+}
+
+
+
+
+PINFVALUE
+SearchValueInLine(
+ IN PLINE pLine,
+ IN ULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PINFVALUE pValue;
+ ULONG i;
+
+ if (pLine == (PLINE)NULL)
+ return ((PINFVALUE)NULL);
+
+ pValue = pLine->pValue;
+ for (i = 0; i < ValueIndex && ((pValue = pValue->pNext) != (PINFVALUE)NULL); i++)
+ ;
+
+ return pValue;
+
+}
+
+PLINE
+SearchLineInSectionByKey(
+ IN PSECTION pSection,
+ IN PCHAR Key
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PLINE pLine;
+
+ if (pSection == (PSECTION)NULL || Key == (PCHAR)NULL) {
+ return ((PLINE)NULL);
+ }
+
+ pLine = pSection->pLine;
+ while ((pLine != (PLINE)NULL) && (pLine->pName == NULL || _strcmpi(pLine->pName, Key))) {
+ pLine = pLine->pNext;
+ }
+
+ return pLine;
+
+}
+
+
+PLINE
+SearchLineInSectionByIndex(
+ IN PSECTION pSection,
+ IN ULONG LineIndex
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PLINE pLine;
+ ULONG i;
+
+ //
+ // Validate the parameters passed in
+ //
+
+ if (pSection == (PSECTION)NULL) {
+ return ((PLINE)NULL);
+ }
+
+ //
+ // find the start of the line list in the section passed in
+ //
+
+ pLine = pSection->pLine;
+
+ //
+ // traverse down the current line list to the LineIndex th line
+ //
+
+ for (i = 0; i < LineIndex && ((pLine = pLine->pNext) != (PLINE)NULL); i++) {
+ ;
+ }
+
+ //
+ // return the Line found
+ //
+
+ return pLine;
+
+}
+
+
+PSECTION
+SearchSectionByName(
+ IN PINF pINF,
+ IN PCHAR SectionName
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSECTION pSection;
+
+ //
+ // validate the parameters passed in
+ //
+
+ if (pINF == (PINF)NULL || SectionName == (PCHAR)NULL) {
+ return ((PSECTION)NULL);
+ }
+
+ //
+ // find the section list
+ //
+ pSection = pINF->pSection;
+
+ //
+ // traverse down the section list searching each section for the section
+ // name mentioned
+ //
+
+ while ((pSection != (PSECTION)NULL) && _strcmpi(pSection->pName, SectionName)) {
+ pSection = pSection->pNext;
+ }
+
+ //
+ // return the section at which we stopped (either NULL or the section
+ // which was found
+ //
+
+ return pSection;
+
+}
+
+
+// what follows was alparse.c
+
+
+//
+// Globals used to make building the lists easier
+//
+
+PINF pINF;
+PSECTION pSectionRecord;
+PLINE pLineRecord;
+PINFVALUE pValueRecord;
+
+
+//
+// Globals used by the token parser
+//
+
+// string terminators are the whitespace characters (isspace: space, tab,
+// linefeed, formfeed, vertical tab, carriage return) or the chars given below
+
+PCHAR szStrTerms = "[]=,\" \t\n\f\v\r";
+PCHAR szBrcStrTerms = "[]=,\"\t\n\f\v\r";
+
+//
+// quoted string terminators allow some of the regular terminators to
+// appear as characters
+
+PCHAR szQStrTerms = "\"\n\f\v\r";
+
+//
+// curly brace string terminators are given below
+//
+
+PCHAR szCBrStrTerms = "}\n\f\v\r";
+
+//
+// Main parser routine
+//
+
+PVOID
+ParseInfBuffer(
+ PCHAR Buffer,
+ ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Given a character buffer containing the INF file, this routine parses
+ the INF into an internal form with Section records, Line records and
+ Value records.
+
+Arguments:
+
+ Buffer - contains to ptr to a buffer containing the INF file
+
+ Size - contains the size of the buffer.
+
+Return Value:
+
+ PVOID - INF handle ptr to be used in subsequent INF calls.
+
+--*/
+
+{
+ PCHAR Stream, MaxStream, pchSectionName, pchValue;
+ ULONG State, InfLine;
+ ULONG LastState;
+ TOKEN Token;
+ BOOLEAN Done;
+ BOOLEAN Error;
+ PCHAR pszStrTermsCur = szStrTerms;
+ PCHAR pszQStrTermsCur = szQStrTerms;
+ PCHAR pszCBrStrTermsCur = szCBrStrTerms;
+
+ ARC_STATUS ErrorCode;
+
+ //
+ // Initialise the globals
+ //
+ pINF = (PINF)NULL;
+ pSectionRecord = (PSECTION)NULL;
+ pLineRecord = (PLINE)NULL;
+ pValueRecord = (PINFVALUE)NULL;
+
+ //
+ // Get INF record
+ //
+ if ((pINF = (PINF)SpMalloc(sizeof(INF))) == NULL) {
+
+ return ( NULL );
+ }
+
+ pINF->pSection = NULL;
+
+ //
+ // Set initial state
+ //
+ State = 1;
+ LastState = State;
+ InfLine = 1;
+ Stream = Buffer;
+ MaxStream = Buffer + Size;
+ Done = FALSE;
+ Error = FALSE;
+
+ pchSectionName = NULL;
+ pchValue = NULL;
+
+ //
+ // Enter token processing loop
+ //
+
+ while (!Done) {
+
+ Token = SpGetToken(&Stream, MaxStream, pszStrTermsCur, pszQStrTermsCur, pszCBrStrTermsCur);
+
+ switch (State) {
+ //
+ // STATE1: Start of file, this state remains till first
+ // section is found
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
+ case 1:
+ switch (Token.Type) {
+ case TOK_EOL:
+ break;
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+ case TOK_LBRACE:
+#ifdef DEBUG
+ printf("LBrace seen\n");
+#endif
+ pszStrTermsCur = szBrcStrTerms;
+ State = 2;
+ break;
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SpSetLastError( ERROR_EXPECTED_LBRACE );
+ break;
+ }
+ break;
+
+ //
+ // STATE 2: Section LBRACE has been received, expecting STRING
+ //
+ // Valid Tokens: TOK_STRING
+ //
+ case 2:
+
+ //
+ // allow spaces in section names
+ //
+ switch (Token.Type) {
+ case TOK_STRING:
+#ifdef DEBUG
+ printf("Section Started for %s\n", Token.pValue);
+#endif
+ State = 3;
+
+ //
+ // restore term. string with space
+ //
+ pszStrTermsCur = szStrTerms;
+ pchSectionName = Token.pValue;
+ break;
+
+ default:
+
+ //
+ // restore term. string with space
+ //
+ pszStrTermsCur = szStrTerms;
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SpSetLastError( ERROR_EXPECTED_STRING );
+ break;
+
+ }
+ break;
+
+ //
+ // STATE 3: Section Name received, expecting RBRACE
+ //
+ // Valid Tokens: TOK_RBRACE
+ //
+ case 3:
+ switch (Token.Type) {
+ case TOK_RBRACE:
+#ifdef DEBUG
+ printf("RBrace Seen \n");
+#endif
+ State = 4;
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SpSetLastError( ERROR_EXPECTED_RBRACE );
+ break;
+ }
+ break;
+ //
+ // STATE 4: Section Definition Complete, expecting EOL
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF
+ //
+ case 4:
+ switch (Token.Type) {
+ case TOK_EOL:
+#ifdef DEBUG
+ printf("Section Definition Complete for %s\n", pchSectionName);
+#endif
+ if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS)
+ Error = Done = TRUE;
+ else {
+ pchSectionName = NULL;
+ State = 5;
+ }
+ break;
+
+ case TOK_EOF:
+#ifdef DEBUG
+ printf("Section Definition Complete for %s\n", pchSectionName);
+#endif
+
+ if ((ErrorCode = SpAppendSection(pchSectionName)) != ESUCCESS)
+ Error = Done = TRUE;
+ else {
+ pchSectionName = NULL;
+ Done = TRUE;
+ }
+ break;
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SpSetLastError( ERROR_EXPECTED_EOL );
+ break;
+ }
+ break;
+
+ //
+ // STATE 5: Expecting Section Lines
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
+ //
+ case 5:
+ switch (Token.Type) {
+ case TOK_EOL:
+ break;
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+ case TOK_STRING:
+#ifdef DEBUG
+ printf("Section Line value %s\n", Token.pValue);
+#endif
+ pchValue = Token.pValue;
+ State = 6;
+ break;
+ case TOK_LBRACE:
+ pszStrTermsCur = szBrcStrTerms;
+ State = 2;
+ break;
+ default:
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ // SpSetLastError( ERROR_EXPECTED_SECTION_LINE );
+ State = 20;
+ LastState = 6;
+ break;
+ }
+ break;
+
+ //
+ // STATE 6: String returned, not sure whether it is key or value
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
+ //
+ case 6:
+ switch (Token.Type) {
+
+#ifdef DEBUG
+ printf("Working determining type of string String %s\n", pchValue);
+#endif
+ case TOK_EOL:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 5;
+ }
+ break;
+
+ case TOK_EOF:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ Done = TRUE;
+ }
+ break;
+
+ case TOK_COMMA:
+ if ( (ErrorCode = SpAppendLine(NULL)) != ESUCCESS ||
+ (ErrorCode = SpAppendValue(pchValue)) !=ESUCCESS )
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 7;
+ }
+ break;
+
+ case TOK_EQUAL:
+ if ( (ErrorCode = SpAppendLine(pchValue)) !=ESUCCESS)
+ Error = Done = TRUE;
+ else {
+ pchValue = NULL;
+ State = 8;
+ }
+ break;
+
+ case TOK_STRING:
+ SpFree(Token.pValue);
+ // fall through
+ default:
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ if(pchValue) {
+ SpFree(pchValue);
+ }
+ State = 20;
+ LastState = 5;
+ SpSetLastError( ERROR_EXPECTED_BAD_LINE );
+ break;
+ }
+ break;
+
+ //
+ // STATE 7: Comma received, Expecting another string
+ //
+ // Valid Tokens: TOK_STRING
+ //
+ case 7:
+ switch (Token.Type) {
+ case TOK_STRING:
+#ifdef DEBUG
+ printf("Comma recieved, looking for string got %s\n", Token.pValue);
+#endif
+ if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
+ Error = Done = TRUE;
+ else
+ State = 9;
+
+ break;
+ default:
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ // SpSetLastError( ERROR_EXPECTED_COMMA_ANOTHER_STRING );
+ State = 20;
+ LastState = 7;
+ break;
+ }
+ break;
+ //
+ // STATE 8: Equal received, Expecting another string
+ //
+ // Valid Tokens: TOK_STRING
+ //
+ case 8:
+ switch (Token.Type) {
+ case TOK_STRING:
+#ifdef DEBUG
+ printf("Equal recieved, looking for string got %s\n", Token.pValue);
+#endif
+
+ if ((ErrorCode = SpAppendValue(Token.pValue)) != ESUCCESS)
+ Error = Done = TRUE;
+ else
+ State = 9;
+
+ break;
+
+ default:
+
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ // SpSetLastError( ERROR_EXPECTED_EQUAL_ANOTHER_STRING );
+ State = 20;
+ LastState = 8;
+ break;
+ }
+ break;
+ //
+ // STATE 9: String received after equal, value string
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
+ //
+ case 9:
+ switch (Token.Type) {
+ case TOK_EOL:
+ State = 5;
+ break;
+
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+
+ case TOK_COMMA:
+ State = 7;
+ break;
+
+ case TOK_STRING:
+ SpFree(Token.pValue);
+ // fall through
+ default:
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ // SpSetLastError( ERROR_EXPECTED_EQUAL_STRING_COMMA );
+ State = 20;
+ LastState = 5;
+ break;
+ }
+ break;
+ //
+ // STATE 10: Value string definitely received
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
+ //
+ case 10:
+ switch (Token.Type) {
+ case TOK_EOL:
+ State =5;
+ break;
+
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+
+ case TOK_COMMA:
+ State = 7;
+ break;
+
+ case TOK_STRING:
+ SpFree(Token.pValue);
+ // fall through
+ default:
+ // Error = Done = TRUE;
+ // ErrorCode = EINVAL;
+ // SpSetLastError( ERROR_EXPECTED_EQUAL_VALUE_RECIEVED );
+ State = 20;
+ LastState = 10;
+ break;
+ }
+ break;
+
+ //
+ // STATE 20: Eat a line of INF
+ //
+ // Valid Tokens: TOK_EOL, TOK_EOF
+ //
+ case 20:
+ switch (Token.Type) {
+ case TOK_EOL:
+ State = LastState;
+ break;
+
+ case TOK_EOF:
+ Done = TRUE;
+ break;
+
+ case TOK_STRING:
+ SpFree(Token.pValue);
+ // fall through
+ default:
+
+ break;
+ }
+ break;
+
+
+
+ default:
+ Error = Done = TRUE;
+ ErrorCode = EINVAL;
+ SpSetLastError( ERROR_UNKOWN_STATE );
+ break;
+
+ } // end switch(State)
+
+
+ if (Error) {
+
+ SpFreeINFBuffer((PVOID)pINF);
+ if (pchSectionName != (PCHAR)NULL) {
+ SpFree(pchSectionName);
+ }
+
+ if (pchValue != (PCHAR)NULL) {
+ SpFree(pchValue);
+ }
+
+ pINF = (PINF)NULL;
+ }
+ else {
+
+ //
+ // Keep track of line numbers so that we can display Errors
+ //
+
+ if (Token.Type == TOK_EOL)
+ InfLine++;
+ }
+
+ } // End while
+
+
+ return((PVOID)pINF);
+}
+
+
+
+ARC_STATUS
+SpAppendSection(
+ IN PCHAR pSectionName
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new section to the section list in the current INF.
+ All further lines and values pertain to this new section, so it resets
+ the line list and value lists too.
+
+Arguments:
+
+ pSectionName - Name of the new section. ( [SectionName] )
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or the INF buffer not
+ initialised
+
+--*/
+
+{
+ PSECTION pNewSection;
+
+ //
+ // Check to see if INF initialised and the parameter passed in is valid
+ //
+
+ if (pINF == (PINF)NULL || pSectionName == (PCHAR)NULL) {
+ return EINVAL;
+ }
+
+
+ //
+ // Allocate memory for the new section
+ //
+
+ if ((pNewSection = (PSECTION)SpMalloc(sizeof(SECTION))) == (PSECTION)NULL) {
+
+ SetMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // initialise the new section
+ //
+ pNewSection->pNext = (PSECTION)NULL;
+ pNewSection->pLine = (PLINE)NULL;
+ pNewSection->pName = pSectionName;
+
+ //
+ // link it in
+ //
+
+ if (pSectionRecord == (PSECTION)NULL) {
+ pINF->pSection = pNewSection;
+ }
+ else {
+ pSectionRecord->pNext = pNewSection;
+ }
+
+ pSectionRecord = pNewSection;
+
+ //
+ // reset the current line record and current value record field
+ //
+
+ pLineRecord = (PLINE)NULL;
+ pValueRecord = (PINFVALUE)NULL;
+
+ return ESUCCESS;
+
+}
+
+
+ARC_STATUS
+SpAppendLine(
+ IN PCHAR pLineKey
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new line to the line list in the current section.
+ All further values pertain to this new line, so it resets
+ the value list too.
+
+Arguments:
+
+ pLineKey - Key to be used for the current line, this could be NULL.
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or current section not
+ initialised
+
+
+--*/
+
+
+{
+ PLINE pNewLine;
+
+ //
+ // Check to see if current section initialised
+ //
+
+ if (pSectionRecord == (PSECTION)NULL) {
+ return EINVAL;
+ }
+
+ //
+ // Allocate memory for the new Line
+ //
+
+ if ((pNewLine = (PLINE)SpMalloc(sizeof(LINE))) == (PLINE)NULL) {
+ SetMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // Link it in
+ //
+ pNewLine->pNext = (PLINE)NULL;
+ pNewLine->pValue = (PINFVALUE)NULL;
+ pNewLine->pName = pLineKey;
+
+ if (pLineRecord == (PLINE)NULL) {
+ pSectionRecord->pLine = pNewLine;
+ }
+ else {
+ pLineRecord->pNext = pNewLine;
+ }
+
+ pLineRecord = pNewLine;
+
+ //
+ // Reset the current value record
+ //
+
+ pValueRecord = (PINFVALUE)NULL;
+
+ return ESUCCESS;
+}
+
+
+
+ARC_STATUS
+SpAppendValue(
+ IN PCHAR pValueString
+ )
+
+/*++
+
+Routine Description:
+
+ This appends a new value to the value list in the current line.
+
+Arguments:
+
+ pValueString - The value string to be added.
+
+Return Value:
+
+ ESUCCESS - if successful.
+ ENOMEM - if memory allocation failed.
+ EINVAL - if invalid parameters passed in or current line not
+ initialised.
+
+--*/
+
+{
+ PINFVALUE pNewValue;
+
+ //
+ // Check to see if current line record has been initialised and
+ // the parameter passed in is valid
+ //
+
+ if (pLineRecord == (PLINE)NULL || pValueString == (PCHAR)NULL) {
+ return EINVAL;
+ }
+
+ //
+ // Allocate memory for the new value record
+ //
+
+ if ((pNewValue = (PINFVALUE)SpMalloc(sizeof(INFVALUE))) == (PINFVALUE)NULL) {
+ SetMemoryError();
+ return ENOMEM;
+ }
+
+ //
+ // Link it in.
+ //
+
+ pNewValue->pNext = (PINFVALUE)NULL;
+ pNewValue->pName = pValueString;
+
+ if (pValueRecord == (PINFVALUE)NULL)
+ pLineRecord->pValue = pNewValue;
+ else
+ pValueRecord->pNext = pNewValue;
+
+ pValueRecord = pNewValue;
+ return ESUCCESS;
+}
+
+TOKEN
+SpGetToken(
+ IN OUT PCHAR *Stream,
+ IN PCHAR MaxStream,
+ IN PCHAR pszStrTerms,
+ IN PCHAR pszQStrTerms,
+ IN PCHAR pszCBrStrTerms
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the Next token from the configuration stream.
+
+Arguments:
+
+ Stream - Supplies the address of the configuration stream. Returns
+ the address of where to start looking for tokens within the
+ stream.
+
+ MaxStream - Supplies the address of the last character in the stream.
+
+
+Return Value:
+
+ TOKEN - Returns the next token
+
+--*/
+
+{
+
+ PCHAR pch, pchStart, pchNew;
+ ULONG Length;
+ TOKEN Token;
+
+ //
+ // Skip whitespace (except for eol)
+ //
+
+ pch = *Stream;
+ while (pch < MaxStream && *pch != '\n' && isspace(*pch))
+ pch++;
+
+
+ //
+ // Check for comments and remove them
+ //
+
+ if (pch < MaxStream &&
+ ((*pch == ';') || (*pch == '#') || (*pch == '/' && pch+1 < MaxStream && *(pch+1) =='/')))
+ while (pch < MaxStream && *pch != '\n')
+ pch++;
+
+ //
+ // Check to see if EOF has been reached, set the token to the right
+ // value
+ //
+
+ if ( pch >= MaxStream ) {
+ *Stream = pch;
+ Token.Type = TOK_EOF;
+ Token.pValue = NULL;
+ return Token;
+ }
+
+
+ switch (*pch) {
+
+ case '[' :
+ pch++;
+ Token.Type = TOK_LBRACE;
+ Token.pValue = NULL;
+ break;
+
+ case ']' :
+ pch++;
+ Token.Type = TOK_RBRACE;
+ Token.pValue = NULL;
+ break;
+
+ case '=' :
+ pch++;
+ Token.Type = TOK_EQUAL;
+ Token.pValue = NULL;
+ break;
+
+ case ',' :
+ pch++;
+ Token.Type = TOK_COMMA;
+ Token.pValue = NULL;
+ break;
+
+ case '\n' :
+ pch++;
+ Token.Type = TOK_EOL;
+ Token.pValue = NULL;
+ break;
+
+ case '\"':
+ pch++;
+ //
+ // determine quoted string
+ //
+ pchStart = pch;
+ while (pch < MaxStream && !IsQStringTerminator(*pch, pszQStrTerms)) {
+ pch++;
+ }
+
+ if (pch >=MaxStream || *pch != '\"') {
+ Token.Type = TOK_ERRPARSE;
+ Token.pValue = NULL;
+ }
+ else {
+ Length = pch - pchStart;
+ if ((pchNew = (PCHAR)SpMalloc(Length + 1)) == NULL) {
+ SetMemoryError();
+ Token.Type = TOK_ERRNOMEM;
+ Token.pValue = NULL;
+ } else {
+ if (Length != 0) { // Null quoted strings are allowed
+ strncpy(pchNew, pchStart, Length);
+ }
+ pchNew[Length] = 0;
+ Token.Type = TOK_STRING;
+ Token.pValue = pchNew;
+ }
+ pch++; // advance past the quote
+ }
+ break;
+
+ case '{':
+ //
+ // determine quoted string
+ //
+ pchStart = pch;
+ while (pch < MaxStream && !IsStringTerminator(*pch, pszCBrStrTerms)) {
+ pch++;
+ }
+
+ if (pch >=MaxStream || *pch != '}') {
+ Token.Type = TOK_ERRPARSE;
+ Token.pValue = NULL;
+ }
+ else {
+ Length = pch - pchStart + 1;
+ if ((pchNew = (PCHAR)SpMalloc(Length + 1)) == NULL) {
+ SetMemoryError();
+ Token.Type = TOK_ERRNOMEM;
+ Token.pValue = NULL;
+ } else {
+ if (Length != 0) { // Null quoted strings are allowed
+ strncpy(pchNew, pchStart, Length);
+ }
+ pchNew[Length] = 0;
+ Token.Type = TOK_STRING;
+ Token.pValue = pchNew;
+ }
+ pch++; // advance past the brace
+ }
+ break;
+
+
+ default:
+ //
+ // determine regular string
+ //
+ pchStart = pch;
+ while (pch < MaxStream && !IsStringTerminator(*pch, pszStrTerms))
+ pch++;
+
+ if (pch == pchStart) {
+ pch++;
+ Token.Type = TOK_ERRPARSE;
+ Token.pValue = NULL;
+ }
+ else {
+ Length = pch - pchStart;
+ if ((pchNew = (PCHAR)SpMalloc(Length + 1)) == NULL) {
+ SetMemoryError();
+ Token.Type = TOK_ERRNOMEM;
+ Token.pValue = NULL;
+ }
+ else {
+ strncpy(pchNew, pchStart, Length);
+ pchNew[Length] = 0;
+ Token.Type = TOK_STRING;
+ Token.pValue = pchNew;
+ }
+ }
+ break;
+ }
+
+ *Stream = pch;
+ return (Token);
+}
+
+
+
+BOOLEAN
+IsStringTerminator(
+ CHAR ch,
+ PCHAR szStrTerms
+ )
+/*++
+
+Routine Description:
+
+ This routine tests whether the given character terminates a quoted
+ string.
+
+Arguments:
+
+ ch - The current character.
+
+Return Value:
+
+ TRUE if the character is a quoted string terminator, FALSE otherwise.
+
+--*/
+
+{
+
+ return(strchr(szStrTerms, ch) != NULL);
+
+}
+
+
+
+BOOLEAN
+IsQStringTerminator(
+ CHAR ch,
+ PCHAR szQStrTerms
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tests whether the given character terminates a quoted
+ string.
+
+Arguments:
+
+ ch - The current character.
+
+
+Return Value:
+
+ TRUE if the character is a quoted string terminator, FALSE otherwise.
+
+
+--*/
+
+
+{
+
+
+ return(strchr(szQStrTerms, ch ) != NULL);
+
+}
diff --git a/private/windows/prsinf/spinf.h b/private/windows/prsinf/spinf.h
new file mode 100644
index 000000000..3a1207380
--- /dev/null
+++ b/private/windows/prsinf/spinf.h
@@ -0,0 +1,104 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ alinfexp.h
+
+Abstract:
+
+ This module contains the inf handling routine exports.
+
+Author:
+
+ Sunil Pai (sunilp) 07-Nov-1991
+
+Revision History:
+
+ Ted Miller (tedm) 30-Jan-1992
+ port to setupprp use
+--*/
+
+#ifndef _ALINF_
+#define _ALINF_
+
+#define ESUCCESS 1
+#define EINVAL 2
+#define ENOMEM 3
+
+//
+// returns a handle to use for further inf parsing
+//
+
+HANDLE
+SpInitINFBuffer (
+ IN PCHAR szInfFile
+ );
+
+//
+// frees an INF Buffer
+//
+VOID
+SpFreeINFBuffer (
+ IN PVOID INFHandle
+ );
+
+
+//
+// searches for the existance of a particular section
+//
+BOOLEAN
+SpSearchINFSection (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName
+ );
+
+
+//
+// given section name, line number and index return the value.
+//
+PCHAR
+SpGetSectionLineIndex (
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex,
+ IN ULONG ValueIndex
+ );
+
+
+//
+// given section name, key searches existance
+//
+BOOLEAN
+SpGetSectionKeyExists (
+ IN PVOID INFBufferHandle,
+ IN PCHAR SectionName,
+ IN PCHAR Key
+ );
+
+
+//
+// given section name, key and index return the value
+//
+PCHAR
+SpGetSectionKeyIndex (
+ IN PVOID INFBufferHandle,
+ IN PCHAR Section,
+ IN PCHAR Key,
+ IN ULONG ValueIndex
+ );
+
+
+//
+// given section name and line index, return key
+//
+PCHAR
+SpGetKeyName(
+ IN PVOID INFHandle,
+ IN PCHAR SectionName,
+ IN ULONG LineIndex
+ );
+
+#endif // _ALINF_
+
diff --git a/private/windows/prsinf/test.c b/private/windows/prsinf/test.c
new file mode 100644
index 000000000..6930ce64f
--- /dev/null
+++ b/private/windows/prsinf/test.c
@@ -0,0 +1,125 @@
+#include <windows.h>
+#include <string.h>
+#include "prsinf.h"
+#include "spinf.h"
+#include <stdio.h>
+
+#define ENGLISH 0
+#define GERMAN 1
+#define FRENCH 2
+#define SPANISH 3
+
+void
+main () {
+
+ HANDLE hndInf;
+ PCHAR pszOptions, pszOptionsT;
+ PCHAR pszOptionText;
+ PCHAR pszFiles, pszFilesT;
+ PCHAR pszAll;
+
+ pszFilesT = pszFiles = GetInfFileList( );
+ printf("\r\n");
+ if (pszFiles == NULL) {
+
+ printf("GetInifFileList: Failed %d", GetLastError());
+ return;
+
+ } else {
+
+ for (; *pszFiles; pszFiles += strlen(pszFiles) + 1 ) {
+
+ printf("File list: \t %s\n", pszFiles);
+
+ }
+
+ printf("GetInifFileList: succeeded");
+
+ }
+ printf("\r\n");
+ for (pszFiles = pszFilesT; *pszFiles; pszFiles += strlen(pszFiles) + 1 ) {
+
+ hndInf = OpenInfFile( pszFiles, "locale" );
+
+ if (hndInf == BADHANDLE) {
+
+ if (GetLastError() == ERROR_INF_TYPE_MISMATCH) {
+
+ printf("\r\n Wrong type on %s\r\n", pszFiles);
+ continue;
+
+ } else {
+
+ printf("\r\nOpen on %s failed error %d", pszFiles, GetLastError());
+ continue;
+
+ }
+
+ } else {
+
+ printf("\n Open success for %s", pszFiles);
+
+ }
+
+ printf("\r\n");
+ pszOptionsT = pszOptions = GetOptionList(hndInf, "OPTIONS");
+ if (pszOptions == NULL) {
+
+ printf("GetOptionList failed");
+ return;
+
+ } else {
+
+ printf("GetOptionList success");
+
+ }
+
+
+ printf("\r\n");
+ while (*pszOptions) {
+
+ printf("\r\n");
+ pszOptionText = GetOptionText(hndInf, pszOptions, ENGLISH);
+ if (pszOptionText == NULL) {
+
+ printf("No Option text for %s in ENGLISH\r\n", pszOptions);
+ continue;
+
+ }
+
+ printf("In File %s Option %s with Text %s ",pszFiles, pszOptions, pszOptionText);
+ // LocalFree( pszOptionText );
+ pszOptions += strlen(pszOptions) + 1;
+
+ }
+
+ LocalFree( pszOptionsT );
+
+ CloseInfFile( hndInf );
+ }
+
+ LocalFree( pszFilesT );
+
+ printf("\r\n Doing it all at once \r\n");
+
+ pszAll = GetAllOptionsText( "Computer", ENGLISH );
+
+ if (pszAll == NULL) {
+
+ printf("GetAllOptionsText failed with error %d", GetLastError());
+ return;
+ }
+
+ while( *pszAll ) {
+
+ printf("Option %s ",pszAll );
+ pszAll += strlen(pszAll) + 1;
+ printf(" Text %s ", pszAll );
+ pszAll += strlen(pszAll) + 1;
+ printf("In File %s ", pszAll);
+ pszAll += strlen(pszAll) + 1;
+ printf("\r\n");
+
+ }
+
+}