|
|
/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
ppdentry.c
Abstract:
Functions for parsing syntactical elements of a PPD file
Environment:
PostScript driver, PPD parser
Revision History:
08/20/96 -davidx- Common coding style for NT 5.0 drivers.
03/26/96 -davidx- Created it.
--*/
#include "lib.h"
#include "ppd.h"
#include "ppdparse.h"
//
// Forward declaration of local functions
//
PPDERROR IParseKeyword(PPARSERDATA); PPDERROR IParseValue(PPARSERDATA); PPDERROR IParseField(PFILEOBJ, PBUFOBJ, BYTE);
PPDERROR IParseEntry( PPARSERDATA pParserData )
/*++
Routine Description:
Parse one entry from a PPD file
Arguments:
pParserData - Points to parser data structure
Return Value:
Status code
--*/
{ PPDERROR iStatus; INT iChar; PFILEOBJ pFile = pParserData->pFile;
//
// Clear values from previous entry
//
CLEAR_BUFFER(&pParserData->Keyword); CLEAR_BUFFER(&pParserData->Option); CLEAR_BUFFER(&pParserData->Xlation); CLEAR_BUFFER(&pParserData->Value);
pParserData->dwValueType = VALUETYPE_NONE;
//
// Parse the keyword field and skip over trailing white spaces
//
if ((iStatus = IParseKeyword(pParserData)) != PPDERR_NONE) return iStatus;
//
// Look at the first non-space character after the keyword field
//
VSkipSpace(pFile);
if ((iChar = IGetNextChar(pFile)) == EOF_CHAR) return PPDERR_EOF;
if (IS_NEWLINE(iChar)) return PPDERR_NONE;
if (iChar != SEPARATOR_CHAR) { //
// Parse the option field and skip over trailing white spaces
//
ASSERT(iChar != EOF_CHAR); VUngetChar(pFile);
if ((iStatus = IParseField(pFile, &pParserData->Option, KEYWORD_MASK)) != PPDERR_NONE) return iStatus;
VSkipSpace(pFile);
//
// Look at the first non-space character after the option field
//
if ((iChar = IGetNextChar(pFile)) == XLATION_CHAR) { //
// Parse the translation string field
//
if ((iStatus = IParseField(pFile, &pParserData->Xlation, XLATION_MASK)) != PPDERR_NONE) return iStatus;
iChar = IGetNextChar(pFile); } if (iChar != SEPARATOR_CHAR) return ISyntaxError(pFile, "Missing ':'"); }
//
// Parse the value field and interpret the entry if it's valid
//
if ((iStatus = IParseValue(pParserData)) == PPDERR_NONE) { //
// Take care of any embedded hexdecimals in the translation string
//
if (! IS_BUFFER_EMPTY(&pParserData->Xlation) && ! BConvertHexString(&pParserData->Xlation)) { return ISyntaxError(pFile, "Invalid hexdecimals in the translation string"); }
//
// Interpret the current entry
//
iStatus = IInterpretEntry(pParserData); }
return iStatus; }
PPDERROR IParseKeyword( PPARSERDATA pParserData )
/*++
Routine Description:
Parse the keyword field of a PPD file entry
Arguments:
pParserData - Points to parser data structure
Return Value:
Status code
--*/
{ PFILEOBJ pFile = pParserData->pFile; INT iChar;
while (TRUE) { //
// Get the first character of a line
//
if ((iChar = IGetNextChar(pFile)) == EOF_CHAR) return PPDERR_EOF;
//
// Ignore empty lines
//
if (IS_NEWLINE(iChar)) continue;
if (IS_SPACE(iChar)) { VSkipSpace(pFile); if ((iChar = IGetNextChar(pFile)) == EOF_CHAR) return PPDERR_EOF;
if (IS_NEWLINE(iChar)) continue;
return ISyntaxError(pFile, "Missing '*'"); }
//
// If the line is not empty, the first character must be the keyword character
//
if (! IS_KEYWORD_CHAR(iChar)) return ISyntaxError(pFile, "Missing '*'"); //
// If the second character is not %, then the line is a normal entry.
// Otherwise, the line is a comment.
//
if ((iChar = IGetNextChar(pFile)) == EOF_CHAR) return PPDERR_EOF;
if (!IS_NEWLINE(iChar) && iChar != COMMENT_CHAR) { VUngetChar(pFile); break; }
VSkipLine(pFile); }
return IParseField(pFile, &pParserData->Keyword, KEYWORD_MASK); }
PPDERROR IParseValue( PPARSERDATA pParserData )
/*++
Routine Description:
Parse the value field of a PPD file entry
Arguments:
pParserData - Points to parser data structure Return Value:
Status code
--*/
{ PPDERROR iStatus; INT iChar; PBUFOBJ pBufObj = &pParserData->Value; PFILEOBJ pFile = pParserData->pFile;
//
// The value is either a StringValue, a SymbolValue, or a QuotedValue
// depending on the first non-space character
//
VSkipSpace(pFile);
if ((iChar = IGetNextChar(pFile)) == EOF_CHAR) return PPDERR_EOF;
if (iChar == QUOTE_CHAR) { //
// The value is a quoted string
//
pParserData->dwValueType = VALUETYPE_QUOTED; if ((iStatus = IParseField(pFile, pBufObj, QUOTED_MASK)) != PPDERR_NONE) return iStatus;
//
// Read the closing quote character
//
if ((iChar = IGetNextChar(pFile)) != QUOTE_CHAR) return ISyntaxError(pFile, "Unbalanced '\"'"); } else if (iChar == SYMBOL_CHAR) { //
// The value is a symbol reference
//
pParserData->dwValueType = VALUETYPE_SYMBOL; ADD_CHAR_TO_BUFFER(pBufObj, iChar);
if ((iStatus = IParseField(pFile, pBufObj, KEYWORD_MASK)) != PPDERR_NONE) return iStatus; } else { PBYTE pubEnd;
//
// The value is a string
//
pParserData->dwValueType = VALUETYPE_STRING; VUngetChar(pFile);
if ((iStatus = IParseField(pFile, pBufObj, STRING_MASK)) != PPDERR_NONE) return iStatus;
//
// Ignore any trailing spaces
//
ASSERT(pBufObj->dwSize > 0); pubEnd = pBufObj->pbuf + (pBufObj->dwSize - 1);
while (IS_SPACE(*pubEnd)) *pubEnd-- = NUL;
pBufObj->dwSize= (DWORD)(pubEnd - pBufObj->pbuf) + 1; ASSERT(pBufObj->dwSize > 0); }
//
// Ignore extra characters after the entry value
//
VSkipSpace(pFile); iChar = IGetNextChar(pFile);
if (! IS_NEWLINE(iChar)) { if (iChar != XLATION_CHAR) { TERSE(("%ws: Extra chars at the end of line %d\n", pFile->ptstrFileName, pFile->iLineNumber)); }
VSkipLine(pFile); }
return PPDERR_NONE; }
PPDERROR IParseField( PFILEOBJ pFile, PBUFOBJ pBufObj, BYTE ubMask )
/*++
Routine Description:
Parse one field of a PPD file entry
Arguments:
pFile - Specifies the input file object pBufObj - Specifies the buffer for storing the field value ubMask - Mask to limit the set of allowable characters
Return Value:
Status code
--*/
{ PPDERROR iStatus; INT iChar;
while ((iChar = IGetNextChar(pFile)) != EOF_CHAR) { if (! IS_MASKED_CHAR(iChar, ubMask)) { //
// Encountered a not-allowed character
//
if (IS_BUFFER_EMPTY(pBufObj) && !(ubMask & QUOTED_MASK)) return ISyntaxError(pFile, "Empty field");
//
// Always put a null byte at the end
//
pBufObj->pbuf[pBufObj->dwSize] = 0;
VUngetChar(pFile); return PPDERR_NONE; } else { //
// If we're parsing a quoted string and we encountered a line
// starting with the keyword character, then we'll assume
// the closing quote is missing. Just give a warning and continue.
//
if ((ubMask & QUOTED_MASK) && IS_KEYWORD_CHAR(iChar) && !IS_BUFFER_EMPTY(pBufObj) && IS_NEWLINE(pBufObj->pbuf[pBufObj->dwSize - 1])) { (VOID) ISyntaxError(pFile, "Expecting '\"'"); }
//
// Grow the buffer if it's full. If we're not allowed to
// grow it, then return a syntax error.
//
if (IS_BUFFER_FULL(pBufObj)) { if (ubMask & (STRING_MASK|QUOTED_MASK)) { if ((iStatus = IGrowValueBuffer(pBufObj)) != PPDERR_NONE) return iStatus; } else { return ISyntaxError(pFile, "Field too long"); } }
ADD_CHAR_TO_BUFFER(pBufObj, iChar); } }
return PPDERR_EOF; }
BOOL BConvertHexString( PBUFOBJ pBufObj )
/*++
Routine Description:
Convert embedded hexdecimal strings into binary data
Arguments:
pBufObj - Specifies the buffer object to be converted
Return Value:
TRUE if everything is ok FALSE if the embedded hexdecimal string is ill-formed
--*/
#define HexDigitValue(c) \
(((c) >= '0' && (c) <= '9') ? ((c) - '0') : \ ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : ((c) - 'a' + 10))
{ PBYTE pubSrc, pubDest; DWORD dwSize; DWORD dwHexMode = 0;
pubSrc = pubDest = pBufObj->pbuf; dwSize = pBufObj->dwSize;
while (dwSize--) { if (dwHexMode) { //
// We're currently inside a hex string:
// switch to normal mode if '>' is encountered
// otherwise, only valid hex digits, newline, and spaces are allowed
//
if (IS_HEX_DIGIT(*pubSrc)) { //
// If we're currently on odd hex digit, save the hex digit value
// in the upper nibble of the destination byte.
// If we're on even hex digit, save the hex digit value in the
// lower nibble of the destination byte. If the destination byte
// is zero and NUL is not allowed, then return with error.
//
if (dwHexMode & 1) *pubDest = HexDigitValue(*pubSrc) << 4; else *pubDest++ |= HexDigitValue(*pubSrc);
dwHexMode++; } else if (*pubSrc == '>') { if ((dwHexMode & 1) == 0) { TERSE(("Odd number of hexdecimal digits\n")); return FALSE; }
dwHexMode = 0; } else if (!IS_SPACE(*pubSrc) && !IS_NEWLINE(*pubSrc)) { TERSE(("Invalid hexdecimal digit\n")); return FALSE; } } else { //
// We're not currently inside a hex string:
// switch to hex mode if '<' is encountered
// otherwise, simply copy the source byte to the destination
//
if (*pubSrc == '<') dwHexMode = 1; else *pubDest++ = *pubSrc; }
pubSrc++; }
if (dwHexMode) { TERSE(("Missing '>' in hexdecimal string\n")); return FALSE; }
//
// Modified the buffer size if it's changed
//
*pubDest = 0; pBufObj->dwSize = (DWORD)(pubDest - pBufObj->pbuf); return TRUE; }
PPDERROR ISyntaxErrorMessage( PFILEOBJ pFile, PSTR pstrMsg )
/*++
Routine Description:
Display syntax error message
Arguments:
pFile - Specifies the input file object pstrMsg - Indicate the reason for the syntax error
Return Value:
PPDERR_SYNTAX
--*/
{ //
// Display an error message
//
TERSE(("%ws: %s on line %d\n", pFile->ptstrFileName, pstrMsg, pFile->iLineNumber));
//
// Skip any remaining characters on the current line
//
VSkipLine(pFile);
return PPDERR_SYNTAX; }
|