/* EXTRAITS DE LA LICENCE Copyright CEA, contributeurs : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) Adresse mèl : BILLARD, non joignable par mèl ; CALISTE, damien P caliste AT cea P fr. Ce logiciel est un programme informatique servant à visualiser des structures atomiques dans un rendu pseudo-3D. Ce logiciel est régi par la licence CeCILL soumise au droit français et respectant les principes de diffusion des logiciels libres. Vous pouvez utiliser, modifier et/ou redistribuer ce programme sous les conditions de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site "http://www.cecill.info". Le fait que vous puissiez accéder à cet en-tête signifie que vous avez pris connaissance de la licence CeCILL, et que vous en avez accepté les termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel). */ /* LICENCE SUM UP Copyright CEA, contributors : Luc BILLARD et Damien CALISTE, laboratoire L_Sim, (2001-2005) E-mail address: BILLARD, not reachable any more ; CALISTE, damien P caliste AT cea P fr. This software is a computer program whose purpose is to visualize atomic configurations in 3D. This software is governed by the CeCILL license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". The fact that you are presently reading this means that you have had knowledge of the CeCILL license and that you accept its terms. You can find a copy of this licence shipped with this software at Documentation/licence.en.txt. */ #include "visu_configFile.h" #include "visu_tools.h" #include "visu_object.h" #include "coreTools/toolConfigFile.h" #include #include #include /* For the access markers R_OK, W_OK ... */ #define PARAMETER_HEADER "#V_Sim parameters file v" #define RESOURCE_HEADER "#V_Sim resources file v" #define VERSION_HEADER "3.0" #define RESOURCES_FILE_NAME "v_sim.res" #define PARAMETERS_FILE_NAME "v_sim.par" #define FLAG_RESOURCES_PATH "main_resourcesPath" #define DESC_RESOURCES_PATH "Favorite paths to find and save the resources file ; chain[:chain]" #define DEFAULT_RESOURCES_PATH "" gboolean readResourcesPaths(gchar **lines, int nbLines, int position, GString *errorMessage); gboolean exportResourcesPaths(GString *data, int *nbLinesWritten, VisuData *dataObj); struct VisuConfigFileEntry_struct { /* Name of the key. */ gchar *key; gchar *description; /* A parameter or a resource */ int kind; /* Number of line used by this resources. This is not used if the entry is a parameter since, parameters are on the same line than the key and are one line. */ int nbLines; /* This method is called when a file is read and the entry is found. */ visuConfigFileReadFunc read; /* Tag, tags are used to ignore or not some entries when a file is read. */ gchar *tag; }; struct writeFunc_struct { visuConfigFileExportFunc writeFunc; }; /* This hashtable stores all the known entries. The keys are the name of the entry (its key), and the value is a pointer to a VisuConfigFileEntry. */ GHashTable *visuConfigFile_entryList; GList *registeredResources, *registeredParameters; GList *visuConfigFile_exportResourcesList, *visuConfigFile_exportParametersList; GHashTable *knownTags; /* Store the paths to where it is possible to store and/or read resource files. This list is ordered and first element is the most prefered path. */ GList *resourcesPath; /* Store the paths to where it is possible to store parameters files. This list is ordered and first element is the most prefered path.*/ GList *parametersPath; gint compareStringsInGList(gconstpointer a, gconstpointer b) { return strcmp((char*)a, (char*)b); } VisuConfigFileEntry* visuConfigFileAdd_entry(int kind, gchar *key, gchar* description, int nbLines, visuConfigFileReadFunc readFunc) { VisuConfigFileEntry *entry; if (!key) { fprintf(stderr, "WARNING! 'visuConfigFileAdd_entry' has been called with" " a null 'key' argument, it should not.\n"); return (VisuConfigFileEntry*)0; } if (nbLines < 1 || (kind != VISU_CONFIGFILE_PARAMETER && kind != VISU_CONFIGFILE_RESOURCE)) { fprintf(stderr, "WARNING! 'visuConfigFileAdd_entry' has been called with" " a wrong 'nbLines' or 'kind' arguments.\n"); return (VisuConfigFileEntry*)0; } if (g_hash_table_lookup(visuConfigFile_entryList, (gpointer)key)) { fprintf(stderr, "WARNING! Can't add this new entry, it's label" " ('%s') already exists.\n", key); return (VisuConfigFileEntry*)0; } entry = malloc(sizeof(VisuConfigFileEntry)); if (!entry) { allocationProblems(); return (VisuConfigFileEntry*)0; } entry->key = g_strdup(key); entry->description = g_strdup(description); entry->kind = kind; if (kind == VISU_CONFIGFILE_PARAMETER) entry->nbLines = 1; else entry->nbLines = nbLines; entry->read = readFunc; entry->tag = (gchar*)0; g_hash_table_insert(visuConfigFile_entryList, (gpointer)entry->key, (gpointer)entry); if (kind == VISU_CONFIGFILE_RESOURCE) registeredResources = g_list_append(registeredResources, (gpointer)entry); else if (kind == VISU_CONFIGFILE_PARAMETER) registeredParameters = g_list_append(registeredParameters, (gpointer)entry); return entry; } /* Method to add a new known tag. */ void visuConfigFileAdd_knownTag(gchar* tag) { if (!tag) { fprintf(stderr, "WARNING! 'addKnownTag' has just been called with a null string.\n"); return; } g_hash_table_insert(knownTags, (gpointer)tag, GINT_TO_POINTER(1)); } void visuConfigFileAdd_exportFunction(int kind, visuConfigFileExportFunc writeFunc) { struct writeFunc_struct *str; if (!writeFunc) return; if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileAdd_exportFunction' has been called with" " a wrong 'kind' argument.\n"); return; } str = malloc(sizeof(struct writeFunc_struct)); if (!str) { allocationProblems(); return; } str->writeFunc = writeFunc; if (kind == VISU_CONFIGFILE_RESOURCE) visuConfigFile_exportResourcesList = g_list_append(visuConfigFile_exportResourcesList, (gpointer)str); else if (kind == VISU_CONFIGFILE_PARAMETER) visuConfigFile_exportParametersList = g_list_append(visuConfigFile_exportParametersList, (gpointer)str); } void freeConfigEntry(gpointer entry) { if (!entry) return; g_free(((VisuConfigFileEntry*)entry)->key); if (((VisuConfigFileEntry*)entry)->tag) g_free(((VisuConfigFileEntry*)entry)->tag); free(entry); } void visuConfigFileSet_tag(VisuConfigFileEntry *entry, gchar *tag) { if (!entry) { fprintf(stderr, "WARNING! 'visuConfigFileSet_tag' has been called with" " a null 'entry' argument, can't work.\n"); return; } entry->tag = g_strdup(tag); } gboolean visuConfigFileLoad(int kind, const char* fileName, GString **message) { GIOChannel *ioFile; gchar *fileUTF8; GError *error; GString *line, *errorMessage; GIOStatus status; int nbLine, i; char *deuxPoints; gchar **tokens; gchar *key, *tag, *finTag, *finKey; VisuConfigFileEntry *entry; int withErrors; DBG_fprintf(stderr, "Visu ConfigFile : parsing '%s' file for" " resources/parameters...\n", fileName); if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileLoad' has been called" " with a wrong 'kind' argument.\n"); *message = (GString*)0; return FALSE; } if (message) { *message = g_string_new(""); fileUTF8 = getStringInUTF8(fileName); if (kind == VISU_CONFIGFILE_RESOURCE) g_string_append_printf(*message, _("Parsing '%s' file for resources...\n\n"), fileUTF8); else if (kind == VISU_CONFIGFILE_PARAMETER) g_string_append_printf(*message, _("Parsing '%s' file for parameters...\n\n"), fileUTF8); g_free(fileUTF8); } error = (GError*)0; ioFile = g_io_channel_new_file(fileName, "r", &error); if (error) { if (*message) g_string_append_printf(*message, _("Error : %s"), error->message); g_error_free(error); return FALSE; } line = g_string_new(""); nbLine = 0; error = (GError*)0; status = g_io_channel_read_line_string(ioFile, line, NULL, &error); if (error) { if (*message) g_string_append_printf(*message, _("Error : %s"), error->message); g_error_free(error); return FALSE; } nbLine += 1; withErrors = 0; while (status == G_IO_STATUS_NORMAL) { if (line->str[0] != '#' && line->str[0] != '\n') { deuxPoints = strchr(line->str, ':'); if (deuxPoints) { tokens = g_strsplit_set(line->str, ":", 2); key = g_strdup(tokens[0]); key = g_strstrip(key); finKey = g_strdup(tokens[1]); g_strfreev(tokens); /* Look for the tag */ tag = strchr(key, '['); if (tag) { *tag = '\0'; tag = tag + 1; finTag = strchr(tag, ']'); if (finTag) *finTag = '\0'; else { if (*message) g_string_append_printf(*message, _("WARNING! Parse error at line %d," " the tag '%s' is not closed.\n"), nbLine, tag); withErrors = 1; } DBG_fprintf(stderr,"Visu ConfigFile : read a flag (tag): '%s' (%s).\n", key, tag); } else DBG_fprintf(stderr,"Visu ConfigFile : read a flag (tag): '%s' (none).\n", key); if (tag && !g_hash_table_lookup(knownTags, (gpointer)tag)) { DBG_fprintf(stderr, "Visu ConfigFile : the entry '%s' has an unknown tag (%s)," " it will be dismissed.\n", key, tag); } else { entry = (VisuConfigFileEntry*)g_hash_table_lookup(visuConfigFile_entryList, (gpointer)key); if (entry) { tokens = malloc(sizeof(gchar*) * (entry->nbLines + 1)); if (!tokens) { allocationProblems(); exit(1); } if (kind == VISU_CONFIGFILE_RESOURCE) for (i = 0; i < entry->nbLines; i++) { error= (GError*)0; status = g_io_channel_read_line_string(ioFile, line, NULL, &error); nbLine += 1; if (status != G_IO_STATUS_NORMAL) { if (*message) { g_string_append_printf(*message, _("Error at line %d :\n"), nbLine); g_string_append_printf(*message, "%s", error->message); } g_error_free(error); tokens[i] = (gchar*)0; g_strfreev(tokens); tokens = (gchar**)0; withErrors = 1; } tokens[i] = g_strdup(line->str); } else tokens[0] = finKey; if (tokens) { tokens[entry->nbLines] = (gchar*)0; if (*message) errorMessage = g_string_new(""); else errorMessage = (GString*)0; if (entry->read && !entry->read(tokens, entry->nbLines, nbLine, errorMessage)) { if (*message) g_string_append_printf(*message, "%s", errorMessage->str); withErrors = 1; } if (*message) g_string_free(errorMessage, TRUE); g_strfreev(tokens); } } else { if (*message) g_string_append_printf(*message, _("WARNING! Parse error at line %d," " '%s' is an unknown markup.\n"), nbLine, key); withErrors = 1; } } g_free(key); } } error = (GError*)0; status = g_io_channel_read_line_string(ioFile, line, NULL, &error); if (error) { if (*message) g_string_append_printf(*message, _("Error : %s"), error->message); g_error_free(error); return FALSE; } nbLine += 1; } if (status == G_IO_STATUS_ERROR) { if (*message) g_string_append_printf(*message, _("Error : %s"), error->message); g_error_free(error); withErrors = 1; } g_string_free(line, TRUE); error = (GError*)0; g_io_channel_shutdown(ioFile, FALSE, &error); if (error) { if (*message) g_string_append_printf(*message, _("Error : %s"), error->message); g_error_free(error); return FALSE; } if (kind == VISU_CONFIGFILE_RESOURCE) { DBG_fprintf(stderr, "Visu ConfigFile : emitting 'resourcesLoaded' signal.\n"); g_signal_emit(visu, VISU_GET_CLASS(visu)->resourcesLoaded_signal_id, 0, NULL); } if (withErrors) return FALSE; else return TRUE; } /* Routine to export the resources (color and material of elements ...) to file. */ gboolean visuConfigFileSave(int kind, const char* fileName, GString **message, int *lines, VisuData *dataObj) { gchar *fileUTF8; GString *exportString, *data; int nbLine, nb; GList *pos; gboolean ok; int withErrors; FILE *file; DBG_fprintf(stderr, "Visu ConfigFile : exporting '%s' file for" " resources/parameters...\n", fileName); if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileSave' has been called" " with a wrong 'kind' argument.\n"); *message = (GString*)0; return FALSE; } if (message) { *message = g_string_new(""); fileUTF8 = getStringInUTF8(fileName); if (kind == VISU_CONFIGFILE_RESOURCE) g_string_append_printf(*message, _("Writing '%s' file for resources...\n\n"), fileUTF8); else if (kind == VISU_CONFIGFILE_PARAMETER) g_string_append_printf(*message, _("Writing '%s' file for parameters...\n\n"), fileUTF8); g_free(fileUTF8); } withErrors = 0; nbLine = 0; exportString = g_string_new(""); if (kind == VISU_CONFIGFILE_RESOURCE) g_string_append_printf(exportString, RESOURCE_HEADER); else if (kind == VISU_CONFIGFILE_PARAMETER) g_string_append_printf(exportString, PARAMETER_HEADER); g_string_append_printf(exportString, VERSION_HEADER "\n" "#====================\n" "\n" "#WARNING: this file format is DIFFERENT from that for\n" "#standard v_sim version <= 2.x\n" "\n"); nbLine += 6; g_string_append_printf(exportString, "#Line beginning with a # are not parsed.\n" "\n"); nbLine += 2; pos = (GList*)0; if (kind == VISU_CONFIGFILE_RESOURCE) { g_string_append_printf(exportString, "#The only \"useful\" lines must have the following contents\n" "#several two or more lines patterns:\n" "#resource_name:\n" "#values separeted by blank characters\n" "\n"); nbLine += 5; g_string_append_printf(exportString, "#The following resource names are valid :\n"); nbLine += 1; pos = registeredResources; } else if (kind == VISU_CONFIGFILE_PARAMETER) { g_string_append_printf(exportString, "#The only \"useful\" lines must have the following pattern:\n" "#parameter_name: value\n" "\n"); nbLine += 3; g_string_append_printf(exportString, "#The following parameter names are valid :\n"); nbLine += 1; pos = registeredParameters; } while(pos) { g_string_append_printf(exportString, "# %s\n", ((VisuConfigFileEntry*)(pos->data))->key); nbLine += 1; pos = g_list_next(pos); } g_string_append_printf(exportString, "\n"); nbLine += 1; pos = (GList*)0; if (kind == VISU_CONFIGFILE_RESOURCE) pos = visuConfigFile_exportResourcesList; else if (kind == VISU_CONFIGFILE_PARAMETER) pos = visuConfigFile_exportParametersList; while(pos) { data = g_string_new(""); ok = ((struct writeFunc_struct*)(pos->data))->writeFunc(data, &nb, dataObj); if (!ok && message) g_string_append_printf(*message, _("Error on line %d.\n"), nbLine); if (ok) { g_string_append_printf(exportString, "%s", data->str); nbLine += nb; } else withErrors = 1; g_string_free(data, TRUE); pos = g_list_next(pos); } file = fopen(fileName, "w"); if (!file) { if (message) g_string_append_printf(*message, _("WARNING! Unable to create the requested" " file. Check that you have enough" " permissions to write it.\n")); g_string_free(exportString, TRUE); return FALSE; } fprintf(file, "%s", exportString->str); fclose(file); g_string_free(exportString, TRUE); if (message) g_string_append_printf(*message, _(" %d line(s) written.\n\n"), nbLine); if (lines) *lines = nbLine; if (withErrors) return FALSE; else return TRUE; } int visuConfigFileSet_floatValue(float *variable, float value, float min, float max) { int outOfBounds; outOfBounds = 0; if (max > min && value > max) { *variable = max; outOfBounds = 1; } if (min < max && value < min) { *variable = min; outOfBounds = 1; } if (!outOfBounds) *variable = value; return outOfBounds; } gchar* getValidFileWithHeader(int mode, char* filename, char* header, GList **list) { gchar *res; FILE *file; char *msg; char line[MAX_LINE_LENGTH]; float version; /* Look for a valid file. If it is for writing, a valid file is just given by a valid path. If it is for reading, a valid file is a valid path AND has a valid header. */ while (*list) { /* We get the next valid path. */ res = getValidPath(list, filename, mode); if (!res) { DBG_fprintf(stderr, "Visu ConfigFile : no file available.\n"); return (gchar*)0; } /* if we are in reading mode, we test the header. */ if (mode & R_OK) { DBG_fprintf(stderr, "Visu ConfigFile : looking for header of \n '%s' ... ", res); file = fopen(res, "r"); if (!file) { fprintf(stderr, _("INTERNAL ERROR! The file '%s' should be readable" " but something goes nasty when one wants to open it.\n"), res); free(res); return (gchar*)0; } version = 0.; msg = fgets(line, MAX_LINE_LENGTH, file); fclose(file); if (msg && !strncmp(line, header, strlen(header)) && sscanf(line + strlen(header), "%f", &version)) if (version >= 3.) { DBG_fprintf(stderr, "ok.\n"); return res; } DBG_fprintf(stderr, "wrong.\n"); } /* We are in writing mode so the valid path is ok. */ else return res; *list = g_list_next(*list); } DBG_fprintf(stderr, "Visu ConfigFile : no file available.\n"); return (gchar*)0; } gchar* visuConfigFileGet_validPath(int kind, int mode, int utf8) { GList *list; gchar* file; gchar* fileUTF8; if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileGet_validPath' has been called" " with a wrong 'kind' argument.\n"); return (gchar*)0; } if (kind == VISU_CONFIGFILE_RESOURCE) { list = resourcesPath; file = getValidFileWithHeader(mode, RESOURCES_FILE_NAME, RESOURCE_HEADER, &list); } else { list = parametersPath; file = getValidFileWithHeader(mode, PARAMETERS_FILE_NAME, PARAMETER_HEADER, &list); } if (!file) return file; if (utf8) { fileUTF8 = getStringInUTF8(file); g_free(file); return fileUTF8; } else return file; } gchar* visuConfigFileGet_nextValidPath(int kind, int accessMode, GList **list, int utf8) { gchar* file; gchar* fileUTF8; if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called" " with a wrong 'kind' argument.\n"); return (gchar*)0; } if (!list) { fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called" " with a wrong 'list' argument.\n"); return (gchar*)0; } if (!*list) return (gchar*)0; if (kind == VISU_CONFIGFILE_RESOURCE) file = getValidFileWithHeader(accessMode, RESOURCES_FILE_NAME, RESOURCE_HEADER, list); else file = getValidFileWithHeader(accessMode, PARAMETERS_FILE_NAME, PARAMETER_HEADER, list); if (*list) *list = g_list_next(*list); if (!file) return file; if (utf8) { fileUTF8 = getStringInUTF8(file); g_free(file); return fileUTF8; } else return file; } gchar* visuConfigFileGet_defaultFileName(int kind) { if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileGet_defaultFileName' has been called" " with a wrong 'kind' argument.\n"); return (gchar*)0; } if (kind == VISU_CONFIGFILE_RESOURCE) return (gchar*)RESOURCES_FILE_NAME; else return (gchar*)PARAMETERS_FILE_NAME; } GList* visuConfigFileGet_pathList(int kind) { if (kind != VISU_CONFIGFILE_RESOURCE && kind != VISU_CONFIGFILE_PARAMETER) { fprintf(stderr, "WARNING! 'visuConfigFileGet_nextValidPath' has been called" " with a wrong 'kind' argument.\n"); return (GList*)0; } if (kind == VISU_CONFIGFILE_RESOURCE) return resourcesPath; else return parametersPath; } GList* visuConfigFileAdd_resourcesPath(char* dir) { GList *element; if (!dir || !dir[0]) return (GList*)0; element = g_list_find_custom(resourcesPath, (gconstpointer)dir, compareStringsInGList); if (!element) { DBG_fprintf(stderr, "Visu ConfigFile : add a new resource directory" " to the path :\n '%s'\n", dir); resourcesPath = g_list_insert(resourcesPath, (gpointer)dir, 1); return resourcesPath->next; } else return (GList*)element; } int visuConfigFile_init() { gchar *homeCfgDir, *currentDir; VisuConfigFileEntry *resourceEntry; DBG_fprintf(stderr, "Visu ConfigFile : initialization process ..."); CONFIG_FILE_ERROR = g_quark_from_string("visu_configFile"); visuConfigFile_entryList = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, freeConfigEntry); if (!visuConfigFile_entryList) { allocationProblems(); return 0; } registeredResources = (GList*)0; registeredParameters = (GList*)0; visuConfigFile_exportResourcesList = (GList*)0; visuConfigFile_exportParametersList = (GList*)0; knownTags = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); if (!knownTags) { allocationProblems(); return 0; } resourcesPath = (GList*)0; parametersPath = (GList*)0; resourcesPath = g_list_prepend(resourcesPath, (gpointer)v_sim_data_dir); parametersPath = g_list_prepend(parametersPath, (gpointer)v_sim_conf_dir); resourcesPath = g_list_prepend(resourcesPath, (gpointer)v_sim_local_conf_dir); parametersPath = g_list_prepend(parametersPath, (gpointer)v_sim_local_conf_dir); currentDir = g_get_current_dir(); resourcesPath = g_list_prepend(resourcesPath, (gpointer)currentDir); parametersPath = g_list_prepend(parametersPath, (gpointer)currentDir); DBG_fprintf(stderr, " OK\n"); resourceEntry = visuConfigFileAdd_entry(VISU_CONFIGFILE_PARAMETER, FLAG_RESOURCES_PATH, DESC_RESOURCES_PATH, 1, readResourcesPaths); visuConfigFileAdd_exportFunction(VISU_CONFIGFILE_PARAMETER, exportResourcesPaths); return 1; } gboolean readResourcesPaths(gchar **lines, int nbLines, int position, GString *errorMessage) { int i; gchar **tokens; gchar *key; tokens = g_strsplit_set(lines[0], ":", -1); for (i = 0; tokens[i]; i++) { key = g_strdup(tokens[i]); key = g_strstrip(key); visuConfigFileAdd_resourcesPath(key); } g_strfreev(tokens); return TRUE; } gboolean exportResourcesPaths(GString *data, int *nbLinesWritten, VisuData *dataObj) { GList *pnt; g_string_append_printf(data, "# %s\n", DESC_RESOURCES_PATH); g_string_append_printf(data, "%s: ", FLAG_RESOURCES_PATH); pnt = resourcesPath; while(pnt) { /* We cancel the first and the last because it's the current working dir and the install dir. */ if (pnt->prev && pnt->next && pnt->next->next) g_string_append_printf(data, "%s", (char*)pnt->data); if (pnt->prev && pnt->next && pnt->next->next && pnt->next->next->next) g_string_append_printf(data, ":"); pnt = g_list_next(pnt); } g_string_append_printf(data, "\n\n"); *nbLinesWritten = 3; return TRUE; }