No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-tree-memory.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-tree-memory.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 * Chris Toshok <toshok@ximian.com>
19 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33
34 #include <libxml/parser.h>
35 #include <libxml/xmlmemory.h>
36
37 #include "e-util/e-util.h"
38 #include "libevolution-utils/e-xml-utils.h"
39
40 #include "e-tree-memory.h"
41
42 #define E_TREE_MEMORY_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), E_TYPE_TREE_MEMORY, ETreeMemoryPrivate))
45
46 G_DEFINE_TYPE (ETreeMemory, e_tree_memory, E_TYPE_TREE_MODEL)
47
48 enum {
49 FILL_IN_CHILDREN,
50 LAST_SIGNAL
51 };
52
53 static guint signals[LAST_SIGNAL] = { 0, };
54
55 typedef struct ETreeMemoryPath ETreeMemoryPath;
56
57 struct ETreeMemoryPath {
58 gpointer node_data;
59
60 guint children_computed : 1;
61
62 /* parent/child/sibling pointers */
63 ETreeMemoryPath *parent;
64 ETreeMemoryPath *next_sibling;
65 ETreeMemoryPath *prev_sibling;
66 ETreeMemoryPath *first_child;
67 ETreeMemoryPath *last_child;
68
69 gint num_children;
70 };
71
72 struct _ETreeMemoryPrivate {
73 ETreeMemoryPath *root;
74
75 /* whether nodes are created expanded
76 * or collapsed by default */
77 gboolean expanded_default;
78
79 gint frozen;
80 GFunc destroy_func;
81 gpointer destroy_user_data;
82 };
83
84 /* ETreeMemoryPath functions */
85
86 static inline void
87 check_children (ETreeMemory *memory,
88 ETreePath node)
89 {
90 ETreeMemoryPath *path = node;
91 if (!path->children_computed) {
92 g_signal_emit (memory, signals[FILL_IN_CHILDREN], 0, node);
93 path->children_computed = TRUE;
94 }
95 }
96
97 static gint
98 e_tree_memory_path_depth (ETreeMemoryPath *path)
99 {
100 gint depth = 0;
101
102 g_return_val_if_fail (path != NULL, -1);
103
104 for (path = path->parent; path; path = path->parent)
105 depth++;
106 return depth;
107 }
108
109 static void
110 e_tree_memory_path_insert (ETreeMemoryPath *parent,
111 gint position,
112 ETreeMemoryPath *child)
113 {
114 g_return_if_fail (position <= parent->num_children && position >= -1);
115
116 child->parent = parent;
117
118 if (parent->first_child == NULL)
119 parent->first_child = child;
120
121 if (position == -1 || position == parent->num_children) {
122 child->prev_sibling = parent->last_child;
123 if (parent->last_child)
124 parent->last_child->next_sibling = child;
125 parent->last_child = child;
126 } else {
127 ETreeMemoryPath *c;
128 for (c = parent->first_child; c; c = c->next_sibling) {
129 if (position == 0) {
130 child->next_sibling = c;
131 child->prev_sibling = c->prev_sibling;
132
133 if (child->next_sibling)
134 child->next_sibling->prev_sibling = child;
135 if (child->prev_sibling)
136 child->prev_sibling->next_sibling = child;
137
138 if (parent->first_child == c)
139 parent->first_child = child;
140 break;
141 }
142 position--;
143 }
144 }
145
146 parent->num_children++;
147 }
148
149 static void
150 e_tree_path_unlink (ETreeMemoryPath *path)
151 {
152 ETreeMemoryPath *parent = path->parent;
153
154 /* unlink first/last child if applicable */
155 if (parent) {
156 if (path == parent->first_child)
157 parent->first_child = path->next_sibling;
158 if (path == parent->last_child)
159 parent->last_child = path->prev_sibling;
160
161 parent->num_children--;
162 }
163
164 /* unlink prev/next sibling links */
165 if (path->next_sibling)
166 path->next_sibling->prev_sibling = path->prev_sibling;
167 if (path->prev_sibling)
168 path->prev_sibling->next_sibling = path->next_sibling;
169
170 path->parent = NULL;
171 path->next_sibling = NULL;
172 path->prev_sibling = NULL;
173 }
174
175 /**
176 * e_tree_memory_freeze:
177 * @etmm: the ETreeModel to freeze.
178 *
179 * This function prepares an ETreeModel for a period of much change.
180 * All signals regarding changes to the tree are deferred until we
181 * thaw the tree.
182 *
183 **/
184 void
185 e_tree_memory_freeze (ETreeMemory *etmm)
186 {
187 ETreeMemoryPrivate *priv = etmm->priv;
188
189 if (priv->frozen == 0)
190 e_tree_model_pre_change (E_TREE_MODEL (etmm));
191
192 priv->frozen++;
193 }
194
195 /**
196 * e_tree_memory_thaw:
197 * @etmm: the ETreeMemory to thaw.
198 *
199 * This function thaws an ETreeMemory. All the defered signals can add
200 * up to a lot, we don't know - so we just emit a model_changed
201 * signal.
202 *
203 **/
204 void
205 e_tree_memory_thaw (ETreeMemory *etmm)
206 {
207 ETreeMemoryPrivate *priv = etmm->priv;
208
209 if (priv->frozen > 0)
210 priv->frozen--;
211 if (priv->frozen == 0) {
212 e_tree_model_node_changed (E_TREE_MODEL (etmm), priv->root);
213 }
214 }
215
216 /* virtual methods */
217
218 static void
219 etmm_dispose (GObject *object)
220 {
221 ETreeMemoryPrivate *priv;
222
223 priv = E_TREE_MEMORY_GET_PRIVATE (object);
224
225 if (priv->root)
226 e_tree_memory_node_remove (
227 E_TREE_MEMORY (object), priv->root);
228
229 G_OBJECT_CLASS (e_tree_memory_parent_class)->dispose (object);
230 }
231
232 static ETreePath
233 etmm_get_root (ETreeModel *etm)
234 {
235 ETreeMemoryPrivate *priv = E_TREE_MEMORY (etm)->priv;
236 return priv->root;
237 }
238
239 static ETreePath
240 etmm_get_parent (ETreeModel *etm,
241 ETreePath node)
242 {
243 ETreeMemoryPath *path = node;
244 return path->parent;
245 }
246
247 static ETreePath
248 etmm_get_first_child (ETreeModel *etm,
249 ETreePath node)
250 {
251 ETreeMemoryPath *path = node;
252
253 check_children (E_TREE_MEMORY (etm), node);
254 return path->first_child;
255 }
256
257 static ETreePath
258 etmm_get_last_child (ETreeModel *etm,
259 ETreePath node)
260 {
261 ETreeMemoryPath *path = node;
262
263 check_children (E_TREE_MEMORY (etm), node);
264 return path->last_child;
265 }
266
267 static ETreePath
268 etmm_get_next (ETreeModel *etm,
269 ETreePath node)
270 {
271 ETreeMemoryPath *path = node;
272 return path->next_sibling;
273 }
274
275 static ETreePath
276 etmm_get_prev (ETreeModel *etm,
277 ETreePath node)
278 {
279 ETreeMemoryPath *path = node;
280 return path->prev_sibling;
281 }
282
283 static gboolean
284 etmm_is_root (ETreeModel *etm,
285 ETreePath node)
286 {
287 ETreeMemoryPath *path = node;
288 return e_tree_memory_path_depth (path) == 0;
289 }
290
291 static gboolean
292 etmm_is_expandable (ETreeModel *etm,
293 ETreePath node)
294 {
295 ETreeMemoryPath *path = node;
296
297 check_children (E_TREE_MEMORY (etm), node);
298 return path->first_child != NULL;
299 }
300
301 static guint
302 etmm_get_children (ETreeModel *etm,
303 ETreePath node,
304 ETreePath **nodes)
305 {
306 ETreeMemoryPath *path = node;
307 guint n_children;
308
309 check_children (E_TREE_MEMORY (etm), node);
310
311 n_children = path->num_children;
312
313 if (nodes) {
314 ETreeMemoryPath *p;
315 gint i = 0;
316
317 (*nodes) = g_new (ETreePath, n_children);
318 for (p = path->first_child; p; p = p->next_sibling) {
319 (*nodes)[i++] = p;
320 }
321 }
322
323 return n_children;
324 }
325
326 static guint
327 etmm_depth (ETreeModel *etm,
328 ETreePath path)
329 {
330 return e_tree_memory_path_depth (path);
331 }
332
333 static gboolean
334 etmm_get_expanded_default (ETreeModel *etm)
335 {
336 ETreeMemory *etmm = E_TREE_MEMORY (etm);
337 ETreeMemoryPrivate *priv = etmm->priv;
338
339 return priv->expanded_default;
340 }
341
342 static void
343 etmm_clear_children_computed (ETreeMemoryPath *path)
344 {
345 for (path = path->first_child; path; path = path->next_sibling) {
346 path->children_computed = FALSE;
347 etmm_clear_children_computed (path);
348 }
349 }
350
351 static void
352 etmm_node_request_collapse (ETreeModel *etm,
353 ETreePath node)
354 {
355 ETreeModelClass *parent_class;
356
357 if (node)
358 etmm_clear_children_computed (node);
359
360 parent_class = E_TREE_MODEL_CLASS (e_tree_memory_parent_class);
361
362 if (parent_class->node_request_collapse != NULL)
363 parent_class->node_request_collapse (etm, node);
364 }
365
366 static void
367 e_tree_memory_class_init (ETreeMemoryClass *class)
368 {
369 GObjectClass *object_class;
370 ETreeModelClass *tree_model_class;
371
372 g_type_class_add_private (class, sizeof (ETreeMemoryPrivate));
373
374 object_class = G_OBJECT_CLASS (class);
375 object_class->dispose = etmm_dispose;
376
377 tree_model_class = E_TREE_MODEL_CLASS (class);
378 tree_model_class->get_root = etmm_get_root;
379 tree_model_class->get_prev = etmm_get_prev;
380 tree_model_class->get_next = etmm_get_next;
381 tree_model_class->get_first_child = etmm_get_first_child;
382 tree_model_class->get_last_child = etmm_get_last_child;
383 tree_model_class->get_parent = etmm_get_parent;
384
385 tree_model_class->is_root = etmm_is_root;
386 tree_model_class->is_expandable = etmm_is_expandable;
387 tree_model_class->get_children = etmm_get_children;
388 tree_model_class->depth = etmm_depth;
389 tree_model_class->get_expanded_default = etmm_get_expanded_default;
390
391 tree_model_class->node_request_collapse = etmm_node_request_collapse;
392
393 class->fill_in_children = NULL;
394
395 signals[FILL_IN_CHILDREN] = g_signal_new (
396 "fill_in_children",
397 G_TYPE_FROM_CLASS (object_class),
398 G_SIGNAL_RUN_LAST,
399 G_STRUCT_OFFSET (ETreeMemoryClass, fill_in_children),
400 (GSignalAccumulator) NULL, NULL,
401 g_cclosure_marshal_VOID__POINTER,
402 G_TYPE_NONE, 1,
403 G_TYPE_POINTER);
404 }
405
406 static void
407 e_tree_memory_init (ETreeMemory *etmm)
408 {
409 etmm->priv = E_TREE_MEMORY_GET_PRIVATE (etmm);
410 }
411
412 /**
413 * e_tree_memory_construct:
414 * @etree:
415 *
416 *
417 **/
418 void
419 e_tree_memory_construct (ETreeMemory *etmm)
420 {
421 }
422
423 /**
424 * e_tree_memory_new
425 *
426 * XXX docs here.
427 *
428 * return values: a newly constructed ETreeMemory.
429 */
430 ETreeMemory *
431 e_tree_memory_new (void)
432 {
433 return g_object_new (E_TYPE_TREE_MEMORY, NULL);
434 }
435
436 /**
437 * e_tree_memory_set_expanded_default
438 *
439 * Sets the state of nodes to be append to a thread.
440 * They will either be expanded or collapsed, according to
441 * the value of @expanded.
442 */
443 void
444 e_tree_memory_set_expanded_default (ETreeMemory *etree,
445 gboolean expanded)
446 {
447 g_return_if_fail (etree != NULL);
448
449 etree->priv->expanded_default = expanded;
450 }
451
452 /**
453 * e_tree_memory_node_get_data:
454 * @etmm:
455 * @node:
456 *
457 *
458 *
459 * Return value:
460 **/
461 gpointer
462 e_tree_memory_node_get_data (ETreeMemory *etmm,
463 ETreePath node)
464 {
465 ETreeMemoryPath *path = node;
466
467 g_return_val_if_fail (path, NULL);
468
469 return path->node_data;
470 }
471
472 /**
473 * e_tree_memory_node_set_data:
474 * @etmm:
475 * @node:
476 * @node_data:
477 *
478 *
479 **/
480 void
481 e_tree_memory_node_set_data (ETreeMemory *etmm,
482 ETreePath node,
483 gpointer node_data)
484 {
485 ETreeMemoryPath *path = node;
486
487 g_return_if_fail (path);
488
489 path->node_data = node_data;
490 }
491
492 /**
493 * e_tree_memory_node_insert:
494 * @tree_model:
495 * @parent_path:
496 * @position:
497 * @node_data:
498 *
499 *
500 *
501 * Return value:
502 **/
503 ETreePath
504 e_tree_memory_node_insert (ETreeMemory *tree_model,
505 ETreePath parent_node,
506 gint position,
507 gpointer node_data)
508 {
509 ETreeMemoryPrivate *priv;
510 ETreeMemoryPath *new_path;
511 ETreeMemoryPath *parent_path = parent_node;
512
513 g_return_val_if_fail (tree_model != NULL, NULL);
514
515 priv = tree_model->priv;
516
517 g_return_val_if_fail (parent_path != NULL || priv->root == NULL, NULL);
518
519 priv = tree_model->priv;
520
521 if (!tree_model->priv->frozen)
522 e_tree_model_pre_change (E_TREE_MODEL (tree_model));
523
524 new_path = g_slice_new0 (ETreeMemoryPath);
525
526 new_path->node_data = node_data;
527 new_path->children_computed = FALSE;
528
529 if (parent_path != NULL) {
530 e_tree_memory_path_insert (parent_path, position, new_path);
531 if (!tree_model->priv->frozen)
532 e_tree_model_node_inserted (
533 E_TREE_MODEL (tree_model),
534 parent_path, new_path);
535 } else {
536 priv->root = new_path;
537 if (!tree_model->priv->frozen)
538 e_tree_model_node_changed (
539 E_TREE_MODEL (tree_model), new_path);
540 }
541
542 return new_path;
543 }
544
545 ETreePath
546 e_tree_memory_node_insert_id (ETreeMemory *etree,
547 ETreePath parent,
548 gint position,
549 gpointer node_data,
550 gchar *id)
551 {
552 return e_tree_memory_node_insert (etree, parent, position, node_data);
553 }
554
555 /**
556 * e_tree_memory_node_insert_before:
557 * @etree:
558 * @parent:
559 * @sibling:
560 * @node_data:
561 *
562 *
563 *
564 * Return value:
565 **/
566 ETreePath
567 e_tree_memory_node_insert_before (ETreeMemory *etree,
568 ETreePath parent,
569 ETreePath sibling,
570 gpointer node_data)
571 {
572 ETreeMemoryPath *child;
573 ETreeMemoryPath *parent_path = parent;
574 ETreeMemoryPath *sibling_path = sibling;
575 gint position = 0;
576
577 g_return_val_if_fail (etree != NULL, NULL);
578
579 if (sibling != NULL) {
580 for (child = parent_path->first_child; child; child = child->next_sibling) {
581 if (child == sibling_path)
582 break;
583 position++;
584 }
585 } else
586 position = parent_path->num_children;
587 return e_tree_memory_node_insert (etree, parent, position, node_data);
588 }
589
590 /* just blows away child data, doesn't take into account unlinking/etc */
591 static void
592 child_free (ETreeMemory *etree,
593 ETreeMemoryPath *node)
594 {
595 ETreeMemoryPath *child, *next;
596
597 child = node->first_child;
598 while (child) {
599 next = child->next_sibling;
600 child_free (etree, child);
601 child = next;
602 }
603
604 if (etree->priv->destroy_func) {
605 etree->priv->destroy_func (node->node_data, etree->priv->destroy_user_data);
606 }
607
608 g_slice_free (ETreeMemoryPath, node);
609 }
610
611 /**
612 * e_tree_memory_node_remove:
613 * @etree:
614 * @path:
615 *
616 *
617 *
618 * Return value:
619 **/
620 gpointer
621 e_tree_memory_node_remove (ETreeMemory *etree,
622 ETreePath node)
623 {
624 ETreeMemoryPath *path = node;
625 ETreeMemoryPath *parent = path->parent;
626 ETreeMemoryPath *sibling;
627 gpointer ret = path->node_data;
628 gint old_position = 0;
629
630 g_return_val_if_fail (etree != NULL, NULL);
631
632 if (!etree->priv->frozen) {
633 e_tree_model_pre_change (E_TREE_MODEL (etree));
634 for (old_position = 0, sibling = path;
635 sibling;
636 old_position++, sibling = sibling->prev_sibling)
637 /* Empty intentionally*/;
638 old_position--;
639 }
640
641 /* unlink this node - we only have to unlink the root node being removed,
642 * since the others are only references from this node */
643 e_tree_path_unlink (path);
644
645 /*printf("removing %d nodes from position %d\n", visible, base);*/
646 if (!etree->priv->frozen)
647 e_tree_model_node_removed (E_TREE_MODEL (etree), parent, path, old_position);
648
649 child_free (etree, path);
650
651 if (path == etree->priv->root)
652 etree->priv->root = NULL;
653
654 if (!etree->priv->frozen)
655 e_tree_model_node_deleted (E_TREE_MODEL (etree), path);
656
657 return ret;
658 }
659
660 typedef struct {
661 ETreeMemory *memory;
662 gpointer closure;
663 ETreeMemorySortCallback callback;
664 } MemoryAndClosure;
665
666 static gint
667 sort_callback (gconstpointer data1,
668 gconstpointer data2,
669 gpointer user_data)
670 {
671 ETreePath path1 = *(ETreePath *) data1;
672 ETreePath path2 = *(ETreePath *) data2;
673 MemoryAndClosure *mac = user_data;
674 return (*mac->callback) (mac->memory, path1, path2, mac->closure);
675 }
676
677 void
678 e_tree_memory_sort_node (ETreeMemory *etmm,
679 ETreePath node,
680 ETreeMemorySortCallback callback,
681 gpointer user_data)
682 {
683 ETreeMemoryPath **children;
684 ETreeMemoryPath *child;
685 gint count;
686 gint i;
687 ETreeMemoryPath *path = node;
688 MemoryAndClosure mac;
689 ETreeMemoryPath *last;
690
691 e_tree_model_pre_change (E_TREE_MODEL (etmm));
692
693 i = 0;
694 for (child = path->first_child; child; child = child->next_sibling)
695 i++;
696
697 children = g_new (ETreeMemoryPath *, i);
698
699 count = i;
700
701 for (child = path->first_child, i = 0;
702 child;
703 child = child->next_sibling, i++) {
704 children[i] = child;
705 }
706
707 mac.memory = etmm;
708 mac.closure = user_data;
709 mac.callback = callback;
710
711 g_qsort_with_data (
712 children, count, sizeof (ETreeMemoryPath *),
713 sort_callback, &mac);
714
715 path->first_child = NULL;
716 last = NULL;
717 for (i = 0;
718 i < count;
719 i++) {
720 children[i]->prev_sibling = last;
721 if (last)
722 last->next_sibling = children[i];
723 else
724 path->first_child = children[i];
725 last = children[i];
726 }
727 if (last)
728 last->next_sibling = NULL;
729
730 path->last_child = last;
731
732 g_free (children);
733
734 e_tree_model_node_changed (E_TREE_MODEL (etmm), node);
735 }
736
737 void
738 e_tree_memory_set_node_destroy_func (ETreeMemory *etmm,
739 GFunc destroy_func,
740 gpointer user_data)
741 {
742 etmm->priv->destroy_func = destroy_func;
743 etmm->priv->destroy_user_data = user_data;
744 }