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 #include "visu_tools.h"
45 
46 #include <string.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h> /* For the access markers R_OK, W_OK ... */
50 #include <math.h>
51 
52 /**
53  * tool_getValidPath:
54  * @pathList: (element-type filename): a pointer to a GList with all the possible path,
55  * @filenames: (array zero-terminated=1) (element-type filename): an array of strings,
56  * @accessMode: a value from R_OK, W_OK and X_OK as described in unistd.h.
57  *
58  * @pathList contains a list of directories (first is most prefered)
59  * and fileName is the file name which one likes have informations on. This routine
60  * look for the first directory where fileName can be writen or read (depending
61  * on accessMode parameter). The pointer to the GList indicates at the end the
62  * first valid entry in the GList.
63  *
64  * Returns: (transfer full): the first valid complete path (from
65  * @pathList plus an entry of @filenames) if one can be found depnding
66  * on @accessMode or NULL if none found. Free it with g_free() after
67  * use.
68  */
tool_getValidPath(GList ** pathList,const char ** filenames,int accessMode)69 gchar* tool_getValidPath(GList **pathList, const char **filenames, int accessMode)
70 {
71   gchar *validPath;
72   int fileOk;
73   guint i;
74 
75   g_return_val_if_fail(pathList && filenames, (gchar*)0);
76 
77   DBG_fprintf(stderr, "Visu Tools : test access (%d) from list of %d elements.\n",
78               accessMode, g_list_length(*pathList));
79   validPath = (char*)0;
80   /* look for a directory to save or read a file. */
81   fileOk = 0;
82   while (*pathList && !fileOk)
83     {
84       for (i = 0; filenames[i]; i++)
85         {
86           validPath = g_build_filename((gchar*)(*pathList)->data, filenames[i], NULL);
87           DBG_fprintf(stderr, "Visu Tools : test access (%d) for '%s' ... ",
88                       accessMode, validPath);
89           fileOk = !access((char*)validPath, accessMode); /* return 0 if success */
90           if (fileOk)
91             break;
92 
93           /* if access mode is write access and the file does not already exist :
94              we test if the directory has written permitions. */
95           if ( accessMode == W_OK && !g_file_test(validPath, G_FILE_TEST_EXISTS) )
96             fileOk = !access((char*)(*pathList)->data, accessMode);
97 
98           if (fileOk)
99             break;
100 
101           DBG_fprintf(stderr, " failed.\n");
102           g_free(validPath);
103         }
104       if (!fileOk)
105         *pathList = g_list_next(*pathList);
106     }
107   if (fileOk)
108     {
109       DBG_fprintf(stderr, " OK.\n");
110       return validPath;
111     }
112   else
113     return (gchar*)0;
114 }
115 
116 /**
117  * tool_modulo_float:
118  * @a: a float ;
119  * @b: an int.
120  *
121  * This function is just like a%b except it works with a float @a argument.
122  * @a can be negative, but the return value of the function is always positive.
123  *
124  * Returns: the new float value after the modulo.
125 */
tool_modulo_float(float a,int b)126 float tool_modulo_float(float a, int b) {
127   float fb = (float)b;
128   while(a < fb) a += fb;
129   while(a >= fb) a -= fb;
130   return a;
131 }
132 
133 /**
134  * tool_path_normalize:
135  * @path: a string, NULL terminated.
136  *
137  * This function normalizes the path, i.e. it removes all . and .. It should
138  * work also on Windows. It must take an absolute path as argument, if not it is converted
139  * assuming the current working directory.
140  *
141  * Returns: a newly created string.
142  */
tool_path_normalize(const gchar * path)143 gchar* tool_path_normalize(const gchar* path)
144 {
145 #if SYSTEM_X11 == 1
146 #define FILE_SYSTEM_SEP "/"
147 #endif
148 #if SYSTEM_WIN32 == 1
149 #define FILE_SYSTEM_SEP "\\"
150 #endif
151   gchar **tokens;
152   int i;
153   GString *normPath;
154   GList *lst, *tmplst;
155   gchar *allPath, *dir;
156 
157   if (!path)
158     return (gchar*)0;
159 
160   if (!g_path_is_absolute(path))
161     {
162       dir = g_get_current_dir();
163       allPath = g_build_filename(dir, path, NULL);
164       g_free(dir);
165     }
166   else
167     allPath = g_strdup(path);
168 
169   tokens = g_strsplit(allPath, FILE_SYSTEM_SEP, -1);
170 
171   normPath = g_string_new("");
172 
173   lst = (GList*)0;
174   for (i = 0; tokens[i]; i++)
175     {
176       /* If tokens[i] == . or is empty (because of //), we ignore. */
177 	if (!strcmp(tokens[i], "."))
178 	  continue;
179       if (!tokens[i][0])
180 	continue;
181       /* If token[i] == .. then we pop one element from lst. */
182       if (!strcmp(tokens[i], ".."))
183 	{
184 	  lst = g_list_delete_link(lst, lst);
185 	  continue;
186 	}
187       /* Token[i] is a valid chain, then we prepend it to the list. */
188       lst = g_list_prepend(lst, tokens[i]);
189     }
190   /* Write the lst to the string. */
191   for (tmplst = lst; tmplst; tmplst = g_list_next(tmplst))
192     {
193       g_string_prepend(normPath, (gchar*)tmplst->data);
194       g_string_prepend(normPath, FILE_SYSTEM_SEP);
195     }
196   g_list_free(lst);
197 #if SYSTEM_WIN32 == 1
198   g_string_erase(normPath, 0,1);
199 #endif
200   g_strfreev(tokens);
201   g_free(allPath);
202   if (!normPath->str[0])
203     g_string_append(normPath, FILE_SYSTEM_SEP);
204   DBG_fprintf(stderr, "Visu Tools : normalizing path, from '%s' to '%s'.\n",
205 	      path, normPath->str);
206   return g_string_free(normPath, FALSE);
207 }
208 
209 #if GLIB_MINOR_VERSION < 5
210 /**
211  * g_file_set_contents:
212  * @fileName: a string ;
213  * @str: a string ;
214  * @len: a length or -1 ;
215  * @error: a location for an error.
216  *
217  * Compiled only if Glib is lower than 2.5.
218  *
219  * Returns: TRUE on success.
220  */
g_file_set_contents(const gchar * fileName,const gchar * str,gsize len _U_,GError ** error _U_)221 gboolean g_file_set_contents(const gchar *fileName, const gchar *str,
222 			     gsize len _U_, GError **error _U_)
223 {
224   FILE *f;
225 
226   f = fopen(fileName, "w");
227   if (!f)
228     return FALSE;
229   if (fwrite(str, strlen(str), 1, f) != strlen(str))
230     return FALSE;
231   fclose(f);
232 
233   return TRUE;
234 }
235 #endif
236 #if GLIB_MINOR_VERSION < 27
237 /**
238  * g_list_free_full:
239  * @list: a pointer to a #GList
240  * @free_func: the function to be called to free each element's data
241  *
242  * Convenience method, which frees all the memory used by a #GList, and
243  * calls the specified destroy function on every element's data.
244  *
245  * Compiled only if Glib is lower than 2.27.
246  */
247 void
g_list_free_full(GList * list,GDestroyNotify free_func)248 g_list_free_full (GList          *list,
249 		  GDestroyNotify  free_func)
250 {
251   g_list_foreach (list, (GFunc) free_func, NULL);
252   g_list_free (list);
253 }
254 #endif
255 
tagLookup(const gchar * tag,const gchar * buffer)256 static gchar* tagLookup(const gchar *tag, const gchar *buffer)
257 {
258   char *ptTag, *ptStart, *ptEnd;
259 
260   ptTag = strstr(buffer, tag);
261   if (!ptTag)
262     return (gchar*)0;
263 
264   /* We check that tag was not in a commentary section. */
265   ptStart = g_strrstr_len(buffer, (gssize)(ptTag - buffer), "<!--");
266   if (!ptStart)
267     return ptTag;
268   ptEnd = g_strstr_len(ptStart, (gssize)(ptTag - ptStart), "-->");
269   if (ptEnd)
270     return ptTag;
271   return tagLookup(tag, ptTag + strlen(tag));
272 }
273 /**
274  * tool_XML_substitute:
275  * @output: a GString to store the substitution ;
276  * @filename: the file to read the data from ;
277  * @tag: the tag to substitute ;
278  * @error: a location to store possible errors.
279  *
280  * Read @filename (must be XML file) and remove the @tag zone from
281  * it. At that place, it puts the contain of @output.
282  *
283  * Returns: TRUE if no error occured.
284  */
tool_XML_substitute(GString * output,const gchar * filename,const gchar * tag,GError ** error)285 gboolean tool_XML_substitute(GString *output, const gchar *filename,
286 				 const gchar *tag, GError **error)
287 {
288   gchar *contents, *ptStart, *ptStop;
289   gchar *tgStart, *tgEnd;
290   gboolean valid;
291 
292     /* If file does exist, we read it and replace only the tag part. */
293   contents = (gchar*)0;
294   ptStart = (gchar*)0;
295   if (g_file_test(filename, G_FILE_TEST_EXISTS))
296     {
297       valid = g_file_get_contents(filename, &contents, (gsize*)0, error);
298       if (!valid)
299 	return FALSE;
300 
301       tgStart = g_strdup_printf("<%s", tag);
302 
303       ptStart = tagLookup(tgStart, contents);
304       if (ptStart)
305 	g_string_prepend_len(output, contents, (gssize)(ptStart - contents));
306       else
307 	{
308           g_string_prepend(output, "  ");
309 	  ptStop = tagLookup("</v_sim>", contents);
310 	  if (ptStop)
311 	    g_string_prepend_len(output, contents, (gssize)(ptStop - contents));
312 	  else
313 	    {
314 	      ptStop = tagLookup("<v_sim>", contents);
315 	      if (ptStop)
316 		g_string_prepend(output, contents);
317 	      else
318 		{
319 		  g_string_prepend(output, contents);
320 		  g_string_prepend(output, "<?xml version=\"1.0\""
321 				   " encoding=\"utf-8\"?>\n<v_sim>");
322 		}
323 	    }
324 	}
325 
326       g_free(tgStart);
327     }
328   else
329     g_string_prepend(output, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<v_sim>\n  ");
330 
331   /* If file does exist, we add the remaining parts. */
332   if (contents && ptStart)
333     {
334       tgEnd = g_strdup_printf("</%s>", tag);
335 
336       ptStop = tagLookup(tgEnd, ptStart);
337       if (ptStop)
338 	g_string_append(output, ptStop + strlen(tgEnd));
339       else
340 	g_string_append(output, "\n</v_sim>");
341 
342       g_free(tgEnd);
343     }
344   else
345     g_string_append(output, "</v_sim>\n");
346 
347   if (contents)
348     g_free(contents);
349 
350   return TRUE;
351 }
352