diff options
Diffstat (limited to 'app/bin/paramfile.c')
-rw-r--r-- | app/bin/paramfile.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/app/bin/paramfile.c b/app/bin/paramfile.c new file mode 100644 index 0000000..2dd9ac7 --- /dev/null +++ b/app/bin/paramfile.c @@ -0,0 +1,393 @@ +/** \file paramfile.c + * Handling of parameter files + */ + + /* XTrackkCad - Model Railroad CAD + * Copyright (C) 2019 Martin Fischer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common.h" +#include "compound.h" +#include "ctrain.h" +#include "custom.h" +#include "fileio.h" +#include "i18n.h" +#include "layout.h" +#include "messages.h" +#include "misc2.h" +#include "paths.h" +#include "include/paramfile.h" +#include "include/paramfilelist.h" +#include "include/utf8convert.h" + +#if _MSC_VER >1300 +#define stricmp( a, b ) _stricmp(a, b ) +#endif + +static long paramCheckSum; + +typedef enum paramFileState(*GetCompatibilityFunction)(int index, + SCALEINX_T scale); + +GetCompatibilityFunction GetCompatibility[] = { + GetTrackCompatibility, + GetStructureCompatibility, + GetCarProtoCompatibility, + GetCarPartCompatibility +}; + +#define COMPATIBILITYCHECKSCOUNT (sizeof(GetCompatibility)/sizeof(GetCompatibility[0])) + +/** + * Check whether parameter file is still loaded + * + * \param fileInx + * \return TRUE if loaded, FALSE otherwise + */ + +wBool_t IsParamValid( + int fileInx) +{ + if (fileInx == PARAM_DEMO) { + return (curDemo >= 0); + } else if (fileInx == PARAM_CUSTOM) { + return TRUE; + } else if (fileInx == PARAM_LAYOUT) { + return TRUE; + } else if (fileInx >= 0 && fileInx < paramFileInfo_da.cnt) { + return (!paramFileInfo(fileInx).deleted); + } else { + return FALSE; + } +} + +char *GetParamFileDir(void) +{ + return (GetCurrentPath(PARAMETERPATHKEY)); +} + +void +SetParamFileDir(char *fullPath) +{ + SetCurrentPath(PARAMETERPATHKEY, fullPath); +} + +char * GetParamFileName( + int fileInx) +{ + return paramFileInfo(fileInx).name; +} + +char * GetParamFileContents( + int fileInx) +{ + return paramFileInfo(fileInx).contents; +} + +bool IsParamFileDeleted(int inx) +{ + return paramFileInfo(inx).deleted; +} + +bool IsParamFileFavorite(int inx) +{ + return paramFileInfo(inx).favorite; +} + +void SetParamFileDeleted(int fileInx, bool deleted) +{ + paramFileInfo(fileInx).deleted = deleted; +} + +void SetParamFileFavorite(int fileInx, bool favorite) +{ + paramFileInfo(fileInx).favorite = favorite; +} + +void ParamCheckSumLine(char * line) +{ + long mult = 1; + while (*line) { + paramCheckSum += (((long)(*line++)) & 0xFF)*(mult++); + } +} + +/** + * Set the compatibility state of a parameter file + * + * \param index parameter file number in list + * \return + */ + +void SetParamFileState(int index) +{ + enum paramFileState state = PARAMFILE_NOTUSABLE; + enum paramFileState newState; + SCALEINX_T scale = GetLayoutCurScale(); + + for (int i = 0; i < COMPATIBILITYCHECKSCOUNT && state < PARAMFILE_FIT && + state != PARAMFILE_UNLOADED; i++) { + newState = (*GetCompatibility[i])(index, scale); + if (newState > state || newState == PARAMFILE_UNLOADED) { + state = newState; + } + } + + paramFileInfo(index).trackState = state; +} + +/** + * Read a single parameter file and update the parameter file list + * + * \param fileName full path for parameter file + * \return + */ + +int +ReadParamFile(const char *fileName) +{ + DYNARR_APPEND(paramFileInfo_t, paramFileInfo_da, 10); + curParamFileIndex = paramFileInfo_da.cnt - 1; + paramFileInfo(curParamFileIndex).name = MyStrdup(fileName); + paramFileInfo(curParamFileIndex).valid = TRUE; + paramFileInfo(curParamFileIndex).deleted = !ReadParams(0, NULL, fileName); + paramFileInfo(curParamFileIndex).contents = MyStrdup(curContents); + + SetParamFileState(curParamFileIndex); + + return (curParamFileIndex); +} + +/** + * Reload a single parameter file that had been unloaded before. + * + * \param fileindex index of previously created paramFileInfo + * + * \returns + */ + +int +ReloadDeletedParamFile(int fileindex) +{ + curParamFileIndex = fileindex; + paramFileInfo(curParamFileIndex).valid = TRUE; + paramFileInfo(curParamFileIndex).deleted = !ReadParams(0, NULL, paramFileInfo(curParamFileIndex).name); + paramFileInfo(curParamFileIndex).contents = MyStrdup(curContents); + + SetParamFileState(curParamFileIndex); + + return (curParamFileIndex); +} + +/** + * Parameter file reader and interpreter + * + * \param key unused + * \param dirName prefix for parameter file path + * \param fileName name of parameter file + * \return + */ + +bool ReadParams( + long key, + const char * dirName, + const char * fileName) +{ + FILE * oldFile; + char *cp; + wIndex_t oldLineNum; + wIndex_t pc; + long oldCheckSum; + long checkSum = 0; + BOOL_T checkSummed; + paramVersion = -1; + char *oldLocale = NULL; + + if (dirName) { + MakeFullpath(¶mFileName, dirName, fileName, NULL); + } else { + MakeFullpath(¶mFileName, fileName, NULL); + } + paramLineNum = 0; + curBarScale = -1; + curContents = MyStrdup(fileName); + curSubContents = curContents; + + //LOG1( log_paramFile, ("ReadParam( %s )\n", fileName ) ) + + oldLocale = SaveLocale("C"); + + paramFile = fopen(paramFileName, "r"); + if (paramFile == NULL) { + /* Reset the locale settings */ + RestoreLocale(oldLocale); + + NoticeMessage(MSG_OPEN_FAIL, _("Continue"), NULL, _("Parameter"), paramFileName, + strerror(errno)); + + return FALSE; + } + paramCheckSum = key; + paramLineNum = 0; + checkSummed = FALSE; + BOOL_T skip = false; + int skipLines = 0; + while (paramFile && (fgets(paramLine, 256, paramFile)) != NULL) { + paramLineNum++; + Stripcr(paramLine); + if (strncmp(paramLine, "CHECKSUM ", 9) == 0) { + checkSum = atol(paramLine + 9); + checkSummed = TRUE; + goto nextLine; + } + ParamCheckSumLine(paramLine); + if (paramLine[0] == '#') { + /* comment */ + } else if (paramLine[0] == 0) { + /* empty paramLine */ + } else if (strncmp(paramLine, "INCLUDE ", 8) == 0) { + cp = ¶mLine[8]; + while (*cp && isspace((unsigned char)*cp)) { + cp++; + } + if (!*cp) { + InputError("INCLUDE - no file name", TRUE); + + /* Close file and reset the locale settings */ + if (paramFile) { + fclose(paramFile); + } + RestoreLocale(oldLocale); + + return FALSE; + } + oldFile = paramFile; + oldLineNum = paramLineNum; + oldCheckSum = paramCheckSum; + if (!ReadParams(key, dirName, cp)) { + RestoreLocale(oldLocale); + return FALSE; + } + paramFile = oldFile; + paramLineNum = oldLineNum; + paramCheckSum = oldCheckSum; + if (dirName) { + MakeFullpath(¶mFileName, dirName, fileName, NULL); + } else { + MakeFullpath(¶mFileName, fileName); + } + skip = FALSE; + } else if (strncmp(paramLine, "CONTENTS ", 9) == 0) { +#ifdef WINDOWS + ConvertUTF8ToSystem(paramLine + 9); +#endif + curContents = MyStrdup(paramLine + 9); + curSubContents = curContents; + skip = FALSE; + } else if (strncmp(paramLine, "SUBCONTENTS ", 12) == 0) { +#ifdef WINDOWS + ConvertUTF8ToSystem(paramLine + 12); +#endif // WINDOWS + curSubContents = MyStrdup(paramLine + 12); + skip = FALSE; + } else if (strncmp(paramLine, "PARAM ", 6) == 0) { + paramVersion = strtol(paramLine + 8, &cp, 10); + if (cp) + while (*cp && isspace((unsigned char)*cp)) cp++; + if (paramVersion > iParamVersion) { + if (cp && *cp) { + NoticeMessage(MSG_PARAM_UPGRADE_VERSION1, _("Ok"), NULL, paramVersion, iParamVersion, sProdName, cp); + } else { + NoticeMessage(MSG_PARAM_UPGRADE_VERSION2, _("Ok"), NULL, paramVersion, iParamVersion, sProdName); + } + break; + } + if (paramVersion < iMinParamVersion) { + NoticeMessage(MSG_PARAM_BAD_FILE_VERSION, _("Ok"), NULL, paramVersion, iMinParamVersion, sProdName); + break; + } + } else if (skip && (strncmp(paramLine, " ", 1) == 0)) { + //Always skip to next line starting in LeftHandColumn + skipLines++; + goto nextLine; + } else { + for (pc = 0; pc < paramProc_da.cnt; pc++) { + if (strncmp(paramLine, paramProc(pc).name, + strlen(paramProc(pc).name)) == 0) { + skip = FALSE; //Stop skip so we re-message + paramProc(pc).proc(paramLine); + goto nextLine; + } + } + if (!skip) { + if (InputError(_("Unknown param file line - skip until next good object?"), TRUE)) { //OK to carry on + /* SKIP until next main line we recognize */ + skip = TRUE; + skipLines++; + goto nextLine; + } else { + if (skipLines > 0) + NoticeMessage(MSG_PARAM_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines); + if (paramFile) { + fclose(paramFile); + paramFile = NULL; + } + if (paramFileName) { + free(paramFileName); + paramFileName = NULL; + } + RestoreLocale(oldLocale); + return FALSE; + } + } + skipLines++; + } + nextLine: + ; + } + if (key) { + if (!checkSummed || checkSum != paramCheckSum) { + /* Close file and reset the locale settings */ + if (paramFile) { + fclose(paramFile); + } + RestoreLocale(oldLocale); + + NoticeMessage(MSG_PROG_CORRUPTED, _("Ok"), NULL, paramFileName); + + return FALSE; + } + } + if (skipLines > 0) + NoticeMessage(MSG_PARAM_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines); + if (paramFile) { + fclose(paramFile); + } + free(paramFileName); + paramFileName = NULL; + RestoreLocale(oldLocale); + + return TRUE; +} |