1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 
45 #include "visu_configFile.h"
46 
47 #include "visu_tools.h"
48 #include "visu_basic.h"
49 #include "visu_commandLine.h"
50 #include "coreTools/toolConfigFile.h"
51 
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h> /* For the access markers R_OK, W_OK ... */
55 
56 /**
57  * SECTION:visu_configFile
58  * @short_description: Defines methods to access (read/write) to
59  * config files and to create different entries.
60  *
61  * <para>V_Sim uses two different configuration files. The first
62  * stores the configuration of the program itself and is called
63  * parameters file. The second stores differents values that control
64  * the way files are rendered. It is called resources file. For
65  * example, their is an entry in the parameters file that controls
66  * your favorite rendering method ; and there is an entry in the
67  * resources file that codes that vacancy elements are rendered by
68  * cube in the atomic rendering method. Most methods of this part uses
69  * a first argument usually called 'kind', that control if the method
70  * will apply on the parameters file or on the resources
71  * file. #VISU_CONFIG_FILE_PARAMETER and #VISU_CONFIG_FILE_RESOURCE are
72  * the two flags that should be used for the 'kind' argument.</para>
73  *
74  * <para>There are different paths where these files can be
75  * stored. These paths are stored in V_Sim with an order : for example
76  * parameters file are first looked for in the current working
77  * directory, then in the $HOME/.v_sim directory and finally in the
78  * installation directory. This is transparent for the user and
79  * visu_config_file_getValidPath() is the right method to access to the
80  * best readable configuration file.</para>
81  *
82  * <para>Different part of V_Sim can add entries in these files. The
83  * method visu_config_file_addEntry() is designed to this purpose. The
84  * entries are defined by their name and they appear in the
85  * configuration file as 'name:' followed by the data associated to
86  * this entry. In the parameters file, the data are on the same
87  * line. In the resources file, the data begin the line after and can
88  * be longer that one line. When a configuration file is read, the
89  * method associated to each entry (VisuConfigFileReadFunc()) is
90  * called with a copy of their data lines. The method
91  * visu_config_file_addExportFunction() should be used to add a callback
92  * when the configurations files are written, then each part of V_Sim
93  * that have entries can put some lines in the configuration
94  * files.</para>
95  */
96 
97 #define PARAMETER_HEADER     "#V_Sim parameters file"
98 #define RESOURCE_HEADER      "#V_Sim resources file"
99 #define VERSION_HEADER       "3.0"
100 
101 static const gchar *RESOURCES_FILENAMES[] = {"v_sim.res.xml", "v_sim.res", (gchar*)0};
102 static const gchar *PARAMETERS_FILENAMES[] = {"v_sim.par", (gchar*)0};
103 
104 #define FLAG_RESOURCES_PATH "main_resourcesPath"
105 #define DESC_RESOURCES_PATH "Favorite paths to find and save the resources file ; chain[:chain]"
106 #define DEFAULT_RESOURCES_PATH ""
107 static gboolean readResourcesPaths(VisuConfigFileEntry *entry, gchar **lines, int nbLines, int position,
108 				   GError **error);
109 static void exportResourcesPaths(GString *data, VisuData *dataObj);
110 static void _addPath(VisuConfigFile *conf, char* dir);
111 
112 /**
113  * VisuConfigFileEntry:
114  *
115  * This is the common name of the structure.
116  */
117 struct _VisuConfigFileEntry
118 {
119   guint refCount;
120 
121   /* Name of the key. */
122   gchar *key;
123   gchar *description;
124   GQuark kquark; /* Quark associated to the key. */
125   /* Version, default is 3.0. */
126   float version;
127   /* If set, entry is obsolete and newKey should replaces it. */
128   gchar *newKey;
129 
130   /* A parameter or a resource */
131   int kind;
132 
133   /* Number of line used by this resources.
134      This is not used if the entry is a parameter
135      since, parameters are on the same line than
136      the key and are one line. */
137   guint nbLines;
138 
139   /* This method is called when a file is read
140      and the entry is found. */
141   VisuConfigFileReadFunc read;
142   gboolean withLabel;
143   gchar *label;
144   guint nValues;
145   guint iToken;
146   gchar **tokens;
147   gpointer storage;
148   union {
149     int i[2];
150     float f[2];
151   } range;
152   VisuConfigFileEnumFunc toEnum;
153   gchar *errMess;
154 
155   /* Tag, tags are used to ignore or not some
156      entries when a file is read. */
157   gchar *tag;
158 };
159 
160 typedef enum
161   {
162     _format_raw,
163     _format_xml
164   } _format_export;
165 _format_export format = _format_raw;
166 struct writeFunc_struct
167 {
168   VisuConfigFileExportFunc writeFunc;
169 };
170 
171 /* This hashtable stores all the known entries.
172    The keys are the name of the entry (its key), and
173    the value is a pointer to a VisuConfigFileEntry. */
174 static GHashTable *knownTags = NULL;
175 static VisuConfigFile *resources = NULL, *parameters = NULL;
176 
177 /* Local methods. */
178 static VisuConfigFileEntry* entry_ref(VisuConfigFileEntry *entry);
179 static void entry_unref(VisuConfigFileEntry *entry);
180 
181 /* Generic reading routines. */
182 static gboolean _readTokens(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
183                             int position, GError **error);
184 static gboolean _readBooleanv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
185                               int position, GError **error);
186 static gboolean _readIntv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
187                           int position, GError **error);
188 static gboolean _readFloatv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
189                             int position, GError **error);
190 static gboolean _readStipplev(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
191                               int position, GError **error);
192 static gboolean _readEnum(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
193                           int position, GError **error);
194 static gboolean _readString(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
195                             int position, GError **error);
196 
compareStringsInGList(gconstpointer a,gconstpointer b)197 static gint compareStringsInGList(gconstpointer a, gconstpointer b)
198 {
199   return strcmp((char*)a, (char*)b);
200 }
201 
202 /**
203  * visu_config_file_entry_get_type:
204  *
205  * Create and retrieve a #GType for a #VisuConfigFileEntry object.
206  *
207  * Since: 3.7
208  *
209  * Returns: a new type for #VisuConfigFileEntry structures.
210  */
visu_config_file_entry_get_type(void)211 GType visu_config_file_entry_get_type(void)
212 {
213   static GType g_define_type_id = 0;
214 
215   if (g_define_type_id == 0)
216     g_define_type_id =
217       g_boxed_type_register_static("VisuConfigFileEntry",
218                                    (GBoxedCopyFunc)entry_ref,
219                                    (GBoxedFreeFunc)entry_unref);
220   return g_define_type_id;
221 }
entry_init(const gchar * key,const gchar * description,VisuConfigFileKind kind,guint nbLines)222 static VisuConfigFileEntry* entry_init(const gchar *key, const gchar *description,
223                                        VisuConfigFileKind kind, guint nbLines)
224 {
225   VisuConfigFileEntry *entry;
226 
227   g_return_val_if_fail(key && *key, (VisuConfigFileEntry*)0);
228   g_return_val_if_fail(description, (VisuConfigFileEntry*)0);
229   g_return_val_if_fail(nbLines > 0 && (kind == VISU_CONFIG_FILE_KIND_PARAMETER ||
230 				       kind == VISU_CONFIG_FILE_KIND_RESOURCE),
231 		       (VisuConfigFileEntry*)0);
232 
233   entry = g_malloc(sizeof(VisuConfigFileEntry));
234   entry->refCount = 1;
235   entry->key = g_strdup(key);
236   entry->kquark = g_quark_from_static_string(entry->key);
237   entry->description = g_strdup(description);
238   entry->kind = kind;
239   if (kind == VISU_CONFIG_FILE_KIND_PARAMETER)
240     entry->nbLines = 1;
241   else
242     entry->nbLines = nbLines;
243   entry->withLabel = FALSE;
244   entry->label = (gchar*)0;
245   entry->storage = (gpointer)0;
246   entry->tokens = (gchar**)0;
247   entry->errMess = (gchar*)0;
248   entry->tag = (gchar*)0;
249   entry->newKey = (gchar*)0;
250   entry->version = 3.0f;
251 
252   return entry;
253 }
entry_ref(VisuConfigFileEntry * entry)254 static VisuConfigFileEntry* entry_ref(VisuConfigFileEntry *entry)
255 {
256   if (!entry)
257     return (VisuConfigFileEntry*)0;
258 
259   entry->refCount += 1;
260   return entry;
261 }
entry_unref(VisuConfigFileEntry * entry)262 static void entry_unref(VisuConfigFileEntry *entry)
263 {
264   entry->refCount -= 1;
265   if (!entry->refCount)
266     {
267       g_free(entry->key);
268       g_free(entry->description);
269       g_free(entry->newKey);
270       g_free(entry->tag);
271       g_free(entry->label);
272       g_free(entry->errMess);
273       g_strfreev(entry->tokens);
274       g_free(entry);
275     }
276 }
277 
278 /**
279  * VisuConfigFile:
280  *
281  * Structure used to define #VisuConfigFile objects.
282  *
283  * Since: 3.8
284  */
285 struct _VisuConfigFilePrivate
286 {
287   VisuConfigFileKind kind;
288 
289   /* This hashtable stores all the known entries.
290      The keys are the name of the entry (its key), and
291      the value is a pointer to a VisuConfigFileEntry. */
292   GHashTable *entryList;
293   GList *exportList;
294 
295   /* Store the paths to where it is possible to store
296      and/or read resource files. This list is ordered
297      and first element is the most prefered path. */
298   GList *paths;
299   gchar *source;
300 };
301 
302 enum
303   {
304     ENTRYPARSED_SIGNAL,
305     VISU_NB_SIGNAL
306   };
307 
308 static guint _signals[VISU_NB_SIGNAL];
309 
310 static void visu_config_file_finalize    (GObject* obj);
311 
G_DEFINE_TYPE_WITH_CODE(VisuConfigFile,visu_config_file,VISU_TYPE_OBJECT,G_ADD_PRIVATE (VisuConfigFile))312 G_DEFINE_TYPE_WITH_CODE(VisuConfigFile, visu_config_file, VISU_TYPE_OBJECT,
313                         G_ADD_PRIVATE(VisuConfigFile))
314 
315 static void visu_config_file_class_init(VisuConfigFileClass *klass)
316 {
317   /* Connect the overloading methods. */
318   G_OBJECT_CLASS(klass)->finalize     = visu_config_file_finalize;
319 
320   /**
321    * VisuConfigFile::parsed:
322    * @visuObj: the object emitting the signal.
323    * @key: the key that has been parsed.
324    *
325    * The entry @key of a configuration file has just been successfully parsed.
326    *
327    * Since: 3.7
328    */
329   _signals[ENTRYPARSED_SIGNAL] =
330     g_signal_new("parsed", G_TYPE_FROM_CLASS (klass),
331                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED,
332                  0 , NULL, NULL, g_cclosure_marshal_VOID__BOXED,
333                  G_TYPE_NONE, 1, VISU_TYPE_CONFIG_FILE_ENTRY);
334 
335   knownTags = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
336 }
visu_config_file_init(VisuConfigFile * obj)337 static void visu_config_file_init(VisuConfigFile *obj)
338 {
339   obj->priv = visu_config_file_get_instance_private(obj);
340 
341   obj->priv->entryList = g_hash_table_new_full(g_str_hash, g_str_equal,
342                                                NULL, (GDestroyNotify)entry_unref);
343   obj->priv->exportList = (GList*)0;
344 
345   obj->priv->source = (gchar*)0;
346 
347   obj->priv->paths = (GList*)0;
348   obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_DATA_DIR));
349   obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_OLD_LOCAL_CONF_DIR));
350   obj->priv->paths = g_list_prepend(obj->priv->paths, g_strdup(V_SIM_LOCAL_CONF_DIR));
351   obj->priv->paths = g_list_prepend(obj->priv->paths, g_get_current_dir());
352 }
visu_config_file_finalize(GObject * obj)353 static void visu_config_file_finalize(GObject *obj)
354 {
355   VisuConfigFile *conf;
356 
357   conf = VISU_CONFIG_FILE(obj);
358 
359   g_hash_table_destroy(conf->priv->entryList);
360   g_list_free(conf->priv->exportList);
361   g_list_free_full(conf->priv->paths, g_free);
362   g_free(conf->priv->source);
363 
364   /* Chain up to the parent class */
365   G_OBJECT_CLASS(visu_config_file_parent_class)->finalize(obj);
366 }
367 /**
368  * visu_config_file_getStatic:
369  * @kind: a kind of configuration file.
370  *
371  * Retrieve the instance used by V_Sim to read resource or parameter files.
372  *
373  * Since: 3.8
374  *
375  * Returns: (transfer none): a #VisuConfigFile object, owned by V_Sim.
376  **/
visu_config_file_getStatic(VisuConfigFileKind kind)377 VisuConfigFile* visu_config_file_getStatic(VisuConfigFileKind kind)
378 {
379   if (kind == VISU_CONFIG_FILE_KIND_PARAMETER)
380     {
381       if (!parameters)
382         {
383           parameters = g_object_new(VISU_TYPE_CONFIG_FILE, NULL);
384           parameters->priv->kind = VISU_CONFIG_FILE_KIND_PARAMETER;
385           /* Private data. */
386           visu_config_file_addEntry(parameters,
387                                     FLAG_RESOURCES_PATH,
388                                     DESC_RESOURCES_PATH,
389                                     1, readResourcesPaths);
390           visu_config_file_addExportFunction(parameters, exportResourcesPaths);
391         }
392       return parameters;
393     }
394   if (kind == VISU_CONFIG_FILE_KIND_RESOURCE)
395     {
396       if (!resources)
397         {
398           resources = g_object_new(VISU_TYPE_CONFIG_FILE, NULL);
399           resources->priv->kind = VISU_CONFIG_FILE_KIND_RESOURCE;
400         }
401       return resources;
402     }
403   return (VisuConfigFile*)0;
404 }
405 
entry_register(VisuConfigFile * conf,VisuConfigFileEntry * entry)406 static gboolean entry_register(VisuConfigFile *conf, VisuConfigFileEntry *entry)
407 {
408   DBG_fprintf(stderr, "Visu ConfigFile: going to add key '%s'.\n", entry->key);
409   if (g_hash_table_lookup(conf->priv->entryList, (gpointer)entry->key))
410     return FALSE;
411 
412   /* Store it. */
413   g_hash_table_insert(conf->priv->entryList, (gpointer)entry->key, (gpointer)entry);
414 
415   return TRUE;
416 }
417 /**
418  * visu_config_file_ignoreEntry:
419  * @conf: a #VisuConfigFile object ;
420  * @key: a string (should not be NULL) ;
421  * @nbLines: an integer ;
422  *
423  * Create a #VisuConfigFileEntry that will ignore @key when found in a
424  * configuration file. This is used for deprecated keys.
425  *
426  * Since: 3.8
427  *
428  * Returns: the newly created #VisuConfigFileEntry object.
429  **/
visu_config_file_ignoreEntry(VisuConfigFile * conf,const gchar * key,guint nbLines)430 VisuConfigFileEntry* visu_config_file_ignoreEntry(VisuConfigFile *conf, const gchar *key,
431                                                   guint nbLines)
432 {
433   VisuConfigFileEntry *entry;
434 
435   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
436 
437   entry = entry_init(key, "Ignored entry", conf->priv->kind, nbLines);
438   if (!entry)
439     return (VisuConfigFileEntry*)0;
440   entry->read = NULL;
441 
442   if (!entry_register(conf, entry))
443     {
444       g_free(entry);
445       entry = (VisuConfigFileEntry*)0;
446       g_warning("entry '%s' already exists!", key);
447     }
448 
449   return entry;
450 }
451 /**
452  * visu_config_file_addEntry:
453  * @conf: a #VisuConfigFile object ;
454  * @key: a string (should not be NULL) ;
455  * @description: (allow-none): a string (can be NULL) ;
456  * @nbLines: an integer ;
457  * @readFunc: (scope call): a VisuConfigFileReadFunc.
458  *
459  * This creates a new #VisuConfigFileEntry object with the given
460  * values. The key and description arguments are copied.
461  *
462  * Returns: the newly created #VisuConfigFileEntry object.
463  */
visu_config_file_addEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,int nbLines,VisuConfigFileReadFunc readFunc)464 VisuConfigFileEntry* visu_config_file_addEntry(VisuConfigFile *conf, const gchar *key,
465                                                const gchar* description, int nbLines,
466                                                VisuConfigFileReadFunc readFunc)
467 {
468   VisuConfigFileEntry *entry;
469 
470   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
471 
472   entry = entry_init(key, description, conf->priv->kind, nbLines);
473   if (!entry)
474     return (VisuConfigFileEntry*)0;
475   entry->read = readFunc;
476 
477   if (!entry_register(conf, entry))
478     {
479       g_free(entry);
480       entry = (VisuConfigFileEntry*)0;
481       g_warning("entry '%s' already exists!", key);
482     }
483 
484   return entry;
485 }
486 /**
487  * visu_config_file_addTokenizedEntry:
488  * @conf: a #VisuConfigFile object ;
489  * @key: a string (should not be %NULL) ;
490  * @description: (allow-none): a string (can be %NULL) ;
491  * @labelled: a boolean.
492  *
493  * Defines a new #VisuConfigFileEntry object characterized by
494  * @key. When @key is found in a configuration file, the data line is
495  * separated into tokens that can be retrieved later with
496  * visu_config_file_entry_popToken() for instance. If @labelled is
497  * %TRUE, the associated label to an entry in the file can be later
498  * retrieved with visu_config_file_entry_getLabel().
499  *
500  * Since: 3.8
501  *
502  * Returns: the newly created #VisuConfigFileEntry object.
503  **/
visu_config_file_addTokenizedEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,gboolean labelled)504 VisuConfigFileEntry* visu_config_file_addTokenizedEntry(VisuConfigFile *conf, const gchar *key,
505                                                         const gchar* description,
506                                                         gboolean labelled)
507 {
508   VisuConfigFileEntry *entry;
509 
510   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
511 
512   entry = entry_init(key, description, conf->priv->kind, 1);
513   if (!entry)
514     return (VisuConfigFileEntry*)0;
515   entry->read = _readTokens;
516   entry->withLabel = labelled;
517 
518   if (!entry_register(conf, entry))
519     {
520       g_free(entry);
521       entry = (VisuConfigFileEntry*)0;
522       g_warning("entry '%s' already exists!", key);
523     }
524 
525   return entry;
526 }
527 /**
528  * visu_config_file_addBooleanEntry:
529  * @conf: a #VisuConfigFile object ;
530  * @key: a string (should not be NULL) ;
531  * @description: (allow-none): a string (can be NULL) ;
532  * @location: a pointer where to store a boolean when the entry is
533  * parsed.
534  * @labelled: a boolean.
535  *
536  * Defines a #VisuConfigFileEntry that will be a single boolean to
537  * read and to store in @location. If @labelled is %TRUE, it retrieves
538  * and store a string before the boolean value. It can be accessed
539  * later with visu_config_file_entry_getLabel().
540  *
541  * Since: 3.7
542  *
543  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
544  **/
visu_config_file_addBooleanEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,gboolean * location,gboolean labelled)545 VisuConfigFileEntry* visu_config_file_addBooleanEntry(VisuConfigFile *conf, const gchar *key,
546                                                       const gchar* description,
547                                                       gboolean *location, gboolean labelled)
548 {
549   VisuConfigFileEntry *entry;
550 
551   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
552   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
553 
554   entry = entry_init(key, description, conf->priv->kind, 1);
555   if (!entry)
556     return (VisuConfigFileEntry*)0;
557   entry->read = _readBooleanv;
558   entry->storage = (gpointer)location;
559   entry->nValues = 1;
560   entry->withLabel = labelled;
561 
562   if (!entry_register(conf, entry))
563     {
564       g_free(entry);
565       entry = (VisuConfigFileEntry*)0;
566       g_warning("entry '%s' already exists!", key);
567     }
568 
569   return entry;
570 }
571 /**
572  * visu_config_file_addBooleanArrayEntry:
573  * @conf: a #VisuConfigFile object ;
574  * @key: a string (should not be NULL) ;
575  * @description: (allow-none): a string (can be NULL) ;
576  * @nValues: the number of floats to read.
577  * @location: a pointer where to store booleans when the entry is
578  * parsed.
579  * @labelled: a boolean.
580  *
581  * Defines a #VisuConfigFileEntry that will be several booleans to
582  * read and to store in @location. If @labelled is %TRUE, it retrieves
583  * and store a string before the boolean value. It can be accessed
584  * later with visu_config_file_entry_getLabel().
585  *
586  * Since: 3.8
587  *
588  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
589  **/
visu_config_file_addBooleanArrayEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,guint nValues,gboolean * location,gboolean labelled)590 VisuConfigFileEntry* visu_config_file_addBooleanArrayEntry(VisuConfigFile *conf, const gchar *key,
591                                                            const gchar* description,
592                                                            guint nValues, gboolean *location,
593                                                            gboolean labelled)
594 {
595   VisuConfigFileEntry *entry;
596 
597   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
598   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
599 
600   entry = entry_init(key, description, conf->priv->kind, 1);
601   if (!entry)
602     return (VisuConfigFileEntry*)0;
603   entry->read = _readBooleanv;
604   entry->storage = (gpointer)location;
605   entry->nValues = nValues;
606   entry->withLabel = labelled;
607 
608   if (!entry_register(conf, entry))
609     {
610       g_free(entry);
611       entry = (VisuConfigFileEntry*)0;
612       g_warning("entry '%s' already exists!", key);
613     }
614 
615   return entry;
616 }
617 /**
618  * visu_config_file_addIntegerArrayEntry:
619  * @conf: a #VisuConfigFile object ;
620  * @key: a string (should not be NULL) ;
621  * @description: (allow-none): a string (can be NULL) ;
622  * @nValues: the number of floats to read.
623  * @location: a pointer where to store floats when the entry is
624  * parsed.
625  * @clamp: the min and max values allowed.
626  * @labelled: TRUE if the entry has a label.
627  *
628  * Defines a #VisuConfigFileEntry that will parse @nValues usable for stipple and
629  * store them consecutively in @location.
630  *
631  * Since: 3.8
632  *
633  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
634  **/
visu_config_file_addIntegerArrayEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,guint nValues,int * location,int clamp[2],gboolean labelled)635 VisuConfigFileEntry* visu_config_file_addIntegerArrayEntry(VisuConfigFile *conf, const gchar *key,
636                                                            const gchar* description,
637                                                            guint nValues, int *location,
638                                                            int clamp[2], gboolean labelled)
639 {
640   VisuConfigFileEntry *entry;
641 
642   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
643   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
644 
645   entry = entry_init(key, description, conf->priv->kind, 1);
646   if (!entry)
647     return (VisuConfigFileEntry*)0;
648   entry->read = _readIntv;
649   entry->storage = (gpointer)location;
650   entry->nValues = nValues;
651   entry->range.i[0] = clamp[0];
652   entry->range.i[1] = clamp[1];
653   entry->withLabel = labelled;
654 
655   if (!entry_register(conf, entry))
656     {
657       g_free(entry);
658       entry = (VisuConfigFileEntry*)0;
659       g_warning("entry '%s' already exists!", key);
660     }
661 
662   return entry;
663 }
664 /**
665  * visu_config_file_addFloatArrayEntry:
666  * @conf: a #VisuConfigFile object ;
667  * @key: a string (should not be NULL) ;
668  * @description: (allow-none): a string (can be NULL) ;
669  * @nValues: the number of floats to read.
670  * @location: a pointer where to store floats when the entry is
671  * parsed.
672  * @clamp: the min and max values allowed.
673  * @labelled: a boolean.
674  *
675  * Defines a #VisuConfigFileEntry that will parse @nValues floats and
676  * store them consecutively in @location. The parsed values are
677  * checked to be in @clamp.
678  *
679  * Since: 3.7
680  *
681  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
682  **/
visu_config_file_addFloatArrayEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,guint nValues,float * location,float clamp[2],gboolean labelled)683 VisuConfigFileEntry* visu_config_file_addFloatArrayEntry(VisuConfigFile *conf, const gchar *key,
684                                                          const gchar* description,
685                                                          guint nValues, float *location,
686                                                          float clamp[2], gboolean labelled)
687 {
688   VisuConfigFileEntry *entry;
689 
690   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
691   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
692 
693   entry = entry_init(key, description, conf->priv->kind, 1);
694   if (!entry)
695     return (VisuConfigFileEntry*)0;
696   entry->read = _readFloatv;
697   entry->storage = (gpointer)location;
698   entry->nValues = nValues;
699   entry->range.f[0] = clamp[0];
700   entry->range.f[1] = clamp[1];
701   entry->withLabel = labelled;
702 
703   if (!entry_register(conf, entry))
704     {
705       g_free(entry);
706       entry = (VisuConfigFileEntry*)0;
707       g_warning("entry '%s' already exists!", key);
708     }
709 
710   return entry;
711 }
712 /**
713  * visu_config_file_addStippleArrayEntry:
714  * @conf: a #VisuConfigFile object ;
715  * @key: a string (should not be NULL) ;
716  * @description: (allow-none): a string (can be NULL) ;
717  * @nValues: the number of floats to read.
718  * @location: a pointer where to store floats when the entry is
719  * parsed.
720  *
721  * Defines a #VisuConfigFileEntry that will parse @nValues usable for stipple and
722  * store them consecutively in @location.
723  *
724  * Since: 3.8
725  *
726  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
727  **/
visu_config_file_addStippleArrayEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,guint nValues,guint16 * location)728 VisuConfigFileEntry* visu_config_file_addStippleArrayEntry(VisuConfigFile *conf, const gchar *key,
729                                                            const gchar* description,
730                                                            guint nValues, guint16 *location)
731 {
732   VisuConfigFileEntry *entry;
733 
734   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
735   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
736 
737   entry = entry_init(key, description, conf->priv->kind, 1);
738   if (!entry)
739     return (VisuConfigFileEntry*)0;
740   entry->read = _readStipplev;
741   entry->storage = (gpointer)location;
742   entry->nValues = nValues;
743 
744   if (!entry_register(conf, entry))
745     {
746       g_free(entry);
747       entry = (VisuConfigFileEntry*)0;
748       g_warning("entry '%s' already exists!", key);
749     }
750 
751   return entry;
752 }
753 /**
754  * visu_config_file_addEnumEntry:
755  * @conf: a #VisuConfigFile object ;
756  * @key: a string (should not be NULL) ;
757  * @description: (allow-none): a string (can be NULL) ;
758  * @location: a location to store an enum value.
759  * @toEnum: (scope call): a method to convert a string to an enum value.
760  * @labelled: a boolean.
761  *
762  * Defines a #VisuConfigFileEntry that will parse a string and convert
763  * it to an enum value with @toEnum function and store it in
764  * @location.
765  *
766  * Since: 3.8
767  *
768  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
769  **/
visu_config_file_addEnumEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,guint * location,VisuConfigFileEnumFunc toEnum,gboolean labelled)770 VisuConfigFileEntry* visu_config_file_addEnumEntry(VisuConfigFile *conf, const gchar *key,
771                                                    const gchar* description, guint *location,
772                                                    VisuConfigFileEnumFunc toEnum,
773                                                    gboolean labelled)
774 {
775   VisuConfigFileEntry *entry;
776 
777   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
778   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
779 
780   entry = entry_init(key, description, conf->priv->kind, 1);
781   if (!entry)
782     return (VisuConfigFileEntry*)0;
783   entry->read = _readEnum;
784   entry->storage = (gpointer)location;
785   entry->toEnum = toEnum;
786   entry->withLabel = labelled;
787 
788   if (!entry_register(conf, entry))
789     {
790       g_free(entry);
791       entry = (VisuConfigFileEntry*)0;
792       g_warning("entry '%s' already exists!", key);
793     }
794 
795   return entry;
796 }
797 /**
798  * visu_config_file_addStringEntry:
799  * @conf: a #VisuConfigFile object ;
800  * @key: a string (should not be NULL) ;
801  * @description: (allow-none): a string (can be NULL) ;
802  * @location: a pointer where to store a string when the entry is
803  * parsed.
804  *
805  * Defines a #VisuConfigFileEntry that will be a string to
806  * read and to store in @location. If @location already contains a
807  * string, it is g_free().
808  *
809  * Since: 3.7
810  *
811  * Returns: (transfer full): the newly created #VisuConfigFileEntry object.
812  **/
visu_config_file_addStringEntry(VisuConfigFile * conf,const gchar * key,const gchar * description,gchar ** location)813 VisuConfigFileEntry* visu_config_file_addStringEntry(VisuConfigFile *conf, const gchar *key,
814                                                      const gchar* description,
815                                                      gchar **location)
816 {
817   VisuConfigFileEntry *entry;
818 
819   g_return_val_if_fail(location, (VisuConfigFileEntry*)0);
820   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (VisuConfigFileEntry*)0);
821 
822   entry = entry_init(key, description, conf->priv->kind, 1);
823   if (!entry)
824     return (VisuConfigFileEntry*)0;
825   entry->read = _readString;
826   entry->storage = (gpointer)location;
827 
828   if (!entry_register(conf, entry))
829     {
830       g_free(entry);
831       entry = (VisuConfigFileEntry*)0;
832       g_warning("entry '%s' already exists!", key);
833     }
834 
835   return entry;
836 }
837 /**
838  * visu_config_file_getEntries:
839  * @conf: a #VisuConfigFile object ;
840  *
841  * This routine should be used for introspections purpose, to know
842  * what resources or parameters are available.
843  *
844  * Returns: (element-type utf8) (transfer none): a #GList own by V_Sim.
845  */
visu_config_file_getEntries(VisuConfigFile * conf)846 GList* visu_config_file_getEntries(VisuConfigFile *conf)
847 {
848   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (GList*)0);
849 
850   return g_hash_table_get_values(conf->priv->entryList);
851 }
852 
853 /**
854  * visu_config_file_addKnownTag:
855  * @tag: a string (not nul or empty).
856  *
857  * If parameter entries have a tag, they are ignored except if their tag
858  * has been declared using this method.
859  */
visu_config_file_addKnownTag(gchar * tag)860 void visu_config_file_addKnownTag(gchar* tag)
861 {
862   g_return_if_fail(tag && *tag);
863 
864   if (!knownTags)
865     g_type_class_ref(VISU_TYPE_CONFIG_FILE);
866 
867   g_hash_table_insert(knownTags, (gpointer)tag, GINT_TO_POINTER(1));
868 }
869 /**
870  * visu_config_file_addExportFunction:
871  * @conf: a #VisuConfigFile object ;
872  * @writeFunc: (scope call): a VisuConfigFileExportFunc method.
873  *
874  * This stores the @writeFunc given. It will be called when resources or parameters
875  * will be exported to disk.
876  */
visu_config_file_addExportFunction(VisuConfigFile * conf,VisuConfigFileExportFunc writeFunc)877 void visu_config_file_addExportFunction(VisuConfigFile *conf, VisuConfigFileExportFunc writeFunc)
878 {
879   struct writeFunc_struct *str;
880 
881   if (!writeFunc)
882     return;
883 
884   g_return_if_fail(VISU_IS_CONFIG_FILE(conf));
885 
886   str = g_malloc(sizeof(struct writeFunc_struct));
887   str->writeFunc = writeFunc;
888   conf->priv->exportList = g_list_prepend(conf->priv->exportList, str);
889 }
890 
891 /**
892  * visu_config_file_entry_setTag:
893  * @entry: a #VisuConfigFileEntry object ;
894  * @tag: a string.
895  *
896  * This method is used to set a tag to the given entry. This tag is used
897  * to ignore or not the entry when the file is read. The @tag argument
898  * is copied.
899  */
visu_config_file_entry_setTag(VisuConfigFileEntry * entry,const gchar * tag)900 void visu_config_file_entry_setTag(VisuConfigFileEntry *entry, const gchar *tag)
901 {
902   g_return_if_fail(entry);
903 
904   if (entry->tag)
905     g_free(entry->tag);
906   entry->tag = g_strdup(tag);
907 }
908 /**
909  * visu_config_file_entry_setVersion:
910  * @entry: a #VisuConfigFileEntry object ;
911  * @version: the version the entry appear in.
912  *
913  * Set the version number the entry appear in.
914  */
visu_config_file_entry_setVersion(VisuConfigFileEntry * entry,float version)915 void visu_config_file_entry_setVersion(VisuConfigFileEntry *entry, float version)
916 {
917   g_return_if_fail(entry && version > 3.0f);
918 
919   entry->version = version;
920 }
921 /**
922  * visu_config_file_entry_setReplace:
923  * @newEntry: a #VisuConfigFileEntry object ;
924  * @oldEntry: idem.
925  *
926  * Use this method to declare that @oldEntry has become obsolete and
927  * has been replaced by @newEntry.
928  */
visu_config_file_entry_setReplace(VisuConfigFileEntry * newEntry,VisuConfigFileEntry * oldEntry)929 void visu_config_file_entry_setReplace(VisuConfigFileEntry *newEntry,
930                                        VisuConfigFileEntry *oldEntry)
931 {
932   g_return_if_fail(newEntry && oldEntry);
933 
934   if (oldEntry->newKey)
935     g_free(oldEntry->newKey);
936   oldEntry->newKey = g_strdup(newEntry->key);
937 }
938 /**
939  * visu_config_file_entry_getKey:
940  * @entry: a #VisuConfigFileEntry object.
941  *
942  * An entry is defined by its key.
943  *
944  * Since: 3.8
945  *
946  * Returns: the key of @entry.
947  **/
visu_config_file_entry_getKey(const VisuConfigFileEntry * entry)948 const gchar* visu_config_file_entry_getKey(const VisuConfigFileEntry *entry)
949 {
950   g_return_val_if_fail(entry, (const gchar*)0);
951 
952   return entry->key;
953 }
954 /**
955  * visu_config_file_entry_getLabel:
956  * @entry: a #VisuConfigFileEntry object.
957  *
958  * An entry can be defined as some values preceeded by a label. After
959  * parsing an entry, this label, if it exists can be retrieve with
960  * this function. See for instance
961  * visu_config_file_addBooleanArrayEntry() to define an entry with a label.
962  *
963  * Since: 3.8
964  *
965  * Returns: (allow-none): the label as parsed.
966  **/
visu_config_file_entry_getLabel(const VisuConfigFileEntry * entry)967 const gchar* visu_config_file_entry_getLabel(const VisuConfigFileEntry *entry)
968 {
969   g_return_val_if_fail(entry, (const gchar*)0);
970 
971   return entry->label;
972 }
973 /**
974  * visu_config_file_entry_popToken:
975  * @entry: a #VisuConfigFileEntry object.
976  * @value: (out caller-allocates): a location to store a string.
977  *
978  * Pop a string from a tokenified data line corresponding to @entry in
979  * a configuration file.
980  *
981  * Since: 3.8
982  *
983  * Returns: TRUE if @entry still has tokens to be retrieved and @value
984  * has be set.
985  **/
visu_config_file_entry_popToken(VisuConfigFileEntry * entry,const gchar ** value)986 gboolean visu_config_file_entry_popToken(VisuConfigFileEntry *entry, const gchar **value)
987 {
988   g_return_val_if_fail(entry && entry->tokens, FALSE);
989 
990   while (entry->tokens[entry->iToken] && !entry->tokens[entry->iToken][0])
991     entry->iToken += 1;
992   if (entry->tokens[entry->iToken])
993     {
994       *value = entry->tokens[entry->iToken];
995       entry->iToken += 1;
996       return TRUE;
997     }
998   return FALSE;
999 }
1000 /**
1001  * visu_config_file_entry_popTokenAsBoolean:
1002  * @entry: a #VisuConfigFileEntry object.
1003  * @nValues: an integer.
1004  * @values: (array length=nValues): an array of boolean.
1005  *
1006  * Read @nValues as boolean from @entry and stores them in
1007  * @values. These tokens are poped from the current list of tokens of @entry.
1008  *
1009  * Since: 3.8
1010  *
1011  * Returns: TRUE if @entry has @nValues boolean tokens to be read.
1012  **/
visu_config_file_entry_popTokenAsBoolean(VisuConfigFileEntry * entry,guint nValues,gboolean * values)1013 gboolean visu_config_file_entry_popTokenAsBoolean(VisuConfigFileEntry *entry, guint nValues,
1014                                                   gboolean *values)
1015 {
1016   int res;
1017   guint i, nb;
1018   int *vals;
1019 
1020   g_return_val_if_fail(entry && entry->tokens, FALSE);
1021   vals = g_malloc(sizeof(int) * nValues);
1022 
1023   /* Read @size inting point values from tokens. */
1024   for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++)
1025     if (entry->tokens[entry->iToken][0] != '\0')
1026       {
1027         res = sscanf(entry->tokens[entry->iToken], "%d", vals + nb);
1028         if (res != 1)
1029           {
1030             visu_config_file_entry_setErrorMessage
1031               (entry, _("%d boolean value(s) should appear here"), nValues);
1032             g_free(vals);
1033             return FALSE;
1034           }
1035         nb += 1;
1036       }
1037   if (nb != nValues)
1038     {
1039       visu_config_file_entry_setErrorMessage
1040         (entry, _("%d boolean value(s) should appear here but %d has been found"),
1041          nValues, nb);
1042       g_free(vals);
1043       return FALSE;
1044     }
1045   for (i = 0; i < nValues; i++)
1046     values[i] = (vals[i] != FALSE);
1047   g_free(vals);
1048   return TRUE;
1049 }
1050 /**
1051  * visu_config_file_entry_popTokenAsInt:
1052  * @entry: a #VisuConfigFileEntry object.
1053  * @nValues: an integer.
1054  * @values: (array length=nValues): an array of integers.
1055  * @clamp: a range.
1056  *
1057  * Like visu_config_file_entry_popTokenAsBoolean() but for
1058  * integers. Additionally conduct a range check using @clamp.
1059  *
1060  * Since: 3.8
1061  *
1062  * Returns: TRUE if @entry has @nValues integer tokens to be read.
1063  **/
visu_config_file_entry_popTokenAsInt(VisuConfigFileEntry * entry,guint nValues,int * values,const int clamp[2])1064 gboolean visu_config_file_entry_popTokenAsInt(VisuConfigFileEntry *entry, guint nValues,
1065                                               int *values, const int clamp[2])
1066 {
1067   int res;
1068   guint i, nb;
1069   int *vals;
1070 
1071   g_return_val_if_fail(entry && entry->tokens, FALSE);
1072   vals = g_malloc(sizeof(int) * nValues);
1073 
1074   /* Read @size inting point values from tokens. */
1075   for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++)
1076     if (entry->tokens[entry->iToken][0] != '\0')
1077       {
1078         res = sscanf(entry->tokens[entry->iToken], "%d", vals + nb);
1079         if (res != 1)
1080           {
1081             visu_config_file_entry_setErrorMessage
1082               (entry, _("%d integer value(s) should appear here"), nValues);
1083             g_free(vals);
1084             return FALSE;
1085           }
1086         nb += 1;
1087       }
1088   if (nb != nValues)
1089     {
1090       visu_config_file_entry_setErrorMessage
1091         (entry, _("%d integer value(s) should appear here but %d has been found"),
1092          nValues, nb);
1093       g_free(vals);
1094       return FALSE;
1095     }
1096   for (i = 0; i < nValues; i++)
1097     if (tool_config_file_clampInt(vals + i, vals[i], clamp[0], clamp[1]))
1098       {
1099         visu_config_file_entry_setErrorMessage
1100           (entry, _("wrong range (%d <= v <= %d) for the %s markup"),
1101            clamp[0], clamp[1], entry->key);
1102         g_free(vals);
1103         return FALSE;
1104       }
1105   memcpy(values, vals, sizeof(int) * nValues);
1106   g_free(vals);
1107   return TRUE;
1108 }
1109 /**
1110  * visu_config_file_entry_popTokenAsColor:
1111  * @entry: a #VisuConfigFileEntry object.
1112  * @color: (out caller-allocates): a location to store a #ToolColor.
1113  *
1114  * Like visu_config_file_entry_popToken() but convert the token as a #ToolColor.
1115  *
1116  * Since: 3.8
1117  *
1118  * Returns: TRUE if @entry has a color tokens to be read.
1119  **/
visu_config_file_entry_popTokenAsColor(VisuConfigFileEntry * entry,const ToolColor ** color)1120 gboolean visu_config_file_entry_popTokenAsColor(VisuConfigFileEntry *entry, const ToolColor **color)
1121 {
1122   gfloat rgba[4];
1123   gfloat rgColor[2] = {0.f, 1.f};
1124 
1125   g_return_val_if_fail(entry && entry->tokens && color, FALSE);
1126 
1127   *color = tool_color_fromStr(entry->tokens[entry->iToken], (int*)0);
1128   if (*color)
1129     {
1130       entry->iToken += 1;
1131       return TRUE;
1132     }
1133 
1134   if (!visu_config_file_entry_popTokenAsFloat(entry, 3, rgba, rgColor))
1135     return FALSE;
1136 
1137   rgba[3] = 1.f;
1138   *color = tool_color_getByValues((int*)0, rgba[0], rgba[1], rgba[2], rgba[3]);
1139   if (!*color)
1140     *color = tool_color_addFloatRGBA(rgba, (int*)0);
1141 
1142   return TRUE;
1143 }
1144 /**
1145  * visu_config_file_entry_popTokenAsFloat:
1146  * @entry: a #VisuConfigFileEntry object.
1147  * @nValues: an integer.
1148  * @values: (array length=nValues): an array of floats.
1149  * @clamp: a range.
1150  *
1151  * Like visu_config_file_entry_popTokenAsInt() but for floats.
1152  *
1153  * Since: 3.8
1154  *
1155  * Returns: TRUE if @entry has @nValues float tokens to be read.
1156  **/
visu_config_file_entry_popTokenAsFloat(VisuConfigFileEntry * entry,guint nValues,float * values,const float clamp[2])1157 gboolean visu_config_file_entry_popTokenAsFloat(VisuConfigFileEntry *entry, guint nValues,
1158                                                 float *values, const float clamp[2])
1159 {
1160   int res;
1161   guint i, nb;
1162   float *vals;
1163 
1164   g_return_val_if_fail(entry && entry->tokens, FALSE);
1165   vals = g_malloc(sizeof(float) * nValues);
1166 
1167   /* Read @size floating point values from tokens. */
1168   for (nb = 0; entry->tokens[entry->iToken] && nb < nValues; entry->iToken++)
1169     if (entry->tokens[entry->iToken][0] != '\0')
1170       {
1171         res = sscanf(entry->tokens[entry->iToken], "%f", vals + nb);
1172         if (res != 1)
1173           {
1174             visu_config_file_entry_setErrorMessage
1175               (entry, _("%d floating point values should appear here"), nValues);
1176             g_free(vals);
1177             return FALSE;
1178           }
1179         nb += 1;
1180       }
1181   if (nb != nValues)
1182     {
1183       visu_config_file_entry_setErrorMessage
1184         (entry, _("%d floating point value(s) should appear here but %d has been found"),
1185          nValues, nb);
1186       g_free(vals);
1187       return FALSE;
1188     }
1189   for (i = 0; i < nValues; i++)
1190     if (tool_config_file_clampFloat(vals + i, vals[i], clamp[0], clamp[1]))
1191       {
1192         visu_config_file_entry_setErrorMessage
1193           (entry, _("wrong range (%g <= v <= %g) for the %s markup"),
1194            clamp[0], clamp[1], entry->key);
1195         g_free(vals);
1196         return FALSE;
1197       }
1198   memcpy(values, vals, sizeof(float) * nValues);
1199   g_free(vals);
1200   return TRUE;
1201 }
1202 /**
1203  * visu_config_file_entry_popTokenAsEnum:
1204  * @entry: a #VisuConfigFileEntry object.
1205  * @value: (out): a location to store an enum value.
1206  * @toEnum: (scope call): a method to convert a string to an enum
1207  * value.
1208  *
1209  * Parse the next non null token in @entry and parse it with @toEnum
1210  * function. The result, if valid, is stored in @value.
1211  *
1212  * Since: 3.8
1213  *
1214  * Returns: TRUE if a token can be found and the conversion succeed.
1215  **/
visu_config_file_entry_popTokenAsEnum(VisuConfigFileEntry * entry,guint * value,VisuConfigFileEnumFunc toEnum)1216 gboolean visu_config_file_entry_popTokenAsEnum(VisuConfigFileEntry *entry, guint *value,
1217                                                VisuConfigFileEnumFunc toEnum)
1218 {
1219   g_return_val_if_fail(entry && entry->tokens, FALSE);
1220 
1221   while (entry->tokens[entry->iToken] && !entry->tokens[entry->iToken][0])
1222     entry->iToken += 1;
1223   if (!entry->tokens[entry->iToken])
1224     {
1225       visu_config_file_entry_setErrorMessage
1226         (entry, _("missing string for %s markup"), entry->key);
1227       return FALSE;
1228     }
1229   if (!toEnum(entry->tokens[entry->iToken], value))
1230     {
1231       visu_config_file_entry_setErrorMessage
1232         (entry, _("'%s' is not a valid value for %s markup"),
1233          entry->tokens[entry->iToken], entry->key);
1234       entry->iToken += 1;
1235       return FALSE;
1236     }
1237   entry->iToken += 1;
1238   return TRUE;
1239 }
1240 /**
1241  * visu_config_file_entry_popAllTokens:
1242  * @entry: a #VisuConfigFileEntry object.
1243  *
1244  * Join the remaining tokens of @entry into a string.
1245  *
1246  * Since: 3.8
1247  *
1248  * Returns: a newly created string.
1249  **/
visu_config_file_entry_popAllTokens(VisuConfigFileEntry * entry)1250 gchar* visu_config_file_entry_popAllTokens(VisuConfigFileEntry *entry)
1251 {
1252   g_return_val_if_fail(entry, (gchar*)0);
1253 
1254   return g_strjoinv(" ", entry->tokens + entry->iToken);
1255 }
1256 /**
1257  * visu_config_file_entry_setErrorMessage:
1258  * @entry: a #VisuConfigFileEntry object.
1259  * @mess: a string.
1260  * @...: additional values, like in printf.
1261  *
1262  * Set error to @entry and format a message.
1263  *
1264  * Since: 3.8
1265  **/
visu_config_file_entry_setErrorMessage(VisuConfigFileEntry * entry,const gchar * mess,...)1266 void visu_config_file_entry_setErrorMessage(VisuConfigFileEntry *entry, const gchar *mess, ...)
1267 {
1268   va_list arglist;
1269 
1270   g_return_if_fail(entry && mess);
1271 
1272   va_start(arglist, mess);
1273   entry->errMess = g_strdup_vprintf(mess, arglist);
1274   va_end(arglist);
1275 }
1276 
_getKey(const gchar * buf,gchar ** key,gchar ** tag,guint iLine,GError ** error)1277 static gchar* _getKey(const gchar *buf, gchar **key, gchar **tag, guint iLine, GError **error)
1278 {
1279   gchar *key_, *tag_, *end, *ret;
1280 
1281   *key = (gchar*)0;
1282   *tag = (gchar*)0;
1283 
1284   ret = strchr(buf, ':');
1285   if (!ret)
1286     return (gchar*)0;
1287 
1288   key_ = g_strndup(buf, ret - buf);
1289   key_ = g_strstrip(key_);
1290   *key = key_;
1291 
1292   /* Look for the tag */
1293   tag_ = strchr(key_, '[');
1294   if (tag_)
1295     {
1296       *tag_ = '\0';
1297       tag_ += 1;
1298       end = strchr(tag_, ']');
1299       if (end)
1300         {
1301           *end = '\0';
1302           tag_ = g_strdup(tag_);
1303           *tag = tag_;
1304         }
1305       else
1306         *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_TAG,
1307                              _("Parse error at line %d,"
1308                                " the tag '%s' is not closed.\n"),
1309                              iLine, tag_);
1310     }
1311 
1312   DBG_fprintf(stderr,"Visu ConfigFile: read a flag (tag): '%s' (%s).\n", key_, tag_);
1313   return ret;
1314 }
_getEntry(VisuConfigFile * conf,const gchar * key,guint iLine,GError ** error)1315 static VisuConfigFileEntry* _getEntry(VisuConfigFile *conf,
1316                                       const gchar *key, guint iLine, GError **error)
1317 {
1318   VisuConfigFileEntry *entry;
1319 
1320   DBG_fprintf(stderr, "Visu ConfigFile: found entry '%s'.\n", key);
1321   entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList,
1322                                                     (gpointer)key);
1323   if (!entry)
1324     *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MARKUP,
1325                          _("Parse error at line %d,"
1326                            " '%s' is an unknown markup.\n"),
1327                          iLine, key);
1328   else if (entry->newKey)
1329     g_warning(_("Markup '%s' is obsolete, replaced by '%s'."), key, entry->newKey);
1330   return entry;
1331 }
_appendMessage(GString * message,GError ** error,const gchar * key,const gchar * context)1332 static void _appendMessage(GString *message, GError **error,
1333                            const gchar *key, const gchar *context)
1334 {
1335   if (*error)
1336     {
1337       g_string_append(message, (*error)->message);
1338       if (key)
1339         g_string_append_printf(message, _(" read line (%s) : '%s'\n"), key, context);
1340       else
1341         g_string_append_printf(message, _(" read line : '%s'\n"), context);
1342       g_error_free(*error);
1343       *error = (GError*)0;
1344     }
1345 }
_parse(VisuConfigFile * conf,VisuConfigFileEntry * entry,gchar ** tokens,guint iLine,GError ** error)1346 static gboolean _parse(VisuConfigFile *conf, VisuConfigFileEntry *entry,
1347                        gchar **tokens, guint iLine, GError **error)
1348 {
1349   gboolean ret;
1350 
1351   ret = TRUE;
1352   if (tokens)
1353     {
1354       if (entry->read)
1355         ret = entry->read(entry, tokens, entry->nbLines, iLine, error);
1356       else if (entry->newKey)
1357         g_warning("Deprecated entry '%s', use '%s' instead.", entry->key, entry->newKey);
1358       if (ret)
1359         {
1360           DBG_fprintf(stderr, "Visu ConfigFile: entry '%s' parsed (%d).\n", entry->key, ret);
1361           g_signal_emit(conf, _signals[ENTRYPARSED_SIGNAL], entry->kquark, entry);
1362           if (entry->errMess)
1363             {
1364               *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ,
1365                                    _("Parse error at line %d, %s.\n"), iLine, entry->errMess);
1366               g_free(entry->errMess);
1367               entry->errMess = (gchar*)0;
1368             }
1369         }
1370       g_strfreev(entry->tokens);
1371       entry->tokens = (gchar**)0;
1372     }
1373   return ret;
1374 }
1375 
_loadRaw(VisuConfigFile * conf,const char * fileName,GError ** error)1376 static gboolean _loadRaw(VisuConfigFile *conf, const char* fileName,
1377                          GError **error)
1378 {
1379   GIOChannel *ioFile;
1380   GString *line= (GString*)0;
1381   GIOStatus status;
1382   guint nbLine, i, iLine;
1383   gchar *deuxPoints;
1384   gchar **tokens, **splits;
1385   gchar *key, *tag;
1386   char *startDef, *endDef;
1387   VisuConfigFileEntry *entry;
1388   GString *message;
1389 
1390   ioFile = g_io_channel_new_file(fileName, "r", error);
1391   if (*error)
1392     return FALSE;
1393 
1394   message = g_string_new("");
1395   line = g_string_new("");
1396   iLine = 0;
1397 
1398   status = G_IO_STATUS_NORMAL;
1399   while (status == G_IO_STATUS_NORMAL)
1400     {
1401       status = g_io_channel_read_line_string(ioFile, line, NULL, error);
1402       if (*error)
1403         {
1404           g_string_free(line, TRUE);
1405           g_string_free(message, TRUE);
1406           return FALSE;
1407         }
1408       iLine += 1;
1409 
1410       if (status == G_IO_STATUS_EOF || line->str[0] == '#' || line->str[0] == '\n')
1411         continue;
1412 
1413       entry = (VisuConfigFileEntry*)0;
1414 
1415       deuxPoints = _getKey(line->str, &key, &tag, iLine, error);
1416       _appendMessage(message, error, (const gchar*)0, line->str);
1417 
1418       if (key)
1419         {
1420           if (tag && !g_hash_table_lookup(knownTags, (gpointer)tag))
1421             {
1422               entry = (VisuConfigFileEntry*)0;
1423               DBG_fprintf(stderr, "Visu ConfigFile: the entry '%s' has an unknown tag (%s),"
1424                           " it will be dismissed.\n", key, tag);
1425             }
1426           else
1427             {
1428               entry = _getEntry(conf, key, iLine, error);
1429               _appendMessage(message, error, (const gchar*)0, line->str);
1430             }
1431           g_free(key);
1432           if (tag)
1433             g_free(tag);
1434         }
1435 
1436       if (entry)
1437         {
1438           nbLine = entry->nbLines;
1439           /* Tricks for backward compatibility. */
1440           if (!strcmp(entry->key, "pair_link"))
1441             nbLine = 2;
1442           tokens = g_malloc0(sizeof(gchar*) * (nbLine + 1));
1443           if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE)
1444             for (i = 0; i < nbLine; i++)
1445               {
1446                 status = g_io_channel_read_line_string(ioFile, line,
1447                                                        NULL, error);
1448                 if (*error)
1449                   {
1450                     g_string_free(line, TRUE);
1451                     g_string_free(message, TRUE);
1452                     return FALSE;
1453                   }
1454                 iLine += 1;
1455                 if (status != G_IO_STATUS_NORMAL)
1456                   {
1457                     g_strfreev(tokens);
1458                     tokens = (gchar**)0;
1459                     *error = g_error_new(TOOL_CONFIG_FILE_ERROR,
1460                                          TOOL_CONFIG_FILE_ERROR_MISSING,
1461                                          _("Parse error at line %d,"
1462                                            " '%s' needs %d lines but only %d were read.\n"),
1463                                          iLine, entry->key, nbLine, i);
1464                     break;
1465                   }
1466                 tokens[i] = g_strdup(line->str);
1467               }
1468           else
1469             tokens[0] = g_strdup(deuxPoints + 1);
1470           /* Tricks for backward compatibility. */
1471           if (entry->withLabel || !strcmp(entry->key, "shade_palette"))
1472             {
1473               i = 0;
1474               if (!strcmp(entry->key, "isosurface_color") ||
1475                   !strcmp(entry->key, "isosurface_properties"))
1476                 {
1477                   splits = g_strsplit_set(tokens[0], "\"", 3);
1478                   i += 1;
1479                 }
1480               else if (!strcmp(entry->key, "shade_palette"))
1481                 {
1482                   splits = g_malloc0(sizeof(gchar*) * 3);
1483                   startDef = strchr(tokens[0], '(');
1484                   endDef = strchr(tokens[0], ')');
1485                   if (!startDef || !endDef)
1486                     {
1487                       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_MISSING,
1488                                            _("Parse error at line %d, cannot find parenthesis"
1489                                              " containing the description of a shade.\n"), iLine);
1490                     }
1491                   else
1492                     {
1493                       splits[0] = g_strndup(tokens[0], startDef - tokens[0] - 1);
1494                       splits[1] = g_strndup(startDef + 1, endDef - startDef - 1);
1495                     }
1496                 }
1497               else if (!strcmp(entry->key, "pair_link"))
1498                 {
1499                   nbLine = 1;
1500                   i = 0;
1501                   splits = g_malloc0(sizeof(gchar*) * 3);
1502                   splits[0] = g_strdup(tokens[0]);
1503                   splits[1] = g_strdup(tokens[1]);
1504                 }
1505               else
1506                 {
1507                   splits = g_strsplit_set(tokens[0], " \n", TOOL_MAX_LINE_LENGTH);
1508                   while (splits[i] && !splits[i][0]) i++;
1509                 }
1510               g_free(entry->label);
1511               entry->label = g_strdup(splits[i]);
1512               g_free(tokens[0]);
1513               tokens[0] = (splits[i] && splits[i + 1]) ? g_strjoinv(" ", splits + i + 1) : g_strdup("");
1514               g_strfreev(splits);
1515             }
1516           if (!error || !*error)
1517             _parse(conf, entry, tokens, iLine, error);
1518           _appendMessage(message, error, entry->key, tokens[0]);
1519           g_strfreev(tokens);
1520         }
1521     }
1522   g_string_free(line, TRUE);
1523 
1524   status = g_io_channel_shutdown(ioFile, FALSE, error);
1525   g_io_channel_unref(ioFile);
1526   if (status != G_IO_STATUS_NORMAL)
1527     {
1528       g_string_free(message, TRUE);
1529       return FALSE;
1530     }
1531   DBG_fprintf(stderr, "Visu ConfigFile: read OK (error len = %d).\n", (int)message->len);
1532 
1533   if (message->len > 0)
1534     {
1535       DBG_fprintf(stderr, " | %s\n", message->str);
1536       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ,
1537                            "%s", message->str);
1538     }
1539   g_string_free(message, TRUE);
1540 
1541   return (*error == (GError*)0);
1542 }
1543 
1544 struct _dt
1545 {
1546   VisuConfigFile *conf;
1547 
1548   gboolean parse;
1549   GString *message;
1550 
1551   VisuConfigFileEntry *entry;
1552   gchar *tag, *id, *text;
1553 };
1554 
_element(GMarkupParseContext * context _U_,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)1555 static void _element(GMarkupParseContext *context _U_,
1556                      const gchar         *element_name,
1557                      const gchar        **attribute_names,
1558                      const gchar        **attribute_values,
1559                      gpointer             user_data,
1560                      GError             **error)
1561 {
1562   struct _dt *dt = (struct _dt*)user_data;
1563   guint i;
1564 
1565   if (!strcmp(element_name, "resources"))
1566     dt->parse = TRUE;
1567   else if (!strcmp(element_name, "entry"))
1568     {
1569       dt->tag  = (gchar*)0;
1570       dt->id   = (gchar*)0;
1571       dt->text = (gchar*)0;
1572       for (i = 0; attribute_names[i]; i++)
1573         {
1574           if (!strcmp(attribute_names[i], "name"))
1575             {
1576               dt->entry = _getEntry(dt->conf, attribute_values[i], 0, error);
1577               _appendMessage(dt->message, error, (const gchar*)0, attribute_values[i]);
1578             }
1579           else if (!strcmp(attribute_names[i], "id"))
1580             dt->id = g_strdup(attribute_values[i]);
1581         }
1582     }
1583 }
_endElement(GMarkupParseContext * context _U_,const gchar * element_name,gpointer user_data,GError ** error)1584 static void _endElement(GMarkupParseContext *context _U_,
1585                         const gchar         *element_name,
1586                         gpointer             user_data,
1587                         GError             **error)
1588 {
1589   struct _dt *dt = (struct _dt*)user_data;
1590 
1591   if (!strcmp(element_name, "resources"))
1592     dt->parse = FALSE;
1593   else if (!strcmp(element_name, "entry") && dt->entry)
1594     {
1595       g_free(dt->entry->label);
1596       dt->entry->label = g_strdup(dt->id);
1597       _parse(dt->conf, dt->entry, &dt->text, 0, error);
1598       _appendMessage(dt->message, error, dt->entry->key, dt->text);
1599       dt->entry = (VisuConfigFileEntry*)0;
1600       g_free(dt->tag);
1601       g_free(dt->id);
1602       g_free(dt->text);
1603     }
1604 }
_text(GMarkupParseContext * context _U_,const gchar * text,gsize text_len _U_,gpointer user_data,GError ** error _U_)1605 static void _text(GMarkupParseContext *context _U_,
1606                   const gchar         *text,
1607                   gsize                text_len _U_,
1608                   gpointer             user_data,
1609                   GError             **error _U_)
1610 {
1611   struct _dt *dt = (struct _dt*)user_data;
1612 
1613   if (dt->entry)
1614     dt->text = g_strdup(text);
1615 }
1616 
_loadXML(VisuConfigFile * conf,const gchar * filename,GError ** error)1617 static gboolean _loadXML(VisuConfigFile *conf, const gchar *filename, GError **error)
1618 {
1619   GMarkupParseContext* xmlContext;
1620   GMarkupParser parser;
1621   gsize size;
1622   gchar *buffer;
1623   struct _dt dt;
1624 
1625   /* Read file. */
1626   buffer = (gchar*)0;
1627   if (!g_file_get_contents(filename, &buffer, &size, error))
1628     return FALSE;
1629 
1630   /* Create context. */
1631   parser.start_element = _element;
1632   parser.end_element   = _endElement;
1633   parser.text          = _text;
1634   parser.passthrough   = NULL;
1635   parser.error         = NULL;
1636   dt.conf = conf;
1637   dt.parse   = FALSE;
1638   dt.message = g_string_new("");
1639   dt.entry   = (VisuConfigFileEntry*)0;
1640   dt.tag     = (gchar*)0;
1641   dt.id      = (gchar*)0;
1642   dt.text    = (gchar*)0;
1643   xmlContext = g_markup_parse_context_new(&parser, 0, &dt, NULL);
1644 
1645   /* Parse data. */
1646   g_markup_parse_context_parse(xmlContext, buffer, size, error);
1647 
1648   /* Free buffers. */
1649   g_markup_parse_context_free(xmlContext);
1650   g_free(buffer);
1651   if (!*error && dt.message->len > 0)
1652     *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ,
1653                          "%s", dt.message->str);
1654   g_string_free(dt.message, TRUE);
1655 
1656   return (*error == (GError*)0);
1657 }
1658 
_setSource(VisuConfigFile * conf,const gchar * filename)1659 static void _setSource(VisuConfigFile *conf, const gchar *filename)
1660 {
1661   gchar *dirname;
1662 
1663   g_return_if_fail(VISU_IS_CONFIG_FILE(conf));
1664 
1665   g_free(conf->priv->source);
1666   conf->priv->source = g_strdup(filename);
1667 
1668   dirname = g_path_get_dirname(filename);
1669   _addPath(resources, dirname);
1670 }
1671 
1672 /**
1673  * visu_config_file_load:
1674  * @conf: a #VisuConfigFile object ;
1675  * @filename: the path to file to read ;
1676  * @error: (allow-none): a pointer to a GError pointer.
1677  *
1678  * Try to load the resources/parameters from the file name given in
1679  * parameter.
1680  *
1681  * Returns: TRUE if everything goes right. If @error is not NULL it
1682  *          should be freed with g_error_free().
1683  */
visu_config_file_load(VisuConfigFile * conf,const char * filename,GError ** error)1684 gboolean visu_config_file_load(VisuConfigFile *conf, const char* filename, GError **error)
1685 {
1686   gboolean res;
1687 
1688   DBG_fprintf(stderr, "Visu ConfigFile: parsing '%s' file for"
1689 	      " resources/parameters...\n", filename);
1690 
1691   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE);
1692 
1693   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE && strstr(filename, ".xml"))
1694     res = _loadXML(conf, filename, error);
1695   else
1696     res = _loadRaw(conf, filename, error);
1697 
1698   /* We save the current path. */
1699   _setSource(conf, filename);
1700 
1701   return res;
1702 }
1703 /**
1704  * visu_config_file_loadCommandLine:
1705  * @error: a location for a #GError pointer.
1706  *
1707  * For every command line option (e.g. -o axes_line_width=3), call the
1708  * corresponding ressource callback.
1709  *
1710  * Since: 3.8
1711  *
1712  * Returns: TRUE on success.
1713  **/
visu_config_file_loadCommandLine(GError ** error)1714 gboolean visu_config_file_loadCommandLine(GError **error)
1715 {
1716   GHashTable *options;
1717   GHashTableIter iter;
1718   gpointer key;
1719   ToolOption *value;
1720   VisuConfigFile *conf;
1721   VisuConfigFileEntry *entry;
1722   gchar **tokens;
1723 
1724   if (!parameters || !resources)
1725     g_type_class_ref(VISU_TYPE_CONFIG_FILE);
1726 
1727   options = commandLineGet_options();
1728   if (!options)
1729     return TRUE;
1730 
1731   g_hash_table_iter_init(&iter, options);
1732   while (g_hash_table_iter_next(&iter, &key, (gpointer*)&value))
1733     {
1734       tokens = g_strsplit_set(key, "[]", 3);
1735       conf = resources;
1736       entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList, tokens[0]);
1737       if (!entry)
1738         {
1739           conf = parameters;
1740           entry = (VisuConfigFileEntry*)g_hash_table_lookup(conf->priv->entryList, tokens[0]);
1741         }
1742       if (entry && tokens[1])
1743         {
1744           g_free(entry->label);
1745           entry->label = g_strdup(tokens[1]);
1746         }
1747       g_strfreev(tokens);
1748       if (entry)
1749         {
1750           tokens = g_malloc0(sizeof(gchar*) * 2);
1751           tokens[0] = g_strdelimit(g_strdup_value_contents(tool_option_getValue(value)), "\"", ' ');
1752           tokens[1] = NULL;
1753           DBG_fprintf(stderr, "Visu ConfigFile: read '%s' = '%s' from command line.\n",
1754                       (gchar*)key, tokens[0]);
1755           if (!_parse(conf, entry, tokens, 0, error))
1756             return FALSE;
1757         }
1758     }
1759   return TRUE;
1760 }
1761 
1762 /**
1763  * visu_config_file_exportComment:
1764  * @buffer: the buffer to add a comment to.
1765  * @comment: a comment.
1766  *
1767  * Append to @buffer the given @comment, using the current output
1768  * style (raw text or XML as instance).
1769  *
1770  * Since: 3.7
1771  **/
visu_config_file_exportComment(GString * buffer,const gchar * comment)1772 void visu_config_file_exportComment(GString *buffer, const gchar *comment)
1773 {
1774   g_return_if_fail(buffer && comment);
1775 
1776   if (!comment[0])
1777     {
1778       g_string_append(buffer, "\n");
1779       return;
1780     }
1781 
1782   switch (format)
1783     {
1784     case (_format_raw):
1785       g_string_append_printf(buffer, "# %s\n", comment);
1786       break;
1787     case (_format_xml):
1788       g_string_append_printf(buffer, "    <!-- %s -->\n", comment);
1789       break;
1790     }
1791 }
1792 /**
1793  * visu_config_file_exportEntry:
1794  * @buffer: the buffer to write the entry to.
1795  * @name: the name of the entry.
1796  * @id_value: (allow-none): an id for the entry.
1797  * @format_: the formatting string for the message.
1798  * @...: the values to print.
1799  *
1800  * Append to @buffer the given @entry, using the current output
1801  * style (raw text or XML as instance). @id_value can be used to
1802  * specify the entry apply to, for instance, the name of the
1803  * #VisuElement the colour property entry apply to.
1804  *
1805  * Since: 3.7
1806  **/
visu_config_file_exportEntry(GString * buffer,const gchar * name,const gchar * id_value,const gchar * format_,...)1807 void visu_config_file_exportEntry(GString *buffer, const gchar *name,
1808                                   const gchar *id_value, const gchar *format_, ...)
1809 {
1810   va_list arglist;
1811   gchar *buf;
1812 
1813   g_return_if_fail(buffer && name && format_);
1814 
1815   va_start(arglist, format_);
1816   buf = g_strdup_vprintf(format_, arglist);
1817   va_end(arglist);
1818   switch (format)
1819     {
1820     case (_format_raw):
1821       /* Special case for backward compatibility. */
1822       if (!strcmp(name, "pair_link"))
1823         g_string_append_printf(buffer, "%s:\n  %s\n  %s\n", name, (id_value)?id_value:"", buf);
1824       else if (!strcmp(name, "isosurface_color") || !strcmp(name, "isosurface_properties"))
1825         g_string_append_printf(buffer, "%s:\n  \"%s\" %s\n", name, (id_value)?id_value:"", buf);
1826       else
1827         g_string_append_printf(buffer, "%s:\n  %s  %s\n", name, (id_value)?id_value:"", buf);
1828       break;
1829     case (_format_xml):
1830       g_string_append_printf(buffer, "    <entry name=\"%s\"", name);
1831       if (id_value && id_value[0])
1832         g_string_append_printf(buffer, " id=\"%s\"", id_value);
1833       g_string_append_printf(buffer, ">%s</entry>\n", buf);
1834       break;
1835     }
1836   g_free(buf);
1837 }
1838 
1839 /**
1840  * visu_config_file_saveResourcesToXML:
1841  * @filename: the path to file to read ;
1842  * @lines: (out): a pointer to an integer (can be NULL) ;
1843  * @dataObj: (allow-none): a #VisuData object (can be NULL) ;
1844  * @error: a location to store a possible error.
1845  *
1846  * Same routine as visu_config_file_save() but use an XML format instead.
1847  *
1848  * Since: 3.7
1849  *
1850  * Returns: TRUE if everything goes right.
1851  */
visu_config_file_saveResourcesToXML(const char * filename,int * lines,VisuData * dataObj,GError ** error)1852 gboolean visu_config_file_saveResourcesToXML(const char* filename, int *lines,
1853                                              VisuData *dataObj, GError **error)
1854 {
1855   gchar *ptCh;
1856   GString *buffer;
1857   int nbLine;
1858   GList *pos;
1859   gboolean success;
1860 
1861   g_return_val_if_fail(error && !*error, FALSE);
1862 
1863   DBG_fprintf(stderr, "Visu ConfigFile: exporting '%s' file for"
1864 	      " XML resources...\n", filename);
1865 
1866   format = _format_xml;
1867   buffer = g_string_new("<resources");
1868   g_string_append_printf(buffer, " version=\"%s\">\n", VERSION_HEADER);
1869   for (pos = resources->priv->exportList; pos; pos = g_list_next(pos))
1870     {
1871       /* g_string_append_printf("  <entry name=\"%s\">\n", ((VisuConfigFileEntry*)pos->data)->key); */
1872       ((struct writeFunc_struct*)(pos->data))->writeFunc(buffer, dataObj);
1873     }
1874   g_string_append(buffer, "  </resources>");
1875 
1876   nbLine = 0;
1877   ptCh = buffer->str;
1878   while ((ptCh = strchr(ptCh + 1, '\n')))
1879     nbLine += 1;
1880 
1881   DBG_fprintf(stderr, "Visu ConfigFile: export OK to string,"
1882 	      " preparing to write file.\n");
1883   success = tool_XML_substitute(buffer, filename, "resources", error);
1884   if (!success)
1885     {
1886       g_string_free(buffer, TRUE);
1887       return FALSE;
1888     }
1889   success = g_file_set_contents(filename, buffer->str, -1, error);
1890   DBG_fprintf(stderr, "Visu ConfigFile: write %d lines (%d).\n", nbLine, success);
1891   g_string_free(buffer, TRUE);
1892 
1893   /* We save the current path. */
1894   if (success)
1895     {
1896       DBG_fprintf(stderr, " | save path '%s' as current.\n", filename);
1897       _setSource(resources, filename);
1898     }
1899 
1900   if (lines)
1901     *lines = nbLine;
1902 
1903   return success;
1904 }
1905 
1906 /**
1907  * visu_config_file_save:
1908  * @conf: a #VisuConfigFile object ;
1909  * @fileName: the path to file to read ;
1910  * @lines: a pointer to an integer (can be NULL) ;
1911  * @dataObj: (allow-none): a #VisuData object (can be NULL) ;
1912  * @error: a location to store a possible error.
1913  *
1914  * Try to export the resources/parameters to the file name given in
1915  * parameter. If @lines argument
1916  * is not NULL, and everything went right, it stores the number of written lines.
1917  * If the argument @dataObj is not null, only resources related
1918  * to the #VisuData object should be exported (for parameters files, @dataObj is
1919  * always NULL).
1920  *
1921  * Returns: TRUE if everything goes right.
1922  */
visu_config_file_save(VisuConfigFile * conf,const char * fileName,int * lines,VisuData * dataObj,GError ** error)1923 gboolean visu_config_file_save(VisuConfigFile *conf, const char* fileName, int *lines,
1924                                VisuData *dataObj, GError **error)
1925 {
1926   gchar *ptCh;
1927   GString *exportString;
1928   int nbLine;
1929   GList *pos, *lst;
1930   gboolean success;
1931 
1932   g_return_val_if_fail(error && !*error, FALSE);
1933 
1934   DBG_fprintf(stderr, "Visu ConfigFile: exporting '%s' file for"
1935 	      " resources/parameters...\n", fileName);
1936 
1937   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE);
1938 
1939   format = _format_raw;
1940   exportString = g_string_new("");
1941   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE)
1942     g_string_append_printf(exportString, RESOURCE_HEADER);
1943   else if (conf->priv->kind == VISU_CONFIG_FILE_KIND_PARAMETER)
1944     g_string_append_printf(exportString, PARAMETER_HEADER);
1945   g_string_append_printf(exportString,
1946 			 " v"VERSION_HEADER
1947 			 "\n"
1948 			 "#====================\n"
1949 			 "\n"
1950 			 "#WARNING: this file format is DIFFERENT from that for\n"
1951 			 "#standard v_sim version <= 2.x\n"
1952 			 "\n"
1953 			 "#Line beginning with a # are not parsed.\n"
1954 			 "\n");
1955   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE)
1956     g_string_append_printf(exportString,
1957 			   "#The only \"useful\" lines must have the following contents\n"
1958 			   "#several two or more lines patterns:\n"
1959 			   "#resource_name:\n"
1960 			   "#values separeted by blank characters\n"
1961 			   "\n"
1962 			   "#The following resource names are valid :\n");
1963   else
1964     g_string_append_printf(exportString,
1965 			   "#The only \"useful\" lines must have the following pattern:\n"
1966 			   "#parameter_name: value\n"
1967 			   "\n"
1968 			   "#The following parameter names are valid :\n");
1969   lst = visu_config_file_getEntries(conf);
1970   for (pos = lst; pos; pos = g_list_next(pos))
1971     if (!((VisuConfigFileEntry*)(pos->data))->newKey)
1972       g_string_append_printf(exportString, "# %s\n",
1973                              ((VisuConfigFileEntry*)(pos->data))->key);
1974   g_string_append_printf(exportString, "\n");
1975   g_list_free(lst);
1976 
1977   for (pos = conf->priv->exportList; pos; pos = g_list_next(pos))
1978     ((struct writeFunc_struct*)(pos->data))->writeFunc(exportString, dataObj);
1979 
1980   nbLine = 0;
1981   ptCh = exportString->str;
1982   while ((ptCh = strchr(ptCh + 1, '\n')))
1983     nbLine += 1;
1984 
1985   DBG_fprintf(stderr, "Visu ConfigFile: export OK to string,"
1986 	      " preparing to write file.\n");
1987 
1988   success = g_file_set_contents(fileName, exportString->str, -1, error);
1989   g_string_free(exportString, TRUE);
1990 
1991   DBG_fprintf(stderr, "Visu ConfigFile: write %d lines (%d).\n", nbLine, success);
1992 
1993   /* We save the current path. */
1994   _setSource(conf, fileName);
1995 
1996   if (lines)
1997     *lines = nbLine;
1998 
1999   return success;
2000 }
2001 
_validateHeader(const gchar * filename,VisuConfigFile * conf)2002 static gboolean _validateHeader(const gchar *filename, VisuConfigFile *conf)
2003 {
2004   FILE *file;
2005   float version;
2006   char *msg, *header;
2007   char line[TOOL_MAX_LINE_LENGTH];
2008 
2009   DBG_fprintf(stderr, "Visu ConfigFile: looking for header of \n  '%s' ... ", filename);
2010   if (strstr(filename, ".xml"))
2011     {
2012       DBG_fprintf(stderr, "accepted.\n");
2013       return TRUE;
2014     }
2015 
2016   file = fopen(filename, "r");
2017   if (!file)
2018     {
2019       g_warning("The file '%s' should be readable but something goes"
2020                 " nasty when one wants to open it.\n", filename);
2021       return FALSE;
2022     }
2023   version = 0.;
2024   msg = fgets(line, TOOL_MAX_LINE_LENGTH, file);
2025   fclose(file);
2026   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE)
2027     header = RESOURCE_HEADER;
2028   else
2029     header = PARAMETER_HEADER;
2030   if (msg && !strncmp(line, header, strlen(header))
2031       && sscanf(line + strlen(header) + 2, "%f", &version))
2032     if (version >= 3.)
2033       {
2034         DBG_fprintf(stderr, "ok.\n");
2035         return TRUE;
2036       }
2037   DBG_fprintf(stderr, "wrong.\n");
2038   return FALSE;
2039 }
2040 
getValidFileWithHeader(int mode,VisuConfigFile * conf,GList ** list)2041 static gchar* getValidFileWithHeader(int mode, VisuConfigFile *conf, GList **list)
2042 {
2043   gchar *res;
2044   const gchar** filenames;
2045 
2046   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_RESOURCE)
2047     filenames = RESOURCES_FILENAMES;
2048   else
2049     filenames = PARAMETERS_FILENAMES;
2050 
2051   /* Look for a valid file.
2052      If it is for writing, a valid file is just given by a valid path.
2053      If it is for reading, a valid file is a valid path AND has a valid header. */
2054 
2055   /* We get the next valid path. */
2056   res = tool_getValidPath(list, filenames, mode);
2057   if (!res)
2058     {
2059       DBG_fprintf(stderr, "Visu ConfigFile: no file available.\n");
2060       return (gchar*)0;
2061     }
2062 
2063   /* if we are in reading mode, we test the header. */
2064   if ((mode & R_OK) && !_validateHeader(res, conf))
2065     {
2066       g_free(res);
2067       res = (gchar*)0;
2068     }
2069   return res;
2070 }
2071 
2072 /**
2073  * visu_config_file_getPath:
2074  * @conf: a #VisuConfigFile object.
2075  *
2076  * The resource file can be read from different places.
2077  *
2078  * Since: 3.6
2079  *
2080  * Returns: the path used to read the last resource file.
2081  */
visu_config_file_getPath(VisuConfigFile * conf)2082 const gchar* visu_config_file_getPath(VisuConfigFile *conf)
2083 {
2084   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (const gchar*)0);
2085   return conf->priv->source;
2086 }
2087 /**
2088  * visu_config_file_getValidPath:
2089  * @conf: a #VisuConfigFile object ;
2090  * @mode: a value from R_OK, W_OK and X_OK as described in unistd.h.
2091  * @utf8: if 1, the path is return in UTF-8 format, otherwise, the locale
2092  * of the file system is used.
2093  *
2094  * Test the entries of the hadoc list to find
2095  * a valid position to read or write a config file.
2096  * It tests access for the specified file.
2097  *
2098  * Returns: the first valid path find in the list of known paths.
2099  */
visu_config_file_getValidPath(VisuConfigFile * conf,int mode,int utf8)2100 gchar* visu_config_file_getValidPath(VisuConfigFile *conf, int mode, int utf8)
2101 {
2102   gchar* file;
2103   gchar* fileUTF8;
2104   GList *lst;
2105 
2106   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (gchar*)0);
2107 
2108   lst = conf->priv->paths;
2109   file = getValidFileWithHeader(mode, conf, &lst);
2110   if (!file)
2111     return file;
2112 
2113   if (utf8)
2114     {
2115       fileUTF8 = g_filename_from_utf8(file, -1, NULL, NULL, NULL);
2116       g_free(file);
2117       return fileUTF8;
2118     }
2119   else
2120     return file;
2121 }
2122 /**
2123  * visu_config_file_getNextValidPath:
2124  * @conf: a #VisuConfigFile object ;
2125  * @accessMode: a value from R_OK, W_OK and X_OK as described in unistd.h ;
2126  * @list: (element-type filename) (inout) (transfer none): a pointer to a valid *GList ;
2127  * @utf8: if 1, the path is return in UTF-8 format, otherwise, the locale
2128  * of the file system is used.
2129  *
2130  * Test the entries of the given list to find
2131  * a valid position to read or write a config file.
2132  * It tests access for the specified file. After a call to this
2133  * method the @list argument points to the next entry in the list, after
2134  * the one found.
2135  *
2136  * Returns: the first valid path find in the given list of paths.
2137  */
visu_config_file_getNextValidPath(VisuConfigFile * conf,int accessMode,GList ** list,int utf8)2138 gchar* visu_config_file_getNextValidPath(VisuConfigFile *conf, int accessMode, GList **list, int utf8)
2139 {
2140   gchar* file;
2141   gchar* fileUTF8;
2142 
2143   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (gchar*)0);
2144   g_return_val_if_fail(list, (gchar*)0);
2145 
2146   if (!*list)
2147     return (gchar*)0;
2148 
2149   file = getValidFileWithHeader(accessMode, conf, list);
2150 
2151   if (*list)
2152     *list = g_list_next(*list);
2153 
2154   if (!file)
2155     return file;
2156 
2157   if (utf8)
2158     {
2159       fileUTF8 = g_filename_from_utf8(file, -1, NULL, NULL, NULL);
2160       g_free(file);
2161       return fileUTF8;
2162     }
2163   else
2164     return file;
2165 }
2166 /**
2167  * visu_config_file_getDefaultFilename:
2168  * @kind: an integer identifier.
2169  *
2170  * This methods is used to get the filename used for different
2171  * config files.
2172  *
2173  * Returns: the filename of config file. The returned *gchar is
2174  *          owned by V_Sim and should not be freed or modified.
2175  */
visu_config_file_getDefaultFilename(VisuConfigFileKind kind)2176 const gchar* visu_config_file_getDefaultFilename(VisuConfigFileKind kind)
2177 {
2178   if (kind == VISU_CONFIG_FILE_KIND_RESOURCE)
2179     return RESOURCES_FILENAMES[0];
2180   else
2181     return PARAMETERS_FILENAMES[0];
2182 }
2183 /**
2184  * visu_config_file_getPathList:
2185  * @conf: a #VisuConfigFile object ;
2186  *
2187  * V_Sim stores a list of paths where to look for resources or parameters
2188  * files, this method is used to get these lists.
2189  *
2190  * Returns: (transfer none) (element-type filename): the list of the
2191  * parameters or resources paths. This list is read-only.
2192  */
visu_config_file_getPathList(VisuConfigFile * conf)2193 GList* visu_config_file_getPathList(VisuConfigFile *conf)
2194 {
2195   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), (GList*)0);
2196 
2197   return conf->priv->paths;
2198 }
_addPath(VisuConfigFile * conf,char * dir)2199 static void _addPath(VisuConfigFile *conf, char* dir)
2200 {
2201   g_return_if_fail(VISU_IS_CONFIG_FILE(conf));
2202   g_return_if_fail(dir && dir[0]);
2203 
2204   if (g_list_find_custom(conf->priv->paths, (gconstpointer)dir,
2205                          compareStringsInGList))
2206     return;
2207 
2208   DBG_fprintf(stderr, "Visu ConfigFile: add a new resource directory"
2209               " to the path :\n '%s'\n", dir);
2210   conf->priv->paths = g_list_prepend(conf->priv->paths, (gpointer)dir);
2211 }
2212 
2213 /**
2214  * visu_config_file_exportToXML:
2215  * @conf: a #VisuConfigFile object ;
2216  * @filename: a string in the encoding of the file system ;
2217  * @error: a location to store an error.
2218  *
2219  * Export all the registered entries for resources or parameters to an
2220  * XML file.
2221  *
2222  * Returns: TRUE if the file is written with success.
2223  */
visu_config_file_exportToXML(VisuConfigFile * conf,const gchar * filename,GError ** error)2224 gboolean visu_config_file_exportToXML(VisuConfigFile *conf, const gchar *filename, GError **error)
2225 {
2226   GString *str;
2227   GList *tmpLst, *lst;
2228   VisuConfigFileEntry *entry;
2229   gboolean status;
2230   gchar *desc;
2231 
2232   g_return_val_if_fail(filename && *filename, FALSE);
2233   g_return_val_if_fail(VISU_IS_CONFIG_FILE(conf), FALSE);
2234 
2235   str = g_string_new("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
2236   if (conf->priv->kind == VISU_CONFIG_FILE_KIND_PARAMETER)
2237     g_string_append_printf(str, "<configFile kind=\"parameters\">\n");
2238   else
2239     g_string_append_printf(str, "<configFile kind=\"resources\">\n");
2240   lst = visu_config_file_getEntries(conf);
2241   for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst))
2242     {
2243       entry = (VisuConfigFileEntry*)tmpLst->data;
2244       if (entry->tag)
2245 	g_string_append_printf(str, "  <entry name=\"%s\" tag=\"%s\" "
2246 			       "version=\"%f3.1\">\n",
2247 			       entry->key, entry->tag, entry->version);
2248       else
2249 	g_string_append_printf(str, "  <entry name=\"%s\" version=\"%3.1f\">\n",
2250 			       entry->key, entry->version);
2251       desc = g_markup_escape_text(entry->description, -1);
2252       g_string_append_printf(str, "    <description>%s</description>\n", desc);
2253       g_free(desc);
2254       if (entry->newKey)
2255 	g_string_append_printf(str, "    <obsolete replacedBy=\"%s\" />\n",
2256 			       entry->newKey);
2257       g_string_append_printf(str, "  </entry>\n");
2258     }
2259   g_string_append_printf(str, "</configFile>\n");
2260   g_list_free(lst);
2261 
2262   status = g_file_set_contents(filename, str->str, -1, error);
2263   g_string_free(str, TRUE);
2264   return status;
2265 }
2266 
readResourcesPaths(VisuConfigFileEntry * entry _U_,gchar ** lines,int nbLines,int position _U_,GError ** error _U_)2267 static gboolean readResourcesPaths(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position _U_,
2268 				   GError **error _U_)
2269 {
2270   int i;
2271   gchar **tokens;
2272   gchar *key;
2273 
2274   g_return_val_if_fail(nbLines == 1, FALSE);
2275 
2276   tokens = g_strsplit_set(lines[0], ":", -1);
2277   for (i = 0; tokens[i]; i++)
2278     {
2279       key = g_strdup(tokens[i]);
2280       key = g_strstrip(key);
2281       if (key[0])
2282         _addPath(VISU_CONFIG_FILE_RESOURCE, key);
2283     }
2284   g_strfreev(tokens);
2285   return TRUE;
2286 }
exportResourcesPaths(GString * data,VisuData * dataObj _U_)2287 static void exportResourcesPaths(GString *data, VisuData *dataObj _U_)
2288 {
2289   GList *pnt;
2290 
2291   g_string_append_printf(data, "# %s\n", DESC_RESOURCES_PATH);
2292   g_string_append_printf(data, "%s: ", FLAG_RESOURCES_PATH);
2293   pnt = visu_config_file_getPathList(resources);
2294   while(pnt)
2295     {
2296       /* We cancel the first and the last because it's the current working dir
2297 	 and the install dir. */
2298       if (pnt->prev && pnt->next && pnt->next->next)
2299 	g_string_append_printf(data, "%s", (char*)pnt->data);
2300       if (pnt->prev && pnt->next && pnt->next->next && pnt->next->next->next)
2301 	g_string_append_printf(data, ":");
2302       pnt = g_list_next(pnt);
2303     }
2304   g_string_append_printf(data, "\n\n");
2305 }
2306 
2307 /* Specific routines. */
_readTokens(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position _U_,GError ** error _U_)2308 static gboolean _readTokens(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2309                             int position _U_, GError **error _U_)
2310 {
2311   g_return_val_if_fail(nbLines == 1 && !entry->tokens, FALSE);
2312 
2313   /* Tokenize the line of values. */
2314   entry->tokens = g_strsplit_set(g_strchug(lines[0]), " \n", TOOL_MAX_LINE_LENGTH);
2315   entry->iToken = 0;
2316   return TRUE;
2317 }
_readBooleanv(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2318 static gboolean _readBooleanv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2319                               int position, GError **error)
2320 {
2321   gboolean *vals;
2322 
2323   g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE);
2324   vals = g_malloc(sizeof(gboolean) * entry->nValues);
2325 
2326   if (!tool_config_file_readBoolean(lines[0], position, vals, entry->nValues, error))
2327     {
2328       g_free(vals);
2329       return FALSE;
2330     }
2331 
2332   memcpy(entry->storage, vals, sizeof(gboolean) * entry->nValues);
2333   g_free(vals);
2334 
2335   return TRUE;
2336 }
_readEnum(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2337 static gboolean _readEnum(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2338                           int position, GError **error)
2339 {
2340   guint val;
2341 
2342   g_return_val_if_fail(nbLines == 1 && entry->storage, FALSE);
2343 
2344   if (!entry->toEnum(g_strstrip(lines[0]), &val))
2345     {
2346       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
2347 			   _("Parse error at line %d: '%s' is not a valid"
2348                              " value for %s markup.\n"), position, lines[0], entry->key);
2349       return FALSE;
2350     }
2351   *(guint*)entry->storage = val;
2352 
2353   return TRUE;
2354 }
_readString(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2355 static gboolean _readString(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2356                             int position, GError **error)
2357 {
2358   gchar **str;
2359 
2360   g_return_val_if_fail(nbLines == 1 && entry->storage, FALSE);
2361 
2362   lines[0] = g_strstrip(lines[0]);
2363 
2364   if (!lines[0][0])
2365     {
2366       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
2367 			   _("Parse error at line %d: 1 string value must appear"
2368 			     " after the %s markup.\n"), position, entry->key);
2369       return FALSE;
2370     }
2371   str = (gchar**)entry->storage;
2372   g_free(*str);
2373   *str = g_strdup(lines[0]);
2374 
2375   return TRUE;
2376 }
_readIntv(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2377 static gboolean _readIntv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2378                           int position, GError **error)
2379 {
2380   guint i;
2381   int *vals;
2382 
2383   g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE);
2384   vals = g_malloc(sizeof(int) * entry->nValues);
2385 
2386   if (!tool_config_file_readInteger(lines[0], position, vals, entry->nValues, error))
2387     {
2388       g_free(vals);
2389       return FALSE;
2390     }
2391 
2392   for (i = 0; i < entry->nValues; i++)
2393     if (tool_config_file_clampInt(vals + i, vals[i], entry->range.i[0], entry->range.i[1]))
2394       {
2395         *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
2396                              _("Parse error at line %d: %d integer values"
2397                                "(%d <= v <= %d) must appear after the %s markup.\n"),
2398                              position, entry->nValues, entry->range.i[0], entry->range.i[1],
2399                              entry->key);
2400         g_free(vals);
2401         return FALSE;
2402       }
2403   memcpy(entry->storage, vals, sizeof(int) * entry->nValues);
2404   g_free(vals);
2405 
2406   return TRUE;
2407 }
_readFloatv(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2408 static gboolean _readFloatv(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2409                             int position, GError **error)
2410 {
2411   guint i;
2412   float *vals;
2413 
2414   g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE);
2415   vals = g_malloc(sizeof(float) * entry->nValues);
2416 
2417   if (!tool_config_file_readFloat(lines[0], position, vals, entry->nValues, error))
2418     {
2419       g_free(vals);
2420       return FALSE;
2421     }
2422 
2423   for (i = 0; i < entry->nValues; i++)
2424     if (tool_config_file_clampFloat(vals + i, vals[i], entry->range.f[0], entry->range.f[1]))
2425       {
2426         *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
2427                              _("Parse error at line %d: %d floating points "
2428                                "(%g <= v <= %g) must appear after the %s markup."
2429                                " Read line was '%s'.\n"),
2430                              position, entry->nValues, entry->range.f[0], entry->range.f[1],
2431                              entry->key, lines[0]);
2432         g_free(vals);
2433         return FALSE;
2434       }
2435   memcpy(entry->storage, vals, sizeof(float) * entry->nValues);
2436   g_free(vals);
2437 
2438   return TRUE;
2439 }
_readStipplev(VisuConfigFileEntry * entry,gchar ** lines,int nbLines,int position,GError ** error)2440 static gboolean _readStipplev(VisuConfigFileEntry *entry, gchar **lines, int nbLines,
2441                               int position, GError **error)
2442 {
2443   guint i;
2444   gint *vals;
2445   guint16 *storage;
2446 
2447   g_return_val_if_fail(nbLines == 1 && entry->storage && entry->nValues > 0, FALSE);
2448   vals = g_malloc(sizeof(float) * entry->nValues);
2449 
2450   if (!tool_config_file_readInteger(lines[0], position, vals, entry->nValues, error))
2451     {
2452       g_free(vals);
2453       return FALSE;
2454     }
2455 
2456   storage = (guint16*)entry->storage;
2457   for (i = 0; i < entry->nValues; i++)
2458     storage[i] = (guint16)vals[i];
2459   g_free(vals);
2460 
2461   return TRUE;
2462 }
2463