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