1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-session.c
4 * Copyright (c) 2005 Naba Kumar <naba@gnome.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:anjuta-session
23 * @short_description: Store local user settings
24 * @see_also:
25 * @stability: Unstable
26 * @include: libanjuta/anjuta-session.h
27 *
28 * A anjuta session contains local user settings, by example the list of files
29 * open in one project. These settings are stored in
30 * a .ini-like config file in a directory named session. Other libraries can
31 * store their own settings in another format in the same directory.
32 */
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "anjuta-session.h"
38 #include "anjuta-utils.h"
39
40 struct _AnjutaSessionPriv {
41 gchar *dir_path;
42 GKeyFile *key_file;
43 };
44
45 static gpointer *parent_class = NULL;
46
47 static void
anjuta_session_finalize(GObject * object)48 anjuta_session_finalize (GObject *object)
49 {
50 AnjutaSession *cobj;
51 cobj = ANJUTA_SESSION (object);
52
53 g_free (cobj->priv->dir_path);
54 g_key_file_free (cobj->priv->key_file);
55 g_free (cobj->priv);
56
57 G_OBJECT_CLASS(parent_class)->finalize(object);
58 }
59
60 static void
anjuta_session_class_init(AnjutaSessionClass * klass)61 anjuta_session_class_init (AnjutaSessionClass *klass)
62 {
63 GObjectClass *object_class = G_OBJECT_CLASS (klass);
64
65 parent_class = g_type_class_peek_parent (klass);
66 object_class->finalize = anjuta_session_finalize;
67 }
68
69 static void
anjuta_session_instance_init(AnjutaSession * obj)70 anjuta_session_instance_init (AnjutaSession *obj)
71 {
72 obj->priv = g_new0 (AnjutaSessionPriv, 1);
73 obj->priv->dir_path = NULL;
74 }
75
76 /**
77 * anjuta_session_new:
78 * @session_directory: Directory where session is loaded from/saved to.
79 *
80 * Created a new session object. @session_directory is the directory
81 * where session information will be stored or loaded in case of existing
82 * session.
83 *
84 * Returns: an #AnjutaSession Object
85 */
86 AnjutaSession*
anjuta_session_new(const gchar * session_directory)87 anjuta_session_new (const gchar *session_directory)
88 {
89 AnjutaSession *obj;
90 gchar *filename;
91
92 g_return_val_if_fail (session_directory != NULL, NULL);
93 g_return_val_if_fail (g_path_is_absolute (session_directory), NULL);
94
95 obj = ANJUTA_SESSION (g_object_new (ANJUTA_TYPE_SESSION, NULL));
96 obj->priv->dir_path = g_strdup (session_directory);
97
98 obj->priv->key_file = g_key_file_new ();
99
100 filename = anjuta_session_get_session_filename (obj);
101 g_key_file_load_from_file (obj->priv->key_file, filename,
102 G_KEY_FILE_NONE, NULL);
103 g_free (filename);
104
105 return obj;
106 }
107
ANJUTA_TYPE_BOILERPLATE(AnjutaSession,anjuta_session,G_TYPE_OBJECT)108 ANJUTA_TYPE_BOILERPLATE (AnjutaSession, anjuta_session, G_TYPE_OBJECT)
109
110 /**
111 * anjuta_session_get_session_directory:
112 * @session: an #AnjutaSession object
113 *
114 * Returns the directory corresponding to this session object.
115 *
116 * Returns: session directory
117 */
118 const gchar*
119 anjuta_session_get_session_directory (AnjutaSession *session)
120 {
121 return session->priv->dir_path;
122 }
123
124 /**
125 * anjuta_session_get_session_filename:
126 * @session: an #AnjutaSession object
127 *
128 * Gets the session filename corresponding to this session object.
129 *
130 * Returns: session (absolute) filename
131 */
132 gchar*
anjuta_session_get_session_filename(AnjutaSession * session)133 anjuta_session_get_session_filename (AnjutaSession *session)
134 {
135 g_return_val_if_fail (ANJUTA_IS_SESSION (session), NULL);
136
137 return g_build_filename (session->priv->dir_path,
138 "anjuta.session", NULL);
139 }
140
141 /**
142 * anjuta_session_sync:
143 * @session: an #AnjutaSession object
144 *
145 * Synchronizes session object with session file
146 */
147 void
anjuta_session_sync(AnjutaSession * session)148 anjuta_session_sync (AnjutaSession *session)
149 {
150 gchar *filename, *data;
151
152 g_return_if_fail (ANJUTA_IS_SESSION (session));
153
154 filename = anjuta_session_get_session_filename (session);
155 data = g_key_file_to_data (session->priv->key_file, NULL, NULL);
156 g_file_set_contents (filename, data, -1, NULL);
157
158 g_free (filename);
159 g_free (data);
160 }
161
162 /**
163 * anjuta_session_clear:
164 * @session: an #AnjutaSession object
165 *
166 * Clears the session.
167 */
168 void
anjuta_session_clear(AnjutaSession * session)169 anjuta_session_clear (AnjutaSession *session)
170 {
171 gchar *cmd;
172 gchar *quoted;
173
174 g_return_if_fail (ANJUTA_IS_SESSION (session));
175
176 g_key_file_free (session->priv->key_file);
177 session->priv->key_file = g_key_file_new ();
178
179 anjuta_session_sync (session);
180
181 quoted = g_shell_quote (session->priv->dir_path);
182 cmd = g_strconcat ("rm -fr ", quoted, NULL);
183 system (cmd);
184 g_free (cmd);
185
186 cmd = g_strconcat ("mkdir -p ", quoted, NULL);
187 system (cmd);
188 g_free (cmd);
189 g_free (quoted);
190 }
191
192 /**
193 * anjuta_session_clear_section:
194 * @session: an #AnjutaSession object.
195 * @section: Section to clear.
196 *
197 * Clears the given section in session object.
198 */
199 void
anjuta_session_clear_section(AnjutaSession * session,const gchar * section)200 anjuta_session_clear_section (AnjutaSession *session,
201 const gchar *section)
202 {
203 g_return_if_fail (ANJUTA_IS_SESSION (session));
204 g_return_if_fail (section != NULL);
205
206 g_key_file_remove_group (session->priv->key_file, section, NULL);
207 }
208
209 /**
210 * anjuta_session_set_int:
211 * @session: an #AnjutaSession object
212 * @section: Section.
213 * @key: Key name.
214 * @value: Key value
215 *
216 * Set an integer @value to @key in given @section.
217 */
218 void
anjuta_session_set_int(AnjutaSession * session,const gchar * section,const gchar * key,gint value)219 anjuta_session_set_int (AnjutaSession *session, const gchar *section,
220 const gchar *key, gint value)
221 {
222 g_return_if_fail (ANJUTA_IS_SESSION (session));
223 g_return_if_fail (section != NULL);
224 g_return_if_fail (key != NULL);
225
226 if (!value)
227 {
228 g_key_file_remove_key (session->priv->key_file, section, key, NULL);
229 return;
230 }
231
232 g_key_file_set_integer (session->priv->key_file, section, key, value);
233 }
234
235 /**
236 * anjuta_session_set_float:
237 * @session: an #AnjutaSession object
238 * @section: Section.
239 * @key: Key name.
240 * @value: Key value
241 *
242 * Set a float @value to @key in given @section.
243 */
244 void
anjuta_session_set_float(AnjutaSession * session,const gchar * section,const gchar * key,gfloat value)245 anjuta_session_set_float (AnjutaSession *session, const gchar *section,
246 const gchar *key, gfloat value)
247 {
248 g_return_if_fail (ANJUTA_IS_SESSION (session));
249 g_return_if_fail (section != NULL);
250 g_return_if_fail (key != NULL);
251
252 if (!value)
253 {
254 g_key_file_remove_key (session->priv->key_file, section, key, NULL);
255 return;
256 }
257
258 g_key_file_set_double (session->priv->key_file, section, key, value);
259 }
260
261 /**
262 * anjuta_session_set_string:
263 * @session: an #AnjutaSession object
264 * @section: Section.
265 * @key: Key name.
266 * @value: Key value
267 *
268 * Set a string @value to @key in given @section.
269 */
270 void
anjuta_session_set_string(AnjutaSession * session,const gchar * section,const gchar * key,const gchar * value)271 anjuta_session_set_string (AnjutaSession *session, const gchar *section,
272 const gchar *key, const gchar *value)
273 {
274 g_return_if_fail (ANJUTA_IS_SESSION (session));
275 g_return_if_fail (section != NULL);
276 g_return_if_fail (key != NULL);
277
278 if (!value)
279 {
280 g_key_file_remove_key (session->priv->key_file, section, key, NULL);
281 return;
282 }
283
284 g_key_file_set_string (session->priv->key_file, section, key, value);
285 }
286
287 /**
288 * anjuta_session_set_string_list:
289 * @session: an #AnjutaSession object
290 * @section: Section.
291 * @key: Key name.
292 * @value: Key value
293 *
294 * Set a list of strings @value to @key in given @section.
295 */
296 void
anjuta_session_set_string_list(AnjutaSession * session,const gchar * section,const gchar * key,GList * value)297 anjuta_session_set_string_list (AnjutaSession *session,
298 const gchar *section,
299 const gchar *key, GList *value)
300 {
301 gchar *value_str;
302 GString *str;
303 GList *node;
304 gboolean first_item = TRUE;
305
306 g_return_if_fail (ANJUTA_IS_SESSION (session));
307 g_return_if_fail (section != NULL);
308 g_return_if_fail (key != NULL);
309
310 if (!value)
311 {
312 g_key_file_remove_key (session->priv->key_file, section, key, NULL);
313 return;
314 }
315
316 str = g_string_new ("");
317 node = value;
318 while (node)
319 {
320 /* Keep empty string */
321 if (node->data != NULL)
322 {
323 if (first_item)
324 first_item = FALSE;
325 else
326 g_string_append (str, "%%%");
327 g_string_append (str, node->data);
328 }
329 node = g_list_next (node);
330 }
331
332 value_str = g_string_free (str, FALSE);
333 g_key_file_set_string (session->priv->key_file, section, key, value_str);
334
335 g_free (value_str);
336 }
337
338 /**
339 * anjuta_session_get_int:
340 * @session: an #AnjutaSession object
341 * @section: Section.
342 * @key: Key name.
343 *
344 * Get an integer @value of @key in given @section.
345 *
346 * Returns: Key value
347 */
348 gint
anjuta_session_get_int(AnjutaSession * session,const gchar * section,const gchar * key)349 anjuta_session_get_int (AnjutaSession *session, const gchar *section,
350 const gchar *key)
351 {
352 gint value;
353
354 g_return_val_if_fail (ANJUTA_IS_SESSION (session), 0);
355 g_return_val_if_fail (section != NULL, 0);
356 g_return_val_if_fail (key != NULL, 0);
357
358 value = g_key_file_get_integer (session->priv->key_file, section, key, NULL);
359
360 return value;
361 }
362
363 /**
364 * anjuta_session_get_float:
365 * @session: an #AnjutaSession object
366 * @section: Section.
367 * @key: Key name.
368 *
369 * Get a float @value of @key in given @section.
370 *
371 * Returns: Key value
372 */
373 gfloat
anjuta_session_get_float(AnjutaSession * session,const gchar * section,const gchar * key)374 anjuta_session_get_float (AnjutaSession *session, const gchar *section,
375 const gchar *key)
376 {
377 gfloat value;
378
379 g_return_val_if_fail (ANJUTA_IS_SESSION (session), 0);
380 g_return_val_if_fail (section != NULL, 0);
381 g_return_val_if_fail (key != NULL, 0);
382
383 value = (float)g_key_file_get_double (session->priv->key_file, section, key, NULL);
384
385 return value;
386 }
387
388 /**
389 * anjuta_session_get_string:
390 * @session: an #AnjutaSession object
391 * @section: Section.
392 * @key: Key name.
393 *
394 * Get a string @value of @key in given @section.
395 *
396 * Returns: Key value
397 */
398 gchar*
anjuta_session_get_string(AnjutaSession * session,const gchar * section,const gchar * key)399 anjuta_session_get_string (AnjutaSession *session, const gchar *section,
400 const gchar *key)
401 {
402 gchar *value;
403
404 g_return_val_if_fail (ANJUTA_IS_SESSION (session), NULL);
405 g_return_val_if_fail (section != NULL, NULL);
406 g_return_val_if_fail (key != NULL, NULL);
407
408 value = g_key_file_get_string (session->priv->key_file, section, key, NULL);
409
410 return value;
411 }
412
413 /**
414 * anjuta_session_get_string_list:
415 * @session: an #AnjutaSession object
416 * @section: Section.
417 * @key: Key name.
418 *
419 * Get a list of strings @value of @key in given @section.
420 *
421 * Returns: Key value
422 */
423 GList*
anjuta_session_get_string_list(AnjutaSession * session,const gchar * section,const gchar * key)424 anjuta_session_get_string_list (AnjutaSession *session,
425 const gchar *section,
426 const gchar *key)
427 {
428 gchar *val, **str, **ptr;
429 GList *value;
430
431 g_return_val_if_fail (ANJUTA_IS_SESSION (session), NULL);
432 g_return_val_if_fail (section != NULL, NULL);
433 g_return_val_if_fail (key != NULL, NULL);
434
435 val = g_key_file_get_string (session->priv->key_file, section, key, NULL);
436
437
438 value = NULL;
439 if (val)
440 {
441 str = g_strsplit (val, "%%%", -1);
442 if (str)
443 {
444 ptr = str;
445 while (*ptr)
446 {
447 /* Keep empty string */
448 value = g_list_prepend (value, g_strdup (*ptr));
449 ptr++;
450 }
451 g_strfreev (str);
452 }
453 g_free (val);
454 }
455
456 return g_list_reverse (value);
457 }
458
459
460 /**
461 * anjuta_session_get_relative_uri_from_file:
462 * @session: an #AnjutaSession object
463 * @file: a GFile
464 * @fragment: an optional fragment
465 *
466 * Return an URI relative to the session directory file with an optional
467 * fragment.
468 * It is useful to keep only relative file paths in a session file to be able
469 * to copy the whole project without breaking references.
470 *
471 * Returns: (transfer full): A string that has to be freed with g_free().
472 */
473 gchar *
anjuta_session_get_relative_uri_from_file(AnjutaSession * session,GFile * file,const gchar * fragment)474 anjuta_session_get_relative_uri_from_file (AnjutaSession *session,
475 GFile *file,
476 const gchar *fragment)
477 {
478 GFile *parent;
479 gchar *uri;
480 gint level;
481
482 parent = g_file_new_for_path (session->priv->dir_path);
483 for (level = 0; (parent != NULL) && !g_file_equal (file, parent) && !g_file_has_prefix (file, parent); level++)
484 {
485 GFile *next = g_file_get_parent (parent);
486 g_object_unref (parent);
487 parent = next;
488 }
489
490 if (parent == NULL)
491 {
492 uri = g_file_get_uri (file);
493 }
494 else
495 {
496 gchar *path;
497
498 if (g_file_equal (file, parent))
499 {
500 uri = g_strdup(".");
501 }
502 else
503 {
504 path = g_file_get_relative_path (parent, file);
505 uri = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
506 g_free (path);
507 }
508 if (level != 0)
509 {
510 gsize len;
511 gchar *buffer;
512 gchar *ptr;
513
514 len = strlen (uri);
515 buffer = g_new (gchar, len + level * 3 + 1);
516 for (ptr = buffer; level; level--)
517 {
518 memcpy (ptr, ".." G_DIR_SEPARATOR_S, 3);
519 ptr += 3;
520 }
521 memcpy (ptr, uri, len + 1);
522 g_free (uri);
523
524 uri = buffer;
525 }
526 }
527
528 if (fragment != NULL)
529 {
530 gchar *with_fragment;
531
532 with_fragment = g_strconcat (uri, "#", fragment, NULL);
533 g_free (uri);
534 uri = with_fragment;
535 }
536
537 return uri;
538 }
539
540
541 /**
542 * anjuta_session_get_file_from_relative_uri:
543 * @session: an #AnjutaSession object
544 * @uri: a relative URI from a key
545 * @fragment: (allow-none): fragment part of the URI if existing, can be %NULL
546 *
547 * Return a GFile corresponding to the URI and and optional fragment,
548 * normally read from a session key.
549 * The path is expected to be relative to the session directory but it works
550 * with an absolute URI, in this case it returns the same file than
551 * g_file_new_for_uri.
552 * It is useful to keep only relative file paths in a session file to be able
553 * to copy the whole project without breaking references.
554 *
555 * Returns: (transfer full): A new GFile that has to be freed with g_object_unref().
556 */
557 GFile*
anjuta_session_get_file_from_relative_uri(AnjutaSession * session,const gchar * uri,const gchar ** fragment)558 anjuta_session_get_file_from_relative_uri (AnjutaSession *session,
559 const gchar *uri,
560 const gchar **fragment)
561 {
562 GFile *file;
563 gchar *scheme;
564
565 scheme =g_uri_parse_scheme (uri);
566 if (scheme != NULL)
567 {
568 free (scheme);
569 file = g_file_new_for_uri (uri);
570 }
571 else
572 {
573 gchar *parent_uri = g_filename_to_uri (session->priv->dir_path, NULL, NULL);
574 gchar *full_uri;
575
576 full_uri = g_strconcat (parent_uri, G_DIR_SEPARATOR_S, uri, NULL);
577 file = g_file_new_for_uri (full_uri);
578 g_free (full_uri);
579 g_free (parent_uri);
580 }
581 if (fragment != NULL)
582 {
583 *fragment = strchr (uri, '#');
584 if (*fragment != NULL) (*fragment)++;
585 }
586
587 return file;
588 }
589
590