Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

943 lines
26 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Forms
// Copyright (C) Microsoft Corporation, 1994-1997
//
// File: nfparse.cxx
//
// Contents: Tool to build .nfh files from .nfi files.
//
//----------------------------------------------------------------------------
#ifndef X_STDLIB_H_
#define X_STDLIB_H_
#include <stdlib.h>
#endif
#ifndef X_STDIO_H_
#define X_STDIO_H_
#include <stdio.h>
#endif
#ifndef X_STDDEF_H_
#define X_STDDEF_H_
#include <stddef.h>
#endif
#ifndef X_SEARCH_H_
#define X_SEARCH_H_
#include <search.h>
#endif
#ifndef X_STRING_H_
#define X_STRING_H_
#include <string.h>
#endif
#ifndef X_CTYPE_H_
#define X_CTYPE_H_
#include <ctype.h>
#endif
#ifndef X_LIMITS_H_
#define X_LIMITS_H_
#include <limits.h>
#endif
#ifndef X_STDARG_H_
#define X_STDARG_H_
#include <stdarg.h>
#endif
// Allow assignment within conditional
#pragma warning ( disable : 4706 )
#define MAX_WORD 256
#define MAX_LINE 4096
#define TRUE 1
#define FALSE 0
#define BOOL int
#define ERROR int
#define E_FAIL 1
#define S_OK 0
char achBlanks[] = " "
" "
" "
" "
" ";
class CNotificationParser
{
public:
CNotificationParser() { memset(this, 0, sizeof(*this)); }
class CNotification {
public:
CNotification() { memset(this, 0, sizeof(*this)); }
void MakeSC( CNotification *pN );
void MarkFirstChance();
CNotification * _pNextN;
char _achType[MAX_WORD];
//
// Targets
//
unsigned _fSelf:1;
unsigned _fAncestors:1;
unsigned _fDescendents:1;
unsigned _fTree:1;
//
// Categories
//
unsigned _fTextChange:1;
unsigned _fTreeChange:1;
unsigned _fLayoutChange:1;
unsigned _fActiveX:1;
unsigned _fLayoutElements:1;
unsigned _fPositionedElements:1;
unsigned _fBubbleUpViewTree:1;
unsigned _fAllElements:1;
unsigned _fFrameSites:1;
//
// Properties
//
unsigned _fSendUntilHandled:1;
unsigned _fLazyRange:1;
unsigned _fCleanChange:1;
unsigned _fSynchronousOnly:1;
unsigned _fDoNotBlock:1;
unsigned _fAutoOnly:1;
unsigned _fZParentsOnly:1;
unsigned _fSecondChanceAvail:1;
unsigned _fSecondChance:1;
//
// Arguments
//
unsigned _fElement:1;
unsigned _fSI:1;
unsigned _fCElements:1;
unsigned _fCp:1;
unsigned _fCch:1;
unsigned _fTreeNode:1;
unsigned _fData:1;
unsigned _fFlags:1;
};
char * _pchInput;
char * _pchOutput;
FILE * _fpOutput;
FILE * _fpInput;
FILE * _fpLog;
ERROR Parse();
BOOL Validate(CNotification * pN);
BOOL ReadLine(char *pchBuf, int cchBuf, int *pcchRead);
void SkipSpace(char **ppch);
void SkipNonspace(char **ppch);
void ChopComment(char *pch);
BOOL GetWord(char **ppch, char **ppchWord);
char * NameOf(char * pchInput, char * pchOutput);
void WriteArg(unsigned fFlag, char * pchArg, char * pchPad, int * pcArgs);
void WriteFlag(unsigned fFlag, char * pchFlag, int * pcFlags);
void ReportError(const char * pchError, ...);
};
ERROR __cdecl
main ( int argc, char *argv[] )
{
CNotificationParser np;
ERROR err = E_FAIL;
if (argc != 3)
{
printf("nfparse: Usage <Notification File> <HeaderFile>\n");
goto Cleanup;
}
np._pchInput = argv[1];
np._pchOutput = argv[2];
err = np.Parse();
Cleanup:
exit(err);
}
ERROR
CNotificationParser::Parse()
{
char achBuf[MAX_LINE];
char achTemp[MAX_WORD];
char * pch;
char * pchWord = NULL;
CNotification * pFirstN = NULL;
CNotification ** ppN = &pFirstN;
CNotification * pN = NULL;
int i;
int cch;
ERROR err;
// open input file
_fpInput = fopen(_pchInput, "r");
if (!_fpInput)
{
err = E_FAIL;
goto Cleanup;
}
// open output file
_fpOutput = fopen(_pchOutput, "w");
if (!_fpOutput)
{
err = E_FAIL;
goto Cleanup;
}
// open log file
strcpy(achBuf, _pchOutput);
strcat(achBuf, "LOG");
_fpLog = fopen(achBuf, "w");
if (!_fpLog)
{
err = E_FAIL;
goto Cleanup;
}
// phase 1: read the file
err = E_FAIL;
while (ReadLine(achBuf, MAX_LINE, NULL))
{
pch = achBuf;
ChopComment(pch);
while (GetWord(&pch, &pchWord))
{
if (!strcmp(pchWord, "type"))
{
if (*ppN == NULL)
{
*ppN = new CNotification();
if (!*ppN)
goto Cleanup;
pN = *ppN;
ppN = &pN->_pNextN;
}
if (!GetWord(&pch, &pchWord))
{
ReportError("Missing notification type");
goto Cleanup;
}
strncpy(pN->_achType, pchWord, MAX_WORD-1);
}
else
if (!strcmp(pchWord, "targets"))
{
if (!pN)
{
ReportError("Notification does not start with 'type:'");
goto Cleanup;
}
while (GetWord(&pch, &pchWord))
{
if (!strcmp(pchWord, "self"))
{
pN->_fSelf = TRUE;
}
else
if (!strcmp(pchWord, "ancestors"))
{
pN->_fAncestors = TRUE;
}
else
if (!strcmp(pchWord, "descendents"))
{
pN->_fDescendents = TRUE;
}
else
if (!strcmp(pchWord, "tree-level"))
{
pN->_fTree = TRUE;
}
}
}
else
if (!strcmp(pchWord, "categories"))
{
if (!pN)
{
ReportError("Notification does not start with 'type:'");
goto Cleanup;
}
while (GetWord(&pch, &pchWord))
{
if (!strcmp(pchWord, "text-change"))
{
pN->_fTextChange = TRUE;
}
else
if (!strcmp(pchWord, "tree-change"))
{
pN->_fTreeChange = TRUE;
}
else
if (!strcmp(pchWord, "layout-change"))
{
pN->_fLayoutChange = TRUE;
}
else
if (!strcmp(pchWord, "activex"))
{
pN->_fActiveX = TRUE;
}
else
if (!strcmp(pchWord, "layout-elements"))
{
pN->_fLayoutElements = TRUE;
}
else
if (!strcmp(pchWord, "positioned-elements"))
{
pN->_fPositionedElements = TRUE;
}
else
if (!strcmp(pchWord, "bubble-up-view-tree"))
{
pN->_fBubbleUpViewTree = TRUE;
}
else
if (!strcmp(pchWord, "all-elements"))
{
pN->_fAllElements = TRUE;
}
else
if (!strcmp(pchWord, "frame-sites"))
{
pN->_fFrameSites = TRUE;
}
}
}
else
if (!strcmp(pchWord, "properties"))
{
if (!pN)
{
ReportError("Notification does not start with 'type:'");
goto Cleanup;
}
while (GetWord(&pch, &pchWord))
{
if (!strcmp(pchWord, "send-until-handled"))
{
pN->_fSendUntilHandled = TRUE;
}
else
if (!strcmp(pchWord, "lazy-range"))
{
pN->_fLazyRange = TRUE;
}
else
if (!strcmp(pchWord, "clean-change"))
{
pN->_fCleanChange = TRUE;
}
else
if (!strcmp(pchWord, "synchronous-only"))
{
pN->_fSynchronousOnly = TRUE;
}
else
if (!strcmp(pchWord, "dont-block"))
{
pN->_fDoNotBlock = TRUE;
}
else
if (!strcmp(pchWord, "auto-only"))
{
pN->_fAutoOnly = TRUE;
}
else
if (!strcmp(pchWord, "zparents-only"))
{
pN->_fZParentsOnly = TRUE;
}
else
if (!strcmp(pchWord, "second-chance"))
{
pN->_fSecondChanceAvail = TRUE;
}
}
}
else
if (!strcmp(pchWord, "arguments"))
{
if (!pN)
{
ReportError("Notification does not start with 'type:'");
goto Cleanup;
}
while (GetWord(&pch, &pchWord))
{
if (!strcmp(pchWord, "element"))
pN->_fElement = 1;
else
if (!strcmp(pchWord, "si"))
pN->_fSI = 1;
else
if (!strcmp(pchWord, "celements"))
pN->_fCElements = 1;
else
if (!strcmp(pchWord, "cp"))
pN->_fCp = 1;
else
if (!strcmp(pchWord, "cch"))
pN->_fCch = 1;
else
if (!strcmp(pchWord, "tree-node"))
pN->_fTreeNode = 1;
else
if (!strcmp(pchWord, "data"))
pN->_fData = 1;
else
if (!strcmp(pchWord, "flags"))
pN->_fFlags = 1;
}
}
else
{
ReportError("Unknown keyword (%s)", pchWord);
goto Cleanup;
}
}
}
// phase 2: validate the notifications
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
if (!Validate(pN))
{
ReportError("Notification %s is invalid", pN->_achType);
goto Cleanup;
}
}
// phase 3: expand second chance notifications
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
if (pN->_fSecondChanceAvail)
{
CNotification * pNNew = new CNotification();
if (!pNNew)
goto Cleanup;
pNNew->MakeSC( pN );
pN->MarkFirstChance();
pNNew->_pNextN = pN->_pNextN;
pN->_pNextN = pNNew;
pN = pNNew;
}
}
// phase 4: output the file
fprintf(_fpOutput, "//-----------------------------------------------------------------------------\n");
fprintf(_fpOutput, "//\n");
fprintf(_fpOutput, "// WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n");
fprintf(_fpOutput, "//\n");
fprintf(_fpOutput, "// %s\n", _pchOutput);
fprintf(_fpOutput, "// Generated by NFPARSE.EXE from %s\n", _pchInput);
fprintf(_fpOutput, "// DO NOT MODIFY BY HAND\n");
fprintf(_fpOutput, "//\n");
fprintf(_fpOutput, "// WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n");
fprintf(_fpOutput, "//\n");
fprintf(_fpOutput, "//-----------------------------------------------------------------------------\n\n");
// generate the enums
fprintf(_fpOutput, "#if defined(_NOTIFYTYPE_ENUM_)\n\n");
for (i=0, pN = pFirstN; pN; pN = pN->_pNextN, i++)
{
sprintf(achTemp, " NTYPE_%s", _strupr(pN->_achType));
cch = 32 - strlen(achTemp);
if (cch < 0)
cch = 0;
fprintf(_fpOutput, "%s", achTemp);
strncpy(achTemp, achBlanks, cch);
achTemp[cch] = '\0';
fprintf(_fpOutput, "%s = 0x%08X,\n", achTemp, (long)i);
}
fprintf(_fpOutput, "#undef _NOTIFYTYPE_ENUM_\n\n");
fprintf(_fpOutput, "\n");
// generate the flag table
fprintf(_fpOutput, "#elif defined(_NOTIFYTYPE_TABLE_)\n\n");
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
int cFlags = 0;
sprintf(achTemp, "/* NTYPE_%s", _strupr(pN->_achType));
cch = 32 - strlen(achTemp);
if (cch < 0)
cch = 0;
fprintf(_fpOutput, "%s", achTemp);
strncpy(achTemp, achBlanks, cch);
achTemp[cch] = '\0';
fprintf(_fpOutput, "%s*/", achTemp);
WriteFlag(pN->_fSelf, "NFLAGS_SELF", &cFlags);
WriteFlag(pN->_fAncestors, "NFLAGS_ANCESTORS", &cFlags);
WriteFlag(pN->_fDescendents, "NFLAGS_DESCENDENTS", &cFlags);
WriteFlag(pN->_fTree, "NFLAGS_TREELEVEL", &cFlags);
WriteFlag(pN->_fTextChange, "NFLAGS_TEXTCHANGE", &cFlags);
WriteFlag(pN->_fTreeChange, "NFLAGS_TREECHANGE", &cFlags);
WriteFlag(pN->_fLayoutChange, "NFLAGS_LAYOUTCHANGE", &cFlags);
WriteFlag(pN->_fActiveX, "NFLAGS_FOR_ACTIVEX", &cFlags);
WriteFlag(pN->_fLayoutElements, "NFLAGS_FOR_LAYOUTS", &cFlags);
WriteFlag(pN->_fPositionedElements, "NFLAGS_FOR_POSITIONED", &cFlags);
WriteFlag(pN->_fBubbleUpViewTree, "NFLAGS_BUBBLE_UP_VIEW_TREE", &cFlags);
WriteFlag(pN->_fAllElements, "NFLAGS_FOR_ALLELEMENTS", &cFlags);
WriteFlag(pN->_fFrameSites, "NFLAGS_FOR_FRAMESITES", &cFlags);
WriteFlag(pN->_fSendUntilHandled, "NFLAGS_SENDUNTILHANDLED", &cFlags);
WriteFlag(pN->_fLazyRange, "NFLAGS_LAZYRANGE", &cFlags);
WriteFlag(pN->_fCleanChange, "NFLAGS_CLEANCHANGE", &cFlags);
WriteFlag(pN->_fSynchronousOnly, "NFLAGS_SYNCHRONOUSONLY", &cFlags);
WriteFlag(pN->_fDoNotBlock, "NFLAGS_DONOTBLOCK", &cFlags);
WriteFlag(pN->_fAutoOnly, "NFLAGS_AUTOONLY", &cFlags);
WriteFlag(pN->_fZParentsOnly, "NFLAGS_ZPARENTSONLY", &cFlags);
WriteFlag(pN->_fSecondChance, "NFLAGS_SC", &cFlags);
WriteFlag(pN->_fSecondChanceAvail, "NFLAGS_SC_AVAILABLE", &cFlags);
fprintf(_fpOutput, ",\n");
}
fprintf(_fpOutput, "#undef _NOTIFYTYPE_TABLE_\n\n");
fprintf(_fpOutput, "\n");
// generate the names
fprintf(_fpOutput, "#elif defined(_NOTIFYTYPE_NAMES_)\n\n");
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
fprintf(_fpOutput, " case NTYPE_%s:\n", _strupr(pN->_achType));
fprintf(_fpOutput, " pch = _T(\"%s\");\n", _strupr(pN->_achType));
fprintf(_fpOutput, " break;\n");
}
fprintf(_fpOutput, "#undef _NOTIFYTYPE_NAMES_\n\n");
fprintf(_fpOutput, "\n");
// generate the prototypes
fprintf(_fpOutput, "#elif defined(_NOTIFYTYPE_PROTO_)\n\n");
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
int cArgs = 0;
fprintf(_fpOutput, " void %s(\n", NameOf(pN->_achType, achTemp));
WriteArg(pN->_fElement, "CElement * pElement", " ", &cArgs);
WriteArg(pN->_fSI, "long siElement", " ", &cArgs);
WriteArg(pN->_fCElements, "long cElements", " ", &cArgs);
WriteArg(pN->_fCp, "long cp", " ", &cArgs);
WriteArg(pN->_fCch, "long cch", " ", &cArgs);
WriteArg(pN->_fTreeNode, "CTreeNode * pNode = NULL", " ", &cArgs);
WriteArg(pN->_fData, "void * pvData = NULL", " ", &cArgs);
WriteArg(pN->_fFlags, "DWORD grfFlags = 0", " ", &cArgs);
fprintf(_fpOutput, ");\n\n");
}
fprintf(_fpOutput, "#undef _NOTIFYTYPE_PROTO_\n\n");
fprintf(_fpOutput, "\n");
// generate the inlines
fprintf(_fpOutput, "#elif defined(_NOTIFYTYPE_INLINE_)\n\n");
for (pN = pFirstN; pN; pN = pN->_pNextN)
{
int cArgs = 0;
fprintf(_fpOutput, "inline void\nCNotification::%s(\n", NameOf(pN->_achType, achTemp));
WriteArg(pN->_fElement, "CElement * pElement", " ", &cArgs);
WriteArg(pN->_fSI, "long siElement", " ", &cArgs);
WriteArg(pN->_fCElements, "long cElements", " ", &cArgs);
WriteArg(pN->_fCp, "long cp", " ", &cArgs);
WriteArg(pN->_fCch, "long cch", " ", &cArgs);
WriteArg(pN->_fTreeNode, "CTreeNode * pNode", " ", &cArgs);
WriteArg(pN->_fData, "void * pvData", " ", &cArgs);
WriteArg(pN->_fFlags, "DWORD grfFlags", " ", &cArgs);
fprintf(_fpOutput, ")\n{\n");
if ( pN->_fElement
&& !pN->_fSI
&& !pN->_fCp
&& !pN->_fTreeChange)
fprintf(_fpOutput, " Assert(pElement);\n");
cArgs = 0;
fprintf(_fpOutput, " Initialize%s%s(NTYPE_%s,\n",
pN->_fSI
? "Si"
: "",
pN->_fCp
? "Cp"
: "",
_strupr(pN->_achType));
WriteArg(pN->_fElement, "pElement", " ", &cArgs);
if (pN->_fSI)
{
WriteArg(pN->_fSI, "siElement", " ", &cArgs);
WriteArg(pN->_fCElements, "cElements", " ", &cArgs);
}
if (pN->_fCp)
{
WriteArg(1, (pN->_fCp
? "cp"
: "-1"), " ", &cArgs);
WriteArg(1, (pN->_fCch
? "cch"
: "-1"), " ", &cArgs);
}
WriteArg(1, (pN->_fTreeNode
? "pNode"
: "NULL"), " ", &cArgs);
WriteArg(1, (pN->_fData
? "pvData"
: "NULL"), " ", &cArgs);
WriteArg(1, (pN->_fFlags
? "grfFlags"
: "0"), " ", &cArgs);
fprintf(_fpOutput, ");\n");
fprintf(_fpOutput, "}\n\n");
}
fprintf(_fpOutput, "#undef _NOTIFYTYPE_INLINE_\n\n");
fprintf(_fpOutput, "\n");
fprintf(_fpOutput, "#endif\n\n");
err = S_OK;
Cleanup:
if (err)
ReportError("Could not build %s\n", _pchOutput);
if (_fpInput)
fclose(_fpInput);
if (_fpOutput)
fclose(_fpOutput);
if (_fpLog)
fclose(_fpLog);
return err;
}
BOOL
CNotificationParser::Validate(CNotification * pN)
{
ERROR err = E_FAIL;
if (!*pN->_achType)
{
ReportError("Notification is missing 'type:'");
goto Cleanup;
}
if ( !pN->_fSelf
&& !pN->_fAncestors
&& !pN->_fDescendents
&& !pN->_fTree)
{
ReportError("Notification is missing targets");
goto Cleanup;
}
if ( pN->_fAncestors
&& pN->_fDescendents)
{
ReportError("Notification is sent to both ancestors and descendents");
goto Cleanup;
}
if ( !pN->_fTextChange
&& !pN->_fTreeChange
&& !pN->_fLayoutChange
&& !pN->_fActiveX
&& !pN->_fLayoutElements
&& !pN->_fBubbleUpViewTree
&& !pN->_fPositionedElements
&& !pN->_fAllElements
&& !pN->_fFrameSites)
{
ReportError("Notification is missing categories");
goto Cleanup;
}
if ( !pN->_fElement
&& !pN->_fSI
&& !pN->_fCp
&& !pN->_fTreeNode)
{
ReportError("Notification requires either 'element', 'si', 'cp', or 'tree-node'");
goto Cleanup;
}
if ( pN->_fCElements
&& !pN->_fSI)
{
ReportError("Notification has 'celement' without 'si'");
goto Cleanup;
}
if ( pN->_fCch
&& !pN->_fCp)
{
ReportError("Notification has 'cch' without 'cp'");
goto Cleanup;
}
if ( pN->_fSecondChanceAvail
&& ( pN->_fSelf && strcmp( pN->_achType, "ELEMENT_EXITTREE" )
|| pN->_fAncestors
|| pN->_fTree))
{
ReportError("Second chance only implemented for descendents and ELEMENT_EXITTREE");
goto Cleanup;
}
err = S_OK;
Cleanup:
return (err == S_OK);
}
char *
CNotificationParser::NameOf(char * pchInput, char * pchOutput)
{
char * pch = pchOutput;
int fMakeUpper = 1;
while (*pchInput)
{
if (*pchInput == '_')
{
fMakeUpper = 1;
}
else
{
*pchOutput++ = (fMakeUpper
? (char)toupper(*pchInput)
: (char)tolower(*pchInput));
fMakeUpper = 0;
}
pchInput++;
}
*pchOutput = '\0';
return pch;
}
void
CNotificationParser::WriteArg(unsigned fFlag, char * pchArg, char * pchPad, int * pcArgs)
{
if (fFlag)
{
if (*pcArgs)
fprintf(_fpOutput, ",\n");
fprintf(_fpOutput, "%s", pchPad);
(*pcArgs)++;
fprintf(_fpOutput, "%s", pchArg);
}
}
void
CNotificationParser::WriteFlag(unsigned fFlag, char * pchFlag, int * pcFlags)
{
char ach[MAX_WORD];
int cch = strlen(pchFlag);
if (fFlag)
{
fprintf(_fpOutput, (*pcFlags
? " | "
: " "));
fprintf(_fpOutput, "%s", pchFlag);
(*pcFlags)++;
}
else
{
strncpy(ach, achBlanks, cch);
ach[cch] = '\0';
fprintf(_fpOutput, " ");
fprintf(_fpOutput, "%s", ach);
}
}
BOOL
CNotificationParser::ReadLine(char *pchBuf, int cchBuf, int *pcchRead)
{
int cchRead;
if (!fgets(pchBuf, cchBuf, _fpInput))
return FALSE;
cchRead = strlen(pchBuf);
if (!cchRead)
return FALSE;
if (pcchRead)
*pcchRead = cchRead;
return TRUE;
}
inline BOOL
IsDelim(char ch)
{
return ( ch == ' '
|| ch == '\t'
|| ch == '\r'
|| ch == '\n'
|| ch == ','
|| ch == ':'
|| ch == ';');
}
void
CNotificationParser::SkipSpace(char **ppch)
{
char *pch = *ppch;
while (*pch && IsDelim(*pch))
pch++;
*ppch = pch;
}
void
CNotificationParser::SkipNonspace(char **ppch)
{
char *pch = *ppch;
while (*pch && !IsDelim(*pch))
pch++;
*ppch = pch;
}
void
CNotificationParser::ChopComment(char *pch)
{
while (*pch)
{
if (*pch == '/' && *(pch+1) == '/')
{
*pch = '\0';
return;
}
pch++;
}
}
BOOL
CNotificationParser::GetWord(char **ppch, char **ppchWord)
{
SkipSpace(ppch);
*ppchWord = *ppch;
SkipNonspace(ppch);
if (**ppch)
{
if (*ppch - *ppchWord > MAX_WORD)
*ppch = *ppchWord + MAX_WORD - 1;
**ppch = '\0';
(*ppch)++;
}
return **ppchWord;
}
void
CNotificationParser::ReportError(const char * pchError, ...)
{
char ach[MAX_LINE];
va_list ap;
va_start(ap, pchError);
vsprintf(ach, pchError, ap);
va_end(ap);
printf("%s(0) : error NF0000: %s\n", _pchInput, ach);
if (_fpLog)
fprintf(_fpLog, "%s(0) : error NF0000: %s\n", _pchInput, ach);
}
void
CNotificationParser::CNotification::MakeSC( CNotification *pN )
{
memcpy( this, pN, sizeof(CNotification) );
strncat(_achType, "_2", MAX_WORD-1);
_fSecondChanceAvail = FALSE;
_fSecondChance = TRUE;
}
void
CNotificationParser::CNotification::MarkFirstChance()
{
strncat(_achType, "_1", MAX_WORD-1);
}