summaryrefslogtreecommitdiff
path: root/app/bin/paramfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/paramfile.c')
-rw-r--r--app/bin/paramfile.c393
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(&paramFileName, dirName, fileName, NULL);
+ } else {
+ MakeFullpath(&paramFileName, 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 = &paramLine[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(&paramFileName, dirName, fileName, NULL);
+ } else {
+ MakeFullpath(&paramFileName, 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;
+}