Serious-Engine/Sources/Ecc/Main.cpp
Ryan C. Gordon 706814653d Simplify dealing with empty files.
Why write a parser when you already have a perfectly good one already?  :)
2016-04-03 02:07:52 -04:00

349 lines
8.8 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "StdH.h"
#include "Main.h"
FILE *_fInput;
int _iLinesCt = 1;
char *_strInputFileName;
int _bTrackLineInformation=0; // this is set if #line should be inserted in tokens
bool _bRemoveLineDirective = 0;
FILE *_fImplementation;
FILE *_fDeclaration;
FILE *_fTables;
FILE *_fExports;
char *_strFileNameBase;
char *_strFileNameBaseIdentifier;
extern FILE *yyin;
extern "C" int yywrap(void)
{
return 1;
}
int ctErrors = 0;
char *stradd(char *str1, char *str2)
{
char *strResult;
strResult = (char*)malloc(strlen(str1)+strlen(str2)+1);
strcpy(strResult, str1);
strcat(strResult, str2);
return strResult;
}
char *stradd(char *str1, char *str2, char *str3)
{
char *strResult;
strResult = (char*)malloc(strlen(str1)+strlen(str2)+strlen(str3)+1);
strcpy(strResult, str1);
strcat(strResult, str2);
strcat(strResult, str3);
return strResult;
}
char *LineDirective(int i)
{
char str[256];
sprintf(str, "\n#line %d %s\n", i, _strInputFileName);
return strdup(str);
}
SType SType::operator+(const SType &other)
{
SType sum;
sum.strString = stradd(strString, other.strString);
sum.iLine = -1;
sum.bCrossesStates = bCrossesStates||other.bCrossesStates;
return sum;
};
/*
* Function used for reporting errors.
*/
void yyerror(char *s)
{
fprintf( stderr, "%s(%d): Error: %s\n", _strInputFileName, _iLinesCt, s);
ctErrors++;
}
/*
* Change the extension of the filename.
*/
char *ChangeFileNameExtension(char *strFileName, char *strNewExtension)
{
char *strChanged = (char*)malloc(strlen(strFileName)+strlen(strNewExtension)+2);
strcpy(strChanged, strFileName);
char *pchDot = strrchr(strChanged, '.');
if (pchDot==NULL) {
pchDot = strChanged+strlen(strChanged);
}
strcpy(pchDot, strNewExtension);
return strChanged;
}
/*
* Open a file and report an error if failed.
*/
FILE *FOpen(const char *strFileName, char *strMode)
{
// open the input file
FILE *f = fopen(strFileName, strMode);
// if not successful
if (f==NULL) {
// report error
fprintf(stderr, "Can't open file '%s': %s\n", strFileName, strerror(errno));
//quit
exit(EXIT_FAILURE);
}
return f;
}
/*
* Print a header to an output file.
*/
static void PrintHeader(FILE *f)
{
fprintf(f, "/*\n");
fprintf(f, " * This file is generated by Entity Class Compiler, (c) CroTeam 1997-98\n");
fprintf(f, " */\n");
fprintf(f, "\n");
}
void TranslateBackSlashes(char *str)
{
char *strNextSlash = str;
while((strNextSlash = strchr(strNextSlash, '\\'))!=NULL) {
*strNextSlash = '/';
}
}
#define READSIZE 1024
/* Relpace File and remove #line directive from file */
void ReplaceFileRL(const char *strOld, const char *strNew)
{
char strOldBuff[READSIZE*3+1];
char strNewBuff[READSIZE+1];
int iOldch=0;
FILE *pfNew = NULL;
FILE *pfOld = NULL;
bool bQuotes = 0;
bool bComment = 0;
// open files
pfNew = fopen(strNew,"rb");
if(!pfNew) goto Error;
pfOld = fopen(strOld,"wb");
if(!pfOld) goto Error;
// until eof
while(!feof(pfNew))
{
// clear buffers
memset(&strOldBuff,0,sizeof(strOldBuff));
memset(&strNewBuff,0,sizeof(strNewBuff));
iOldch = 0;
bQuotes = 0;
bComment = 0;
// read one line from file
int iRead = fread(strNewBuff,1,READSIZE,pfNew);
char *chLineEnd = strchr(strNewBuff,13);
if(chLineEnd) *(chLineEnd+2) = 0;
// get line length
int ctch = strlen(strNewBuff);
int iSeek = -iRead+ctch;
// seek file for extra characters read
if(iSeek!=0) fseek(pfNew,iSeek ,SEEK_CUR);
if(strncmp(strNewBuff,"#line",5)==0)
{
continue;
}
// process each charachter
for(int ich=0;ich<ctch;ich++)
{
char *pchOld = &strOldBuff[iOldch];
char *pchNew = &strNewBuff[ich];
if((*pchNew == '{') || (*pchNew == '}') || *pchNew == ';')
{
if((!bComment) && (!bQuotes) && (*(pchNew+1) != 13))
{
strOldBuff[iOldch++] = strNewBuff[ich];
strOldBuff[iOldch++] = 13;
strOldBuff[iOldch++] = 10;
continue;
}
}
if(*pchNew == '"')
{
// if this is quote
if((ich>0) && (*(pchNew-1)=='\\')) { }
else bQuotes = !bQuotes;
}
else if((*pchNew == '/') && (*(pchNew+1) == '/'))
{
// if this is comment
bComment = 1;
}
strOldBuff[iOldch++] = strNewBuff[ich];
}
fwrite(&strOldBuff,1,iOldch,pfOld);
}
if(pfNew) fclose(pfNew);
if(pfOld) fclose(pfOld);
remove(strNew);
return;
Error:
if(pfNew) fclose(pfNew);
if(pfOld) fclose(pfOld);
}
/* Replace a file with a new file. */
void ReplaceFile(const char *strOld, const char *strNew)
{
if(_bRemoveLineDirective)
{
ReplaceFileRL(strOld,strNew);
return;
}
remove(strOld);
rename(strNew, strOld);
}
/* Replace a file with a new file if they are different.
* Used to keep .h files from constantly changing when you change the implementation.
*/
void ReplaceIfChanged(const char *strOld, const char *strNew)
{
int iChanged = 1;
FILE *fOld = fopen(strOld, "r");
if (fOld!=NULL) {
iChanged = 0;
FILE *fNew = FOpen(strNew, "r");
while (!feof(fOld)) {
char strOldLine[4096] = "#l";
char strNewLine[4096] = "#l";
// skip #line directives
while(strNewLine[0]=='#' && strNewLine[1]=='l' && !feof(fNew)) {
fgets(strNewLine, sizeof(strNewLine)-1, fNew);
}
while(strOldLine[0]=='#' && strOldLine[1]=='l' && !feof(fOld)) {
fgets(strOldLine, sizeof(strOldLine)-1, fOld);
}
if (strcmp(strNewLine, strOldLine)!=0) {
iChanged = 1;
break;
}
}
fclose(fNew);
fclose(fOld);
}
if (iChanged) {
remove(strOld);
rename(strNew, strOld);
} else {
remove(strNew);
}
}
int main(int argc, char *argv[])
{
// if there is not one argument on the command line
if (argc<1+1) {
// print usage
printf("Usage: Ecc <es_file_name>\n -line\n");
//quit
return EXIT_FAILURE;
}
if(argc>2)
{
if(strcmp(argv[2],"-line")==0)
{
_bRemoveLineDirective=1;
}
}
// open the input file
_fInput = FOpen(argv[1], "r");
//printf("%s\n", argv[1]);
// open all the output files
char *strImplementation = ChangeFileNameExtension(argv[1], ".cpp_tmp");
char *strImplementationOld = ChangeFileNameExtension(argv[1], ".cpp");
char *strDeclaration = ChangeFileNameExtension(argv[1], ".h_tmp");
char *strDeclarationOld = ChangeFileNameExtension(argv[1], ".h");
char *strTables = ChangeFileNameExtension(argv[1], "_tables.h_tmp");
char *strTablesOld = ChangeFileNameExtension(argv[1], "_tables.h");
_fImplementation = FOpen(strImplementation, "w");
_fDeclaration = FOpen(strDeclaration , "w");
_fTables = FOpen(strTables , "w");
// get the filename as preprocessor usable identifier
_strFileNameBase = ChangeFileNameExtension(argv[1], "");
_strFileNameBaseIdentifier = strdup(_strFileNameBase);
{char *strNextSlash = _strFileNameBaseIdentifier;
while((strNextSlash = strchr(strNextSlash, '/'))!=NULL) {
*strNextSlash = '_';
}}
{char *strNextSlash = _strFileNameBaseIdentifier;
while((strNextSlash = strchr(strNextSlash, '\\'))!=NULL) {
*strNextSlash = '_';
}}
// print their headers
PrintHeader(_fImplementation );
PrintHeader(_fDeclaration );
PrintHeader(_fTables );
// remember input filename
char strFullInputName[MAXPATHLEN];
_fullpath(strFullInputName, argv[1], MAXPATHLEN);
_strInputFileName = strFullInputName;
TranslateBackSlashes(_strInputFileName);
// make lex use the input file
yyin = _fInput;
// parse input file and generate the output files
yyparse();
// close all files
fclose(_fImplementation);
fclose(_fDeclaration);
fclose(_fTables);
// if there were no errors
if (ctErrors==0) {
// update the files that have changed
ReplaceFile(strImplementationOld, strImplementation);
ReplaceIfChanged(strDeclarationOld, strDeclaration);
ReplaceIfChanged(strTablesOld, strTables);
return EXIT_SUCCESS;
// if there were errors
} else {
// delete all files (the old declaration file is left intact!)
remove(strImplementation);
remove(strDeclaration );
remove(strTables );
return EXIT_FAILURE;
}
}