Bug Summary

File:menu-layout.c
Warning:line 567, column 20
Access to field 'prev' results in a dereference of a null pointer (loaded from field 'next')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name menu-layout.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/libmenu -fcoverage-compilation-dir=/rootdir/libmenu -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D CAFEMENU_I_KNOW_THIS_IS_UNSTABLE -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-02-13-080227-11729-1 -x c menu-layout.c
1/* Menu layout in-memory data structure (a custom "DOM tree") */
2
3/*
4 * Copyright (C) 2002 - 2004 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#include <config.h>
23
24#include "menu-layout.h"
25
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <errno(*__errno_location ()).h>
31
32#include "entry-directories.h"
33#include "menu-util.h"
34
35typedef struct MenuLayoutNodeMenu MenuLayoutNodeMenu;
36typedef struct MenuLayoutNodeRoot MenuLayoutNodeRoot;
37typedef struct MenuLayoutNodeLegacyDir MenuLayoutNodeLegacyDir;
38typedef struct MenuLayoutNodeMergeFile MenuLayoutNodeMergeFile;
39typedef struct MenuLayoutNodeDefaultLayout MenuLayoutNodeDefaultLayout;
40typedef struct MenuLayoutNodeMenuname MenuLayoutNodeMenuname;
41typedef struct MenuLayoutNodeMerge MenuLayoutNodeMerge;
42
43struct MenuLayoutNode
44{
45 /* Node lists are circular, for length-one lists
46 * prev/next point back to the node itself.
47 */
48 MenuLayoutNode *prev;
49 MenuLayoutNode *next;
50 MenuLayoutNode *parent;
51 MenuLayoutNode *children;
52
53 char *content;
54
55 guint refcount : 20;
56 guint type : 7;
57};
58
59struct MenuLayoutNodeRoot
60{
61 MenuLayoutNode node;
62
63 char *basedir;
64 char *name;
65
66 GMainContext *main_context;
67
68 GSList *monitors;
69 GSource *monitors_idle_handler;
70};
71
72struct MenuLayoutNodeMenu
73{
74 MenuLayoutNode node;
75
76 MenuLayoutNode *name_node; /* cache of the <Name> node */
77
78 EntryDirectoryList *app_dirs;
79 EntryDirectoryList *dir_dirs;
80};
81
82struct MenuLayoutNodeLegacyDir
83{
84 MenuLayoutNode node;
85
86 char *prefix;
87};
88
89struct MenuLayoutNodeMergeFile
90{
91 MenuLayoutNode node;
92
93 MenuMergeFileType type;
94};
95
96struct MenuLayoutNodeDefaultLayout
97{
98 MenuLayoutNode node;
99
100 MenuLayoutValues layout_values;
101};
102
103struct MenuLayoutNodeMenuname
104{
105 MenuLayoutNode node;
106
107 MenuLayoutValues layout_values;
108};
109
110struct MenuLayoutNodeMerge
111{
112 MenuLayoutNode node;
113
114 MenuLayoutMergeType merge_type;
115};
116
117typedef struct
118{
119 MenuLayoutNodeEntriesChangedFunc callback;
120 gpointer user_data;
121} MenuLayoutNodeEntriesMonitor;
122
123
124static inline MenuLayoutNode *
125node_next (MenuLayoutNode *node)
126{
127 /* root nodes (no parent) never have siblings */
128 if (node->parent == NULL((void*)0))
129 return NULL((void*)0);
130
131 /* circular list */
132 if (node->next == node->parent->children)
133 return NULL((void*)0);
134
135 return node->next;
136}
137
138static gboolean
139menu_layout_invoke_monitors (MenuLayoutNodeRoot *nr)
140{
141 GSList *tmp;
142
143 g_assert (nr->node.type == MENU_LAYOUT_NODE_ROOT)do { if (nr->node.type == MENU_LAYOUT_NODE_ROOT) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 143, ((const char*) (__func__
)), "nr->node.type == MENU_LAYOUT_NODE_ROOT"); } while (0)
;
144
145 nr->monitors_idle_handler = NULL((void*)0);
146
147 tmp = nr->monitors;
148 while (tmp != NULL((void*)0))
149 {
150 MenuLayoutNodeEntriesMonitor *monitor = tmp->data;
151 GSList *next = tmp->next;
152
153 monitor->callback ((MenuLayoutNode *) nr, monitor->user_data);
154
155 tmp = next;
156 }
157
158 return FALSE(0);
159}
160
161static void
162handle_entry_directory_changed (EntryDirectory *dir G_GNUC_UNUSED__attribute__ ((__unused__)),
163 MenuLayoutNode *node)
164{
165 MenuLayoutNodeRoot *nr;
166
167 g_assert (node->type == MENU_LAYOUT_NODE_MENU)do { if (node->type == MENU_LAYOUT_NODE_MENU) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 167, ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENU"); } while (0)
;
168
169 nr = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
170
171 if (nr->monitors_idle_handler == NULL((void*)0))
172 {
173 nr->monitors_idle_handler = g_idle_source_new ();
174 g_source_set_callback (nr->monitors_idle_handler,
175 (GSourceFunc) menu_layout_invoke_monitors, nr, NULL((void*)0));
176 g_source_attach (nr->monitors_idle_handler, nr->main_context);
177 g_source_unref (nr->monitors_idle_handler);
178 }
179}
180
181static void
182remove_entry_directory_list (MenuLayoutNodeMenu *nm,
183 EntryDirectoryList **dirs)
184{
185 if (*dirs)
186 {
187 entry_directory_list_remove_monitors (*dirs,
188 (EntryDirectoryChangedFunc) handle_entry_directory_changed,
189 nm);
190 entry_directory_list_unref (*dirs);
191 *dirs = NULL((void*)0);
192 }
193}
194
195MenuLayoutNode *
196menu_layout_node_ref (MenuLayoutNode *node)
197{
198 g_return_val_if_fail (node != NULL, NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return
(((void*)0)); } } while (0)
;
199
200 node->refcount += 1;
201
202 return node;
203}
204
205void
206menu_layout_node_unref (MenuLayoutNode *node)
207{
208 g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return
; } } while (0)
;
209 g_return_if_fail (node->refcount > 0)do { if ((node->refcount > 0)) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node->refcount > 0"
); return; } } while (0)
;
210
211 node->refcount -= 1;
212 if (node->refcount == 0)
213 {
214 MenuLayoutNode *iter;
215
216 iter = node->children;
217 while (iter != NULL((void*)0))
218 {
219 MenuLayoutNode *next = node_next (iter);
220
221 menu_layout_node_unref (iter);
222
223 iter = next;
224 }
225
226 if (node->type == MENU_LAYOUT_NODE_MENU)
227 {
228 MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node;
229
230 if (nm->name_node)
231 menu_layout_node_unref (nm->name_node);
232
233 remove_entry_directory_list (nm, &nm->app_dirs);
234 remove_entry_directory_list (nm, &nm->dir_dirs);
235 }
236 else if (node->type == MENU_LAYOUT_NODE_LEGACY_DIR)
237 {
238 MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) node;
239
240 g_free (legacy->prefix);
241 }
242 else if (node->type == MENU_LAYOUT_NODE_ROOT)
243 {
244 MenuLayoutNodeRoot *nr = (MenuLayoutNodeRoot*) node;
245
246 g_slist_foreach (nr->monitors, (GFunc) g_free, NULL((void*)0));
247 g_slist_free (nr->monitors);
248
249 if (nr->monitors_idle_handler != NULL((void*)0))
250 g_source_destroy (nr->monitors_idle_handler);
251 nr->monitors_idle_handler = NULL((void*)0);
252
253 if (nr->main_context != NULL((void*)0))
254 g_main_context_unref (nr->main_context);
255 nr->main_context = NULL((void*)0);
256
257 g_free (nr->basedir);
258 g_free (nr->name);
259 }
260
261 g_free (node->content);
262 g_free (node);
263 }
264}
265
266MenuLayoutNode *
267menu_layout_node_new (MenuLayoutNodeType type)
268{
269 MenuLayoutNode *node;
270
271 switch (type)
272 {
273 case MENU_LAYOUT_NODE_MENU:
274 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenu, 1)((MenuLayoutNodeMenu *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMenu
)))
;
275 break;
276
277 case MENU_LAYOUT_NODE_LEGACY_DIR:
278 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeLegacyDir, 1)((MenuLayoutNodeLegacyDir *) g_malloc0_n ((1), sizeof (MenuLayoutNodeLegacyDir
)))
;
279 break;
280
281 case MENU_LAYOUT_NODE_ROOT:
282 node = (MenuLayoutNode*) g_new0 (MenuLayoutNodeRoot, 1)((MenuLayoutNodeRoot *) g_malloc0_n ((1), sizeof (MenuLayoutNodeRoot
)))
;
283 break;
284
285 case MENU_LAYOUT_NODE_MERGE_FILE:
286 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMergeFile, 1)((MenuLayoutNodeMergeFile *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMergeFile
)))
;
287 break;
288
289 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
290 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeDefaultLayout, 1)((MenuLayoutNodeDefaultLayout *) g_malloc0_n ((1), sizeof (MenuLayoutNodeDefaultLayout
)))
;
291 break;
292
293 case MENU_LAYOUT_NODE_MENUNAME:
294 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenuname, 1)((MenuLayoutNodeMenuname *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMenuname
)))
;
295 break;
296
297 case MENU_LAYOUT_NODE_MERGE:
298 node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMerge, 1)((MenuLayoutNodeMerge *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMerge
)))
;
299 break;
300
301 default:
302 node = g_new0 (MenuLayoutNode, 1)((MenuLayoutNode *) g_malloc0_n ((1), sizeof (MenuLayoutNode)
))
;
303 break;
304 }
305
306 node->type = type;
307
308 node->refcount = 1;
309
310 /* we're in a list of one node */
311 node->next = node;
312 node->prev = node;
313
314 return node;
315}
316
317MenuLayoutNode *
318menu_layout_node_get_next (MenuLayoutNode *node)
319{
320 return node_next (node);
321}
322
323MenuLayoutNode *
324menu_layout_node_get_parent (MenuLayoutNode *node)
325{
326 return node->parent;
327}
328
329MenuLayoutNode *
330menu_layout_node_get_children (MenuLayoutNode *node)
331{
332 return node->children;
333}
334
335MenuLayoutNode *
336menu_layout_node_get_root (MenuLayoutNode *node)
337{
338 MenuLayoutNode *parent;
339
340 parent = node;
341 while (parent->parent != NULL((void*)0))
342 parent = parent->parent;
343
344 g_assert (parent->type == MENU_LAYOUT_NODE_ROOT)do { if (parent->type == MENU_LAYOUT_NODE_ROOT) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 344, ((const char*) (__func__
)), "parent->type == MENU_LAYOUT_NODE_ROOT"); } while (0)
;
345
346 return parent;
347}
348
349char *
350menu_layout_node_get_content_as_path (MenuLayoutNode *node)
351{
352 if (node->content == NULL((void*)0))
353 {
354 menu_verbose (" (node has no content to get as a path)\n");
355 return NULL((void*)0);
356 }
357
358 if (g_path_is_absolute (node->content))
359 {
360 return g_strdup (node->content)g_strdup_inline (node->content);
361 }
362 else
363 {
364 MenuLayoutNodeRoot *root;
365
366 root = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node);
367
368 if (root->basedir == NULL((void*)0))
369 {
370 menu_verbose ("No basedir available, using \"%s\" as-is\n",
371 node->content);
372 return g_strdup (node->content)g_strdup_inline (node->content);
373 }
374 else
375 {
376 menu_verbose ("Using basedir \"%s\" filename \"%s\"\n",
377 root->basedir, node->content);
378 return g_build_filename (root->basedir, node->content, NULL((void*)0));
379 }
380 }
381}
382
383#define RETURN_IF_NO_PARENT(node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, "
"it must not be the root node, " "and must be linked in below some root node\n"
"node parent = %p and type = %d", (node)->parent, (node)->
type); return; } } while (0)
G_STMT_STARTdo { \
384 if ((node)->parent == NULL((void*)0)) \
385 { \
386 g_warning ("To add siblings to a menu node, " \
387 "it must not be the root node, " \
388 "and must be linked in below some root node\n" \
389 "node parent = %p and type = %d", \
390 (node)->parent, (node)->type); \
391 return; \
392 } \
393 } G_STMT_ENDwhile (0)
394
395#define RETURN_IF_HAS_ENTRY_DIRS(node)do { if ((node)->type == MENU_LAYOUT_NODE_MENU && (
((MenuLayoutNodeMenu*)(node))->app_dirs != ((void*)0) || (
(MenuLayoutNodeMenu*)(node))->dir_dirs != ((void*)0))) { g_warning
("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n"
); return; } } while (0)
G_STMT_STARTdo { \
396 if ((node)->type == MENU_LAYOUT_NODE_MENU && \
397 (((MenuLayoutNodeMenu*)(node))->app_dirs != NULL((void*)0) || \
398 ((MenuLayoutNodeMenu*)(node))->dir_dirs != NULL((void*)0))) \
399 { \
400 g_warning ("node acquired ->app_dirs or ->dir_dirs " \
401 "while not rooted in a tree\n"); \
402 return; \
403 } \
404 } G_STMT_ENDwhile (0) \
405
406void
407menu_layout_node_insert_before (MenuLayoutNode *node,
408 MenuLayoutNode *new_sibling)
409{
410 g_return_if_fail (new_sibling != NULL)do { if ((new_sibling != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "new_sibling != NULL"
); return; } } while (0)
;
411 g_return_if_fail (new_sibling->parent == NULL)do { if ((new_sibling->parent == ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "new_sibling->parent == NULL"
); return; } } while (0)
;
412
413 RETURN_IF_NO_PARENT (node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, "
"it must not be the root node, " "and must be linked in below some root node\n"
"node parent = %p and type = %d", (node)->parent, (node)->
type); return; } } while (0)
;
414 RETURN_IF_HAS_ENTRY_DIRS (new_sibling)do { if ((new_sibling)->type == MENU_LAYOUT_NODE_MENU &&
(((MenuLayoutNodeMenu*)(new_sibling))->app_dirs != ((void
*)0) || ((MenuLayoutNodeMenu*)(new_sibling))->dir_dirs != (
(void*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs "
"while not rooted in a tree\n"); return; } } while (0)
;
415
416 new_sibling->next = node;
417 new_sibling->prev = node->prev;
418
419 node->prev = new_sibling;
420 new_sibling->prev->next = new_sibling;
421
422 new_sibling->parent = node->parent;
423
424 if (node == node->parent->children)
425 node->parent->children = new_sibling;
426
427 menu_layout_node_ref (new_sibling);
428}
429
430void
431menu_layout_node_insert_after (MenuLayoutNode *node,
432 MenuLayoutNode *new_sibling)
433{
434 g_return_if_fail (new_sibling != NULL)do { if ((new_sibling != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "new_sibling != NULL"
); return; } } while (0)
;
435 g_return_if_fail (new_sibling->parent == NULL)do { if ((new_sibling->parent == ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "new_sibling->parent == NULL"
); return; } } while (0)
;
436
437 RETURN_IF_NO_PARENT (node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, "
"it must not be the root node, " "and must be linked in below some root node\n"
"node parent = %p and type = %d", (node)->parent, (node)->
type); return; } } while (0)
;
438 RETURN_IF_HAS_ENTRY_DIRS (new_sibling)do { if ((new_sibling)->type == MENU_LAYOUT_NODE_MENU &&
(((MenuLayoutNodeMenu*)(new_sibling))->app_dirs != ((void
*)0) || ((MenuLayoutNodeMenu*)(new_sibling))->dir_dirs != (
(void*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs "
"while not rooted in a tree\n"); return; } } while (0)
;
439
440 new_sibling->prev = node;
441 new_sibling->next = node->next;
442
443 node->next = new_sibling;
444 new_sibling->next->prev = new_sibling;
445
446 new_sibling->parent = node->parent;
447
448 menu_layout_node_ref (new_sibling);
449}
450
451void
452menu_layout_node_prepend_child (MenuLayoutNode *parent,
453 MenuLayoutNode *new_child)
454{
455 RETURN_IF_HAS_ENTRY_DIRS (new_child)do { if ((new_child)->type == MENU_LAYOUT_NODE_MENU &&
(((MenuLayoutNodeMenu*)(new_child))->app_dirs != ((void*)
0) || ((MenuLayoutNodeMenu*)(new_child))->dir_dirs != ((void
*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs "
"while not rooted in a tree\n"); return; } } while (0)
;
456
457 if (parent->children)
458 {
459 menu_layout_node_insert_before (parent->children, new_child);
460 }
461 else
462 {
463 parent->children = menu_layout_node_ref (new_child);
464 new_child->parent = parent;
465 }
466}
467
468void
469menu_layout_node_append_child (MenuLayoutNode *parent,
470 MenuLayoutNode *new_child)
471{
472 RETURN_IF_HAS_ENTRY_DIRS (new_child)do { if ((new_child)->type == MENU_LAYOUT_NODE_MENU &&
(((MenuLayoutNodeMenu*)(new_child))->app_dirs != ((void*)
0) || ((MenuLayoutNodeMenu*)(new_child))->dir_dirs != ((void
*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs "
"while not rooted in a tree\n"); return; } } while (0)
;
473
474 if (parent->children)
475 {
476 menu_layout_node_insert_after (parent->children->prev, new_child);
477 }
478 else
479 {
480 parent->children = menu_layout_node_ref (new_child);
481 new_child->parent = parent;
482 }
483}
484
485void
486menu_layout_node_unlink (MenuLayoutNode *node)
487{
488 g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return
; } } while (0)
;
30
Taking true branch
31
Loop condition is false. Exiting loop
489 g_return_if_fail (node->parent != NULL)do { if ((node->parent != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node->parent != NULL"
); return; } } while (0)
;
32
Taking true branch
33
Loop condition is false. Exiting loop
490
491 menu_layout_node_steal (node);
34
Calling 'menu_layout_node_steal'
492 menu_layout_node_unref (node);
493}
494
495static void
496recursive_clean_entry_directory_lists (MenuLayoutNode *node,
497 gboolean apps)
498{
499 EntryDirectoryList **dirs;
500 MenuLayoutNodeMenu *nm;
501 MenuLayoutNode *iter;
502
503 if (node->type != MENU_LAYOUT_NODE_MENU)
504 return;
505
506 nm = (MenuLayoutNodeMenu *) node;
507
508 dirs = apps ? &nm->app_dirs : &nm->dir_dirs;
509
510 if (*dirs == NULL((void*)0) || entry_directory_list_get_length (*dirs) == 0)
511 return; /* child menus continue to have valid lists */
512
513 remove_entry_directory_list (nm, dirs);
514
515 iter = node->children;
516 while (iter != NULL((void*)0))
517 {
518 if (iter->type == MENU_LAYOUT_NODE_MENU)
519 recursive_clean_entry_directory_lists (iter, apps);
520
521 iter = node_next (iter);
522 }
523}
524
525void
526menu_layout_node_steal (MenuLayoutNode *node)
527{
528 g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return
; } } while (0)
;
35
Taking true branch
36
Loop condition is false. Exiting loop
529 g_return_if_fail (node->parent != NULL)do { if ((node->parent != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "node->parent != NULL"
); return; } } while (0)
;
37
Taking true branch
38
Loop condition is false. Exiting loop
530
531 switch (node->type)
39
Control jumps to the 'default' case at line 553
532 {
533 case MENU_LAYOUT_NODE_NAME:
534 {
535 MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node->parent;
536
537 if (nm->name_node == node)
538 {
539 menu_layout_node_unref (nm->name_node);
540 nm->name_node = NULL((void*)0);
541 }
542 }
543 break;
544
545 case MENU_LAYOUT_NODE_APP_DIR:
546 recursive_clean_entry_directory_lists (node->parent, TRUE(!(0)));
547 break;
548
549 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
550 recursive_clean_entry_directory_lists (node->parent, FALSE(0));
551 break;
552
553 default:
554 break;
40
Execution continues on line 557
555 }
556
557 if (node->parent
40.1
Field 'parent' is non-null
&& node->parent->children == node)
41
Assuming 'node' is not equal to field 'children'
42
Taking false branch
558 {
559 if (node->next != node)
560 node->parent->children = node->next;
561 else
562 node->parent->children = NULL((void*)0);
563 }
564
565 /* these are no-ops for length-one node lists */
566 node->prev->next = node->next;
567 node->next->prev = node->prev;
43
Access to field 'prev' results in a dereference of a null pointer (loaded from field 'next')
568
569 node->parent = NULL((void*)0);
570
571 /* point to ourselves, now we're length one */
572 node->next = node;
573 node->prev = node;
574}
575
576MenuLayoutNodeType
577menu_layout_node_get_type (MenuLayoutNode *node)
578{
579 return node->type;
580}
581
582const char *
583menu_layout_node_get_content (MenuLayoutNode *node)
584{
585 return node->content;
586}
587
588void
589menu_layout_node_set_content (MenuLayoutNode *node,
590 const char *content)
591{
592 if (node->content == content)
593 return;
594
595 g_free (node->content);
596 node->content = g_strdup (content)g_strdup_inline (content);
597}
598
599const char *
600menu_layout_node_root_get_name (MenuLayoutNode *node)
601{
602 MenuLayoutNodeRoot *nr;
603
604 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_ROOT"); return (((void
*)0)); } } while (0)
;
605
606 nr = (MenuLayoutNodeRoot*) node;
607
608 return nr->name;
609}
610
611const char *
612menu_layout_node_root_get_basedir (MenuLayoutNode *node)
613{
614 MenuLayoutNodeRoot *nr;
615
616 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_ROOT"); return (((void
*)0)); } } while (0)
;
617
618 nr = (MenuLayoutNodeRoot*) node;
619
620 return nr->basedir;
621}
622
623const char *
624menu_layout_node_menu_get_name (MenuLayoutNode *node)
625{
626 MenuLayoutNodeMenu *nm;
627
628 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void
*)0)); } } while (0)
;
629
630 nm = (MenuLayoutNodeMenu*) node;
631
632 if (nm->name_node == NULL((void*)0))
633 {
634 MenuLayoutNode *iter;
635
636 iter = node->children;
637 while (iter != NULL((void*)0))
638 {
639 if (iter->type == MENU_LAYOUT_NODE_NAME)
640 {
641 nm->name_node = menu_layout_node_ref (iter);
642 break;
643 }
644
645 iter = node_next (iter);
646 }
647 }
648
649 if (nm->name_node == NULL((void*)0))
650 return NULL((void*)0);
651
652 return menu_layout_node_get_content (nm->name_node);
653}
654
655static void
656ensure_dir_lists (MenuLayoutNodeMenu *nm)
657{
658 MenuLayoutNode *node;
659 MenuLayoutNode *iter;
660 EntryDirectoryList *app_dirs;
661 EntryDirectoryList *dir_dirs;
662
663 node = (MenuLayoutNode *) nm;
664
665 if (nm->app_dirs && nm->dir_dirs)
666 return;
667
668 app_dirs = NULL((void*)0);
669 dir_dirs = NULL((void*)0);
670
671 if (nm->app_dirs == NULL((void*)0))
672 {
673 app_dirs = entry_directory_list_new ();
674
675 if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU)
676 {
677 EntryDirectoryList *dirs;
678
679 if ((dirs = menu_layout_node_menu_get_app_dirs (node->parent)))
680 entry_directory_list_append_list (app_dirs, dirs);
681 }
682 }
683
684 if (nm->dir_dirs == NULL((void*)0))
685 {
686 dir_dirs = entry_directory_list_new ();
687
688 if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU)
689 {
690 EntryDirectoryList *dirs;
691
692 if ((dirs = menu_layout_node_menu_get_directory_dirs (node->parent)))
693 entry_directory_list_append_list (dir_dirs, dirs);
694 }
695 }
696
697 iter = node->children;
698 while (iter != NULL((void*)0))
699 {
700 EntryDirectory *ed;
701
702 if (app_dirs != NULL((void*)0) && iter->type == MENU_LAYOUT_NODE_APP_DIR)
703 {
704 char *path;
705
706 path = menu_layout_node_get_content_as_path (iter);
707
708 ed = entry_directory_new (DESKTOP_ENTRY_DESKTOP, path);
709 if (ed != NULL((void*)0))
710 {
711 entry_directory_list_prepend (app_dirs, ed);
712 entry_directory_unref (ed);
713 }
714
715 g_free (path);
716 }
717
718 if (dir_dirs != NULL((void*)0) && iter->type == MENU_LAYOUT_NODE_DIRECTORY_DIR)
719 {
720 char *path;
721
722 path = menu_layout_node_get_content_as_path (iter);
723
724 ed = entry_directory_new (DESKTOP_ENTRY_DIRECTORY, path);
725 if (ed != NULL((void*)0))
726 {
727 entry_directory_list_prepend (dir_dirs, ed);
728 entry_directory_unref (ed);
729 }
730
731 g_free (path);
732 }
733
734 if (iter->type == MENU_LAYOUT_NODE_LEGACY_DIR)
735 {
736 MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) iter;
737 char *path;
738
739 path = menu_layout_node_get_content_as_path (iter);
740
741 if (app_dirs != NULL((void*)0)) /* we're loading app dirs */
742 {
743 ed = entry_directory_new_legacy (DESKTOP_ENTRY_DESKTOP,
744 path,
745 legacy->prefix);
746 if (ed != NULL((void*)0))
747 {
748 entry_directory_list_prepend (app_dirs, ed);
749 entry_directory_unref (ed);
750 }
751 }
752
753 if (dir_dirs != NULL((void*)0)) /* we're loading dir dirs */
754 {
755 ed = entry_directory_new_legacy (DESKTOP_ENTRY_DIRECTORY,
756 path,
757 legacy->prefix);
758 if (ed != NULL((void*)0))
759 {
760 entry_directory_list_prepend (dir_dirs, ed);
761 entry_directory_unref (ed);
762 }
763 }
764
765 g_free (path);
766 }
767
768 iter = node_next (iter);
769 }
770
771 if (app_dirs)
772 {
773 g_assert (nm->app_dirs == NULL)do { if (nm->app_dirs == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 773, ((const char*) (__func__
)), "nm->app_dirs == NULL"); } while (0)
;
774
775 nm->app_dirs = app_dirs;
776 entry_directory_list_add_monitors (nm->app_dirs,
777 (EntryDirectoryChangedFunc) handle_entry_directory_changed,
778 nm);
779 }
780
781 if (dir_dirs)
782 {
783 g_assert (nm->dir_dirs == NULL)do { if (nm->dir_dirs == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 783, ((const char*) (__func__
)), "nm->dir_dirs == NULL"); } while (0)
;
784
785 nm->dir_dirs = dir_dirs;
786 entry_directory_list_add_monitors (nm->dir_dirs,
787 (EntryDirectoryChangedFunc) handle_entry_directory_changed,
788 nm);
789 }
790}
791
792EntryDirectoryList *
793menu_layout_node_menu_get_app_dirs (MenuLayoutNode *node)
794{
795 MenuLayoutNodeMenu *nm;
796
797 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void
*)0)); } } while (0)
;
798
799 nm = (MenuLayoutNodeMenu *) node;
800
801 ensure_dir_lists (nm);
802
803 return nm->app_dirs;
804}
805
806EntryDirectoryList *
807menu_layout_node_menu_get_directory_dirs (MenuLayoutNode *node)
808{
809 MenuLayoutNodeMenu *nm;
810
811 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void
*)0)); } } while (0)
;
812
813 nm = (MenuLayoutNodeMenu *) node;
814
815 ensure_dir_lists (nm);
816
817 return nm->dir_dirs;
818}
819
820const char *
821menu_layout_node_move_get_old (MenuLayoutNode *node)
822{
823 MenuLayoutNode *iter;
824
825 iter = node->children;
826 while (iter != NULL((void*)0))
827 {
828 if (iter->type == MENU_LAYOUT_NODE_OLD)
829 return iter->content;
830
831 iter = node_next (iter);
832 }
833
834 return NULL((void*)0);
835}
836
837const char *
838menu_layout_node_move_get_new (MenuLayoutNode *node)
839{
840 MenuLayoutNode *iter;
841
842 iter = node->children;
843 while (iter != NULL((void*)0))
844 {
845 if (iter->type == MENU_LAYOUT_NODE_NEW)
846 return iter->content;
847
848 iter = node_next (iter);
849 }
850
851 return NULL((void*)0);
852}
853
854const char *
855menu_layout_node_legacy_dir_get_prefix (MenuLayoutNode *node)
856{
857 MenuLayoutNodeLegacyDir *legacy;
858
859 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR, NULL)do { if ((node->type == MENU_LAYOUT_NODE_LEGACY_DIR)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_LEGACY_DIR"); return (
((void*)0)); } } while (0)
;
860
861 legacy = (MenuLayoutNodeLegacyDir *) node;
862
863 return legacy->prefix;
864}
865
866void
867menu_layout_node_legacy_dir_set_prefix (MenuLayoutNode *node,
868 const char *prefix)
869{
870 MenuLayoutNodeLegacyDir *legacy;
871
872 g_return_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR)do { if ((node->type == MENU_LAYOUT_NODE_LEGACY_DIR)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_LEGACY_DIR"); return; }
} while (0)
;
873
874 legacy = (MenuLayoutNodeLegacyDir *) node;
875
876 g_free (legacy->prefix);
877 legacy->prefix = g_strdup (prefix)g_strdup_inline (prefix);
878}
879
880MenuMergeFileType
881menu_layout_node_merge_file_get_type (MenuLayoutNode *node)
882{
883 MenuLayoutNodeMergeFile *merge_file;
884
885 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE, FALSE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE_FILE)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MERGE_FILE"); return (
(0)); } } while (0)
;
886
887 merge_file = (MenuLayoutNodeMergeFile *) node;
888
889 return merge_file->type;
890}
891
892void
893menu_layout_node_merge_file_set_type (MenuLayoutNode *node,
894 MenuMergeFileType type)
895{
896 MenuLayoutNodeMergeFile *merge_file;
897
898 g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE_FILE)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MERGE_FILE"); return; }
} while (0)
;
899
900 merge_file = (MenuLayoutNodeMergeFile *) node;
901
902 merge_file->type = type;
903}
904
905MenuLayoutMergeType
906menu_layout_node_merge_get_type (MenuLayoutNode *node)
907{
908 MenuLayoutNodeMerge *merge;
909
910 g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE, 0)do { if ((node->type == MENU_LAYOUT_NODE_MERGE)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MERGE"); return (0); }
} while (0)
;
911
912 merge = (MenuLayoutNodeMerge *) node;
913
914 return merge->merge_type;
915}
916
917static void
918menu_layout_node_merge_set_type (MenuLayoutNode *node,
919 const char *merge_type)
920{
921 MenuLayoutNodeMerge *merge;
922
923 g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MERGE"); return; } } while
(0)
;
924
925 merge = (MenuLayoutNodeMerge *) node;
926
927 merge->merge_type = MENU_LAYOUT_MERGE_NONE;
928
929 if (strcmp (merge_type, "menus") == 0)
930 {
931 merge->merge_type = MENU_LAYOUT_MERGE_MENUS;
932 }
933 else if (strcmp (merge_type, "files") == 0)
934 {
935 merge->merge_type = MENU_LAYOUT_MERGE_FILES;
936 }
937 else if (strcmp (merge_type, "all") == 0)
938 {
939 merge->merge_type = MENU_LAYOUT_MERGE_ALL;
940 }
941}
942
943void
944menu_layout_node_default_layout_get_values (MenuLayoutNode *node,
945 MenuLayoutValues *values)
946{
947 MenuLayoutNodeDefaultLayout *default_layout;
948
949 g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)do { if ((node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)) {
} else { g_return_if_fail_warning (((gchar*) 0), ((const char
*) (__func__)), "node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT"
); return; } } while (0)
;
950 g_return_if_fail (values != NULL)do { if ((values != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "values != NULL")
; return; } } while (0)
;
951
952 default_layout = (MenuLayoutNodeDefaultLayout *) node;
953
954 *values = default_layout->layout_values;
955}
956
957void
958menu_layout_node_menuname_get_values (MenuLayoutNode *node,
959 MenuLayoutValues *values)
960{
961 MenuLayoutNodeMenuname *menuname;
962
963 g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME)do { if ((node->type == MENU_LAYOUT_NODE_MENUNAME)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENUNAME"); return; } }
while (0)
;
964 g_return_if_fail (values != NULL)do { if ((values != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "values != NULL")
; return; } } while (0)
;
965
966 menuname = (MenuLayoutNodeMenuname *) node;
967
968 *values = menuname->layout_values;
969}
970
971static void
972menu_layout_values_set (MenuLayoutValues *values,
973 const char *show_empty,
974 const char *inline_menus,
975 const char *inline_limit,
976 const char *inline_header,
977 const char *inline_alias)
978{
979 values->mask = MENU_LAYOUT_VALUES_NONE;
980 values->show_empty = FALSE(0);
981 values->inline_menus = FALSE(0);
982 values->inline_limit = 4;
983 values->inline_header = FALSE(0);
984 values->inline_alias = FALSE(0);
985
986 if (show_empty != NULL((void*)0))
987 {
988 values->show_empty = strcmp (show_empty, "true") == 0;
989 values->mask |= MENU_LAYOUT_VALUES_SHOW_EMPTY;
990 }
991
992 if (inline_menus != NULL((void*)0))
993 {
994 values->inline_menus = strcmp (inline_menus, "true") == 0;
995 values->mask |= MENU_LAYOUT_VALUES_INLINE_MENUS;
996 }
997
998 if (inline_limit != NULL((void*)0))
999 {
1000 char *end;
1001 int limit;
1002
1003 limit = strtol (inline_limit, &end, 10);
1004 if (*end == '\0')
1005 {
1006 values->inline_limit = limit;
1007 values->mask |= MENU_LAYOUT_VALUES_INLINE_LIMIT;
1008 }
1009 }
1010
1011 if (inline_header != NULL((void*)0))
1012 {
1013 values->inline_header = strcmp (inline_header, "true") == 0;
1014 values->mask |= MENU_LAYOUT_VALUES_INLINE_HEADER;
1015 }
1016
1017 if (inline_alias != NULL((void*)0))
1018 {
1019 values->inline_alias = strcmp (inline_alias, "true") == 0;
1020 values->mask |= MENU_LAYOUT_VALUES_INLINE_ALIAS;
1021 }
1022}
1023
1024static void
1025menu_layout_node_default_layout_set_values (MenuLayoutNode *node,
1026 const char *show_empty,
1027 const char *inline_menus,
1028 const char *inline_limit,
1029 const char *inline_header,
1030 const char *inline_alias)
1031{
1032 MenuLayoutNodeDefaultLayout *default_layout;
1033
1034 g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)do { if ((node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)) {
} else { g_return_if_fail_warning (((gchar*) 0), ((const char
*) (__func__)), "node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT"
); return; } } while (0)
;
1035
1036 default_layout = (MenuLayoutNodeDefaultLayout *) node;
1037
1038 menu_layout_values_set (&default_layout->layout_values,
1039 show_empty,
1040 inline_menus,
1041 inline_limit,
1042 inline_header,
1043 inline_alias);
1044}
1045
1046static void
1047menu_layout_node_menuname_set_values (MenuLayoutNode *node,
1048 const char *show_empty,
1049 const char *inline_menus,
1050 const char *inline_limit,
1051 const char *inline_header,
1052 const char *inline_alias)
1053{
1054 MenuLayoutNodeMenuname *menuname;
1055
1056 g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME)do { if ((node->type == MENU_LAYOUT_NODE_MENUNAME)) { } else
{ g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_MENUNAME"); return; } }
while (0)
;
1057
1058 menuname = (MenuLayoutNodeMenuname *) node;
1059
1060 menu_layout_values_set (&menuname->layout_values,
1061 show_empty,
1062 inline_menus,
1063 inline_limit,
1064 inline_header,
1065 inline_alias);
1066}
1067
1068void
1069menu_layout_node_root_add_entries_monitor (MenuLayoutNode *node,
1070 MenuLayoutNodeEntriesChangedFunc callback,
1071 gpointer user_data)
1072{
1073 MenuLayoutNodeEntriesMonitor *monitor;
1074 MenuLayoutNodeRoot *nr;
1075 GSList *tmp;
1076
1077 g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_ROOT"); return; } } while
(0)
;
1078
1079 nr = (MenuLayoutNodeRoot *) node;
1080
1081 tmp = nr->monitors;
1082 while (tmp != NULL((void*)0))
1083 {
1084 monitor = tmp->data;
1085
1086 if (monitor->callback == callback &&
1087 monitor->user_data == user_data)
1088 break;
1089
1090 tmp = tmp->next;
1091 }
1092
1093 if (tmp == NULL((void*)0))
1094 {
1095 monitor = g_new0 (MenuLayoutNodeEntriesMonitor, 1)((MenuLayoutNodeEntriesMonitor *) g_malloc0_n ((1), sizeof (MenuLayoutNodeEntriesMonitor
)))
;
1096 monitor->callback = callback;
1097 monitor->user_data = user_data;
1098
1099 nr->monitors = g_slist_append (nr->monitors, monitor);
1100 }
1101}
1102
1103void
1104menu_layout_node_root_remove_entries_monitor (MenuLayoutNode *node,
1105 MenuLayoutNodeEntriesChangedFunc callback,
1106 gpointer user_data)
1107{
1108 MenuLayoutNodeRoot *nr;
1109 GSList *tmp;
1110
1111 g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else {
g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__
)), "node->type == MENU_LAYOUT_NODE_ROOT"); return; } } while
(0)
;
1112
1113 nr = (MenuLayoutNodeRoot *) node;
1114
1115 tmp = nr->monitors;
1116 while (tmp != NULL((void*)0))
1117 {
1118 MenuLayoutNodeEntriesMonitor *monitor = tmp->data;
1119 GSList *next = tmp->next;
1120
1121 if (monitor->callback == callback &&
1122 monitor->user_data == user_data)
1123 {
1124 nr->monitors = g_slist_delete_link (nr->monitors, tmp);
1125 g_free (monitor);
1126 }
1127
1128 tmp = next;
1129 }
1130}
1131
1132
1133/*
1134 * Menu file parsing
1135 */
1136
1137typedef struct
1138{
1139 MenuLayoutNode *root;
1140 MenuLayoutNode *stack_top;
1141} MenuParser;
1142
1143static void set_error (GError **err,
1144 GMarkupParseContext *context,
1145 int error_domain,
1146 int error_code,
1147 const char *format,
1148 ...) G_GNUC_PRINTF (5, 6)__attribute__((__format__ (__printf__, 5, 6)));
1149
1150static void add_context_to_error (GError **err,
1151 GMarkupParseContext *context);
1152
1153static void start_element_handler (GMarkupParseContext *context,
1154 const char *element_name,
1155 const char **attribute_names,
1156 const char **attribute_values,
1157 gpointer user_data,
1158 GError **error);
1159static void end_element_handler (GMarkupParseContext *context,
1160 const char *element_name,
1161 gpointer user_data,
1162 GError **error);
1163static void text_handler (GMarkupParseContext *context,
1164 const char *text,
1165 gsize text_len,
1166 gpointer user_data,
1167 GError **error);
1168static void passthrough_handler (GMarkupParseContext *context,
1169 const char *passthrough_text,
1170 gsize text_len,
1171 gpointer user_data,
1172 GError **error);
1173
1174
1175static GMarkupParser menu_funcs = {
1176 start_element_handler,
1177 end_element_handler,
1178 text_handler,
1179 passthrough_handler,
1180 NULL((void*)0)
1181};
1182
1183static void
1184set_error (GError **err,
1185 GMarkupParseContext *context,
1186 int error_domain,
1187 int error_code,
1188 const char *format,
1189 ...)
1190{
1191 int line, ch;
1192 va_list args;
1193 char *str;
1194
1195 g_markup_parse_context_get_position (context, &line, &ch);
1196
1197 va_start (args, format)__builtin_va_start(args, format);
1198 str = g_strdup_vprintf (format, args);
1199 va_end (args)__builtin_va_end(args);
1200
1201 g_set_error (err, error_domain, error_code,
1202 "Line %d character %d: %s",
1203 line, ch, str);
1204
1205 g_free (str);
1206}
1207
1208static void
1209add_context_to_error (GError **err,
1210 GMarkupParseContext *context)
1211{
1212 int line, ch;
1213 char *str;
1214
1215 if (err == NULL((void*)0) || *err == NULL((void*)0))
1216 return;
1217
1218 g_markup_parse_context_get_position (context, &line, &ch);
1219
1220 str = g_strdup_printf ("Line %d character %d: %s",
1221 line, ch, (*err)->message);
1222 g_free ((*err)->message);
1223 (*err)->message = str;
1224}
1225
1226#define ELEMENT_IS(name)(strcmp (element_name, (name)) == 0) (strcmp (element_name, (name)) == 0)
1227
1228typedef struct
1229{
1230 const char *name;
1231 const char **retloc;
1232} LocateAttr;
1233
1234static gboolean
1235locate_attributes (GMarkupParseContext *context,
1236 const char *element_name,
1237 const char **attribute_names,
1238 const char **attribute_values,
1239 GError **error,
1240 const char *first_attribute_name,
1241 const char **first_attribute_retloc,
1242 ...)
1243{
1244#define MAX_ATTRS 24
1245 LocateAttr attrs[MAX_ATTRS];
1246 int n_attrs;
1247 va_list args;
1248 const char *name;
1249 const char **retloc;
1250 gboolean retval;
1251 int i;
1252
1253 g_return_val_if_fail (first_attribute_name != NULL, FALSE)do { if ((first_attribute_name != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "first_attribute_name != NULL"
); return ((0)); } } while (0)
;
1254 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE)do { if ((first_attribute_retloc != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "first_attribute_retloc != NULL"
); return ((0)); } } while (0)
;
1255
1256 retval = TRUE(!(0));
1257
1258 n_attrs = 1;
1259 attrs[0].name = first_attribute_name;
1260 attrs[0].retloc = first_attribute_retloc;
1261 *first_attribute_retloc = NULL((void*)0);
1262
1263 va_start (args, first_attribute_retloc)__builtin_va_start(args, first_attribute_retloc);
1264
1265 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1266 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1267
1268 while (name != NULL((void*)0))
1269 {
1270 g_return_val_if_fail (retloc != NULL, FALSE)do { if ((retloc != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "retloc != NULL")
; return ((0)); } } while (0)
;
1271
1272 g_assert (n_attrs < MAX_ATTRS)do { if (n_attrs < MAX_ATTRS) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 1272, ((const char*) (__func__
)), "n_attrs < MAX_ATTRS"); } while (0)
;
1273
1274 attrs[n_attrs].name = name;
1275 attrs[n_attrs].retloc = retloc;
1276 n_attrs += 1;
1277 *retloc = NULL((void*)0);
1278
1279 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1280 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1281 }
1282
1283 va_end (args)__builtin_va_end(args);
1284
1285 i = 0;
1286 while (attribute_names[i])
1287 {
1288 int j;
1289
1290 j = 0;
1291 while (j < n_attrs)
1292 {
1293 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
1294 {
1295 retloc = attrs[j].retloc;
1296
1297 if (*retloc != NULL((void*)0))
1298 {
1299 set_error (error, context,
1300 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1301 "Attribute \"%s\" repeated twice on the same <%s> element",
1302 attrs[j].name, element_name);
1303 retval = FALSE(0);
1304 goto out;
1305 }
1306
1307 *retloc = attribute_values[i];
1308 break;
1309 }
1310
1311 ++j;
1312 }
1313
1314 if (j == n_attrs)
1315 {
1316 set_error (error, context,
1317 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1318 "Attribute \"%s\" is invalid on <%s> element in this context",
1319 attribute_names[i], element_name);
1320 retval = FALSE(0);
1321 goto out;
1322 }
1323
1324 ++i;
1325 }
1326
1327 out:
1328 return retval;
1329
1330#undef MAX_ATTRS
1331}
1332
1333static gboolean
1334check_no_attributes (GMarkupParseContext *context,
1335 const char *element_name,
1336 const char **attribute_names,
1337 const char **attribute_values G_GNUC_UNUSED__attribute__ ((__unused__)),
1338 GError **error)
1339{
1340 if (attribute_names[0] != NULL((void*)0))
1341 {
1342 set_error (error, context,
1343 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1344 "Attribute \"%s\" is invalid on <%s> element in this context",
1345 attribute_names[0], element_name);
1346 return FALSE(0);
1347 }
1348
1349 return TRUE(!(0));
1350}
1351
1352static int
1353has_child_of_type (MenuLayoutNode *node,
1354 MenuLayoutNodeType type)
1355{
1356 MenuLayoutNode *iter;
1357
1358 iter = node->children;
1359 while (iter)
1360 {
1361 if (iter->type == type)
1362 return TRUE(!(0));
1363
1364 iter = node_next (iter);
1365 }
1366
1367 return FALSE(0);
1368}
1369
1370static void
1371push_node (MenuParser *parser,
1372 MenuLayoutNodeType type)
1373{
1374 MenuLayoutNode *node;
1375
1376 node = menu_layout_node_new (type);
1377 menu_layout_node_append_child (parser->stack_top, node);
1378 menu_layout_node_unref (node);
1379
1380 parser->stack_top = node;
1381}
1382
1383static void
1384start_menu_element (MenuParser *parser,
1385 GMarkupParseContext *context,
1386 const char *element_name,
1387 const char **attribute_names,
1388 const char **attribute_values,
1389 GError **error)
1390{
1391 if (!check_no_attributes (context, element_name,
1392 attribute_names, attribute_values,
1393 error))
1394 return;
1395
1396 if (!(parser->stack_top->type == MENU_LAYOUT_NODE_ROOT ||
1397 parser->stack_top->type == MENU_LAYOUT_NODE_MENU))
1398 {
1399 set_error (error, context,
1400 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1401 "<Menu> element can only appear below other <Menu> elements or at toplevel\n");
1402 }
1403 else
1404 {
1405 push_node (parser, MENU_LAYOUT_NODE_MENU);
1406 }
1407}
1408
1409static void
1410start_menu_child_element (MenuParser *parser,
1411 GMarkupParseContext *context,
1412 const char *element_name,
1413 const char **attribute_names,
1414 const char **attribute_values,
1415 GError **error)
1416{
1417 if (ELEMENT_IS ("LegacyDir")(strcmp (element_name, ("LegacyDir")) == 0))
1418 {
1419 const char *prefix;
1420
1421 push_node (parser, MENU_LAYOUT_NODE_LEGACY_DIR);
1422
1423 if (!locate_attributes (context, element_name,
1424 attribute_names, attribute_values,
1425 error,
1426 "prefix", &prefix,
1427 NULL((void*)0)))
1428 return;
1429
1430 menu_layout_node_legacy_dir_set_prefix (parser->stack_top, prefix);
1431 }
1432 else if (ELEMENT_IS ("MergeFile")(strcmp (element_name, ("MergeFile")) == 0))
1433 {
1434 const char *type;
1435
1436 push_node (parser, MENU_LAYOUT_NODE_MERGE_FILE);
1437
1438 if (!locate_attributes (context, element_name,
1439 attribute_names, attribute_values,
1440 error,
1441 "type", &type,
1442 NULL((void*)0)))
1443 return;
1444
1445 if (type != NULL((void*)0) && strcmp (type, "parent") == 0)
1446 {
1447 menu_layout_node_merge_file_set_type (parser->stack_top,
1448 MENU_MERGE_FILE_TYPE_PARENT);
1449 }
1450 }
1451 else if (ELEMENT_IS ("DefaultLayout")(strcmp (element_name, ("DefaultLayout")) == 0))
1452 {
1453 const char *show_empty;
1454 const char *inline_menus;
1455 const char *inline_limit;
1456 const char *inline_header;
1457 const char *inline_alias;
1458
1459 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
1460
1461 locate_attributes (context, element_name,
1462 attribute_names, attribute_values,
1463 error,
1464 "show_empty", &show_empty,
1465 "inline", &inline_menus,
1466 "inline_limit", &inline_limit,
1467 "inline_header", &inline_header,
1468 "inline_alias", &inline_alias,
1469 NULL((void*)0));
1470
1471 menu_layout_node_default_layout_set_values (parser->stack_top,
1472 show_empty,
1473 inline_menus,
1474 inline_limit,
1475 inline_header,
1476 inline_alias);
1477 }
1478 else
1479 {
1480 if (!check_no_attributes (context, element_name,
1481 attribute_names, attribute_values,
1482 error))
1483 return;
1484
1485 if (ELEMENT_IS ("AppDir")(strcmp (element_name, ("AppDir")) == 0))
1486 {
1487 push_node (parser, MENU_LAYOUT_NODE_APP_DIR);
1488 }
1489 else if (ELEMENT_IS ("DefaultAppDirs")(strcmp (element_name, ("DefaultAppDirs")) == 0))
1490 {
1491 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_APP_DIRS);
1492 }
1493 else if (ELEMENT_IS ("DirectoryDir")(strcmp (element_name, ("DirectoryDir")) == 0))
1494 {
1495 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY_DIR);
1496 }
1497 else if (ELEMENT_IS ("DefaultDirectoryDirs")(strcmp (element_name, ("DefaultDirectoryDirs")) == 0))
1498 {
1499 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS);
1500 }
1501 else if (ELEMENT_IS ("DefaultMergeDirs")(strcmp (element_name, ("DefaultMergeDirs")) == 0))
1502 {
1503 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS);
1504 }
1505 else if (ELEMENT_IS ("Name")(strcmp (element_name, ("Name")) == 0))
1506 {
1507 if (has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
1508 {
1509 set_error (error, context,
1510 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1511 "Multiple <Name> elements in a <Menu> element is not allowed\n");
1512 return;
1513 }
1514
1515 push_node (parser, MENU_LAYOUT_NODE_NAME);
1516 }
1517 else if (ELEMENT_IS ("Directory")(strcmp (element_name, ("Directory")) == 0))
1518 {
1519 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY);
1520 }
1521 else if (ELEMENT_IS ("OnlyUnallocated")(strcmp (element_name, ("OnlyUnallocated")) == 0))
1522 {
1523 push_node (parser, MENU_LAYOUT_NODE_ONLY_UNALLOCATED);
1524 }
1525 else if (ELEMENT_IS ("NotOnlyUnallocated")(strcmp (element_name, ("NotOnlyUnallocated")) == 0))
1526 {
1527 push_node (parser, MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED);
1528 }
1529 else if (ELEMENT_IS ("Include")(strcmp (element_name, ("Include")) == 0))
1530 {
1531 push_node (parser, MENU_LAYOUT_NODE_INCLUDE);
1532 }
1533 else if (ELEMENT_IS ("Exclude")(strcmp (element_name, ("Exclude")) == 0))
1534 {
1535 push_node (parser, MENU_LAYOUT_NODE_EXCLUDE);
1536 }
1537 else if (ELEMENT_IS ("MergeDir")(strcmp (element_name, ("MergeDir")) == 0))
1538 {
1539 push_node (parser, MENU_LAYOUT_NODE_MERGE_DIR);
1540 }
1541 else if (ELEMENT_IS ("KDELegacyDirs")(strcmp (element_name, ("KDELegacyDirs")) == 0))
1542 {
1543 push_node (parser, MENU_LAYOUT_NODE_KDE_LEGACY_DIRS);
1544 }
1545 else if (ELEMENT_IS ("Move")(strcmp (element_name, ("Move")) == 0))
1546 {
1547 push_node (parser, MENU_LAYOUT_NODE_MOVE);
1548 }
1549 else if (ELEMENT_IS ("Deleted")(strcmp (element_name, ("Deleted")) == 0))
1550 {
1551 push_node (parser, MENU_LAYOUT_NODE_DELETED);
1552
1553 }
1554 else if (ELEMENT_IS ("NotDeleted")(strcmp (element_name, ("NotDeleted")) == 0))
1555 {
1556 push_node (parser, MENU_LAYOUT_NODE_NOT_DELETED);
1557 }
1558 else if (ELEMENT_IS ("Layout")(strcmp (element_name, ("Layout")) == 0))
1559 {
1560 push_node (parser, MENU_LAYOUT_NODE_LAYOUT);
1561 }
1562 else
1563 {
1564 set_error (error, context,
1565 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1566 "Element <%s> may not appear below <%s>\n",
1567 element_name, "Menu");
1568 }
1569 }
1570}
1571
1572static void
1573start_matching_rule_element (MenuParser *parser,
1574 GMarkupParseContext *context,
1575 const char *element_name,
1576 const char **attribute_names,
1577 const char **attribute_values,
1578 GError **error)
1579{
1580 if (!check_no_attributes (context, element_name,
1581 attribute_names, attribute_values,
1582 error))
1583 return;
1584
1585
1586 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1587 {
1588 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1589 }
1590 else if (ELEMENT_IS ("Category")(strcmp (element_name, ("Category")) == 0))
1591 {
1592 push_node (parser, MENU_LAYOUT_NODE_CATEGORY);
1593 }
1594 else if (ELEMENT_IS ("All")(strcmp (element_name, ("All")) == 0))
1595 {
1596 push_node (parser, MENU_LAYOUT_NODE_ALL);
1597 }
1598 else if (ELEMENT_IS ("And")(strcmp (element_name, ("And")) == 0))
1599 {
1600 push_node (parser, MENU_LAYOUT_NODE_AND);
1601 }
1602 else if (ELEMENT_IS ("Or")(strcmp (element_name, ("Or")) == 0))
1603 {
1604 push_node (parser, MENU_LAYOUT_NODE_OR);
1605 }
1606 else if (ELEMENT_IS ("Not")(strcmp (element_name, ("Not")) == 0))
1607 {
1608 push_node (parser, MENU_LAYOUT_NODE_NOT);
1609 }
1610 else
1611 {
1612 set_error (error, context,
1613 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1614 "Element <%s> may not appear in this context\n",
1615 element_name);
1616 }
1617}
1618
1619static void
1620start_move_child_element (MenuParser *parser,
1621 GMarkupParseContext *context,
1622 const char *element_name,
1623 const char **attribute_names,
1624 const char **attribute_values,
1625 GError **error)
1626{
1627 if (!check_no_attributes (context, element_name,
1628 attribute_names, attribute_values,
1629 error))
1630 return;
1631
1632 if (ELEMENT_IS ("Old")(strcmp (element_name, ("Old")) == 0))
1633 {
1634 push_node (parser, MENU_LAYOUT_NODE_OLD);
1635 }
1636 else if (ELEMENT_IS ("New")(strcmp (element_name, ("New")) == 0))
1637 {
1638 push_node (parser, MENU_LAYOUT_NODE_NEW);
1639 }
1640 else
1641 {
1642 set_error (error, context,
1643 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1644 "Element <%s> may not appear below <%s>\n",
1645 element_name, "Move");
1646 }
1647}
1648
1649static void
1650start_layout_child_element (MenuParser *parser,
1651 GMarkupParseContext *context,
1652 const char *element_name,
1653 const char **attribute_names,
1654 const char **attribute_values,
1655 GError **error)
1656{
1657 if (ELEMENT_IS ("Menuname")(strcmp (element_name, ("Menuname")) == 0))
1658 {
1659 const char *show_empty;
1660 const char *inline_menus;
1661 const char *inline_limit;
1662 const char *inline_header;
1663 const char *inline_alias;
1664
1665 push_node (parser, MENU_LAYOUT_NODE_MENUNAME);
1666
1667 locate_attributes (context, element_name,
1668 attribute_names, attribute_values,
1669 error,
1670 "show_empty", &show_empty,
1671 "inline", &inline_menus,
1672 "inline_limit", &inline_limit,
1673 "inline_header", &inline_header,
1674 "inline_alias", &inline_alias,
1675 NULL((void*)0));
1676
1677 menu_layout_node_menuname_set_values (parser->stack_top,
1678 show_empty,
1679 inline_menus,
1680 inline_limit,
1681 inline_header,
1682 inline_alias);
1683 }
1684 else if (ELEMENT_IS ("Merge")(strcmp (element_name, ("Merge")) == 0))
1685 {
1686 const char *type;
1687
1688 push_node (parser, MENU_LAYOUT_NODE_MERGE);
1689
1690 locate_attributes (context, element_name,
1691 attribute_names, attribute_values,
1692 error,
1693 "type", &type,
1694 NULL((void*)0));
1695
1696 menu_layout_node_merge_set_type (parser->stack_top, type);
1697 }
1698 else
1699 {
1700 if (!check_no_attributes (context, element_name,
1701 attribute_names, attribute_values,
1702 error))
1703 return;
1704
1705 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1706 {
1707 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1708 }
1709 else if (ELEMENT_IS ("Separator")(strcmp (element_name, ("Separator")) == 0))
1710 {
1711 push_node (parser, MENU_LAYOUT_NODE_SEPARATOR);
1712 }
1713 else
1714 {
1715 set_error (error, context,
1716 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1717 "Element <%s> may not appear below <%s>\n",
1718 element_name, "Move");
1719 }
1720 }
1721}
1722
1723static void
1724start_element_handler (GMarkupParseContext *context,
1725 const char *element_name,
1726 const char **attribute_names,
1727 const char **attribute_values,
1728 gpointer user_data,
1729 GError **error)
1730{
1731 MenuParser *parser = user_data;
1732
1733 if (ELEMENT_IS ("Menu")(strcmp (element_name, ("Menu")) == 0))
1734 {
1735 if (parser->stack_top == parser->root &&
1736 has_child_of_type (parser->root, MENU_LAYOUT_NODE_MENU))
1737 {
1738 set_error (error, context,
1739 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1740 "Multiple root elements in menu file, only one toplevel <Menu> is allowed\n");
1741 return;
1742 }
1743
1744 start_menu_element (parser, context, element_name,
1745 attribute_names, attribute_values,
1746 error);
1747 }
1748 else if (parser->stack_top == parser->root)
1749 {
1750 set_error (error, context,
1751 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1752 "Root element in a menu file must be <Menu>, not <%s>\n",
1753 element_name);
1754 }
1755 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MENU)
1756 {
1757 start_menu_child_element (parser, context, element_name,
1758 attribute_names, attribute_values,
1759 error);
1760 }
1761 else if (parser->stack_top->type == MENU_LAYOUT_NODE_INCLUDE ||
1762 parser->stack_top->type == MENU_LAYOUT_NODE_EXCLUDE ||
1763 parser->stack_top->type == MENU_LAYOUT_NODE_AND ||
1764 parser->stack_top->type == MENU_LAYOUT_NODE_OR ||
1765 parser->stack_top->type == MENU_LAYOUT_NODE_NOT)
1766 {
1767 start_matching_rule_element (parser, context, element_name,
1768 attribute_names, attribute_values,
1769 error);
1770 }
1771 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MOVE)
1772 {
1773 start_move_child_element (parser, context, element_name,
1774 attribute_names, attribute_values,
1775 error);
1776 }
1777 else if (parser->stack_top->type == MENU_LAYOUT_NODE_LAYOUT ||
1778 parser->stack_top->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)
1779 {
1780 start_layout_child_element (parser, context, element_name,
1781 attribute_names, attribute_values,
1782 error);
1783 }
1784 else
1785 {
1786 set_error (error, context,
1787 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1788 "Element <%s> may not appear in this context\n",
1789 element_name);
1790 }
1791
1792 add_context_to_error (error, context);
1793}
1794
1795/* we want to make sure that the <Layout> or <DefaultLayout> is either empty,
1796 * or contain one <Merge> of type "all", or contain one <Merge> of type "menus"
1797 * and one <Merge> of type "files". If this is not the case, we try to clean up
1798 * things:
1799 * + if there is at least one <Merge> of type "all", then we only keep the
1800 * last <Merge> of type "all" and remove all others <Merge>
1801 * + if there is no <Merge> with type "all", we keep only the last <Merge> of
1802 * type "menus" and the last <Merge> of type "files". If there's no <Merge>
1803 * of type "menus" we append one, and then if there's no <Merge> of type
1804 * "files", we append one. (So menus are before files)
1805 */
1806static gboolean
1807fixup_layout_node (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
1808 MenuParser *parser G_GNUC_UNUSED__attribute__ ((__unused__)),
1809 MenuLayoutNode *node,
1810 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
1811{
1812 MenuLayoutNode *child;
1813 MenuLayoutNode *last_all;
1814 MenuLayoutNode *last_menus;
1815 MenuLayoutNode *last_files;
1816 int n_all;
1817 int n_menus;
1818 int n_files;
1819
1820 if (!node->children)
6
Assuming field 'children' is non-null
7
Taking false branch
1821 {
1822 return TRUE(!(0));
1823 }
1824
1825 last_all = NULL((void*)0);
1826 last_menus = NULL((void*)0);
1827 last_files = NULL((void*)0);
1828 n_all = 0;
1829 n_menus = 0;
1830 n_files = 0;
1831
1832 child = node->children;
1833 while (child
7.1
'child' is not equal to NULL
!= NULL((void*)0)
)
8
Loop condition is true. Entering loop body
13
Assuming 'child' is not equal to NULL
14
Loop condition is true. Entering loop body
19
Assuming 'child' is equal to NULL
1834 {
1835 switch (child->type)
9
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1837
15
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1837
1836 {
1837 case MENU_LAYOUT_NODE_MERGE:
1838 switch (menu_layout_node_merge_get_type (child))
10
Control jumps to 'case MENU_LAYOUT_MERGE_ALL:' at line 1853
16
Control jumps to 'case MENU_LAYOUT_MERGE_MENUS:' at line 1843
1839 {
1840 case MENU_LAYOUT_MERGE_NONE:
1841 break;
1842
1843 case MENU_LAYOUT_MERGE_MENUS:
1844 last_menus = child;
1845 n_menus++;
1846 break;
17
Execution continues on line 1862
1847
1848 case MENU_LAYOUT_MERGE_FILES:
1849 last_files = child;
1850 n_files++;
1851 break;
1852
1853 case MENU_LAYOUT_MERGE_ALL:
1854 last_all = child;
1855 n_all++;
1856 break;
11
Execution continues on line 1862
1857
1858 default:
1859 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c",
1859, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1860 break;
1861 }
1862 break;
1863
1864 default:
1865 break;
1866 }
1867
1868 child = node_next (child);
12
Execution continues on line 1868
18
Execution continues on line 1868
1869 }
1870
1871 if ((n_all
19.1
'n_all' is equal to 1
== 1 && n_menus
19.2
'n_menus' is not equal to 0
== 0 && n_files == 0) ||
1872 (n_all
19.3
'n_all' is not equal to 0
== 0 && n_menus == 1 && n_files == 1))
1873 {
1874 return TRUE(!(0));
1875 }
1876 else if (n_all
19.4
'n_all' is <= 1
> 1 || n_menus
19.5
'n_menus' is <= 1
> 1 || n_files
19.6
'n_files' is <= 1
> 1 ||
1877 (n_all
19.7
'n_all' is equal to 1
== 1 && (n_menus
19.8
'n_menus' is not equal to 0
!= 0 || n_files != 0)))
1878 {
1879 child = node->children;
1880 while (child
19.9
'child' is not equal to NULL
25.1
'child' is not equal to NULL
!= NULL((void*)0))
20
Loop condition is true. Entering loop body
26
Loop condition is true. Entering loop body
1881 {
1882 MenuLayoutNode *next;
1883
1884 next = node_next (child);
1885
1886 switch (child->type)
21
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1888
27
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1888
1887 {
1888 case MENU_LAYOUT_NODE_MERGE:
1889 switch (menu_layout_node_merge_get_type (child))
22
Control jumps to 'case MENU_LAYOUT_MERGE_ALL:' at line 1910
28
Control jumps to 'case MENU_LAYOUT_MERGE_MENUS:' at line 1894
1890 {
1891 case MENU_LAYOUT_MERGE_NONE:
1892 break;
1893
1894 case MENU_LAYOUT_MERGE_MENUS:
1895 if (n_all
28.1
'n_all' is 1
|| last_menus != child)
1896 {
1897 menu_verbose ("removing duplicated merge menus element\n");
1898 menu_layout_node_unlink (child);
29
Calling 'menu_layout_node_unlink'
1899 }
1900 break;
1901
1902 case MENU_LAYOUT_MERGE_FILES:
1903 if (n_all || last_files != child)
1904 {
1905 menu_verbose ("removing duplicated merge files element\n");
1906 menu_layout_node_unlink (child);
1907 }
1908 break;
1909
1910 case MENU_LAYOUT_MERGE_ALL:
1911 if (last_all
22.1
'last_all' is equal to 'child'
!= child)
23
Taking false branch
1912 {
1913 menu_verbose ("removing duplicated merge all element\n");
1914 menu_layout_node_unlink (child);
1915 }
1916 break;
24
Execution continues on line 1922
1917
1918 default:
1919 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c",
1919, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1920 break;
1921 }
1922 break;
25
Execution continues on line 1928
1923
1924 default:
1925 break;
1926 }
1927
1928 child = next;
1929 }
1930 }
1931
1932 if (n_all == 0 && n_menus == 0)
1933 {
1934 last_menus = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1935 menu_layout_node_merge_set_type (last_menus, "menus");
1936 menu_verbose ("appending missing merge menus element\n");
1937 menu_layout_node_append_child (node, last_menus);
1938 }
1939
1940 if (n_all == 0 && n_files == 0)
1941 {
1942 last_files = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1943 menu_layout_node_merge_set_type (last_files, "files");
1944 menu_verbose ("appending missing merge files element\n");
1945 menu_layout_node_append_child (node, last_files);
1946 }
1947
1948 return TRUE(!(0));
1949}
1950
1951/* we want to a) check that we have old-new pairs and b) canonicalize
1952 * such that each <Move> has exactly one old-new pair
1953 */
1954static gboolean
1955fixup_move_node (GMarkupParseContext *context,
1956 MenuParser *parser G_GNUC_UNUSED__attribute__ ((__unused__)),
1957 MenuLayoutNode *node,
1958 GError **error)
1959{
1960 MenuLayoutNode *child;
1961 int n_old;
1962 int n_new;
1963
1964 n_old = 0;
1965 n_new = 0;
1966
1967 child = node->children;
1968 while (child != NULL((void*)0))
1969 {
1970 switch (child->type)
1971 {
1972 case MENU_LAYOUT_NODE_OLD:
1973 if (n_new != n_old)
1974 {
1975 set_error (error, context,
1976 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1977 "<Old>/<New> elements not paired properly\n");
1978 return FALSE(0);
1979 }
1980
1981 n_old += 1;
1982
1983 break;
1984
1985 case MENU_LAYOUT_NODE_NEW:
1986 n_new += 1;
1987
1988 if (n_new != n_old)
1989 {
1990 set_error (error, context,
1991 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1992 "<Old>/<New> elements not paired properly\n");
1993 return FALSE(0);
1994 }
1995
1996 break;
1997
1998 default:
1999 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c",
1999, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2000 break;
2001 }
2002
2003 child = node_next (child);
2004 }
2005
2006 if (n_new == 0 || n_old == 0)
2007 {
2008 set_error (error, context,
2009 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2010 "<Old>/<New> elements missing under <Move>\n");
2011 return FALSE(0);
2012 }
2013
2014 g_assert (n_new == n_old)do { if (n_new == n_old) ; else g_assertion_message_expr (((gchar
*) 0), "menu-layout.c", 2014, ((const char*) (__func__)), "n_new == n_old"
); } while (0)
;
2015 g_assert ((n_new + n_old) % 2 == 0)do { if ((n_new + n_old) % 2 == 0) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 2015, ((const char*) (__func__
)), "(n_new + n_old) % 2 == 0"); } while (0)
;
2016
2017 if (n_new > 1)
2018 {
2019 MenuLayoutNode *prev;
2020 MenuLayoutNode *append_after;
2021
2022 /* Need to split the <Move> into multiple <Move> */
2023
2024 n_old = 0;
2025 n_new = 0;
2026 prev = NULL((void*)0);
2027 append_after = node;
2028
2029 child = node->children;
2030 while (child != NULL((void*)0))
2031 {
2032 MenuLayoutNode *next;
2033
2034 next = node_next (child);
2035
2036 switch (child->type)
2037 {
2038 case MENU_LAYOUT_NODE_OLD:
2039 n_old += 1;
2040 break;
2041
2042 case MENU_LAYOUT_NODE_NEW:
2043 n_new += 1;
2044 break;
2045
2046 default:
2047 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c",
2047, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2048 break;
2049 }
2050
2051 if (n_old == n_new &&
2052 n_old > 1)
2053 {
2054 /* Move the just-completed pair */
2055 MenuLayoutNode *new_move;
2056
2057 g_assert (prev != NULL)do { if (prev != ((void*)0)) ; else g_assertion_message_expr (
((gchar*) 0), "menu-layout.c", 2057, ((const char*) (__func__
)), "prev != NULL"); } while (0)
;
2058
2059 new_move = menu_layout_node_new (MENU_LAYOUT_NODE_MOVE);
2060 menu_verbose ("inserting new_move after append_after\n");
2061 menu_layout_node_insert_after (append_after, new_move);
2062 append_after = new_move;
2063
2064 menu_layout_node_steal (prev);
2065 menu_layout_node_steal (child);
2066
2067 menu_verbose ("appending prev to new_move\n");
2068 menu_layout_node_append_child (new_move, prev);
2069 menu_verbose ("appending child to new_move\n");
2070 menu_layout_node_append_child (new_move, child);
2071
2072 menu_verbose ("Created new move element old = %s new = %s\n",
2073 menu_layout_node_move_get_old (new_move),
2074 menu_layout_node_move_get_new (new_move));
2075
2076 menu_layout_node_unref (new_move);
2077 menu_layout_node_unref (prev);
2078 menu_layout_node_unref (child);
2079
2080 prev = NULL((void*)0);
2081 }
2082 else
2083 {
2084 prev = child;
2085 }
2086
2087 prev = child;
2088 child = next;
2089 }
2090 }
2091
2092 return TRUE(!(0));
2093}
2094
2095static void
2096end_element_handler (GMarkupParseContext *context,
2097 const char *element_name,
2098 gpointer user_data,
2099 GError **error)
2100{
2101 MenuParser *parser = user_data;
2102
2103 g_assert (parser->stack_top != NULL)do { if (parser->stack_top != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "menu-layout.c", 2103, ((const char*) (__func__
)), "parser->stack_top != NULL"); } while (0)
;
1
Assuming field 'stack_top' is not equal to null
2
Taking true branch
3
Loop condition is false. Exiting loop
2104
2105 switch (parser->stack_top->type)
4
Control jumps to 'case MENU_LAYOUT_NODE_LAYOUT:' at line 2159
2106 {
2107 case MENU_LAYOUT_NODE_APP_DIR:
2108 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2109 case MENU_LAYOUT_NODE_NAME:
2110 case MENU_LAYOUT_NODE_DIRECTORY:
2111 case MENU_LAYOUT_NODE_FILENAME:
2112 case MENU_LAYOUT_NODE_CATEGORY:
2113 case MENU_LAYOUT_NODE_MERGE_DIR:
2114 case MENU_LAYOUT_NODE_LEGACY_DIR:
2115 case MENU_LAYOUT_NODE_OLD:
2116 case MENU_LAYOUT_NODE_NEW:
2117 case MENU_LAYOUT_NODE_MENUNAME:
2118 if (menu_layout_node_get_content (parser->stack_top) == NULL((void*)0))
2119 {
2120 set_error (error, context,
2121 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_INVALID_CONTENT,
2122 "Element <%s> is required to contain text and was empty\n",
2123 element_name);
2124 goto out;
2125 }
2126 break;
2127
2128 case MENU_LAYOUT_NODE_MENU:
2129 if (!has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
2130 {
2131 set_error (error, context,
2132 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2133 "<Menu> elements are required to contain a <Name> element\n");
2134 goto out;
2135 }
2136 break;
2137
2138 case MENU_LAYOUT_NODE_ROOT:
2139 case MENU_LAYOUT_NODE_PASSTHROUGH:
2140 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2141 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2142 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2143 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2144 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2145 case MENU_LAYOUT_NODE_INCLUDE:
2146 case MENU_LAYOUT_NODE_EXCLUDE:
2147 case MENU_LAYOUT_NODE_ALL:
2148 case MENU_LAYOUT_NODE_AND:
2149 case MENU_LAYOUT_NODE_OR:
2150 case MENU_LAYOUT_NODE_NOT:
2151 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2152 case MENU_LAYOUT_NODE_DELETED:
2153 case MENU_LAYOUT_NODE_NOT_DELETED:
2154 case MENU_LAYOUT_NODE_SEPARATOR:
2155 case MENU_LAYOUT_NODE_MERGE:
2156 case MENU_LAYOUT_NODE_MERGE_FILE:
2157 break;
2158
2159 case MENU_LAYOUT_NODE_LAYOUT:
2160 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2161 if (!fixup_layout_node (context, parser, parser->stack_top, error))
5
Calling 'fixup_layout_node'
2162 goto out;
2163 break;
2164
2165 case MENU_LAYOUT_NODE_MOVE:
2166 if (!fixup_move_node (context, parser, parser->stack_top, error))
2167 goto out;
2168 break;
2169 }
2170
2171 out:
2172 parser->stack_top = parser->stack_top->parent;
2173}
2174
2175static gboolean
2176all_whitespace (const char *text,
2177 int text_len)
2178{
2179 const char *p;
2180 const char *end;
2181
2182 p = text;
2183 end = text + text_len;
2184
2185 while (p != end)
2186 {
2187 if (!g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
2188 return FALSE(0);
2189
2190 p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
2191 }
2192
2193 return TRUE(!(0));
2194}
2195
2196static void
2197text_handler (GMarkupParseContext *context,
2198 const char *text,
2199 gsize text_len,
2200 gpointer user_data,
2201 GError **error)
2202{
2203 MenuParser *parser = user_data;
2204
2205 switch (parser->stack_top->type)
2206 {
2207 case MENU_LAYOUT_NODE_APP_DIR:
2208 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2209 case MENU_LAYOUT_NODE_NAME:
2210 case MENU_LAYOUT_NODE_DIRECTORY:
2211 case MENU_LAYOUT_NODE_FILENAME:
2212 case MENU_LAYOUT_NODE_CATEGORY:
2213 case MENU_LAYOUT_NODE_MERGE_FILE:
2214 case MENU_LAYOUT_NODE_MERGE_DIR:
2215 case MENU_LAYOUT_NODE_LEGACY_DIR:
2216 case MENU_LAYOUT_NODE_OLD:
2217 case MENU_LAYOUT_NODE_NEW:
2218 case MENU_LAYOUT_NODE_MENUNAME:
2219 g_assert (menu_layout_node_get_content (parser->stack_top) == NULL)do { if (menu_layout_node_get_content (parser->stack_top) ==
((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c"
, 2219, ((const char*) (__func__)), "menu_layout_node_get_content (parser->stack_top) == NULL"
); } while (0)
;
2220
2221 menu_layout_node_set_content (parser->stack_top, text);
2222 break;
2223
2224 case MENU_LAYOUT_NODE_ROOT:
2225 case MENU_LAYOUT_NODE_PASSTHROUGH:
2226 case MENU_LAYOUT_NODE_MENU:
2227 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2228 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2229 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2230 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2231 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2232 case MENU_LAYOUT_NODE_INCLUDE:
2233 case MENU_LAYOUT_NODE_EXCLUDE:
2234 case MENU_LAYOUT_NODE_ALL:
2235 case MENU_LAYOUT_NODE_AND:
2236 case MENU_LAYOUT_NODE_OR:
2237 case MENU_LAYOUT_NODE_NOT:
2238 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2239 case MENU_LAYOUT_NODE_MOVE:
2240 case MENU_LAYOUT_NODE_DELETED:
2241 case MENU_LAYOUT_NODE_NOT_DELETED:
2242 case MENU_LAYOUT_NODE_LAYOUT:
2243 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2244 case MENU_LAYOUT_NODE_SEPARATOR:
2245 case MENU_LAYOUT_NODE_MERGE:
2246 if (!all_whitespace (text, text_len))
2247 {
2248 set_error (error, context,
2249 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2250 "No text is allowed inside element <%s>",
2251 g_markup_parse_context_get_element (context));
2252 }
2253 break;
2254 }
2255
2256 add_context_to_error (error, context);
2257}
2258
2259static void
2260passthrough_handler (GMarkupParseContext *context,
2261 const char *passthrough_text,
2262 gsize text_len G_GNUC_UNUSED__attribute__ ((__unused__)),
2263 gpointer user_data,
2264 GError **error)
2265{
2266 MenuParser *parser = user_data;
2267 MenuLayoutNode *node;
2268
2269 /* don't push passthrough on the stack, it's not an element */
2270
2271 node = menu_layout_node_new (MENU_LAYOUT_NODE_PASSTHROUGH);
2272 menu_layout_node_set_content (node, passthrough_text);
2273
2274 menu_layout_node_append_child (parser->stack_top, node);
2275 menu_layout_node_unref (node);
2276
2277 add_context_to_error (error, context);
2278}
2279
2280static void
2281menu_parser_init (MenuParser *parser)
2282{
2283 parser->root = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT);
2284 parser->stack_top = parser->root;
2285}
2286
2287static void
2288menu_parser_free (MenuParser *parser)
2289{
2290 if (parser->root)
2291 menu_layout_node_unref (parser->root);
2292}
2293
2294MenuLayoutNode *
2295menu_layout_load (const char *filename,
2296 const char *non_prefixed_basename,
2297 GError **err)
2298{
2299 GMainContext *main_context;
2300 GMarkupParseContext *context;
2301 MenuLayoutNodeRoot *root;
2302 MenuLayoutNode *retval;
2303 MenuParser parser;
2304 GError *error;
2305 GString *str;
2306 char *text;
2307 char *s;
2308 gsize length;
2309
2310 text = NULL((void*)0);
2311 length = 0;
2312 retval = NULL((void*)0);
2313 context = NULL((void*)0);
2314
2315 main_context = g_main_context_get_thread_default ();
2316
2317 menu_verbose ("Loading \"%s\" from disk\n", filename);
2318
2319 if (!g_file_get_contents (filename,
2320 &text,
2321 &length,
2322 err))
2323 {
2324 menu_verbose ("Failed to load \"%s\"\n",
2325 filename);
2326 return NULL((void*)0);
2327 }
2328
2329 g_assert (text != NULL)do { if (text != ((void*)0)) ; else g_assertion_message_expr (
((gchar*) 0), "menu-layout.c", 2329, ((const char*) (__func__
)), "text != NULL"); } while (0)
;
2330
2331 menu_parser_init (&parser);
2332
2333 root = (MenuLayoutNodeRoot *) parser.root;
2334
2335 root->basedir = g_path_get_dirname (filename);
2336 menu_verbose ("Set basedir \"%s\"\n", root->basedir);
2337
2338 if (non_prefixed_basename)
2339 s = g_strdup (non_prefixed_basename)g_strdup_inline (non_prefixed_basename);
2340 else
2341 s = g_path_get_basename (filename);
2342 str = g_string_new (s);
2343 if (g_str_has_suffix (str->str, ".menu")(__builtin_constant_p (".menu")? __extension__ ({ const char *
const __str = (str->str); const char * const __suffix = (
".menu"); gboolean __result = (0); if (__str == ((void*)0) ||
__suffix == ((void*)0)) __result = (g_str_has_suffix) (__str
, __suffix); else { const size_t __str_len = strlen (((__str)
+ !(__str))); const size_t __suffix_len = strlen (((__suffix
) + !(__suffix))); if (__str_len >= __suffix_len) __result
= memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(
__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix
) (str->str, ".menu") )
)
2344 g_string_truncate (str, str->len - strlen (".menu"))g_string_truncate_inline (str, str->len - strlen (".menu")
)
;
2345
2346 root->name = str->str;
2347 menu_verbose ("Set menu name \"%s\"\n", root->name);
2348
2349 g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
2350 g_free (s);
2351
2352 context = g_markup_parse_context_new (&menu_funcs, 0, &parser, NULL((void*)0));
2353
2354 error = NULL((void*)0);
2355 if (!g_markup_parse_context_parse (context,
2356 text,
2357 length,
2358 &error))
2359 goto out;
2360
2361 error = NULL((void*)0);
2362 g_markup_parse_context_end_parse (context, &error);
2363
2364 root->main_context = main_context ? g_main_context_ref (main_context) : NULL((void*)0);
2365
2366 out:
2367 if (context)
2368 g_markup_parse_context_free (context);
2369 g_free (text);
2370
2371 if (error)
2372 {
2373 menu_verbose ("Error \"%s\" loading \"%s\"\n",
2374 error->message, filename);
2375 g_propagate_error (err, error);
2376 }
2377 else if (has_child_of_type (parser.root, MENU_LAYOUT_NODE_MENU))
2378 {
2379 menu_verbose ("File loaded OK\n");
2380 retval = parser.root;
2381 parser.root = NULL((void*)0);
2382 }
2383 else
2384 {
2385 menu_verbose ("Did not have a root element in file\n");
2386 g_set_error (err, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2387 "Menu file %s did not contain a root <Menu> element",
2388 filename);
2389 }
2390
2391 menu_parser_free (&parser);
2392
2393 return retval;
2394}