RetroZilla/config/mantomak.c
2015-10-20 23:03:22 -04:00

1006 lines
21 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define DEFAULT_MANIFEST_EXT ".mn"
#define DEFAULT_MAKEFILE_EXT ".win"
typedef struct char_list_struct {
char *m_pString;
struct char_list_struct *m_pNext;
} char_list;
typedef struct macro_list_struct {
char *m_pMacro;
char_list *m_pValue;
struct macro_list_struct *m_pNext;
} macro_list;
void help(void);
char *input_filename(const char *);
char *output_filename(const char *, const char *);
int input_to_output(FILE *, FILE *);
int output_rules(FILE *);
int output_end(FILE *);
int buffer_to_output(char *, FILE *);
macro_list *extract_macros(char *);
char *find_macro(char *, char **);
void add_macro(char *, macro_list **);
int macro_length(char *);
int value_length(char *);
void add_values(char *, char_list **);
char *skip_white(char *);
int write_macros(macro_list *, FILE *);
int write_values(char_list *, FILE *, int);
void free_macro_list(macro_list *);
void free_char_list(char_list *);
void morph_macro(macro_list **, char *, char *, char *);
void slash_convert(macro_list *, char *);
int explicit_rules(macro_list *, char *, FILE *);
void create_classroot(macro_list **ppList );
int main(int argc, char *argv[])
{
int iOS = 0;
char *pInputFile = NULL;
char *pOutputFile = NULL;
/* Figure out arguments.
* [REQUIRED] First argument is input file.
* [OPTIONAL] Second argument is output file.
*/
if(argc > 1) {
FILE *pInputStream = NULL;
FILE *pOutputStream = NULL;
/* Form respective filenames.
*/
pInputFile = input_filename(argv[1]);
pOutputFile = output_filename(pInputFile, argc > 2 ? argv[2] : NULL);
if(pInputFile == NULL) {
fprintf(stderr, "MANTOMAK: Unable to form input filename\n");
iOS = 1;
}
else {
pInputStream = fopen(pInputFile, "rb");
if(pInputStream == NULL) {
fprintf(stderr, "MANTOMAK: Unable to open input file %s\n", pInputFile);
iOS = 1;
}
}
if(pOutputFile == NULL) {
fprintf(stderr, "MANTOMAK: Unable to form output filename\n");
iOS = 1;
}
else if(pInputStream != NULL) {
pOutputStream = fopen(pOutputFile, "wt");
if(pOutputStream == NULL) {
fprintf(stderr, "MANTOMAK: Unable to open output file %s\n", pOutputFile);
iOS = 1;
}
}
/* Only do the real processing if our error code is not
* already set.
*/
if(iOS == 0) {
iOS = input_to_output(pInputStream, pOutputStream);
}
if(pInputStream != NULL) {
fclose(pInputStream);
pInputStream = NULL;
}
if(pOutputStream != NULL) {
fclose(pOutputStream);
pOutputStream = NULL;
}
}
else {
help();
iOS = 1;
}
if(pInputFile) {
free(pInputFile);
pInputFile = NULL;
}
if(pOutputFile) {
free(pOutputFile);
pOutputFile = NULL;
}
return(iOS);
}
void help(void)
{
fprintf(stderr, "USAGE:\tmantomak.exe InputFile [OutputFile]\n\n");
fprintf(stderr, "InputFile:\tManifest file. If without extension, \"%s\" assumed.\n", DEFAULT_MANIFEST_EXT);
fprintf(stderr, "OutputFile:\tNMake file. If not present, \"InputFile%s\" assumed.\n", DEFAULT_MAKEFILE_EXT);
}
char *input_filename(const char *pInputFile)
{
char aResult[_MAX_PATH];
char aDrive[_MAX_DRIVE];
char aDir[_MAX_DIR];
char aName[_MAX_FNAME];
char aExt[_MAX_EXT];
if(pInputFile == NULL) {
return(NULL);
}
_splitpath(pInputFile, aDrive, aDir, aName, aExt);
if(aExt[0] == '\0') {
/* No extension provided.
* Use the default.
*/
strcpy(aExt, DEFAULT_MANIFEST_EXT);
}
aResult[0] = '\0';
_makepath(aResult, aDrive, aDir, aName, aExt);
if(aResult[0] == '\0') {
return(NULL);
}
else {
return(strdup(aResult));
}
}
char *output_filename(const char *pInputFile, const char *pOutputFile)
{
char aResult[_MAX_PATH];
char aDrive[_MAX_DRIVE];
char aDir[_MAX_DIR];
char aName[_MAX_FNAME];
char aExt[_MAX_EXT];
if(pOutputFile != NULL) {
return(strdup(pOutputFile));
}
/* From here on out, we have to create our own filename,
* implied from the input file name.
*/
if(pInputFile == NULL) {
return(NULL);
}
_splitpath(pInputFile, aDrive, aDir, aName, aExt);
strcpy(aExt, DEFAULT_MAKEFILE_EXT);
aResult[0] = '\0';
_makepath(aResult, aDrive, aDir, aName, aExt);
if(aResult[0] == '\0') {
return(NULL);
}
else {
return(strdup(aResult));
}
}
int input_to_output(FILE *pInput, FILE *pOutput)
{
char *pHog = NULL;
long lSize = 0;
int iRetval = 0;
/* Read the entire file into memory.
*/
fseek(pInput, 0, SEEK_END);
lSize = ftell(pInput);
fseek(pInput, 0, SEEK_SET);
pHog = (char *)malloc(lSize + 1);
if(pHog) {
*(pHog + lSize) = '\0';
fread(pHog, lSize, 1, pInput);
iRetval = buffer_to_output(pHog, pOutput);
free(pHog);
pHog = NULL;
}
else {
fprintf(stderr, "MANTOMAK: Out of Memory....\n");
iRetval = 1;
}
return(iRetval);
}
int output_rules(FILE *pOutput)
{
int iRetval = 0;
if(EOF ==
fputs("\n"
"!if \"$(MANIFEST_LEVEL)\"==\"RULES\""
"\n",
pOutput))
{
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
}
return(iRetval);
}
int output_end(FILE *pOutput)
{
int iRetval = 0;
if(EOF ==
fputs("\n"
"!endif"
"\n",
pOutput))
{
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
}
return(iRetval);
}
int buffer_to_output(char *pBuffer, FILE *pOutput)
{
int iRetval = 0;
macro_list *pMacros = NULL;
/* Tokenize the macros and their corresponding values.
*/
pMacros = extract_macros(pBuffer);
if(pMacros != NULL) {
/* Perform forward to backslash conversion on those macros known to be
* path information only.
*/
slash_convert(pMacros, "JBOOTDIRS");
slash_convert(pMacros, "JDIRS");
slash_convert(pMacros, "DEPTH");
slash_convert(pMacros, "NS_DEPTH");
slash_convert(pMacros, "PACKAGE");
slash_convert(pMacros, "JMC_GEN_DIR");
slash_convert(pMacros, "DIST_PUBLIC");
/* Process some of the macros, and convert them
* into different macros with different data.
*/
morph_macro(&pMacros, "JMC_GEN", "JMC_HEADERS", "$(JMC_GEN_DIR)\\%s.h");
morph_macro(&pMacros, "JMC_GEN", "JMC_STUBS", "$(JMC_GEN_DIR)\\%s.c");
morph_macro(&pMacros, "JMC_GEN", "JMC_OBJS", ".\\$(OBJDIR)\\%s.obj");
morph_macro(&pMacros, "CSRCS", "C_OBJS", ".\\$(OBJDIR)\\%s.obj");
morph_macro(&pMacros, "CPPSRCS", "CPP_OBJS", ".\\$(OBJDIR)\\%s.obj");
morph_macro(&pMacros, "REQUIRES", "LINCS", "-I$(XPDIST)\\public\\%s");
create_classroot( &pMacros );
/* Output the Macros and the corresponding values.
*/
iRetval = write_macros(pMacros, pOutput);
/* Output rule file inclusion
*/
if(iRetval == 0) {
iRetval = output_rules(pOutput);
}
/* Output explicit build rules/dependencies for JMC_GEN.
*/
if(iRetval == 0) {
iRetval = explicit_rules(pMacros, "JMC_GEN", pOutput);
}
if(iRetval == 0) {
iRetval = output_end(pOutput);
}
/* Free off the macro list.
*/
free_macro_list(pMacros);
pMacros = NULL;
}
return(iRetval);
}
int explicit_rules(macro_list *pList, char *pMacro, FILE *pOutput)
{
int iRetval = 0;
macro_list *pEntry = NULL;
if(pList == NULL || pMacro == NULL || pOutput == NULL) {
return(0);
}
/* Find macro of said name.
* Case insensitive.
*/
pEntry = pList;
while(pEntry) {
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
break;
}
pEntry = pEntry->m_pNext;
}
if(pEntry) {
/* Decide style of rule depending on macro name.
*/
if(stricmp(pEntry->m_pMacro, "JMC_GEN") == 0) {
char_list *pNames = NULL;
char *pModuleName = NULL;
char *pClassName = NULL;
pNames = pEntry->m_pValue;
while(pNames) {
pModuleName = pNames->m_pString;
pClassName = pModuleName + 1;
fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.h", pModuleName);
fprintf(pOutput, ": ");
fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
fprintf(pOutput, "\n ");
fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)");
fprintf(pOutput, "\n");
fprintf(pOutput, "$(JMC_GEN_DIR)\\%s.c", pModuleName);
fprintf(pOutput, ": ");
fprintf(pOutput, "$(JMCSRCDIR)\\%s.class", pClassName);
fprintf(pOutput, "\n ");
fprintf(pOutput, "$(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)");
fprintf(pOutput, "\n");
pNames = pNames->m_pNext;
}
}
else {
/* Don't know how to format macro.
*/
iRetval = 69;
}
}
return(iRetval);
}
void slash_convert(macro_list *pList, char *pMacro)
{
macro_list *pEntry = NULL;
if(pList == NULL || pMacro == NULL) {
return;
}
/* Find macro of said name.
* Case insensitive.
*/
pEntry = pList;
while(pEntry) {
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
break;
}
pEntry = pEntry->m_pNext;
}
if(pEntry) {
char *pConvert = NULL;
char_list *pValue = pEntry->m_pValue;
while(pValue) {
pConvert = pValue->m_pString;
while(pConvert && *pConvert) {
if(*pConvert == '/') {
*pConvert = '\\';
}
pConvert++;
}
pValue = pValue->m_pNext;
}
}
}
void morph_macro(macro_list **ppList, char *pMacro, char *pMorph, char *pPrintf)
{
macro_list *pEntry = NULL;
if(ppList == NULL || pMacro == NULL || pMorph == NULL || pPrintf == NULL) {
return;
}
/* Find macro of said name.
* Case insensitive.
*/
pEntry = *ppList;
while(pEntry) {
if(stricmp(pEntry->m_pMacro, pMacro) == 0) {
break;
}
pEntry = pEntry->m_pNext;
}
if(pEntry) {
char_list *pFilename = NULL;
char aPath[_MAX_PATH];
char aDrive[_MAX_DRIVE];
char aDir[_MAX_DIR];
char aFName[_MAX_FNAME];
char aExt[_MAX_EXT];
char *pBuffer = NULL;
/* Start with buffer size needed.
* We expand this as we go along if needed.
*/
pBuffer = (char *)malloc(strlen(pMorph) + 2);
strcpy(pBuffer, pMorph);
strcat(pBuffer, "=");
/* Go through each value, converting over to new macro.
*/
pFilename = pEntry->m_pValue;
while(pFilename) {
_splitpath(pFilename->m_pString, aDrive, aDir, aFName, aExt);
/* Expand buffer by required amount.
*/
sprintf(aPath, pPrintf, aFName);
strcat(aPath, " ");
pBuffer = (char *)realloc(pBuffer, _msize(pBuffer) + strlen(aPath));
strcat(pBuffer, aPath);
pFilename = pFilename->m_pNext;
}
/* Add the macro.
*/
add_macro(pBuffer, ppList);
free(pBuffer);
pBuffer = NULL;
}
}
void create_classroot(macro_list **ppList )
{
char cwd[512];
int i, i2;
macro_list *pEntry = NULL;
macro_list *pE;
/* Find macro of said name.
* Case insensitive.
*/
pEntry = *ppList;
while(pEntry) {
if(stricmp(pEntry->m_pMacro, "PACKAGE") == 0) {
break;
}
pEntry = pEntry->m_pNext;
}
if(pEntry == 0 || pEntry->m_pValue == 0 || pEntry->m_pValue->m_pString == 0) {
return;
}
_getcwd( cwd, 512 );
i = strlen( pEntry->m_pValue->m_pString );
i2 = strlen( cwd );
cwd[i2-i-1] = 0;
pE = NULL;
pE = (macro_list *)calloc(sizeof(macro_list),1);
pE->m_pMacro = strdup("CLASSROOT");
pE->m_pValue = (char_list *)calloc(sizeof(char_list),1);
pE->m_pValue->m_pString = strdup(cwd);
while(*ppList) {
ppList = &((*ppList)->m_pNext);
}
*ppList = pE;
}
int write_macros(macro_list *pList, FILE *pOutput)
{
int iRetval = 0;
int iLineLength = 0;
if(pList == NULL || pOutput == NULL) {
return(0);
}
if(EOF ==
fputs("\n"
"!if \"$(MANIFEST_LEVEL)\"==\"MACROS\""
"\n",
pOutput))
{
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
return(1);
}
while(pList) {
int bIgnoreForWin16 = 0;
/* The following macros should not be emitted for Win16 */
if (0 == strcmp(pList->m_pMacro, "LINCS")) {
bIgnoreForWin16 = 1;
}
if (bIgnoreForWin16) {
if(0 > fprintf(pOutput, "!if \"$(MOZ_BITS)\" != \"16\"\n")) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
}
if(0 > fprintf(pOutput, "%s=", pList->m_pMacro)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength += strlen(pList->m_pMacro) + 1;
iRetval = write_values(pList->m_pValue, pOutput, iLineLength);
if(iRetval) {
break;
}
if(EOF == fputc('\n', pOutput)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength = 0;
pList = pList->m_pNext;
if (bIgnoreForWin16) {
if(0 > fprintf(pOutput, "!endif\n")) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
bIgnoreForWin16 = 0;
}
}
if(EOF ==
fputs("\n"
"!endif"
"\n",
pOutput))
{
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
return(1);
}
return(iRetval);
}
int write_values(char_list *pList, FILE *pOutput, int iLineLength)
{
int iRetval = 0;
if(pList == NULL || pOutput == NULL) {
return(0);
}
while(pList) {
if(iLineLength == 0) {
if(EOF == fputs(" ", pOutput)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength += 4;
if(0 > fprintf(pOutput, "%s ", pList->m_pString)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength += strlen(pList->m_pString) + 1;
}
else if(iLineLength + strlen(pList->m_pString) > 72) {
if(EOF == fputs("\\\n", pOutput)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength = 0;
continue;
}
else {
if(0 > fprintf(pOutput, "%s ", pList->m_pString)) {
fprintf(stderr, "MANTOMAK: Error writing to file....\n");
iRetval = 1;
break;
}
iLineLength += strlen(pList->m_pString) + 1;
}
pList = pList->m_pNext;
}
return(iRetval);
}
macro_list *extract_macros(char *pBuffer)
{
macro_list *pRetval = NULL;
char *pTraverse = NULL;
char *pMacro = NULL;
pTraverse = pBuffer;
while(pTraverse) {
pMacro = NULL;
pTraverse = find_macro(pTraverse, &pMacro);
if(pMacro) {
add_macro(pMacro, &pRetval);
}
}
return(pRetval);
}
void add_macro(char *pString, macro_list **ppList)
{
macro_list *pEntry = NULL;
int iLength = 0;
if(pString == NULL || *pString == '\0' || ppList == NULL) {
return;
}
/* Allocate a new list entry for the macro.
*/
pEntry = (macro_list *)calloc(1, sizeof(macro_list));
/* Very first part of the string is the macro name.
* How long is it?
*/
iLength = macro_length(pString);
pEntry->m_pMacro = (char *)calloc(iLength + 1, 1);
strncpy(pEntry->m_pMacro, pString, iLength);
/* Skip to the values.
* These are always on the right side of an '='
*/
pString = strchr(pString, '=');
if(pString) {
pString++;
}
add_values(pString, &(pEntry->m_pValue));
/* Add the macro to the end of the macro list.
*/
while(*ppList) {
ppList = &((*ppList)->m_pNext);
}
*ppList = pEntry;
}
void add_values(char *pString, char_list **ppList)
{
char_list **ppTraverse = NULL;
char_list *pEntry = NULL;
int iLength = 0;
int iBackslash = 0;
if(pString == NULL || *pString == '\0' || ppList == NULL) {
return;
}
while(pString) {
/* Find start of value.
*/
iBackslash = 0;
while(*pString) {
if(*pString == '\\') {
iBackslash++;
}
else if(*pString == '\n') {
if(iBackslash == 0) {
/* End of values.
* Setting to NULL gets out of all loops.
*/
pString = NULL;
break;
}
iBackslash = 0;
}
else if(!isspace(*pString)) {
/* Backslashes part of string.
* This screws up if a backslash is in the middle of the string.
*/
pString -= iBackslash;
break;
}
pString++;
}
if(pString == NULL || *pString == '\0') {
break;
}
/* Do not honor anything beginning with a #
*/
if(*pString == '#') {
/* End of line.
*/
while(*pString && *pString != '\n') {
pString++;
}
continue;
}
/* Very first part of the string is value name.
* How long is it?
*/
iLength = value_length(pString);
/* Do not honor $(NULL)
*/
if(_strnicmp(pString, "$(NULL)", 7) == 0) {
pString += iLength;
continue;
}
/* Allocate a new list entry for the next value.
*/
pEntry = (char_list *)calloc(1, sizeof(char_list));
pEntry->m_pString = (char *)calloc(iLength + 1, 1);
strncpy(pEntry->m_pString, pString, iLength);
/* Add new value entry to the end of the list.
*/
ppTraverse = ppList;
while(*ppTraverse) {
ppTraverse = &((*ppTraverse)->m_pNext);
}
*ppTraverse = pEntry;
/* Go on to next value.
*/
pString += iLength;
}
}
char *find_macro(char *pBuffer, char **ppMacro)
{
char *pRetval = NULL;
int iBackslash = 0;
if(pBuffer == NULL || ppMacro == NULL) {
return(NULL);
}
/* Skip any whitespace in the buffer.
* If comments need to be skipped also, this is the place.
*/
while(1) {
while(*pBuffer && isspace(*pBuffer)) {
pBuffer++;
}
if(*pBuffer == '#') {
/* Go to the end of the line, it's a comment.
*/
while(*pBuffer && *pBuffer != '\n') {
pBuffer++;
}
continue;
}
break;
}
if(*pBuffer) {
/* Should be at the start of a macro.
*/
*ppMacro = pBuffer;
}
/* Find the end of the macro for the return value.
* This is the end of a line which does not contain a backslash at the end.
*/
while(*pBuffer) {
if(*pBuffer == '\\') {
iBackslash++;
}
else if(*pBuffer == '\n') {
if(iBackslash == 0) {
pRetval = pBuffer + 1;
break;
}
iBackslash = 0;
}
else if(!isspace(*pBuffer)) {
iBackslash = 0;
}
pBuffer++;
}
return(pRetval);
}
int macro_length(char *pMacro)
{
int iRetval = 0;
if(pMacro == NULL) {
return(0);
}
/* Length is no big deal.
* Problem is finding the end:
* whitespace
* '='
*/
while(*pMacro) {
if(*pMacro == '=') {
break;
}
else if(isspace(*pMacro)) {
break;
}
pMacro++;
iRetval++;
}
return(iRetval);
}
int value_length(char *pValue)
{
int iRetval = 0;
if(pValue == NULL) {
return(0);
}
/* Length is no big deal.
* Problem is finding the end:
* whitespace
* '\\'whitespace
*/
while(*pValue) {
if(*pValue == '\\') {
char *pFindNewline = pValue + 1;
/* If whitespace to end of line, break here.
*/
while(isspace(*pFindNewline)) {
if(*pFindNewline == '\n') {
break;
}
pFindNewline++;
}
if(*pFindNewline == '\n') {
break;
}
}
else if(isspace(*pValue)) {
break;
}
pValue++;
iRetval++;
}
return(iRetval);
}
char *skip_white(char *pString)
{
if(pString == NULL) {
return(NULL);
}
while(*pString && isspace(*pString)) {
pString++;
}
return(pString);
}
void free_macro_list(macro_list *pList)
{
macro_list *pFree = NULL;
if(pList == NULL) {
return;
}
while(pList) {
pFree = pList;
pList = pList->m_pNext;
pFree->m_pNext = NULL;
free_char_list(pFree->m_pValue);
pFree->m_pValue = NULL;
free(pFree->m_pMacro);
pFree->m_pMacro = NULL;
free(pFree);
pFree = NULL;
}
}
void free_char_list(char_list *pList)
{
char_list *pFree = NULL;
if(pList == NULL) {
return;
}
while(pList) {
pFree = pList;
pList = pList->m_pNext;
pFree->m_pNext = NULL;
free(pFree->m_pString);
pFree->m_pString = NULL;
free(pFree);
pFree = NULL;
}
}