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.
 
 
 
 
 
 

735 lines
19 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Forms
// Copyright (C) Microsoft Corporation, 1994-1997
//
// File: ascparse.cxx
//
// Contents: Tool to build .hsc files from .asc files.
//
// Does the work of precomputing hash tables for associative
// arrays of strings.
//
//----------------------------------------------------------------------------
#define INCMSG(x)
#include "headers.hxx"
#ifndef X_LIMITS_H_
#define X_LIMITS_H_
#include <limits.h>
#endif
#ifndef X_PLATFORM_H_
#define X_PLATFORM_H_
#include <platform.h>
#endif
#ifndef X_MSHTMDBG_H_
#define X_MSHTMDBG_H_
#undef PERFMETER
#include <mshtmdbg.h>
#endif
#define ASCPARSE
// The following macro definitions allow us to use assoc.cxx
// without bringing in the whole CORE directory
#ifndef X_TCHAR_H_
#define X_TCHAR_H_
#include "tchar.h"
#endif
#define THR(x) (x)
#define RRETURN(x) return(x)
#define _MemAlloc(cb) malloc(cb)
#define _MemAllocClear(cb) calloc(1,cb)
#define _MemFree(x) free(x)
#define MemAlloc(mt,cb) _MemAlloc(cb)
#define MemAllocClear(mt,cb) _MemAllocClear(cb)
#define MemFree(x) _MemFree(x)
#define MemRealloc(mt, ppv, cb) _MemRealloc(ppv, cb)
#define _tcsequal(x,y) (!_tcscmp(x,y))
#define Assert(x) if (!(x)) { fprintf(stderr, "%s", #x); exit(1); }
#define Verify(x) if (!(x)) { fprintf(stderr, "%s", #x); exit(1); }
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
HRESULT
_MemRealloc(void **ppv, size_t cb)
{
void *pv;
if (*ppv == NULL)
{
*ppv = _MemAlloc(cb);
if (*ppv == NULL)
return E_OUTOFMEMORY;
}
else
{
pv = realloc(*ppv, cb);
if (pv == NULL)
return E_OUTOFMEMORY;
*ppv = pv;
}
return S_OK;
};
void GetSuffix(LPCSTR pAssocString, LPSTR pSuffix, int nNumber)
{
pSuffix[0] = '\0'; // NULL terminate the suffix
// check if the First Character is a Captial letter.
if ( islower(pAssocString[0]) )
return;
_itoa(nNumber, pSuffix, 10);
}
#include "assoc.cxx"
// end of stubs
#define MAX_WORD 64
#define MAX_LINE 4096
class CAscParser
{
public:
CAscParser() { memset(this, 0, sizeof(*this)); }
class CAscEntry {
public:
CAscEntry() { memset(this, 0, sizeof(*this)); }
CAscEntry *_pEntryNext;
char _achString[MAX_WORD];
int _number;
char _achNumber[MAX_WORD];
char _achStringName[MAX_WORD];
char _achAssoc[MAX_WORD];
char _achEnum[MAX_WORD];
BOOL _fNoassoc;
BOOL _fNostring;
BOOL _fNoenum;
const CAssoc *_pAssoc;
};
HRESULT ProcessAscFile(char *pchInputFile, char *pchOutputFile);
char _achAssocArray[MAX_WORD];
char _achAssocPrefix[MAX_WORD];
char _achEnumType[MAX_WORD];
char _achEnumPrefix[MAX_WORD];
char _achStringNamePrefix[MAX_WORD];
BOOL _fInsensitive;
BOOL _fReversible;
CAscEntry *_pEntryFirst;
CAscEntry *_pEntryLast;
};
static BOOL ReadLine(FILE *fp, char *pchBuf, int cchBuf, int *pcchRead);
static void SkipSpace(char **ppch);
static void SkipNonspace(char **ppch);
static void ChopComment(char *pch);
static void GetWord(char **ppch, char **ppchWord);
int __cdecl
main ( int argc, char *argv[] )
{
HRESULT hr = E_FAIL;
CAscParser np;
if (argc != 3)
goto Cleanup;
hr = np.ProcessAscFile(argv[1], argv[2]);
Cleanup:
if (hr)
printf ( "Error %lx building ASC file\n", hr);
exit(hr);
}
HRESULT
CAscParser::ProcessAscFile(char *pchInputFile, char *pchOutputFile)
{
HRESULT hr;
FILE *fpInput = NULL;
FILE *fpOutput = NULL;
char achBuf[MAX_LINE];
char *pch;
char *pchWord;
CAscEntry *pEntryNew;
CAscEntry *pEntry;
CAssocArray nt;
nt.Init();
_fReversible = FALSE;
// open input file
fpInput = fopen(pchInputFile, "r");
if (!fpInput)
{
hr = E_FAIL;
goto Cleanup;
}
// open output file
fpOutput = fopen(pchOutputFile, "w");
if (!fpOutput)
{
hr = E_FAIL;
goto Cleanup;
}
// phase 1: read the header section
hr = E_FAIL;
for (;;)
{
if (!ReadLine(fpInput, achBuf, MAX_LINE, NULL))
goto Cleanup;
pch = achBuf;
ChopComment(pch);
GetWord(&pch, &pchWord);
if (!*pchWord)
continue;
if (!strcmp(pchWord, "assocarray"))
{
GetWord(&pch, &pchWord);
strcpy(_achAssocArray, pchWord);
GetWord(&pch, &pchWord);
strcpy(_achAssocPrefix, pchWord);
}
else
if (!strcmp(pchWord, "enum"))
{
GetWord(&pch, &pchWord);
strcpy(_achEnumType, pchWord);
GetWord(&pch, &pchWord);
strcpy(_achEnumPrefix, pchWord);
}
else
if (!strcmp(pchWord, "string"))
{
GetWord(&pch, &pchWord);
strcpy(_achStringNamePrefix, pchWord);
}
else
if (!strcmp(pchWord, "case-insensitive"))
{
_fInsensitive = TRUE;
}
else
if (!strcmp(pchWord, "case-sensitive"))
{
_fInsensitive = FALSE;
}
else
if (!strcmp(pchWord, "reversible"))
{
_fReversible = TRUE;
}
else
if (!strcmp(pchWord, "start"))
break;
}
// phase 2: read the assoc table section
hr = S_OK;
while (ReadLine(fpInput, achBuf, MAX_LINE, NULL))
{
pch = achBuf;
ChopComment(pch);
GetWord(&pch, &pchWord);
if (!*pchWord)
continue;
// allocate
pEntryNew = new CAscEntry;
if (!pEntryNew)
return E_OUTOFMEMORY;
// link up
if (!_pEntryLast)
{
pEntryNew->_number = 0;
_pEntryLast = _pEntryFirst = pEntryNew;
}
else
{
pEntryNew->_number = _pEntryLast->_number+1;
_pEntryLast->_pEntryNext = pEntryNew;
_pEntryLast = pEntryNew;
}
// fill in assoc
strcpy(pEntryNew->_achString, pchWord);
// fill in other fields
for (;;)
{
GetWord(&pch, &pchWord);
if (!*pchWord)
break;
if (!strcmp(pchWord, "number"))
{
GetWord(&pch, &pchWord);
if (*pchWord == '=')
{
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!strcmp(pchWord+1, pEntry->_achString))
{
break;
}
}
if (!pEntry)
{
hr = E_FAIL;
goto Cleanup;
}
pEntryNew->_number = pEntry->_number;
strcpy(pEntryNew->_achNumber, pEntry->_achNumber);
}
else if (*pchWord >= '0' && *pchWord <= '9' || *pchWord == '-')
{
pEntryNew->_number = atol(pchWord);
*pEntryNew->_achNumber = '\0';
}
else
{
pEntryNew->_number = 0;
strcpy(pEntryNew->_achNumber, pchWord);
}
}
else
if (!strcmp(pchWord, "string"))
{
GetWord(&pch, &pchWord);
strcpy(pEntryNew->_achStringName, pchWord);
}
else
if (!strcmp(pchWord, "enum"))
{
GetWord(&pch, &pchWord);
strcpy(pEntryNew->_achEnum, pchWord);
}
else
if (!strcmp(pchWord, "assoc"))
{
GetWord(&pch, &pchWord);
strcpy(pEntryNew->_achAssoc, pchWord);
}
else
if (!strcmp(pchWord, "noassoc"))
{
pEntryNew->_fNoassoc = TRUE;
}
else
if (!strcmp(pchWord, "nostring"))
{
pEntryNew->_fNostring = TRUE;
}
else
if (!strcmp(pchWord, "noenum"))
{
pEntryNew->_fNoenum = TRUE;
}
}
}
// compute assocs
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!pEntry->_fNoassoc)
{
WCHAR awch[MAX_WORD];
WCHAR *pwch = awch;
char *pch = pEntry->_achString;
DWORD len;
DWORD hash;
const CAssoc *passoc;
do { *pwch++ = *pch; } while (*pch++);
len = _tcslen(awch);
if (_fInsensitive)
hash = HashStringCi(awch, len, 0);
else
hash = HashString(awch, len, 0);
passoc = nt.AddAssoc((DWORD_PTR)pEntry, awch, len, hash);
if (!passoc)
{
hr = E_FAIL;
goto Cleanup;
}
pEntry->_pAssoc = passoc;
}
}
// phase 3: output header decls enums
fprintf(fpOutput, "// %s\n", pchOutputFile);
fprintf(fpOutput, "// Generated by ascparse.exe from %s\n", pchInputFile);
fprintf(fpOutput, "// Do not modify by hand!\n");
fprintf(fpOutput, "\n#ifndef _cxx_\n\n");
// assocarray and hash
fprintf(fpOutput, "class CAssoc;\n");
fprintf(fpOutput, "class CAssocArray;\n\n");
fprintf(fpOutput, "extern const CAssoc * const %s_HashTable[%d];\n", _achAssocArray, nt._mHash);
if (_fReversible)
{
fprintf(fpOutput, "extern const CAssoc * const %s_RevSearch[];\n", _achAssocArray);
}
fprintf(fpOutput, "extern const CAssocArray %s;\n\n", _achAssocArray);
// enums
if (*_achEnumType)
{
fprintf(fpOutput, "enum %s\n{\n", _achEnumType);
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!pEntry->_fNoenum)
{
if (*pEntry->_achEnum)
{
fprintf(fpOutput, " %s = %d,\n", pEntry->_achEnum, pEntry->_number);
}
else
{
fprintf(fpOutput, " %s%s = %d,\n", _achEnumPrefix, pEntry->_achString, pEntry->_number);
}
}
}
fprintf(fpOutput, " %s_FORCE_LONG = LONG_MAX\n", _achEnumType);
fprintf(fpOutput, "};\n\n");
}
// assocs
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!pEntry->_fNoassoc)
{
if (!*pEntry->_achAssoc)
{
char suffix[32];
GetSuffix(pEntry->_achString, suffix, pEntry->_number);
fprintf(fpOutput, "extern const CAssoc %s%s%s;\n",
_achAssocPrefix, pEntry->_achString, suffix);
}
else
{
fprintf(fpOutput, "extern const CAssoc %s;\n",
pEntry->_achAssoc);
}
}
}
fprintf(fpOutput, "\n\n");
// strings
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!pEntry->_fNostring)
{
if (!pEntry->_fNoassoc && (*_achStringNamePrefix || *pEntry->_achStringName))
{
if (*pEntry->_achStringName)
{
fprintf(fpOutput, "#define %s ",
pEntry->_achStringName);
}
else
{
fprintf(fpOutput, "#define %s%s ",
_achStringNamePrefix, pEntry->_achString);
}
if (!*pEntry->_achAssoc)
{
char suffix[32];
GetSuffix(pEntry->_achString, suffix, pEntry->_number);
fprintf(fpOutput, "(%s%s%s._ach)\n",
_achAssocPrefix, pEntry->_achString, suffix);
}
else
{
fprintf(fpOutput, "(%s._ach)\n",
pEntry->_achAssoc);
}
}
else
{
if (*pEntry->_achStringName)
{
fprintf(fpOutput, "#define %s (_T(\"%s\"))\n",
pEntry->_achStringName, pEntry->_achString);
}
else if (*_achStringNamePrefix)
{
fprintf(fpOutput, "#define *%s%s (_T(\"%s\"))\n",
_achStringNamePrefix, pEntry->_achString, pEntry->_achString);
}
}
}
}
// end of header section; start of cxx section
fprintf(fpOutput, "\n#else _cxx_\n\n");
fprintf(fpOutput, "\n#undef _cxx_\n\n");
// phase 4: output assocs
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (!pEntry->_fNoassoc)
{
if (!*pEntry->_achAssoc)
{
char suffix[32];
GetSuffix(pEntry->_achString, suffix, pEntry->_number);
fprintf(fpOutput, "const CAssoc %s%s%s\t\t\t= ",
_achAssocPrefix, pEntry->_achString, suffix);
}
else
{
fprintf(fpOutput, "const CAssoc %s = ",
pEntry->_achAssoc);
}
if (*pEntry->_achNumber)
{
fprintf(fpOutput, "{ %12s, 0x%08x, _T(\"%s\") };\n",
pEntry->_achNumber, pEntry->_pAssoc->_hash, pEntry->_achString);
}
else
{
fprintf(fpOutput, "{ %5d, 0x%08x, _T(\"%s\") };\n",
pEntry->_number, pEntry->_pAssoc->_hash, pEntry->_achString);
}
}
}
// phase 5: output table
// output hash table
fprintf(fpOutput, "\n\nconst CAssoc * const %s_HashTable[%d] =\n{\n", _achAssocArray, nt._mHash);
{
int i;
int c;
int s;
int d;
const CAssoc * const *ppAssoc;
for (ppAssoc = nt._pHashTable, c=nt._mHash; c; ppAssoc++, c--)
{
if (!*ppAssoc)
{
fprintf(fpOutput, " NULL,\n");
}
else
{
i = (*ppAssoc)->Hash() % nt._mHash;
s = ((*ppAssoc)->Hash() & nt._sHash) + 1;
d = 0;
while (nt._pHashTable + i != ppAssoc)
{
if (i < s)
i += nt._mHash;
i -= s;
d++;
}
fprintf(fpOutput, "/*%2d */ ",d);
pEntry = (CAscEntry*)(*ppAssoc)->Number();
if (!*pEntry->_achAssoc)
{
char suffix[32];
GetSuffix(pEntry->_achString, suffix, pEntry->_number);
fprintf(fpOutput, "&%s%s%s,\n",
_achAssocPrefix, pEntry->_achString, suffix);
}
else
{
char suffix[32];
GetSuffix(pEntry->_achAssoc, suffix, pEntry->_number);
fprintf(fpOutput, "&%s%s,\n",
pEntry->_achAssoc, suffix);
}
}
}
}
fprintf(fpOutput, "};\n\n");
// phase 6: output table for reverse search (if requested)
if (_fReversible)
{
CAscParser::CAscEntry * pFound;
CAscParser::CAscEntry * pEntry;
int nCurrMin;
int nPrevMin;
int nCurrVal;
fprintf(fpOutput, "const CAssoc * const %s_RevSearch[] =\n{\n", _achAssocArray);
// find and print the entries in order from numeric min to max
nPrevMin = 0;
for(;;)
{
// find the next entry
nCurrMin = INT_MAX;
pFound = NULL;
for (pEntry = _pEntryFirst; pEntry; pEntry = pEntry->_pEntryNext)
{
if (*pEntry->_achNumber)
{
nCurrVal = atol(pEntry->_achNumber);
}
else
{
nCurrVal = pEntry->_number;
}
if (nCurrVal > nPrevMin && nCurrVal < nCurrMin)
{
nCurrMin = nCurrVal;
pFound = pEntry;
}
}
// break out once we've done everything
if (pFound == NULL)
{
break;
}
// output a pointer to the assoc
if (!*pFound->_achAssoc)
{
char suffix[32];
GetSuffix(pFound->_achString, suffix, pFound->_number);
fprintf(fpOutput, "\t&%s%s%s,\n",
_achAssocPrefix, pFound->_achString, suffix);
}
else
{
fprintf(fpOutput, "\t%s,\n", pFound->_achAssoc);
}
nPrevMin = nCurrMin;
}
fprintf(fpOutput, "};\n\n");
}
// output assoc table struct itself
fprintf(fpOutput, "const CAssocArray %s = {\n", _achAssocArray);
fprintf(fpOutput, " %s_HashTable,\n", _achAssocArray);
fprintf(fpOutput, " %d,\n", nt._cHash);
fprintf(fpOutput, " %d,\n", nt._mHash);
fprintf(fpOutput, " %d,\n", nt._sHash);
fprintf(fpOutput, " %d,\n", nt._cHash);
fprintf(fpOutput, " %d,\n", nt._iSize);
fprintf(fpOutput, " TRUE,\n");
fprintf(fpOutput, "};\n\n");
fprintf(fpOutput, "\n#endif _cxx_\n\n");
Cleanup:
nt.Deinit();
if (fpInput)
fclose(fpInput);
if (fpOutput)
fclose(fpOutput);
return hr;
}
static
BOOL
ReadLine(FILE *fp, char *pchBuf, int cchBuf, int *pcchRead)
{
int cchRead;
if (!fgets(pchBuf, cchBuf, fp))
return FALSE;
cchRead = strlen(pchBuf);
if (!cchRead)
return FALSE;
if (pcchRead)
*pcchRead = cchRead;
return TRUE;
}
static
void
SkipSpace(char **ppch)
{
char *pch = *ppch;
while (*pch && (*pch == ' ' || *pch == '\t' || *pch == '\r' || *pch == '\n'))
pch++;
*ppch = pch;
}
static
void
SkipNonspace(char **ppch)
{
char *pch = *ppch;
while (*pch && (*pch != ' ' && *pch != '\t' && *pch != '\r' && *pch != '\n'))
pch++;
*ppch = pch;
}
static
void
ChopComment(char *pch)
{
while (*pch)
{
if (*pch == '/' && *(pch+1) == '/')
{
*pch = '\0';
return;
}
pch++;
}
}
static
void
GetWord(char **ppch, char **ppchWord)
{
SkipSpace(ppch);
*ppchWord = *ppch;
SkipNonspace(ppch);
if (**ppch)
{
**ppch = '\0';
if (*ppch - *ppchWord > MAX_WORD)
*(*ppchWord + MAX_WORD-1) = '\0';
(*ppch)++;
}
}