mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
788 lines
21 KiB
788 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ppdkwd.c
|
|
|
|
Abstract:
|
|
|
|
PS driver PPD parser - keyword search
|
|
|
|
Revision History:
|
|
|
|
4/25/95 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
|
|
#include "pslib.h"
|
|
#include "ppdchar.h"
|
|
#include "ppdfile.h"
|
|
#include "ppdparse.h"
|
|
#include "ppdkwd.h"
|
|
|
|
// Include the implementation of PPD entry handlers
|
|
|
|
#include "ppdproc.c"
|
|
|
|
// Default keyword prefix string
|
|
|
|
const char defaultPrefixStr[] = "Default";
|
|
|
|
// Keyword table
|
|
|
|
static KEYWORD_TABLE_ENTRY keywordTable[] = {
|
|
{ "Include", IncludeProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|QUOTED_VALUE},
|
|
{ "ColorDevice", ColorDeviceProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "Protocols", ProtocolsProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "NickName", NickNameProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "LanguageLevel", LanguageLevelProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "LanguageEncoding", LanguageEncodingProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "LanguageVersion", LanguageVersionProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "TTRasterizer", TTRasterizerProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "ExitServer", ExitServerProc,
|
|
UIGRP_UNKNOWN, INVOCATION_VALUE},
|
|
{ "Password", PasswordProc,
|
|
UIGRP_UNKNOWN, INVOCATION_VALUE},
|
|
{ "SuggestedJobTimeout", JobTimeoutProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "SuggestedWaitTimeout", WaitTimeoutProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "PrintPSError", PrintPsErrorProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "JCLBegin", JclBeginProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "JCLToPSInterpreter", JclToPsProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "JCLEnd", JclEndProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "LandscapeOrientation", LsOrientationProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "Font", FontProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|STRING_VALUE},
|
|
{ "CustomPageSize", CustomPageSizeProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "ParamCustomPageSize", ParamCustomPageProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|STRING_VALUE},
|
|
{ "MaxMediaWidth", MaxMediaWidthProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "MaxMediaHeight", MaxMediaHeightProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "HWMargins", HwMarginsProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "PageSize", PageSizeProc,
|
|
UIGRP_PAGESIZE, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultPageSize", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "PageRegion", PageRegionProc,
|
|
UIGRP_PAGESIZE, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "ImageableArea", ImageableAreaProc,
|
|
UIGRP_PAGESIZE, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "PaperDimension", PaperDimensionProc,
|
|
UIGRP_PAGESIZE, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "InputSlot", InputSlotProc,
|
|
UIGRP_INPUTSLOT, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultInputSlot", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "RequiresPageRegion", RequiresPageRgnProc,
|
|
UIGRP_INPUTSLOT, KWF_OPTION|STRING_VALUE},
|
|
{ "Collate", CommonUiOptionProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultCollate", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "Duplex", CommonUiOptionProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultDuplex", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "ManualFeed", CommonUiOptionProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultManualFeed", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "Resolution", ResolutionProc,
|
|
UIGRP_RESOLUTION, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "JCLResolution", JclResolutionProc,
|
|
UIGRP_RESOLUTION, KWF_OPTION|QUOTED_VALUE},
|
|
{ "DefaultResolution", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "DefaultJCLResolution", DefaultJclResProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "SetResolution", SetResolutionProc,
|
|
UIGRP_RESOLUTION, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "ScreenAngle", ScreenAngleProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "ScreenFreq", ScreenFreqProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "ResScreenAngle", ResScreenAngleProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|QUOTED_VALUE},
|
|
{ "ResScreenFreq", ResScreenFreqProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|QUOTED_VALUE},
|
|
{ "FreeVM", FreeVmProc,
|
|
UIGRP_UNKNOWN, QUOTED_VALUE},
|
|
{ "InstalledMemory", InstalledMemProc,
|
|
UIGRP_VMOPTION, KWF_OPTION|INVOCATION_VALUE},
|
|
{ "DefaultInstalledMemory", CommonUiDefaultProc,
|
|
UIGRP_UNKNOWN, STRING_VALUE},
|
|
{ "VMOption", VmOptionProc,
|
|
UIGRP_VMOPTION, KWF_OPTION|QUOTED_VALUE},
|
|
{ "OpenGroup", OpenGroupProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "CloseGroup", CloseGroupProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "OpenUI", OpenUiProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|STRING_VALUE},
|
|
{ "CloseUI", CloseUiProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "JCLOpenUI", OpenUiProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|STRING_VALUE},
|
|
{ "JCLCloseUI", CloseUiProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "OrderDependency", OrderDepProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "UIConstraints", UiConstraintsProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "Extensions", ExtensionsProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI|STRING_VALUE},
|
|
{ "End", NullProc,
|
|
UIGRP_UNKNOWN, KWF_MULTI},
|
|
{ "JCLRes", NullProc,
|
|
UIGRP_UNKNOWN, KWF_OPTION|QUOTED_VALUE},
|
|
};
|
|
|
|
#define KEYWORD_TABLE_SIZE (sizeof(keywordTable)/sizeof(KEYWORD_TABLE_ENTRY))
|
|
#define INVALID_KEYWORD_TABLE_INDEX KEYWORD_TABLE_SIZE
|
|
|
|
// Hash table
|
|
// Note: The hash table size must be larger than KEYWORD_TABLE_SIZE,
|
|
// preferably a prime number. This means there is at least one empty
|
|
// entry in the hash table.
|
|
|
|
#define HASH_TABLE_SIZE 127
|
|
|
|
static HASH_TABLE_ENTRY hashTable[HASH_TABLE_SIZE];
|
|
|
|
#define ClearHashEntry(index) \
|
|
hashTable[(index)].dwHashValue = 0, \
|
|
hashTable[(index)].kwdTableIndex = INVALID_KEYWORD_TABLE_INDEX
|
|
|
|
#define HashEntryEmpty(index) \
|
|
(hashTable[(index)].kwdTableIndex == INVALID_KEYWORD_TABLE_INDEX)
|
|
|
|
|
|
|
|
VOID
|
|
InitKeywordTable(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the keyword search table.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
static BOOL bInitialized = FALSE;
|
|
WORD wKeywordIndex;
|
|
|
|
// Reset the flag bits of every keyword table entry
|
|
|
|
for (wKeywordIndex=0;
|
|
wKeywordIndex < KEYWORD_TABLE_SIZE;
|
|
wKeywordIndex++)
|
|
{
|
|
keywordTable[wKeywordIndex].wFlags &= ~KWF_SEENBEFORE;
|
|
}
|
|
|
|
// We only need to initialize the table once.
|
|
|
|
if (! bInitialized) {
|
|
|
|
WORD wHashIndex;
|
|
WORD wCollision, wDuplicate;
|
|
|
|
// Make sure the hash table is large enough to hold all keywords
|
|
|
|
DBGMSG1(DBG_LEVEL_TERSE,
|
|
"Number of PPD keywords supported = %d\n",
|
|
KEYWORD_TABLE_SIZE);
|
|
ASSERT(KEYWORD_TABLE_SIZE < HASH_TABLE_SIZE);
|
|
|
|
// Clear the hash table
|
|
|
|
for (wHashIndex=0; wHashIndex < HASH_TABLE_SIZE; wHashIndex++) {
|
|
ClearHashEntry(wHashIndex);
|
|
}
|
|
|
|
// Initialize the hash table
|
|
|
|
wCollision = wDuplicate = 0;
|
|
for (wKeywordIndex=0;
|
|
wKeywordIndex < KEYWORD_TABLE_SIZE;
|
|
wKeywordIndex++)
|
|
{
|
|
DWORD dwHashValue;
|
|
|
|
// Compute the hash value and hash table index corresponding
|
|
// to the current keyword string.
|
|
|
|
dwHashValue = HashKeyword(keywordTable[wKeywordIndex].pKeyword);
|
|
wHashIndex = (WORD) (dwHashValue % HASH_TABLE_SIZE);
|
|
|
|
if (! HashEntryEmpty(wHashIndex)) {
|
|
|
|
// The hash table entry is occupied, we have
|
|
// a collision.
|
|
|
|
DBGMSG1(DBG_LEVEL_VERBOSE,
|
|
"Collision on keyword *%s\n",
|
|
keywordTable[wKeywordIndex].pKeyword);
|
|
|
|
// Sequentially search the hash table to find
|
|
// the next empty entry. This is guaranteed to
|
|
// stop because the hash table is larger
|
|
// than the keyword table.
|
|
|
|
do {
|
|
// Collect stats about duplicate hash values.
|
|
|
|
wCollision++;
|
|
if (hashTable[wHashIndex].dwHashValue == dwHashValue) {
|
|
|
|
DBGMSG(DBG_LEVEL_WARNING,
|
|
"Duplicate hash values for different keywords!\n");
|
|
wDuplicate++;
|
|
}
|
|
|
|
if (++wHashIndex >= HASH_TABLE_SIZE)
|
|
wHashIndex = 0;
|
|
} while (! HashEntryEmpty(wHashIndex));
|
|
}
|
|
|
|
// At this point, wHashIndex points to an empty hash table
|
|
// entry. Map the current keyword string to it.
|
|
|
|
hashTable[wHashIndex].dwHashValue = dwHashValue;
|
|
hashTable[wHashIndex].kwdTableIndex = wKeywordIndex;
|
|
}
|
|
|
|
DBGMSG1(DBG_LEVEL_TERSE,
|
|
"Total number of keyword collisions: %d\n",
|
|
wCollision);
|
|
DBGMSG1(DBG_LEVEL_TERSE,
|
|
"Total number of duplicate hash values: %d\n",
|
|
wDuplicate);
|
|
|
|
// Mark the hash table as initialized
|
|
|
|
bInitialized = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
KEYWORD_TABLE_ENTRY *
|
|
SearchKeyword(
|
|
PCSTR pKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for a keyword and return its index.
|
|
|
|
Arguments:
|
|
|
|
pKeyword - pointer to keyword string
|
|
|
|
Return Value:
|
|
|
|
Pointer to keyword table entry corresponding to the keyword string.
|
|
NULL if the keyword is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwHashValue;
|
|
WORD wHashIndex;
|
|
|
|
dwHashValue = HashKeyword(pKeyword);
|
|
wHashIndex = (WORD) (dwHashValue % HASH_TABLE_SIZE);
|
|
|
|
// When we found an empty hash table entry,
|
|
// we know for sure the keyword is not supported.
|
|
// This is guaranteed to happen because the hash
|
|
// table is always larger than the keyword table.
|
|
// So there is at least one empty hash table entry.
|
|
|
|
while (! HashEntryEmpty(wHashIndex)) {
|
|
|
|
// If the hash value matches what's in the
|
|
// current entry, we will go ahead and compare
|
|
// the keyword string with that from the keyword
|
|
// table. If the strings match also, we're done.
|
|
// Otherwise, we have different keywords with
|
|
// the same hash value. This is not supposed
|
|
// to happen with supported keywords. But in
|
|
// rare cases, it could happen with unsupported
|
|
// keywords. So we'll handle it anyway.
|
|
|
|
if (hashTable[wHashIndex].dwHashValue == dwHashValue) {
|
|
|
|
WORD wKeywordIndex;
|
|
|
|
wKeywordIndex = hashTable[wHashIndex].kwdTableIndex;
|
|
if (strcmp(pKeyword, keywordTable[wKeywordIndex].pKeyword) == EQUAL_STRING) {
|
|
|
|
// We're found a true match, return the keyword index
|
|
|
|
return & keywordTable[wKeywordIndex];
|
|
} else {
|
|
|
|
// Display a warning message for duplicate hash values
|
|
|
|
DBGMSG(DBG_LEVEL_WARNING,
|
|
"Duplicate hash values for different keywords!\n");
|
|
DBGMSG1(DBG_LEVEL_WARNING,
|
|
"Keyword 1: *%s\n",
|
|
pKeyword);
|
|
DBGMSG1(DBG_LEVEL_WARNING,
|
|
"Keyword 2: *%s\n",
|
|
keywordTable[wKeywordIndex].pKeyword);
|
|
}
|
|
}
|
|
|
|
// Sequentially search the next hash table entry
|
|
|
|
if (++wHashIndex >= HASH_TABLE_SIZE)
|
|
wHashIndex = 0;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
HashKeyword(
|
|
PCSTR pKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute the hash value given a keyword string.
|
|
|
|
Arguments:
|
|
|
|
pKeyword - pointer to keyword string
|
|
|
|
Return Value:
|
|
|
|
Hash value computed from the keyword string
|
|
|
|
--*/
|
|
|
|
{
|
|
BYTE * pByte = (BYTE *) pKeyword;
|
|
DWORD dwHashValue = 0;
|
|
|
|
while (*pByte != 0)
|
|
dwHashValue = (dwHashValue << 1) ^ *pByte++;
|
|
|
|
return dwHashValue;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CheckKeywordParams(
|
|
KEYWORD_TABLE_ENTRY * pKwdEntry,
|
|
PPARSEROBJ pParserObj
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform a preliminary syntax check on a PPD entry:
|
|
1) whether an option field should be present
|
|
2) whether the type of entry value matches what the keyword expects
|
|
|
|
Arguments:
|
|
|
|
pKwdEntry - pointer to a keyword table entry
|
|
pParserObj - pointer to a parser object
|
|
(resulting from parsing a PPD entry)
|
|
|
|
Return Value:
|
|
|
|
TRUE if passed preliminary syntax check
|
|
FALSE if syntax error is detected
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bRequireOption, bOptionPresent;
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Make sure the option is present when it's required
|
|
// and not present when it's not required.
|
|
|
|
bRequireOption = (pKwdEntry->wFlags & KWF_OPTION) != 0;
|
|
bOptionPresent = ! BUFOBJ_IsEmpty(& pParserObj->option);
|
|
|
|
if (bRequireOption != bOptionPresent) {
|
|
|
|
DBGMSG1(DBG_LEVEL_ERROR,
|
|
"Option field for *%s mismatch\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
} else {
|
|
|
|
PPDVALUE expectedType, parsedType;
|
|
|
|
// Match the expected value type with the parsed value type
|
|
|
|
expectedType = pKwdEntry->wFlags & KWF_VALUEMASK;
|
|
parsedType = pParserObj->valueType;
|
|
|
|
switch (expectedType) {
|
|
|
|
case STRING_VALUE:
|
|
|
|
if (parsedType != STRING_VALUE ||
|
|
BUFOBJ_IsEmpty(&pParserObj->value))
|
|
{
|
|
|
|
DBGMSG1(DBG_LEVEL_WARNING,
|
|
"*%s expects a StringValue\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
} else
|
|
bReturn = TRUE;
|
|
|
|
break;
|
|
|
|
case QUOTED_VALUE:
|
|
|
|
if (parsedType == STRING_VALUE) {
|
|
|
|
// This is an error conditions according to the spec.
|
|
// But in order to work with some older PPDs, we'll
|
|
// relax the rules a little and let it through.
|
|
// Display an error message but don't fail.
|
|
|
|
DBGMSG1(DBG_LEVEL_WARNING,
|
|
"*%s expects QuotedValue instead of StringValue\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
bReturn = TRUE;
|
|
|
|
} else if (parsedType == QUOTED_VALUE) {
|
|
|
|
if (BUFOBJ_IsEmpty(&pParserObj->value)) {
|
|
|
|
DBGMSG1(DBG_LEVEL_WARNING,
|
|
"*%s has an empty QuotedValue\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
}
|
|
bReturn = TRUE;
|
|
}
|
|
break;
|
|
|
|
|
|
case NO_VALUE:
|
|
|
|
if (parsedType != NO_VALUE) {
|
|
|
|
// This keyword shouldn't have any value. Display
|
|
// an error message but don't fail.
|
|
|
|
DBGMSG1(DBG_LEVEL_ERROR,
|
|
"*%s is not expected to have any value\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
break;
|
|
|
|
case INVOCATION_VALUE:
|
|
|
|
if (parsedType == SYMBOL_VALUE) {
|
|
|
|
DBGMSG1(DBG_LEVEL_ERROR,
|
|
"Symbol values are not currently supported (%*s)\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
|
|
} else if (parsedType == QUOTED_VALUE)
|
|
bReturn = TRUE;
|
|
break;
|
|
|
|
case SYMBOL_VALUE:
|
|
|
|
// We should never expect a symbol value.
|
|
|
|
ASSERTMSG(FALSE, "Should never expect a symbol value.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! bReturn) {
|
|
DBGMSG1(DBG_LEVEL_ERROR,
|
|
"Syntax error near entry: *%s\n",
|
|
BUFOBJ_Buffer(& pParserObj->keyword));
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CheckKeywordDuplicates(
|
|
KEYWORD_TABLE_ENTRY * pKwdEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Screen out duplicate PPD entries.
|
|
|
|
Arguments:
|
|
|
|
pKwdEntry - pointer to a keyword table entry
|
|
|
|
Return Value:
|
|
|
|
TRUE if the entry should be processed normally.
|
|
FALSE if the entry has appeared before and should be ignored.
|
|
|
|
--*/
|
|
|
|
{
|
|
// A PPD entry is considered a duplicate if all of the
|
|
// following conditions are met:
|
|
// 1) The entry has appeared before.
|
|
// 2) The entry is not allowed to appear multiple times.
|
|
// 3) The entry does not have option field.
|
|
|
|
return ((pKwdEntry->wFlags & KWF_SEENBEFORE) == 0 ||
|
|
(pKwdEntry->wFlags & KWF_MULTI) != 0 ||
|
|
(pKwdEntry->wFlags & KWF_OPTION) != 0);
|
|
}
|
|
|
|
|
|
// Make sure the order matches the constants defined in ppdkwd.h.
|
|
|
|
static UIGROUPINFO uigrpInfo[MAXUIGRP] = {
|
|
{"PageSize", sizeof(MEDIAOPTION), UITYPE_PICKONE, UIGRP_PAGESIZE},
|
|
{"InputSlot", sizeof(INPUTSLOT), UITYPE_PICKONE, UIGRP_INPUTSLOT},
|
|
{"ManualFeed", sizeof(UIOPTION), UITYPE_BOOLEAN, UIGRP_MANUALFEED},
|
|
{"Duplex", sizeof(UIOPTION), UITYPE_PICKONE, UIGRP_DUPLEX},
|
|
{"Collate", sizeof(UIOPTION), UITYPE_BOOLEAN, UIGRP_COLLATE},
|
|
{"Resolution", sizeof(RESOPTION), UITYPE_PICKONE, UIGRP_RESOLUTION},
|
|
{"VMOption", sizeof(VMOPTION), UITYPE_PICKONE, UIGRP_VMOPTION}
|
|
};
|
|
|
|
|
|
|
|
WORD
|
|
GetUiGroupIndex(
|
|
PCSTR pKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a keyword to a predefined UI group index
|
|
|
|
Arguments:
|
|
|
|
pKeyword - pointer to keyword string
|
|
|
|
Return Value:
|
|
|
|
UIGRP_UNKNOWN if the UI group is not predefined.
|
|
Otherwise, a valid UI group index.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD uigrpIndex;
|
|
DWORD dwHash;
|
|
|
|
ASSERT(pKeyword != NULL);
|
|
|
|
for (uigrpIndex = 0;
|
|
uigrpIndex < MAXUIGRP &&
|
|
strcmp(pKeyword, uigrpInfo[uigrpIndex].pKeyword) != EQUAL_STRING;
|
|
uigrpIndex++)
|
|
{
|
|
}
|
|
|
|
return uigrpIndex;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
GetUiGroupInfo(
|
|
PUIGROUPINFO pUiGroupInfo,
|
|
WORD uigrpIndex,
|
|
PCSTR pKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return information about predefined UI groups
|
|
|
|
Arguments:
|
|
|
|
pUiGroupInfo - pointer to a UIGROUPINFO for returning information
|
|
uigrpIndex - predefined UI group index
|
|
pKeyword - pointer to a keyword string
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(uigrpIndex >= 0 && uigrpIndex <= MAXUIGRP);
|
|
|
|
// If an index is not provided, try to map the
|
|
// keyword string to a predefined UI group index.
|
|
|
|
if (uigrpIndex >= MAXUIGRP)
|
|
uigrpIndex = GetUiGroupIndex(pKeyword);
|
|
|
|
if (uigrpIndex >= MAXUIGRP) {
|
|
|
|
// The UI group is not found - return default information
|
|
|
|
pUiGroupInfo->pKeyword = pKeyword;
|
|
pUiGroupInfo->dwObjectSize = sizeof(UIOPTION);
|
|
pUiGroupInfo->wType = UITYPE_PICKONE;
|
|
pUiGroupInfo->uigrpIndex = UIGRP_UNKNOWN;
|
|
|
|
} else
|
|
*pUiGroupInfo = uigrpInfo[uigrpIndex];
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
|
|
|
|
VOID
|
|
DumpHashTable(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump out the content of the hash table
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
INT index;
|
|
|
|
DBGPRINT("Dumping hash table contents (%d entries):\n",
|
|
HASH_TABLE_SIZE);
|
|
|
|
for (index=0; index < HASH_TABLE_SIZE; index++) {
|
|
|
|
DBGPRINT("%3d : ", index);
|
|
if (! HashEntryEmpty(index)) {
|
|
DBGPRINT("%08x, %s",
|
|
hashTable[index].dwHashValue,
|
|
keywordTable[hashTable[index].kwdTableIndex].pKeyword);
|
|
}
|
|
DBGPRINT("\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CheckHashTable(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check the integrity of the hash table.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
KEYWORD_TABLE_ENTRY *pKwdTableEntry;
|
|
KEYWORD_TABLE_ENTRY *pSearchResult;
|
|
INT index;
|
|
|
|
DBGPRINT("Checking the integrity of the hash table ...\n");
|
|
|
|
pKwdTableEntry = keywordTable;
|
|
for (index=0; index < KEYWORD_TABLE_SIZE; index++) {
|
|
|
|
pSearchResult = SearchKeyword(pKwdTableEntry->pKeyword);
|
|
ASSERT(pSearchResult == pKwdTableEntry);
|
|
pKwdTableEntry++;
|
|
}
|
|
|
|
pSearchResult = SearchKeyword("");
|
|
ASSERT(pSearchResult == NULL);
|
|
|
|
DBGPRINT("Check completed successfully.\n");
|
|
}
|
|
|
|
|
|
#endif // DBG
|