602 lines
18 KiB
C
602 lines
18 KiB
C
/****************************** Module Header ******************************\
|
|
* Module Name: hsplit.c
|
|
*
|
|
* Structure parser - struct field name-offset tabel generator.
|
|
*
|
|
* Copyright (c) 1985-96, Microsoft Corporation
|
|
*
|
|
* 09/05/96 GerardoB Created
|
|
\***************************************************************************/
|
|
#include "hsplit.h"
|
|
|
|
/*
|
|
* Maximum size of tags (gphst) table including possible user defined tags
|
|
*/
|
|
#define HSTAGTABLESIZE (sizeof(ghstPredefined) + ((32 - HST_MASKBITCOUNT) * sizeof(HSTAG)))
|
|
/***************************************************************************\
|
|
* hsAddTag
|
|
*
|
|
\***************************************************************************/
|
|
PHSTAG hsAddTag (char * pszTag, DWORD dwMask)
|
|
{
|
|
PHSTAG phst;
|
|
DWORD dwTagSize;
|
|
|
|
/*
|
|
* Make sure we still have mask bits to uniquely identified this tag
|
|
*/
|
|
if (((dwMask | HST_EXTRACT) == HST_EXTRACT) && (gdwLastTagMask == HST_MAXMASK)) {
|
|
hsLogMsg(HSLM_ERROR, "Too many user defined tags. Max allowed: %d", 32 - HST_MASKBITCOUNT);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Create the table the first time around.
|
|
*/
|
|
if (gphst == ghstPredefined) {
|
|
gphst = (PHSTAG) LocalAlloc(LPTR, HSTAGTABLESIZE);
|
|
if (gphst == NULL) {
|
|
hsLogMsg(HSLM_APIERROR, "LocalAlloc");
|
|
hsLogMsg(HSLM_ERROR, "hsAddTag Allocation failed. Size:%#lx", HSTAGTABLESIZE);
|
|
return NULL;
|
|
}
|
|
|
|
CopyMemory(gphst, &ghstPredefined, sizeof(ghstPredefined));
|
|
}
|
|
|
|
/*
|
|
* If the string is in the table, we update the mask.
|
|
*/
|
|
dwTagSize = strlen(pszTag);
|
|
phst = hsFindTagInList(gphst, pszTag, dwTagSize);
|
|
if (phst == NULL) {
|
|
/*
|
|
* New string. Find next available entry in the table
|
|
*/
|
|
phst = gphst;
|
|
while (phst->dwLabelSize != 0) {
|
|
phst++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize it
|
|
*/
|
|
phst->dwLabelSize = dwTagSize;
|
|
phst->pszLabel = pszTag;
|
|
|
|
/*
|
|
* If generating a mask, use the next available bit in the tag mask
|
|
* else use the one supplied by the caller
|
|
*/
|
|
if ((dwMask | HST_EXTRACT) == HST_EXTRACT) {
|
|
gdwLastTagMask *= 2;
|
|
phst->dwMask = (gdwLastTagMask | dwMask);
|
|
} else {
|
|
phst->dwMask = dwMask;
|
|
}
|
|
|
|
/*
|
|
* Add this tag's mask to the filter mask so lines mark with this tag
|
|
* will be included
|
|
*/
|
|
gdwFilterMask |= (phst->dwMask & HST_USERTAGSMASK);
|
|
|
|
return phst;
|
|
}
|
|
/***************************************************************************\
|
|
* hsIsSwitch
|
|
*
|
|
\***************************************************************************/
|
|
__inline BOOL hsIsSwitch(char c)
|
|
{
|
|
return (c == '/') || (c == '-');
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* hsAddUserDefinedTag
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL hsAddUserDefinedTag(DWORD* pdwMask, int* pargc, char*** pargv)
|
|
{
|
|
DWORD dwRetMask = *pdwMask;
|
|
PHSTAG phst;
|
|
|
|
if (*pargc < 2) {
|
|
return FALSE; // invalid switch
|
|
}
|
|
|
|
/*
|
|
* Allow multiple tags to be specified for one switch
|
|
* i.e., -t tag1 <tag2 tag2....>
|
|
*/
|
|
do {
|
|
(*pargc)--, (*pargv)++;
|
|
|
|
/*
|
|
* Add tag to table
|
|
*/
|
|
phst = hsAddTag(**pargv, *pdwMask);
|
|
if (phst == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
dwRetMask |= phst->dwMask;
|
|
|
|
} while ((*pargc >= 2) && !hsIsSwitch(**(*pargv + 1)));
|
|
|
|
/*
|
|
* save the new mask
|
|
*/
|
|
*pdwMask = dwRetMask;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* hsAddExtractFile
|
|
*
|
|
\***************************************************************************/
|
|
BOOL hsAddExtractFile(char* pszExtractFile, DWORD dwMask, BOOL bAppend)
|
|
{
|
|
PHSEXTRACT pe;
|
|
|
|
pe = LocalAlloc(LPTR, sizeof(HSEXTRACT));
|
|
|
|
if (pe == NULL) {
|
|
return FALSE;
|
|
}
|
|
pe->pszFile = pszExtractFile;
|
|
pe->dwMask = dwMask;
|
|
|
|
pe->hfile = CreateFile(pszExtractFile, GENERIC_WRITE, 0, NULL,
|
|
(bAppend ? OPEN_EXISTING : CREATE_ALWAYS),
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (pe->hfile == INVALID_HANDLE_VALUE) {
|
|
hsLogMsg(HSLM_APIERROR | HSLM_NOLINE, "CreateFile failed for file %s",
|
|
pszExtractFile);
|
|
LocalFree(pe);
|
|
return FALSE;
|
|
}
|
|
if (bAppend) {
|
|
if (0xFFFFFFFF == SetFilePointer (pe->hfile, 0, 0, FILE_END)) {
|
|
hsLogMsg(HSLM_APIERROR | HSLM_NOLINE, "SetFilePointer failed for file %s",
|
|
pszExtractFile);
|
|
CloseHandle(pe->hfile);
|
|
LocalFree(pe);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* link it in the list of extract files
|
|
*/
|
|
pe->pNext = gpExtractFile;
|
|
gpExtractFile = pe;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* hsProcessParameters
|
|
*
|
|
\***************************************************************************/
|
|
int hsProcessParameters(int argc, LPSTR argv[])
|
|
{
|
|
char c, *p;
|
|
DWORD dwMask;
|
|
int argcParm = argc;
|
|
PHSTAG phst;
|
|
|
|
/*
|
|
* Compatibility. Assume default project the first time this
|
|
* function is called
|
|
*/
|
|
if (!(gdwOptions & HSO_APPENDOUTPUT)) {
|
|
gdwOptions |= HSO_OLDPROJSW_N;
|
|
}
|
|
|
|
/*
|
|
* Loop through parameters.
|
|
*/
|
|
while (--argc) {
|
|
p = *++argv;
|
|
if (hsIsSwitch(*p)) {
|
|
while (c = *++p) {
|
|
switch (toupper(c)) {
|
|
/*
|
|
* Compatibility.
|
|
* Chicago/Nashvilled header.
|
|
*/
|
|
case '4':
|
|
gdwOptions &= ~HSO_OLDPROJSW;
|
|
gdwOptions |= HSO_OLDPROJSW_4;
|
|
break;
|
|
|
|
/*
|
|
* Old bt2 and btb switches to replace internal and
|
|
* both block tags.
|
|
*/
|
|
case 'B':
|
|
p++;
|
|
if (toupper(*p++) != 'T') {
|
|
goto InvalidSwitch;
|
|
}
|
|
if (toupper(*p) == 'B') {
|
|
dwMask = HST_BOTH | HST_USERBOTHBLOCK;
|
|
gdwOptions |= HSO_USERBOTHBLOCK;
|
|
} else if (*p == '2') {
|
|
dwMask = HST_INTERNAL | HST_USERINTERNALBLOCK;
|
|
gdwOptions |= HSO_USERINTERNALBLOCK;
|
|
} else {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
if (argc < 3) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
|
|
/*
|
|
* Add these strings as tags and mark them as blocks
|
|
*/
|
|
argc--, argv++;
|
|
phst = hsAddTag(*argv, HST_BEGIN | dwMask);
|
|
if (phst == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
argc--, argv++;
|
|
phst = hsAddTag(*argv, HST_END | dwMask);
|
|
if (phst == NULL) {
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Tag marker
|
|
*/
|
|
case 'C':
|
|
if (argc < 2) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
argc--, argv++;
|
|
gpszTagMarker = *argv;
|
|
*gszMarkerCharAndEOL = *gpszTagMarker;
|
|
gdwTagMarkerSize = strlen(gpszTagMarker);
|
|
if (gdwTagMarkerSize == 0) {
|
|
goto InvalidSwitch;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Compatibility.
|
|
* NT SUR header
|
|
*/
|
|
case 'E':
|
|
gdwOptions &= ~HSO_OLDPROJSW;
|
|
gdwOptions |= HSO_OLDPROJSW_E;
|
|
break;
|
|
|
|
/*
|
|
* Input file
|
|
*/
|
|
case 'I':
|
|
if (argc < 2) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
argc--, argv++;
|
|
gpszInputFile = *argv;
|
|
goto ProcessInputFile;
|
|
break;
|
|
|
|
/*
|
|
* Extract file
|
|
*/
|
|
case 'X':
|
|
{
|
|
char* pszExtractFile;
|
|
BOOL bAppend = FALSE;
|
|
|
|
if (toupper(*(p+1)) == 'A') {
|
|
p++;
|
|
bAppend = TRUE;
|
|
}
|
|
|
|
if (argc < 3) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
argc--, argv++;
|
|
pszExtractFile = *argv;
|
|
|
|
dwMask = HST_EXTRACT;
|
|
if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
|
|
goto InvalidSwitch;
|
|
|
|
hsAddExtractFile(pszExtractFile, dwMask, bAppend);
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Old lt2 and ltb switches to replace internal and
|
|
* both tags.
|
|
*/
|
|
case 'L':
|
|
p++;
|
|
if (toupper(*p++) != 'T') {
|
|
goto InvalidSwitch;
|
|
}
|
|
if (toupper(*p) == 'B') {
|
|
dwMask = HST_BOTH | HST_USERBOTHTAG;
|
|
gdwOptions |= HSO_USERBOTHTAG;
|
|
} else if (*p == '2') {
|
|
dwMask = HST_INTERNAL | HST_USERINTERNALTAG;
|
|
gdwOptions |= HSO_USERINTERNALTAG;
|
|
} else {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
|
|
goto InvalidSwitch;
|
|
|
|
break;
|
|
|
|
/*
|
|
* Compatibility.
|
|
* NT header
|
|
*/
|
|
case 'N':
|
|
gdwOptions &= ~HSO_OLDPROJSW;
|
|
gdwOptions |= HSO_OLDPROJSW_N;
|
|
break;
|
|
|
|
/*
|
|
* Ouput files
|
|
*/
|
|
case 'O':
|
|
if (argc < 3) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
argc--, argv++;
|
|
gpszPublicFile = *argv;
|
|
|
|
argc--, argv++;
|
|
gpszInternalFile = *argv;
|
|
break;
|
|
|
|
/*
|
|
* Compatibility.
|
|
* NT SURPlus header
|
|
*/
|
|
case 'P':
|
|
gdwOptions &= ~HSO_OLDPROJSW;
|
|
gdwOptions |= HSO_OLDPROJSW_P;
|
|
break;
|
|
|
|
/*
|
|
* Split only. Process internal/both tags only. Tags
|
|
* including other tags as well (i.e., internal_NT)
|
|
* are treated as untagged.
|
|
*/
|
|
case 'S':
|
|
gdwOptions |= HSO_SPLITONLY;
|
|
break;
|
|
|
|
/*
|
|
* User defined tags.
|
|
*/
|
|
case 'T':
|
|
switch (toupper(*++p)) {
|
|
/*
|
|
* Include lines mark with this tag
|
|
*/
|
|
case 'A':
|
|
dwMask = 0;
|
|
break;
|
|
/*
|
|
* Ignore lines marked with this tag (i.e, treated
|
|
* as untagged)
|
|
*/
|
|
case 'I':
|
|
dwMask = HST_IGNORE;
|
|
break;
|
|
/*
|
|
* Skip lines marked with this tag (i.e., not
|
|
* included in header files)
|
|
*/
|
|
case 'S':
|
|
dwMask = HST_SKIP;
|
|
break;
|
|
|
|
default:
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
if (!hsAddUserDefinedTag(&dwMask, &argc, &argv))
|
|
goto InvalidSwitch;
|
|
|
|
break;
|
|
|
|
/*
|
|
* Version
|
|
*/
|
|
case 'V':
|
|
if (argc < 2) {
|
|
goto InvalidSwitch;
|
|
}
|
|
|
|
argc--, argv++;
|
|
if (!hsVersionFromString (*argv, strlen(*argv), &gdwVersion)) {
|
|
goto InvalidSwitch;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Unknown tags are to be skipped, as opposed to ignored.
|
|
*/
|
|
case 'U':
|
|
gdwOptions |= HSO_SKIPUNKNOWN;
|
|
break;
|
|
|
|
/*
|
|
* Invalid switch
|
|
*/
|
|
default:
|
|
InvalidSwitch:
|
|
hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Invalid switch or parameter: %c", c);
|
|
// Fall through
|
|
|
|
/*
|
|
* Help
|
|
*/
|
|
case '?':
|
|
goto PrintHelp;
|
|
|
|
} /* switch (toupper(c)) */
|
|
} /* while (c = *++p) */
|
|
} else { /* hsIsSwitch(*p) { */
|
|
/*
|
|
* No switch specified. Process this input file
|
|
*/
|
|
gpszInputFile = *argv;
|
|
break;
|
|
}
|
|
} /* while (--argc) */
|
|
|
|
ProcessInputFile:
|
|
/*
|
|
* Make sure we got input and ouput files.
|
|
*/
|
|
if ((gpszInputFile == NULL)
|
|
|| (gpszPublicFile == NULL)
|
|
|| (gpszInternalFile == NULL)) {
|
|
|
|
hsLogMsg(HSLM_ERROR | HSLM_NOLINE, "Missing input or ouput file");
|
|
goto PrintHelp;
|
|
}
|
|
|
|
/*
|
|
* Add compatibility tags for default projects (first call only)
|
|
*/
|
|
if ((gdwOptions & HSO_OLDPROJSW) && !(gdwOptions & HSO_APPENDOUTPUT)) {
|
|
if (!(gdwOptions & HSO_OLDPROJSW_4)) {
|
|
phst = hsAddTag(gszNT, 0);
|
|
if (phst == NULL) {
|
|
return 0;
|
|
}
|
|
phst->dwMask |= HST_MAPOLD;
|
|
dwMask = phst->dwMask;
|
|
}
|
|
|
|
if (gdwOptions & HSO_OLDPROJSW_E) {
|
|
hsAddTag(gszCairo, dwMask);
|
|
hsAddTag(gszSur, dwMask);
|
|
hsAddTag(gszWin40, dwMask);
|
|
hsAddTag(gsz35, dwMask);
|
|
|
|
} else if (gdwOptions & HSO_OLDPROJSW_P) {
|
|
hsAddTag(gszWin40, dwMask);
|
|
hsAddTag(gszWin40a, dwMask);
|
|
hsAddTag(gszCairo, dwMask);
|
|
hsAddTag(gszSur, dwMask);
|
|
hsAddTag(gszSurplus, dwMask);
|
|
hsAddTag(gsz35, dwMask);
|
|
|
|
} else if (gdwOptions & HSO_OLDPROJSW_4) {
|
|
gdwOptions |= HSO_INCINTERNAL;
|
|
phst = hsAddTag(gszChicago, 0);
|
|
if (phst == NULL) {
|
|
return 0;
|
|
}
|
|
phst->dwMask |= HST_MAPOLD;
|
|
dwMask = phst->dwMask;
|
|
hsAddTag(gszNashville, dwMask);
|
|
hsAddTag(gszWin40, dwMask);
|
|
hsAddTag(gszWin40a, dwMask);
|
|
|
|
} else if (!(gdwOptions & HSO_APPENDOUTPUT)) {
|
|
gdwOptions |= HSO_OLDPROJSW_N;
|
|
}
|
|
|
|
} /* (gdOptions & HSO_OLDPROJW) */
|
|
|
|
|
|
/*
|
|
* Compatibility. If doing split only, don't include internal tags
|
|
* in public file
|
|
*/
|
|
if (gdwOptions & HSO_SPLITONLY) {
|
|
gdwOptions &= ~HSO_INCINTERNAL;
|
|
}
|
|
|
|
return argcParm - argc;
|
|
|
|
PrintHelp:
|
|
hsLogMsg(HSLM_DEFAULT, "Header Split Utility. Version 2.1");
|
|
hsLogMsg(HSLM_NOLABEL, "Usage: hsplit [options] <-o PublicFile InternalFile> [-i] File1 [-i] File2...");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-4] Generate chicago/nashville headers");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-bt2 BeginStr EndStr] Replace begin_internal/end_internal - Obsolete");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-btb BeginStr EndStr] Replace begin_both/end_both tags - Obsolete");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-c TagMarker] Replace tag marker. default \";\"");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-e] Generate NT sur headers");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[[-i] file1 file2 ..] Input files - Required");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-lt2 str] Replace internal tag - Obsolete");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-ltb str] Replace both tag - Obsolete");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-n] Generate NT headers - default");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-x[a] ExtractHeader ExtractTag] Extract files and tags files");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-o PublicHeader InternalHeader] Output files - Required");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-p] Generate NT surplus headers");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-s] Process internal and both tags only");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-ta tag1 tag2 ..] Include lines using these tags");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-ti tag1 tag2 ..] Ignore these tags");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-ts tag1 tag2 ..] Skip lines using these tags");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-u] Skip unknown tags. Default: ignore");
|
|
hsLogMsg(HSLM_NOLABEL, "\t[-v] Version number. Default: LATEST_WIN32_WINNT_VERSION");
|
|
hsLogMsg(HSLM_NOLABEL, "\r\nTags Format:");
|
|
hsLogMsg(HSLM_NOLABEL, "\t<TagMarker>[begin/end][_public/internal][[_tag1][_tag2]...][_if_(str)_version | _version]");
|
|
return 0;
|
|
}
|
|
/***************************************************************************\
|
|
* main
|
|
*
|
|
\***************************************************************************/
|
|
int __cdecl main (int argc, char *argv[])
|
|
{
|
|
int argcProcessed;
|
|
|
|
/*
|
|
* Each loop processes one input file
|
|
*/
|
|
do {
|
|
argcProcessed = hsProcessParameters(argc, argv);
|
|
if (argcProcessed == 0) {
|
|
break;
|
|
}
|
|
|
|
if (!hsOpenWorkingFiles()
|
|
|| !hsSplit()) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
hsCloseWorkingFiles();
|
|
|
|
gdwOptions |= HSO_APPENDOUTPUT;
|
|
|
|
argc -= argcProcessed;
|
|
argv += argcProcessed;
|
|
|
|
} while (argc > 1);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|