From 8d46b0347ce6cfff71a769b7aec8d402b572bb0b Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Thu, 15 Feb 2024 16:29:48 +0000 Subject: Deploy mate-desktop/mate-menus to github.com/mate-desktop/mate-menus.git:gh-pages --- .../index.html | 106 + .../report-092be5.html | 3075 +++++++++++++++++++ .../report-587aef.html | 3210 ++++++++++++++++++++ .../report-a1f4b3.html | 1113 +++++++ .../report-fb6164.html | 1417 +++++++++ .../scanview.css | 62 + .../sorttable.js | 492 +++ 7 files changed, 9475 insertions(+) create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/index.html create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/report-092be5.html create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/report-587aef.html create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/report-a1f4b3.html create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/report-fb6164.html create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/scanview.css create mode 100644 2024-02-15-162655-4954-1@29e36d7cf10c_master/sorttable.js (limited to '2024-02-15-162655-4954-1@29e36d7cf10c_master') diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/index.html b/2024-02-15-162655-4954-1@29e36d7cf10c_master/index.html new file mode 100644 index 0000000..726fe3e --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/index.html @@ -0,0 +1,106 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@80603059170b
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 17.0.6 (Fedora 17.0.6-2.fc39) +
Date:Thu Feb 15 16:26:55 2024
+

Bug Summary

+ + + + + + + +
Bug TypeQuantityDisplay?
All Bugs4
Logic error
Dereference of null pointer1
Unused code
Dead assignment2
Unreachable code1
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Unused codeDead assignmentmenu-layout.cfixup_move_node20811View Report
Unused codeDead assignmentmenu-monitor.cmonitor_callback1611View Report
Logic errorDereference of null pointermenu-layout.cmenu_layout_node_steal56751View Report
Unused codeUnreachable codetmp-introspectwsrdc1ky/MateMenu-2.0.cvalue_to_string1811View Report
+ + diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-092be5.html b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-092be5.html new file mode 100644 index 0000000..f8761a7 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-092be5.html @@ -0,0 +1,3075 @@ + + + +menu-layout.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:menu-layout.c
Warning:line 2081, column 15
Value stored to 'prev' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-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 -fcoverage-compilation-dir=/rootdir/libmenu -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D MATEMENU_I_KNOW_THIS_IS_UNSTABLE -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmenu -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-15-162655-4954-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 * Copyright (C) 2012-2021 MATE Developers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include <config.h>
24
25#include "menu-layout.h"
26
27#include <string.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <errno(*__errno_location ()).h>
32
33#include "entry-directories.h"
34#include "menu-util.h"
35
36typedef struct MenuLayoutNodeMenu MenuLayoutNodeMenu;
37typedef struct MenuLayoutNodeRoot MenuLayoutNodeRoot;
38typedef struct MenuLayoutNodeLegacyDir MenuLayoutNodeLegacyDir;
39typedef struct MenuLayoutNodeMergeFile MenuLayoutNodeMergeFile;
40typedef struct MenuLayoutNodeDefaultLayout MenuLayoutNodeDefaultLayout;
41typedef struct MenuLayoutNodeMenuname MenuLayoutNodeMenuname;
42typedef struct MenuLayoutNodeMerge MenuLayoutNodeMerge;
43
44struct MenuLayoutNode
45{
46 /* Node lists are circular, for length-one lists
47 * prev/next point back to the node itself.
48 */
49 MenuLayoutNode *prev;
50 MenuLayoutNode *next;
51 MenuLayoutNode *parent;
52 MenuLayoutNode *children;
53
54 char *content;
55
56 guint refcount : 20;
57 guint type : 7;
58};
59
60struct MenuLayoutNodeRoot
61{
62 MenuLayoutNode node;
63
64 char *basedir;
65 char *name;
66
67 GMainContext *main_context;
68
69 GSList *monitors;
70 GSource *monitors_idle_handler;
71};
72
73struct MenuLayoutNodeMenu
74{
75 MenuLayoutNode node;
76
77 MenuLayoutNode *name_node; /* cache of the <Name> node */
78
79 EntryDirectoryList *app_dirs;
80 EntryDirectoryList *dir_dirs;
81};
82
83struct MenuLayoutNodeLegacyDir
84{
85 MenuLayoutNode node;
86
87 char *prefix;
88};
89
90struct MenuLayoutNodeMergeFile
91{
92 MenuLayoutNode node;
93
94 MenuMergeFileType type;
95};
96
97struct MenuLayoutNodeDefaultLayout
98{
99 MenuLayoutNode node;
100
101 MenuLayoutValues layout_values;
102};
103
104struct MenuLayoutNodeMenuname
105{
106 MenuLayoutNode node;
107
108 MenuLayoutValues layout_values;
109};
110
111struct MenuLayoutNodeMerge
112{
113 MenuLayoutNode node;
114
115 MenuLayoutMergeType merge_type;
116};
117
118typedef struct
119{
120 MenuLayoutNodeEntriesChangedFunc callback;
121 gpointer user_data;
122} MenuLayoutNodeEntriesMonitor;
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 { (void) 0; } 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,
163 MenuLayoutNode *node)
164{
165 MenuLayoutNodeRoot *nr;
166
167 g_assert (node->type == MENU_LAYOUT_NODE_MENU)do { (void) 0; } 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{ (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{ (void)0; }while (0);
209 g_return_if_fail (node->refcount > 0)do{ (void)0; }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 { (void) 0; } 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{ (void)0; }while (0);
411 g_return_if_fail (new_sibling->parent == NULL)do{ (void)0; }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{ (void)0; }while (0);
435 g_return_if_fail (new_sibling->parent == NULL)do{ (void)0; }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{ (void)0; }while (0);
489 g_return_if_fail (node->parent != NULL)do{ (void)0; }while (0);
490
491 menu_layout_node_steal (node);
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{ (void)0; }while (0);
529 g_return_if_fail (node->parent != NULL)do{ (void)0; }while (0);
530
531 switch (node->type)
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;
555 }
556
557 if (node->parent && node->parent->children == node)
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;
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{ (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{ (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{ (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 { (void) 0; } 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 { (void) 0; } 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{ (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{ (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{ (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{ (void)0; }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{ (void)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{ (void)0; }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{ (void)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{ (void)0; }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{ (void)0; }while (0);
950 g_return_if_fail (values != NULL)do{ (void)0; }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{ (void)0; }while (0);
964 g_return_if_fail (values != NULL)do{ (void)0; }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 unsigned long limit;
1002
1003 limit = strtoul (inline_limit, &end, 10);
1004 if (*end == '\0')
1005 {
1006 values->inline_limit = (guint) 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{ (void)0; }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{ (void)0; }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{ (void)0; }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{ (void)0; }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 * Menu file parsing
1134 */
1135
1136typedef struct
1137{
1138 MenuLayoutNode *root;
1139 MenuLayoutNode *stack_top;
1140} MenuParser;
1141
1142static void set_error (GError **err,
1143 GMarkupParseContext *context,
1144 GQuark error_domain,
1145 int error_code,
1146 const char *format,
1147 ...) G_GNUC_PRINTF (5, 6)__attribute__((__format__ (__printf__, 5, 6)));
1148
1149static void add_context_to_error (GError **err,
1150 GMarkupParseContext *context);
1151
1152static void start_element_handler (GMarkupParseContext *context,
1153 const char *element_name,
1154 const char **attribute_names,
1155 const char **attribute_values,
1156 gpointer user_data,
1157 GError **error);
1158static void end_element_handler (GMarkupParseContext *context,
1159 const char *element_name,
1160 gpointer user_data,
1161 GError **error);
1162static void text_handler (GMarkupParseContext *context,
1163 const char *text,
1164 gsize text_len,
1165 gpointer user_data,
1166 GError **error);
1167static void passthrough_handler (GMarkupParseContext *context,
1168 const char *passthrough_text,
1169 gsize text_len,
1170 gpointer user_data,
1171 GError **error);
1172
1173static GMarkupParser menu_funcs = {
1174 start_element_handler,
1175 end_element_handler,
1176 text_handler,
1177 passthrough_handler,
1178 NULL((void*)0)
1179};
1180
1181static void
1182set_error (GError **err,
1183 GMarkupParseContext *context,
1184 GQuark error_domain,
1185 int error_code,
1186 const char *format,
1187 ...)
1188{
1189 int line, ch;
1190 va_list args;
1191 char *str;
1192
1193 g_markup_parse_context_get_position (context, &line, &ch);
1194
1195 va_start (args, format)__builtin_va_start(args, format);
1196 str = g_strdup_vprintf (format, args);
1197 va_end (args)__builtin_va_end(args);
1198
1199 g_set_error (err, error_domain, error_code,
1200 "Line %d character %d: %s",
1201 line, ch, str);
1202
1203 g_free (str);
1204}
1205
1206static void
1207add_context_to_error (GError **err,
1208 GMarkupParseContext *context)
1209{
1210 int line, ch;
1211 char *str;
1212
1213 if (err == NULL((void*)0) || *err == NULL((void*)0))
1214 return;
1215
1216 g_markup_parse_context_get_position (context, &line, &ch);
1217
1218 str = g_strdup_printf ("Line %d character %d: %s",
1219 line, ch, (*err)->message);
1220 g_free ((*err)->message);
1221 (*err)->message = str;
1222}
1223
1224#define ELEMENT_IS(name)(strcmp (element_name, (name)) == 0) (strcmp (element_name, (name)) == 0)
1225
1226typedef struct
1227{
1228 const char *name;
1229 const char **retloc;
1230} LocateAttr;
1231
1232static gboolean
1233locate_attributes (GMarkupParseContext *context,
1234 const char *element_name,
1235 const char **attribute_names,
1236 const char **attribute_values,
1237 GError **error,
1238 const char *first_attribute_name,
1239 const char **first_attribute_retloc,
1240 ...)
1241{
1242#define MAX_ATTRS 24
1243 LocateAttr attrs[MAX_ATTRS];
1244 int n_attrs;
1245 va_list args;
1246 const char *name;
1247 const char **retloc;
1248 gboolean retval;
1249 int i;
1250
1251 g_return_val_if_fail (first_attribute_name != NULL, FALSE)do{ (void)0; }while (0);
1252 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE)do{ (void)0; }while (0);
1253
1254 retval = TRUE(!(0));
1255
1256 n_attrs = 1;
1257 attrs[0].name = first_attribute_name;
1258 attrs[0].retloc = first_attribute_retloc;
1259 *first_attribute_retloc = NULL((void*)0);
1260
1261 va_start (args, first_attribute_retloc)__builtin_va_start(args, first_attribute_retloc);
1262
1263 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1264 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1265
1266 while (name != NULL((void*)0))
1267 {
1268 g_return_val_if_fail (retloc != NULL, FALSE)do{ (void)0; }while (0);
1269
1270 g_assert (n_attrs < MAX_ATTRS)do { (void) 0; } while (0);
1271
1272 attrs[n_attrs].name = name;
1273 attrs[n_attrs].retloc = retloc;
1274 n_attrs += 1;
1275 *retloc = NULL((void*)0);
1276
1277 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1278 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1279 }
1280
1281 va_end (args)__builtin_va_end(args);
1282
1283 i = 0;
1284 while (attribute_names[i])
1285 {
1286 int j;
1287
1288 j = 0;
1289 while (j < n_attrs)
1290 {
1291 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
1292 {
1293 retloc = attrs[j].retloc;
1294
1295 if (*retloc != NULL((void*)0))
1296 {
1297 set_error (error, context,
1298 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1299 "Attribute \"%s\" repeated twice on the same <%s> element",
1300 attrs[j].name, element_name);
1301 retval = FALSE(0);
1302 goto out;
1303 }
1304
1305 *retloc = attribute_values[i];
1306 break;
1307 }
1308
1309 ++j;
1310 }
1311
1312 if (j == n_attrs)
1313 {
1314 set_error (error, context,
1315 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1316 "Attribute \"%s\" is invalid on <%s> element in this context",
1317 attribute_names[i], element_name);
1318 retval = FALSE(0);
1319 goto out;
1320 }
1321
1322 ++i;
1323 }
1324
1325 out:
1326 return retval;
1327
1328#undef MAX_ATTRS
1329}
1330
1331static gboolean
1332check_no_attributes (GMarkupParseContext *context,
1333 const char *element_name,
1334 const char **attribute_names,
1335 const char **attribute_values,
1336 GError **error)
1337{
1338 if (attribute_names[0] != NULL((void*)0))
1339 {
1340 set_error (error, context,
1341 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1342 "Attribute \"%s\" is invalid on <%s> element in this context",
1343 attribute_names[0], element_name);
1344 return FALSE(0);
1345 }
1346
1347 return TRUE(!(0));
1348}
1349
1350static int
1351has_child_of_type (MenuLayoutNode *node,
1352 MenuLayoutNodeType type)
1353{
1354 MenuLayoutNode *iter;
1355
1356 iter = node->children;
1357 while (iter)
1358 {
1359 if (iter->type == type)
1360 return TRUE(!(0));
1361
1362 iter = node_next (iter);
1363 }
1364
1365 return FALSE(0);
1366}
1367
1368static void
1369push_node (MenuParser *parser,
1370 MenuLayoutNodeType type)
1371{
1372 MenuLayoutNode *node;
1373
1374 node = menu_layout_node_new (type);
1375 menu_layout_node_append_child (parser->stack_top, node);
1376 menu_layout_node_unref (node);
1377
1378 parser->stack_top = node;
1379}
1380
1381static void
1382start_menu_element (MenuParser *parser,
1383 GMarkupParseContext *context,
1384 const char *element_name,
1385 const char **attribute_names,
1386 const char **attribute_values,
1387 GError **error)
1388{
1389 if (!check_no_attributes (context, element_name,
1390 attribute_names, attribute_values,
1391 error))
1392 return;
1393
1394 if (!(parser->stack_top->type == MENU_LAYOUT_NODE_ROOT ||
1395 parser->stack_top->type == MENU_LAYOUT_NODE_MENU))
1396 {
1397 set_error (error, context,
1398 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1399 "<Menu> element can only appear below other <Menu> elements or at toplevel\n");
1400 }
1401 else
1402 {
1403 push_node (parser, MENU_LAYOUT_NODE_MENU);
1404 }
1405}
1406
1407static void
1408start_menu_child_element (MenuParser *parser,
1409 GMarkupParseContext *context,
1410 const char *element_name,
1411 const char **attribute_names,
1412 const char **attribute_values,
1413 GError **error)
1414{
1415 if (ELEMENT_IS ("LegacyDir")(strcmp (element_name, ("LegacyDir")) == 0))
1416 {
1417 const char *prefix;
1418
1419 push_node (parser, MENU_LAYOUT_NODE_LEGACY_DIR);
1420
1421 if (!locate_attributes (context, element_name,
1422 attribute_names, attribute_values,
1423 error,
1424 "prefix", &prefix,
1425 NULL((void*)0)))
1426 return;
1427
1428 menu_layout_node_legacy_dir_set_prefix (parser->stack_top, prefix);
1429 }
1430 else if (ELEMENT_IS ("MergeFile")(strcmp (element_name, ("MergeFile")) == 0))
1431 {
1432 const char *type;
1433
1434 push_node (parser, MENU_LAYOUT_NODE_MERGE_FILE);
1435
1436 if (!locate_attributes (context, element_name,
1437 attribute_names, attribute_values,
1438 error,
1439 "type", &type,
1440 NULL((void*)0)))
1441 return;
1442
1443 if (type != NULL((void*)0) && strcmp (type, "parent") == 0)
1444 {
1445 menu_layout_node_merge_file_set_type (parser->stack_top,
1446 MENU_MERGE_FILE_TYPE_PARENT);
1447 }
1448 }
1449 else if (ELEMENT_IS ("DefaultLayout")(strcmp (element_name, ("DefaultLayout")) == 0))
1450 {
1451 const char *show_empty;
1452 const char *inline_menus;
1453 const char *inline_limit;
1454 const char *inline_header;
1455 const char *inline_alias;
1456
1457 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
1458
1459 locate_attributes (context, element_name,
1460 attribute_names, attribute_values,
1461 error,
1462 "show_empty", &show_empty,
1463 "inline", &inline_menus,
1464 "inline_limit", &inline_limit,
1465 "inline_header", &inline_header,
1466 "inline_alias", &inline_alias,
1467 NULL((void*)0));
1468
1469 menu_layout_node_default_layout_set_values (parser->stack_top,
1470 show_empty,
1471 inline_menus,
1472 inline_limit,
1473 inline_header,
1474 inline_alias);
1475 }
1476 else
1477 {
1478 if (!check_no_attributes (context, element_name,
1479 attribute_names, attribute_values,
1480 error))
1481 return;
1482
1483 if (ELEMENT_IS ("AppDir")(strcmp (element_name, ("AppDir")) == 0))
1484 {
1485 push_node (parser, MENU_LAYOUT_NODE_APP_DIR);
1486 }
1487 else if (ELEMENT_IS ("DefaultAppDirs")(strcmp (element_name, ("DefaultAppDirs")) == 0))
1488 {
1489 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_APP_DIRS);
1490 }
1491 else if (ELEMENT_IS ("DirectoryDir")(strcmp (element_name, ("DirectoryDir")) == 0))
1492 {
1493 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY_DIR);
1494 }
1495 else if (ELEMENT_IS ("DefaultDirectoryDirs")(strcmp (element_name, ("DefaultDirectoryDirs")) == 0))
1496 {
1497 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS);
1498 }
1499 else if (ELEMENT_IS ("DefaultMergeDirs")(strcmp (element_name, ("DefaultMergeDirs")) == 0))
1500 {
1501 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS);
1502 }
1503 else if (ELEMENT_IS ("Name")(strcmp (element_name, ("Name")) == 0))
1504 {
1505 if (has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
1506 {
1507 set_error (error, context,
1508 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1509 "Multiple <Name> elements in a <Menu> element is not allowed\n");
1510 return;
1511 }
1512
1513 push_node (parser, MENU_LAYOUT_NODE_NAME);
1514 }
1515 else if (ELEMENT_IS ("Directory")(strcmp (element_name, ("Directory")) == 0))
1516 {
1517 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY);
1518 }
1519 else if (ELEMENT_IS ("OnlyUnallocated")(strcmp (element_name, ("OnlyUnallocated")) == 0))
1520 {
1521 push_node (parser, MENU_LAYOUT_NODE_ONLY_UNALLOCATED);
1522 }
1523 else if (ELEMENT_IS ("NotOnlyUnallocated")(strcmp (element_name, ("NotOnlyUnallocated")) == 0))
1524 {
1525 push_node (parser, MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED);
1526 }
1527 else if (ELEMENT_IS ("Include")(strcmp (element_name, ("Include")) == 0))
1528 {
1529 push_node (parser, MENU_LAYOUT_NODE_INCLUDE);
1530 }
1531 else if (ELEMENT_IS ("Exclude")(strcmp (element_name, ("Exclude")) == 0))
1532 {
1533 push_node (parser, MENU_LAYOUT_NODE_EXCLUDE);
1534 }
1535 else if (ELEMENT_IS ("MergeDir")(strcmp (element_name, ("MergeDir")) == 0))
1536 {
1537 push_node (parser, MENU_LAYOUT_NODE_MERGE_DIR);
1538 }
1539 else if (ELEMENT_IS ("KDELegacyDirs")(strcmp (element_name, ("KDELegacyDirs")) == 0))
1540 {
1541 push_node (parser, MENU_LAYOUT_NODE_KDE_LEGACY_DIRS);
1542 }
1543 else if (ELEMENT_IS ("Move")(strcmp (element_name, ("Move")) == 0))
1544 {
1545 push_node (parser, MENU_LAYOUT_NODE_MOVE);
1546 }
1547 else if (ELEMENT_IS ("Deleted")(strcmp (element_name, ("Deleted")) == 0))
1548 {
1549 push_node (parser, MENU_LAYOUT_NODE_DELETED);
1550
1551 }
1552 else if (ELEMENT_IS ("NotDeleted")(strcmp (element_name, ("NotDeleted")) == 0))
1553 {
1554 push_node (parser, MENU_LAYOUT_NODE_NOT_DELETED);
1555 }
1556 else if (ELEMENT_IS ("Layout")(strcmp (element_name, ("Layout")) == 0))
1557 {
1558 push_node (parser, MENU_LAYOUT_NODE_LAYOUT);
1559 }
1560 else
1561 {
1562 set_error (error, context,
1563 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1564 "Element <%s> may not appear below <%s>\n",
1565 element_name, "Menu");
1566 }
1567 }
1568}
1569
1570static void
1571start_matching_rule_element (MenuParser *parser,
1572 GMarkupParseContext *context,
1573 const char *element_name,
1574 const char **attribute_names,
1575 const char **attribute_values,
1576 GError **error)
1577{
1578 if (!check_no_attributes (context, element_name,
1579 attribute_names, attribute_values,
1580 error))
1581 return;
1582
1583 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1584 {
1585 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1586 }
1587 else if (ELEMENT_IS ("Category")(strcmp (element_name, ("Category")) == 0))
1588 {
1589 push_node (parser, MENU_LAYOUT_NODE_CATEGORY);
1590 }
1591 else if (ELEMENT_IS ("All")(strcmp (element_name, ("All")) == 0))
1592 {
1593 push_node (parser, MENU_LAYOUT_NODE_ALL);
1594 }
1595 else if (ELEMENT_IS ("And")(strcmp (element_name, ("And")) == 0))
1596 {
1597 push_node (parser, MENU_LAYOUT_NODE_AND);
1598 }
1599 else if (ELEMENT_IS ("Or")(strcmp (element_name, ("Or")) == 0))
1600 {
1601 push_node (parser, MENU_LAYOUT_NODE_OR);
1602 }
1603 else if (ELEMENT_IS ("Not")(strcmp (element_name, ("Not")) == 0))
1604 {
1605 push_node (parser, MENU_LAYOUT_NODE_NOT);
1606 }
1607 else
1608 {
1609 set_error (error, context,
1610 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1611 "Element <%s> may not appear in this context\n",
1612 element_name);
1613 }
1614}
1615
1616static void
1617start_move_child_element (MenuParser *parser,
1618 GMarkupParseContext *context,
1619 const char *element_name,
1620 const char **attribute_names,
1621 const char **attribute_values,
1622 GError **error)
1623{
1624 if (!check_no_attributes (context, element_name,
1625 attribute_names, attribute_values,
1626 error))
1627 return;
1628
1629 if (ELEMENT_IS ("Old")(strcmp (element_name, ("Old")) == 0))
1630 {
1631 push_node (parser, MENU_LAYOUT_NODE_OLD);
1632 }
1633 else if (ELEMENT_IS ("New")(strcmp (element_name, ("New")) == 0))
1634 {
1635 push_node (parser, MENU_LAYOUT_NODE_NEW);
1636 }
1637 else
1638 {
1639 set_error (error, context,
1640 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1641 "Element <%s> may not appear below <%s>\n",
1642 element_name, "Move");
1643 }
1644}
1645
1646static void
1647start_layout_child_element (MenuParser *parser,
1648 GMarkupParseContext *context,
1649 const char *element_name,
1650 const char **attribute_names,
1651 const char **attribute_values,
1652 GError **error)
1653{
1654 if (ELEMENT_IS ("Menuname")(strcmp (element_name, ("Menuname")) == 0))
1655 {
1656 const char *show_empty;
1657 const char *inline_menus;
1658 const char *inline_limit;
1659 const char *inline_header;
1660 const char *inline_alias;
1661
1662 push_node (parser, MENU_LAYOUT_NODE_MENUNAME);
1663
1664 locate_attributes (context, element_name,
1665 attribute_names, attribute_values,
1666 error,
1667 "show_empty", &show_empty,
1668 "inline", &inline_menus,
1669 "inline_limit", &inline_limit,
1670 "inline_header", &inline_header,
1671 "inline_alias", &inline_alias,
1672 NULL((void*)0));
1673
1674 menu_layout_node_menuname_set_values (parser->stack_top,
1675 show_empty,
1676 inline_menus,
1677 inline_limit,
1678 inline_header,
1679 inline_alias);
1680 }
1681 else if (ELEMENT_IS ("Merge")(strcmp (element_name, ("Merge")) == 0))
1682 {
1683 const char *type;
1684
1685 push_node (parser, MENU_LAYOUT_NODE_MERGE);
1686
1687 locate_attributes (context, element_name,
1688 attribute_names, attribute_values,
1689 error,
1690 "type", &type,
1691 NULL((void*)0));
1692
1693 menu_layout_node_merge_set_type (parser->stack_top, type);
1694 }
1695 else
1696 {
1697 if (!check_no_attributes (context, element_name,
1698 attribute_names, attribute_values,
1699 error))
1700 return;
1701
1702 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1703 {
1704 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1705 }
1706 else if (ELEMENT_IS ("Separator")(strcmp (element_name, ("Separator")) == 0))
1707 {
1708 push_node (parser, MENU_LAYOUT_NODE_SEPARATOR);
1709 }
1710 else
1711 {
1712 set_error (error, context,
1713 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1714 "Element <%s> may not appear below <%s>\n",
1715 element_name, "Move");
1716 }
1717 }
1718}
1719
1720static void
1721start_element_handler (GMarkupParseContext *context,
1722 const char *element_name,
1723 const char **attribute_names,
1724 const char **attribute_values,
1725 gpointer user_data,
1726 GError **error)
1727{
1728 MenuParser *parser = user_data;
1729
1730 if (ELEMENT_IS ("Menu")(strcmp (element_name, ("Menu")) == 0))
1731 {
1732 if (parser->stack_top == parser->root &&
1733 has_child_of_type (parser->root, MENU_LAYOUT_NODE_MENU))
1734 {
1735 set_error (error, context,
1736 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1737 "Multiple root elements in menu file, only one toplevel <Menu> is allowed\n");
1738 return;
1739 }
1740
1741 start_menu_element (parser, context, element_name,
1742 attribute_names, attribute_values,
1743 error);
1744 }
1745 else if (parser->stack_top == parser->root)
1746 {
1747 set_error (error, context,
1748 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1749 "Root element in a menu file must be <Menu>, not <%s>\n",
1750 element_name);
1751 }
1752 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MENU)
1753 {
1754 start_menu_child_element (parser, context, element_name,
1755 attribute_names, attribute_values,
1756 error);
1757 }
1758 else if (parser->stack_top->type == MENU_LAYOUT_NODE_INCLUDE ||
1759 parser->stack_top->type == MENU_LAYOUT_NODE_EXCLUDE ||
1760 parser->stack_top->type == MENU_LAYOUT_NODE_AND ||
1761 parser->stack_top->type == MENU_LAYOUT_NODE_OR ||
1762 parser->stack_top->type == MENU_LAYOUT_NODE_NOT)
1763 {
1764 start_matching_rule_element (parser, context, element_name,
1765 attribute_names, attribute_values,
1766 error);
1767 }
1768 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MOVE)
1769 {
1770 start_move_child_element (parser, context, element_name,
1771 attribute_names, attribute_values,
1772 error);
1773 }
1774 else if (parser->stack_top->type == MENU_LAYOUT_NODE_LAYOUT ||
1775 parser->stack_top->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)
1776 {
1777 start_layout_child_element (parser, context, element_name,
1778 attribute_names, attribute_values,
1779 error);
1780 }
1781 else
1782 {
1783 set_error (error, context,
1784 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1785 "Element <%s> may not appear in this context\n",
1786 element_name);
1787 }
1788
1789 add_context_to_error (error, context);
1790}
1791
1792/* we want to make sure that the <Layout> or <DefaultLayout> is either empty,
1793 * or contain one <Merge> of type "all", or contain one <Merge> of type "menus"
1794 * and one <Merge> of type "files". If this is not the case, we try to clean up
1795 * things:
1796 * + if there is at least one <Merge> of type "all", then we only keep the
1797 * last <Merge> of type "all" and remove all others <Merge>
1798 * + if there is no <Merge> with type "all", we keep only the last <Merge> of
1799 * type "menus" and the last <Merge> of type "files". If there's no <Merge>
1800 * of type "menus" we append one, and then if there's no <Merge> of type
1801 * "files", we append one. (So menus are before files)
1802 */
1803static gboolean
1804fixup_layout_node (GMarkupParseContext *context,
1805 MenuParser *parser,
1806 MenuLayoutNode *node,
1807 GError **error)
1808{
1809 MenuLayoutNode *child;
1810 MenuLayoutNode *last_all;
1811 MenuLayoutNode *last_menus;
1812 MenuLayoutNode *last_files;
1813 int n_all;
1814 int n_menus;
1815 int n_files;
1816
1817 if (!node->children)
1818 {
1819 return TRUE(!(0));
1820 }
1821
1822 last_all = NULL((void*)0);
1823 last_menus = NULL((void*)0);
1824 last_files = NULL((void*)0);
1825 n_all = 0;
1826 n_menus = 0;
1827 n_files = 0;
1828
1829 child = node->children;
1830 while (child != NULL((void*)0))
1831 {
1832 switch (child->type)
1833 {
1834 case MENU_LAYOUT_NODE_MERGE:
1835 switch (menu_layout_node_merge_get_type (child))
1836 {
1837 case MENU_LAYOUT_MERGE_NONE:
1838 break;
1839
1840 case MENU_LAYOUT_MERGE_MENUS:
1841 last_menus = child;
1842 n_menus++;
1843 break;
1844
1845 case MENU_LAYOUT_MERGE_FILES:
1846 last_files = child;
1847 n_files++;
1848 break;
1849
1850 case MENU_LAYOUT_MERGE_ALL:
1851 last_all = child;
1852 n_all++;
1853 break;
1854
1855 default:
1856 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1857 break;
1858 }
1859 break;
1860
1861 default:
1862 break;
1863 }
1864
1865 child = node_next (child);
1866 }
1867
1868 if ((n_all == 1 && n_menus == 0 && n_files == 0) ||
1869 (n_all == 0 && n_menus == 1 && n_files == 1))
1870 {
1871 return TRUE(!(0));
1872 }
1873 else if (n_all > 1 || n_menus > 1 || n_files > 1 ||
1874 (n_all == 1 && (n_menus != 0 || n_files != 0)))
1875 {
1876 child = node->children;
1877 while (child != NULL((void*)0))
1878 {
1879 MenuLayoutNode *next;
1880
1881 next = node_next (child);
1882
1883 switch (child->type)
1884 {
1885 case MENU_LAYOUT_NODE_MERGE:
1886 switch (menu_layout_node_merge_get_type (child))
1887 {
1888 case MENU_LAYOUT_MERGE_NONE:
1889 break;
1890
1891 case MENU_LAYOUT_MERGE_MENUS:
1892 if (n_all || last_menus != child)
1893 {
1894 menu_verbose ("removing duplicated merge menus element\n");
1895 menu_layout_node_unlink (child);
1896 }
1897 break;
1898
1899 case MENU_LAYOUT_MERGE_FILES:
1900 if (n_all || last_files != child)
1901 {
1902 menu_verbose ("removing duplicated merge files element\n");
1903 menu_layout_node_unlink (child);
1904 }
1905 break;
1906
1907 case MENU_LAYOUT_MERGE_ALL:
1908 if (last_all != child)
1909 {
1910 menu_verbose ("removing duplicated merge all element\n");
1911 menu_layout_node_unlink (child);
1912 }
1913 break;
1914
1915 default:
1916 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1917 break;
1918 }
1919 break;
1920
1921 default:
1922 break;
1923 }
1924
1925 child = next;
1926 }
1927 }
1928
1929 if (n_all == 0 && n_menus == 0)
1930 {
1931 last_menus = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1932 menu_layout_node_merge_set_type (last_menus, "menus");
1933 menu_verbose ("appending missing merge menus element\n");
1934 menu_layout_node_append_child (node, last_menus);
1935 }
1936
1937 if (n_all == 0 && n_files == 0)
1938 {
1939 last_files = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1940 menu_layout_node_merge_set_type (last_files, "files");
1941 menu_verbose ("appending missing merge files element\n");
1942 menu_layout_node_append_child (node, last_files);
1943 }
1944
1945 return TRUE(!(0));
1946}
1947
1948/* we want to a) check that we have old-new pairs and b) canonicalize
1949 * such that each <Move> has exactly one old-new pair
1950 */
1951static gboolean
1952fixup_move_node (GMarkupParseContext *context,
1953 MenuParser *parser,
1954 MenuLayoutNode *node,
1955 GError **error)
1956{
1957 MenuLayoutNode *child;
1958 int n_old;
1959 int n_new;
1960
1961 n_old = 0;
1962 n_new = 0;
1963
1964 child = node->children;
1965 while (child != NULL((void*)0))
1966 {
1967 switch (child->type)
1968 {
1969 case MENU_LAYOUT_NODE_OLD:
1970 if (n_new != n_old)
1971 {
1972 set_error (error, context,
1973 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1974 "<Old>/<New> elements not paired properly\n");
1975 return FALSE(0);
1976 }
1977
1978 n_old += 1;
1979
1980 break;
1981
1982 case MENU_LAYOUT_NODE_NEW:
1983 n_new += 1;
1984
1985 if (n_new != n_old)
1986 {
1987 set_error (error, context,
1988 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1989 "<Old>/<New> elements not paired properly\n");
1990 return FALSE(0);
1991 }
1992
1993 break;
1994
1995 default:
1996 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1997 break;
1998 }
1999
2000 child = node_next (child);
2001 }
2002
2003 if (n_new == 0 || n_old == 0)
2004 {
2005 set_error (error, context,
2006 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2007 "<Old>/<New> elements missing under <Move>\n");
2008 return FALSE(0);
2009 }
2010
2011 g_assert (n_new == n_old)do { (void) 0; } while (0);
2012 g_assert ((n_new + n_old) % 2 == 0)do { (void) 0; } while (0);
2013
2014 if (n_new > 1)
2015 {
2016 MenuLayoutNode *prev;
2017 MenuLayoutNode *append_after;
2018
2019 /* Need to split the <Move> into multiple <Move> */
2020
2021 n_old = 0;
2022 n_new = 0;
2023 prev = NULL((void*)0);
2024 append_after = node;
2025
2026 child = node->children;
2027 while (child != NULL((void*)0))
2028 {
2029 MenuLayoutNode *next;
2030
2031 next = node_next (child);
2032
2033 switch (child->type)
2034 {
2035 case MENU_LAYOUT_NODE_OLD:
2036 n_old += 1;
2037 break;
2038
2039 case MENU_LAYOUT_NODE_NEW:
2040 n_new += 1;
2041 break;
2042
2043 default:
2044 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
2045 break;
2046 }
2047
2048 if (n_old == n_new &&
2049 n_old > 1)
2050 {
2051 /* Move the just-completed pair */
2052 MenuLayoutNode *new_move;
2053
2054 g_assert (prev != NULL)do { (void) 0; } while (0);
2055
2056 new_move = menu_layout_node_new (MENU_LAYOUT_NODE_MOVE);
2057 menu_verbose ("inserting new_move after append_after\n");
2058 menu_layout_node_insert_after (append_after, new_move);
2059 append_after = new_move;
2060
2061 menu_layout_node_steal (prev);
2062 menu_layout_node_steal (child);
2063
2064 menu_verbose ("appending prev to new_move\n");
2065 menu_layout_node_append_child (new_move, prev);
2066 menu_verbose ("appending child to new_move\n");
2067 menu_layout_node_append_child (new_move, child);
2068
2069 menu_verbose ("Created new move element old = %s new = %s\n",
2070 menu_layout_node_move_get_old (new_move),
2071 menu_layout_node_move_get_new (new_move));
2072
2073 menu_layout_node_unref (new_move);
2074 menu_layout_node_unref (prev);
2075 menu_layout_node_unref (child);
2076
2077 prev = NULL((void*)0);
2078 }
2079 else
2080 {
2081 prev = child;
Value stored to 'prev' is never read
2082 }
2083
2084 prev = child;
2085 child = next;
2086 }
2087 }
2088
2089 return TRUE(!(0));
2090}
2091
2092static void
2093end_element_handler (GMarkupParseContext *context,
2094 const char *element_name,
2095 gpointer user_data,
2096 GError **error)
2097{
2098 MenuParser *parser = user_data;
2099
2100 g_assert (parser->stack_top != NULL)do { (void) 0; } while (0);
2101
2102 switch (parser->stack_top->type)
2103 {
2104 case MENU_LAYOUT_NODE_APP_DIR:
2105 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2106 case MENU_LAYOUT_NODE_NAME:
2107 case MENU_LAYOUT_NODE_DIRECTORY:
2108 case MENU_LAYOUT_NODE_FILENAME:
2109 case MENU_LAYOUT_NODE_CATEGORY:
2110 case MENU_LAYOUT_NODE_MERGE_DIR:
2111 case MENU_LAYOUT_NODE_LEGACY_DIR:
2112 case MENU_LAYOUT_NODE_OLD:
2113 case MENU_LAYOUT_NODE_NEW:
2114 case MENU_LAYOUT_NODE_MENUNAME:
2115 if (menu_layout_node_get_content (parser->stack_top) == NULL((void*)0))
2116 {
2117 set_error (error, context,
2118 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_INVALID_CONTENT,
2119 "Element <%s> is required to contain text and was empty\n",
2120 element_name);
2121 goto out;
2122 }
2123 break;
2124
2125 case MENU_LAYOUT_NODE_MENU:
2126 if (!has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
2127 {
2128 set_error (error, context,
2129 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2130 "<Menu> elements are required to contain a <Name> element\n");
2131 goto out;
2132 }
2133 break;
2134
2135 case MENU_LAYOUT_NODE_ROOT:
2136 case MENU_LAYOUT_NODE_PASSTHROUGH:
2137 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2138 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2139 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2140 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2141 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2142 case MENU_LAYOUT_NODE_INCLUDE:
2143 case MENU_LAYOUT_NODE_EXCLUDE:
2144 case MENU_LAYOUT_NODE_ALL:
2145 case MENU_LAYOUT_NODE_AND:
2146 case MENU_LAYOUT_NODE_OR:
2147 case MENU_LAYOUT_NODE_NOT:
2148 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2149 case MENU_LAYOUT_NODE_DELETED:
2150 case MENU_LAYOUT_NODE_NOT_DELETED:
2151 case MENU_LAYOUT_NODE_SEPARATOR:
2152 case MENU_LAYOUT_NODE_MERGE:
2153 case MENU_LAYOUT_NODE_MERGE_FILE:
2154 break;
2155
2156 case MENU_LAYOUT_NODE_LAYOUT:
2157 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2158 if (!fixup_layout_node (context, parser, parser->stack_top, error))
2159 goto out;
2160 break;
2161
2162 case MENU_LAYOUT_NODE_MOVE:
2163 if (!fixup_move_node (context, parser, parser->stack_top, error))
2164 goto out;
2165 break;
2166 default:
2167 g_assert_not_reached()do { (void) 0; __builtin_unreachable (); } while (0);
2168 }
2169
2170 out:
2171 parser->stack_top = parser->stack_top->parent;
2172}
2173
2174static gboolean
2175all_whitespace (const char *text,
2176 gsize text_len)
2177{
2178 const char *p;
2179 const char *end;
2180
2181 p = text;
2182 end = text + text_len;
2183
2184 while (p != end)
2185 {
2186 if (!g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
2187 return FALSE(0);
2188
2189 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
2190 }
2191
2192 return TRUE(!(0));
2193}
2194
2195static void
2196text_handler (GMarkupParseContext *context,
2197 const char *text,
2198 gsize text_len,
2199 gpointer user_data,
2200 GError **error)
2201{
2202 MenuParser *parser = user_data;
2203
2204 switch (parser->stack_top->type)
2205 {
2206 case MENU_LAYOUT_NODE_APP_DIR:
2207 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2208 case MENU_LAYOUT_NODE_NAME:
2209 case MENU_LAYOUT_NODE_DIRECTORY:
2210 case MENU_LAYOUT_NODE_FILENAME:
2211 case MENU_LAYOUT_NODE_CATEGORY:
2212 case MENU_LAYOUT_NODE_MERGE_FILE:
2213 case MENU_LAYOUT_NODE_MERGE_DIR:
2214 case MENU_LAYOUT_NODE_LEGACY_DIR:
2215 case MENU_LAYOUT_NODE_OLD:
2216 case MENU_LAYOUT_NODE_NEW:
2217 case MENU_LAYOUT_NODE_MENUNAME:
2218 g_assert (menu_layout_node_get_content (parser->stack_top) == NULL)do { (void) 0; } while (0);
2219
2220 menu_layout_node_set_content (parser->stack_top, text);
2221 break;
2222
2223 case MENU_LAYOUT_NODE_ROOT:
2224 case MENU_LAYOUT_NODE_PASSTHROUGH:
2225 case MENU_LAYOUT_NODE_MENU:
2226 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2227 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2228 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2229 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2230 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2231 case MENU_LAYOUT_NODE_INCLUDE:
2232 case MENU_LAYOUT_NODE_EXCLUDE:
2233 case MENU_LAYOUT_NODE_ALL:
2234 case MENU_LAYOUT_NODE_AND:
2235 case MENU_LAYOUT_NODE_OR:
2236 case MENU_LAYOUT_NODE_NOT:
2237 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2238 case MENU_LAYOUT_NODE_MOVE:
2239 case MENU_LAYOUT_NODE_DELETED:
2240 case MENU_LAYOUT_NODE_NOT_DELETED:
2241 case MENU_LAYOUT_NODE_LAYOUT:
2242 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2243 case MENU_LAYOUT_NODE_SEPARATOR:
2244 case MENU_LAYOUT_NODE_MERGE:
2245 if (!all_whitespace (text, text_len))
2246 {
2247 set_error (error, context,
2248 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2249 "No text is allowed inside element <%s>",
2250 g_markup_parse_context_get_element (context));
2251 }
2252 break;
2253 default:
2254 g_assert_not_reached()do { (void) 0; __builtin_unreachable (); } while (0);
2255 }
2256
2257 add_context_to_error (error, context);
2258}
2259
2260static void
2261passthrough_handler (GMarkupParseContext *context,
2262 const char *passthrough_text,
2263 gsize text_len,
2264 gpointer user_data,
2265 GError **error)
2266{
2267 MenuParser *parser = user_data;
2268 MenuLayoutNode *node;
2269
2270 /* don't push passthrough on the stack, it's not an element */
2271
2272 node = menu_layout_node_new (MENU_LAYOUT_NODE_PASSTHROUGH);
2273 menu_layout_node_set_content (node, passthrough_text);
2274
2275 menu_layout_node_append_child (parser->stack_top, node);
2276 menu_layout_node_unref (node);
2277
2278 add_context_to_error (error, context);
2279}
2280
2281static void
2282menu_parser_init (MenuParser *parser)
2283{
2284 parser->root = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT);
2285 parser->stack_top = parser->root;
2286}
2287
2288static void
2289menu_parser_free (MenuParser *parser)
2290{
2291 if (parser->root)
2292 menu_layout_node_unref (parser->root);
2293}
2294
2295MenuLayoutNode *
2296menu_layout_load (const char *filename,
2297 const char *non_prefixed_basename,
2298 GError **err)
2299{
2300 GMainContext *main_context;
2301 GMarkupParseContext *context;
2302 MenuLayoutNodeRoot *root;
2303 MenuLayoutNode *retval;
2304 MenuParser parser;
2305 GError *error;
2306 GString *str;
2307 char *text;
2308 char *s;
2309 gsize length;
2310
2311 text = NULL((void*)0);
2312 length = 0;
2313 retval = NULL((void*)0);
2314 context = NULL((void*)0);
2315
2316 main_context = g_main_context_get_thread_default ();
2317
2318 menu_verbose ("Loading \"%s\" from disk\n", filename);
2319
2320 if (!g_file_get_contents (filename,
2321 &text,
2322 &length,
2323 err))
2324 {
2325 menu_verbose ("Failed to load \"%s\"\n",
2326 filename);
2327 return NULL((void*)0);
2328 }
2329
2330 g_assert (text != NULL)do { (void) 0; } while (0);
2331
2332 menu_parser_init (&parser);
2333
2334 root = (MenuLayoutNodeRoot *) parser.root;
2335
2336 root->basedir = g_path_get_dirname (filename);
2337 menu_verbose ("Set basedir \"%s\"\n", root->basedir);
2338
2339 if (non_prefixed_basename)
2340 s = g_strdup (non_prefixed_basename)g_strdup_inline (non_prefixed_basename);
2341 else
2342 s = g_path_get_basename (filename);
2343 str = g_string_new (s);
2344 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") )
)
2345 g_string_truncate (str, str->len - strlen (".menu"))g_string_truncate_inline (str, str->len - strlen (".menu")
)
;
2346
2347 root->name = str->str;
2348 menu_verbose ("Set menu name \"%s\"\n", root->name);
2349
2350 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))))
;
2351 g_free (s);
2352
2353 context = g_markup_parse_context_new (&menu_funcs, 0, &parser, NULL((void*)0));
2354
2355 error = NULL((void*)0);
2356 if (!g_markup_parse_context_parse (context,
2357 text,
2358 (gssize) length,
2359 &error))
2360 goto out;
2361
2362 error = NULL((void*)0);
2363 g_markup_parse_context_end_parse (context, &error);
2364
2365 root->main_context = main_context ? g_main_context_ref (main_context) : NULL((void*)0);
2366
2367 out:
2368 if (context)
2369 g_markup_parse_context_free (context);
2370 g_free (text);
2371
2372 if (error)
2373 {
2374 menu_verbose ("Error \"%s\" loading \"%s\"\n",
2375 error->message, filename);
2376 g_propagate_error (err, error);
2377 }
2378 else if (has_child_of_type (parser.root, MENU_LAYOUT_NODE_MENU))
2379 {
2380 menu_verbose ("File loaded OK\n");
2381 retval = parser.root;
2382 parser.root = NULL((void*)0);
2383 }
2384 else
2385 {
2386 menu_verbose ("Did not have a root element in file\n");
2387 g_set_error (err, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2388 "Menu file %s did not contain a root <Menu> element",
2389 filename);
2390 }
2391
2392 menu_parser_free (&parser);
2393
2394 return retval;
2395}
diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-587aef.html b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-587aef.html new file mode 100644 index 0000000..5b57799 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-587aef.html @@ -0,0 +1,3210 @@ + + + +menu-layout.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

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-redhat-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 -fcoverage-compilation-dir=/rootdir/libmenu -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D MATEMENU_I_KNOW_THIS_IS_UNSTABLE -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmenu -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-15-162655-4954-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 * Copyright (C) 2012-2021 MATE Developers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include <config.h>
24
25#include "menu-layout.h"
26
27#include <string.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <errno(*__errno_location ()).h>
32
33#include "entry-directories.h"
34#include "menu-util.h"
35
36typedef struct MenuLayoutNodeMenu MenuLayoutNodeMenu;
37typedef struct MenuLayoutNodeRoot MenuLayoutNodeRoot;
38typedef struct MenuLayoutNodeLegacyDir MenuLayoutNodeLegacyDir;
39typedef struct MenuLayoutNodeMergeFile MenuLayoutNodeMergeFile;
40typedef struct MenuLayoutNodeDefaultLayout MenuLayoutNodeDefaultLayout;
41typedef struct MenuLayoutNodeMenuname MenuLayoutNodeMenuname;
42typedef struct MenuLayoutNodeMerge MenuLayoutNodeMerge;
43
44struct MenuLayoutNode
45{
46 /* Node lists are circular, for length-one lists
47 * prev/next point back to the node itself.
48 */
49 MenuLayoutNode *prev;
50 MenuLayoutNode *next;
51 MenuLayoutNode *parent;
52 MenuLayoutNode *children;
53
54 char *content;
55
56 guint refcount : 20;
57 guint type : 7;
58};
59
60struct MenuLayoutNodeRoot
61{
62 MenuLayoutNode node;
63
64 char *basedir;
65 char *name;
66
67 GMainContext *main_context;
68
69 GSList *monitors;
70 GSource *monitors_idle_handler;
71};
72
73struct MenuLayoutNodeMenu
74{
75 MenuLayoutNode node;
76
77 MenuLayoutNode *name_node; /* cache of the <Name> node */
78
79 EntryDirectoryList *app_dirs;
80 EntryDirectoryList *dir_dirs;
81};
82
83struct MenuLayoutNodeLegacyDir
84{
85 MenuLayoutNode node;
86
87 char *prefix;
88};
89
90struct MenuLayoutNodeMergeFile
91{
92 MenuLayoutNode node;
93
94 MenuMergeFileType type;
95};
96
97struct MenuLayoutNodeDefaultLayout
98{
99 MenuLayoutNode node;
100
101 MenuLayoutValues layout_values;
102};
103
104struct MenuLayoutNodeMenuname
105{
106 MenuLayoutNode node;
107
108 MenuLayoutValues layout_values;
109};
110
111struct MenuLayoutNodeMerge
112{
113 MenuLayoutNode node;
114
115 MenuLayoutMergeType merge_type;
116};
117
118typedef struct
119{
120 MenuLayoutNodeEntriesChangedFunc callback;
121 gpointer user_data;
122} MenuLayoutNodeEntriesMonitor;
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 { (void) 0; } 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,
163 MenuLayoutNode *node)
164{
165 MenuLayoutNodeRoot *nr;
166
167 g_assert (node->type == MENU_LAYOUT_NODE_MENU)do { (void) 0; } 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{ (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{ (void)0; }while (0);
209 g_return_if_fail (node->refcount > 0)do{ (void)0; }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 { (void) 0; } 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{ (void)0; }while (0);
411 g_return_if_fail (new_sibling->parent == NULL)do{ (void)0; }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{ (void)0; }while (0);
435 g_return_if_fail (new_sibling->parent == NULL)do{ (void)0; }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{ (void)0; }while (0);
28
Loop condition is false. Exiting loop
489 g_return_if_fail (node->parent != NULL)do{ (void)0; }while (0);
29
Loop condition is false. Exiting loop
490
491 menu_layout_node_steal (node);
30
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{ (void)0; }while (0);
31
Loop condition is false. Exiting loop
529 g_return_if_fail (node->parent != NULL)do{ (void)0; }while (0);
32
Loop condition is false. Exiting loop
530
531 switch (node->type)
33
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;
34
Execution continues on line 557
555 }
556
557 if (node->parent
34.1
Field 'parent' is non-null
&& node->parent->children == node)
35
Assuming 'node' is not equal to field 'children'
36
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;
37
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{ (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{ (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{ (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 { (void) 0; } 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 { (void) 0; } 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{ (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{ (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{ (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{ (void)0; }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{ (void)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{ (void)0; }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{ (void)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{ (void)0; }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{ (void)0; }while (0);
950 g_return_if_fail (values != NULL)do{ (void)0; }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{ (void)0; }while (0);
964 g_return_if_fail (values != NULL)do{ (void)0; }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 unsigned long limit;
1002
1003 limit = strtoul (inline_limit, &end, 10);
1004 if (*end == '\0')
1005 {
1006 values->inline_limit = (guint) 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{ (void)0; }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{ (void)0; }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{ (void)0; }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{ (void)0; }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 * Menu file parsing
1134 */
1135
1136typedef struct
1137{
1138 MenuLayoutNode *root;
1139 MenuLayoutNode *stack_top;
1140} MenuParser;
1141
1142static void set_error (GError **err,
1143 GMarkupParseContext *context,
1144 GQuark error_domain,
1145 int error_code,
1146 const char *format,
1147 ...) G_GNUC_PRINTF (5, 6)__attribute__((__format__ (__printf__, 5, 6)));
1148
1149static void add_context_to_error (GError **err,
1150 GMarkupParseContext *context);
1151
1152static void start_element_handler (GMarkupParseContext *context,
1153 const char *element_name,
1154 const char **attribute_names,
1155 const char **attribute_values,
1156 gpointer user_data,
1157 GError **error);
1158static void end_element_handler (GMarkupParseContext *context,
1159 const char *element_name,
1160 gpointer user_data,
1161 GError **error);
1162static void text_handler (GMarkupParseContext *context,
1163 const char *text,
1164 gsize text_len,
1165 gpointer user_data,
1166 GError **error);
1167static void passthrough_handler (GMarkupParseContext *context,
1168 const char *passthrough_text,
1169 gsize text_len,
1170 gpointer user_data,
1171 GError **error);
1172
1173static GMarkupParser menu_funcs = {
1174 start_element_handler,
1175 end_element_handler,
1176 text_handler,
1177 passthrough_handler,
1178 NULL((void*)0)
1179};
1180
1181static void
1182set_error (GError **err,
1183 GMarkupParseContext *context,
1184 GQuark error_domain,
1185 int error_code,
1186 const char *format,
1187 ...)
1188{
1189 int line, ch;
1190 va_list args;
1191 char *str;
1192
1193 g_markup_parse_context_get_position (context, &line, &ch);
1194
1195 va_start (args, format)__builtin_va_start(args, format);
1196 str = g_strdup_vprintf (format, args);
1197 va_end (args)__builtin_va_end(args);
1198
1199 g_set_error (err, error_domain, error_code,
1200 "Line %d character %d: %s",
1201 line, ch, str);
1202
1203 g_free (str);
1204}
1205
1206static void
1207add_context_to_error (GError **err,
1208 GMarkupParseContext *context)
1209{
1210 int line, ch;
1211 char *str;
1212
1213 if (err == NULL((void*)0) || *err == NULL((void*)0))
1214 return;
1215
1216 g_markup_parse_context_get_position (context, &line, &ch);
1217
1218 str = g_strdup_printf ("Line %d character %d: %s",
1219 line, ch, (*err)->message);
1220 g_free ((*err)->message);
1221 (*err)->message = str;
1222}
1223
1224#define ELEMENT_IS(name)(strcmp (element_name, (name)) == 0) (strcmp (element_name, (name)) == 0)
1225
1226typedef struct
1227{
1228 const char *name;
1229 const char **retloc;
1230} LocateAttr;
1231
1232static gboolean
1233locate_attributes (GMarkupParseContext *context,
1234 const char *element_name,
1235 const char **attribute_names,
1236 const char **attribute_values,
1237 GError **error,
1238 const char *first_attribute_name,
1239 const char **first_attribute_retloc,
1240 ...)
1241{
1242#define MAX_ATTRS 24
1243 LocateAttr attrs[MAX_ATTRS];
1244 int n_attrs;
1245 va_list args;
1246 const char *name;
1247 const char **retloc;
1248 gboolean retval;
1249 int i;
1250
1251 g_return_val_if_fail (first_attribute_name != NULL, FALSE)do{ (void)0; }while (0);
1252 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE)do{ (void)0; }while (0);
1253
1254 retval = TRUE(!(0));
1255
1256 n_attrs = 1;
1257 attrs[0].name = first_attribute_name;
1258 attrs[0].retloc = first_attribute_retloc;
1259 *first_attribute_retloc = NULL((void*)0);
1260
1261 va_start (args, first_attribute_retloc)__builtin_va_start(args, first_attribute_retloc);
1262
1263 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1264 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1265
1266 while (name != NULL((void*)0))
1267 {
1268 g_return_val_if_fail (retloc != NULL, FALSE)do{ (void)0; }while (0);
1269
1270 g_assert (n_attrs < MAX_ATTRS)do { (void) 0; } while (0);
1271
1272 attrs[n_attrs].name = name;
1273 attrs[n_attrs].retloc = retloc;
1274 n_attrs += 1;
1275 *retloc = NULL((void*)0);
1276
1277 name = va_arg (args, const char *)__builtin_va_arg(args, const char *);
1278 retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **);
1279 }
1280
1281 va_end (args)__builtin_va_end(args);
1282
1283 i = 0;
1284 while (attribute_names[i])
1285 {
1286 int j;
1287
1288 j = 0;
1289 while (j < n_attrs)
1290 {
1291 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
1292 {
1293 retloc = attrs[j].retloc;
1294
1295 if (*retloc != NULL((void*)0))
1296 {
1297 set_error (error, context,
1298 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1299 "Attribute \"%s\" repeated twice on the same <%s> element",
1300 attrs[j].name, element_name);
1301 retval = FALSE(0);
1302 goto out;
1303 }
1304
1305 *retloc = attribute_values[i];
1306 break;
1307 }
1308
1309 ++j;
1310 }
1311
1312 if (j == n_attrs)
1313 {
1314 set_error (error, context,
1315 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1316 "Attribute \"%s\" is invalid on <%s> element in this context",
1317 attribute_names[i], element_name);
1318 retval = FALSE(0);
1319 goto out;
1320 }
1321
1322 ++i;
1323 }
1324
1325 out:
1326 return retval;
1327
1328#undef MAX_ATTRS
1329}
1330
1331static gboolean
1332check_no_attributes (GMarkupParseContext *context,
1333 const char *element_name,
1334 const char **attribute_names,
1335 const char **attribute_values,
1336 GError **error)
1337{
1338 if (attribute_names[0] != NULL((void*)0))
1339 {
1340 set_error (error, context,
1341 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1342 "Attribute \"%s\" is invalid on <%s> element in this context",
1343 attribute_names[0], element_name);
1344 return FALSE(0);
1345 }
1346
1347 return TRUE(!(0));
1348}
1349
1350static int
1351has_child_of_type (MenuLayoutNode *node,
1352 MenuLayoutNodeType type)
1353{
1354 MenuLayoutNode *iter;
1355
1356 iter = node->children;
1357 while (iter)
1358 {
1359 if (iter->type == type)
1360 return TRUE(!(0));
1361
1362 iter = node_next (iter);
1363 }
1364
1365 return FALSE(0);
1366}
1367
1368static void
1369push_node (MenuParser *parser,
1370 MenuLayoutNodeType type)
1371{
1372 MenuLayoutNode *node;
1373
1374 node = menu_layout_node_new (type);
1375 menu_layout_node_append_child (parser->stack_top, node);
1376 menu_layout_node_unref (node);
1377
1378 parser->stack_top = node;
1379}
1380
1381static void
1382start_menu_element (MenuParser *parser,
1383 GMarkupParseContext *context,
1384 const char *element_name,
1385 const char **attribute_names,
1386 const char **attribute_values,
1387 GError **error)
1388{
1389 if (!check_no_attributes (context, element_name,
1390 attribute_names, attribute_values,
1391 error))
1392 return;
1393
1394 if (!(parser->stack_top->type == MENU_LAYOUT_NODE_ROOT ||
1395 parser->stack_top->type == MENU_LAYOUT_NODE_MENU))
1396 {
1397 set_error (error, context,
1398 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1399 "<Menu> element can only appear below other <Menu> elements or at toplevel\n");
1400 }
1401 else
1402 {
1403 push_node (parser, MENU_LAYOUT_NODE_MENU);
1404 }
1405}
1406
1407static void
1408start_menu_child_element (MenuParser *parser,
1409 GMarkupParseContext *context,
1410 const char *element_name,
1411 const char **attribute_names,
1412 const char **attribute_values,
1413 GError **error)
1414{
1415 if (ELEMENT_IS ("LegacyDir")(strcmp (element_name, ("LegacyDir")) == 0))
1416 {
1417 const char *prefix;
1418
1419 push_node (parser, MENU_LAYOUT_NODE_LEGACY_DIR);
1420
1421 if (!locate_attributes (context, element_name,
1422 attribute_names, attribute_values,
1423 error,
1424 "prefix", &prefix,
1425 NULL((void*)0)))
1426 return;
1427
1428 menu_layout_node_legacy_dir_set_prefix (parser->stack_top, prefix);
1429 }
1430 else if (ELEMENT_IS ("MergeFile")(strcmp (element_name, ("MergeFile")) == 0))
1431 {
1432 const char *type;
1433
1434 push_node (parser, MENU_LAYOUT_NODE_MERGE_FILE);
1435
1436 if (!locate_attributes (context, element_name,
1437 attribute_names, attribute_values,
1438 error,
1439 "type", &type,
1440 NULL((void*)0)))
1441 return;
1442
1443 if (type != NULL((void*)0) && strcmp (type, "parent") == 0)
1444 {
1445 menu_layout_node_merge_file_set_type (parser->stack_top,
1446 MENU_MERGE_FILE_TYPE_PARENT);
1447 }
1448 }
1449 else if (ELEMENT_IS ("DefaultLayout")(strcmp (element_name, ("DefaultLayout")) == 0))
1450 {
1451 const char *show_empty;
1452 const char *inline_menus;
1453 const char *inline_limit;
1454 const char *inline_header;
1455 const char *inline_alias;
1456
1457 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_LAYOUT);
1458
1459 locate_attributes (context, element_name,
1460 attribute_names, attribute_values,
1461 error,
1462 "show_empty", &show_empty,
1463 "inline", &inline_menus,
1464 "inline_limit", &inline_limit,
1465 "inline_header", &inline_header,
1466 "inline_alias", &inline_alias,
1467 NULL((void*)0));
1468
1469 menu_layout_node_default_layout_set_values (parser->stack_top,
1470 show_empty,
1471 inline_menus,
1472 inline_limit,
1473 inline_header,
1474 inline_alias);
1475 }
1476 else
1477 {
1478 if (!check_no_attributes (context, element_name,
1479 attribute_names, attribute_values,
1480 error))
1481 return;
1482
1483 if (ELEMENT_IS ("AppDir")(strcmp (element_name, ("AppDir")) == 0))
1484 {
1485 push_node (parser, MENU_LAYOUT_NODE_APP_DIR);
1486 }
1487 else if (ELEMENT_IS ("DefaultAppDirs")(strcmp (element_name, ("DefaultAppDirs")) == 0))
1488 {
1489 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_APP_DIRS);
1490 }
1491 else if (ELEMENT_IS ("DirectoryDir")(strcmp (element_name, ("DirectoryDir")) == 0))
1492 {
1493 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY_DIR);
1494 }
1495 else if (ELEMENT_IS ("DefaultDirectoryDirs")(strcmp (element_name, ("DefaultDirectoryDirs")) == 0))
1496 {
1497 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS);
1498 }
1499 else if (ELEMENT_IS ("DefaultMergeDirs")(strcmp (element_name, ("DefaultMergeDirs")) == 0))
1500 {
1501 push_node (parser, MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS);
1502 }
1503 else if (ELEMENT_IS ("Name")(strcmp (element_name, ("Name")) == 0))
1504 {
1505 if (has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
1506 {
1507 set_error (error, context,
1508 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1509 "Multiple <Name> elements in a <Menu> element is not allowed\n");
1510 return;
1511 }
1512
1513 push_node (parser, MENU_LAYOUT_NODE_NAME);
1514 }
1515 else if (ELEMENT_IS ("Directory")(strcmp (element_name, ("Directory")) == 0))
1516 {
1517 push_node (parser, MENU_LAYOUT_NODE_DIRECTORY);
1518 }
1519 else if (ELEMENT_IS ("OnlyUnallocated")(strcmp (element_name, ("OnlyUnallocated")) == 0))
1520 {
1521 push_node (parser, MENU_LAYOUT_NODE_ONLY_UNALLOCATED);
1522 }
1523 else if (ELEMENT_IS ("NotOnlyUnallocated")(strcmp (element_name, ("NotOnlyUnallocated")) == 0))
1524 {
1525 push_node (parser, MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED);
1526 }
1527 else if (ELEMENT_IS ("Include")(strcmp (element_name, ("Include")) == 0))
1528 {
1529 push_node (parser, MENU_LAYOUT_NODE_INCLUDE);
1530 }
1531 else if (ELEMENT_IS ("Exclude")(strcmp (element_name, ("Exclude")) == 0))
1532 {
1533 push_node (parser, MENU_LAYOUT_NODE_EXCLUDE);
1534 }
1535 else if (ELEMENT_IS ("MergeDir")(strcmp (element_name, ("MergeDir")) == 0))
1536 {
1537 push_node (parser, MENU_LAYOUT_NODE_MERGE_DIR);
1538 }
1539 else if (ELEMENT_IS ("KDELegacyDirs")(strcmp (element_name, ("KDELegacyDirs")) == 0))
1540 {
1541 push_node (parser, MENU_LAYOUT_NODE_KDE_LEGACY_DIRS);
1542 }
1543 else if (ELEMENT_IS ("Move")(strcmp (element_name, ("Move")) == 0))
1544 {
1545 push_node (parser, MENU_LAYOUT_NODE_MOVE);
1546 }
1547 else if (ELEMENT_IS ("Deleted")(strcmp (element_name, ("Deleted")) == 0))
1548 {
1549 push_node (parser, MENU_LAYOUT_NODE_DELETED);
1550
1551 }
1552 else if (ELEMENT_IS ("NotDeleted")(strcmp (element_name, ("NotDeleted")) == 0))
1553 {
1554 push_node (parser, MENU_LAYOUT_NODE_NOT_DELETED);
1555 }
1556 else if (ELEMENT_IS ("Layout")(strcmp (element_name, ("Layout")) == 0))
1557 {
1558 push_node (parser, MENU_LAYOUT_NODE_LAYOUT);
1559 }
1560 else
1561 {
1562 set_error (error, context,
1563 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1564 "Element <%s> may not appear below <%s>\n",
1565 element_name, "Menu");
1566 }
1567 }
1568}
1569
1570static void
1571start_matching_rule_element (MenuParser *parser,
1572 GMarkupParseContext *context,
1573 const char *element_name,
1574 const char **attribute_names,
1575 const char **attribute_values,
1576 GError **error)
1577{
1578 if (!check_no_attributes (context, element_name,
1579 attribute_names, attribute_values,
1580 error))
1581 return;
1582
1583 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1584 {
1585 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1586 }
1587 else if (ELEMENT_IS ("Category")(strcmp (element_name, ("Category")) == 0))
1588 {
1589 push_node (parser, MENU_LAYOUT_NODE_CATEGORY);
1590 }
1591 else if (ELEMENT_IS ("All")(strcmp (element_name, ("All")) == 0))
1592 {
1593 push_node (parser, MENU_LAYOUT_NODE_ALL);
1594 }
1595 else if (ELEMENT_IS ("And")(strcmp (element_name, ("And")) == 0))
1596 {
1597 push_node (parser, MENU_LAYOUT_NODE_AND);
1598 }
1599 else if (ELEMENT_IS ("Or")(strcmp (element_name, ("Or")) == 0))
1600 {
1601 push_node (parser, MENU_LAYOUT_NODE_OR);
1602 }
1603 else if (ELEMENT_IS ("Not")(strcmp (element_name, ("Not")) == 0))
1604 {
1605 push_node (parser, MENU_LAYOUT_NODE_NOT);
1606 }
1607 else
1608 {
1609 set_error (error, context,
1610 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1611 "Element <%s> may not appear in this context\n",
1612 element_name);
1613 }
1614}
1615
1616static void
1617start_move_child_element (MenuParser *parser,
1618 GMarkupParseContext *context,
1619 const char *element_name,
1620 const char **attribute_names,
1621 const char **attribute_values,
1622 GError **error)
1623{
1624 if (!check_no_attributes (context, element_name,
1625 attribute_names, attribute_values,
1626 error))
1627 return;
1628
1629 if (ELEMENT_IS ("Old")(strcmp (element_name, ("Old")) == 0))
1630 {
1631 push_node (parser, MENU_LAYOUT_NODE_OLD);
1632 }
1633 else if (ELEMENT_IS ("New")(strcmp (element_name, ("New")) == 0))
1634 {
1635 push_node (parser, MENU_LAYOUT_NODE_NEW);
1636 }
1637 else
1638 {
1639 set_error (error, context,
1640 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1641 "Element <%s> may not appear below <%s>\n",
1642 element_name, "Move");
1643 }
1644}
1645
1646static void
1647start_layout_child_element (MenuParser *parser,
1648 GMarkupParseContext *context,
1649 const char *element_name,
1650 const char **attribute_names,
1651 const char **attribute_values,
1652 GError **error)
1653{
1654 if (ELEMENT_IS ("Menuname")(strcmp (element_name, ("Menuname")) == 0))
1655 {
1656 const char *show_empty;
1657 const char *inline_menus;
1658 const char *inline_limit;
1659 const char *inline_header;
1660 const char *inline_alias;
1661
1662 push_node (parser, MENU_LAYOUT_NODE_MENUNAME);
1663
1664 locate_attributes (context, element_name,
1665 attribute_names, attribute_values,
1666 error,
1667 "show_empty", &show_empty,
1668 "inline", &inline_menus,
1669 "inline_limit", &inline_limit,
1670 "inline_header", &inline_header,
1671 "inline_alias", &inline_alias,
1672 NULL((void*)0));
1673
1674 menu_layout_node_menuname_set_values (parser->stack_top,
1675 show_empty,
1676 inline_menus,
1677 inline_limit,
1678 inline_header,
1679 inline_alias);
1680 }
1681 else if (ELEMENT_IS ("Merge")(strcmp (element_name, ("Merge")) == 0))
1682 {
1683 const char *type;
1684
1685 push_node (parser, MENU_LAYOUT_NODE_MERGE);
1686
1687 locate_attributes (context, element_name,
1688 attribute_names, attribute_values,
1689 error,
1690 "type", &type,
1691 NULL((void*)0));
1692
1693 menu_layout_node_merge_set_type (parser->stack_top, type);
1694 }
1695 else
1696 {
1697 if (!check_no_attributes (context, element_name,
1698 attribute_names, attribute_values,
1699 error))
1700 return;
1701
1702 if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0))
1703 {
1704 push_node (parser, MENU_LAYOUT_NODE_FILENAME);
1705 }
1706 else if (ELEMENT_IS ("Separator")(strcmp (element_name, ("Separator")) == 0))
1707 {
1708 push_node (parser, MENU_LAYOUT_NODE_SEPARATOR);
1709 }
1710 else
1711 {
1712 set_error (error, context,
1713 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1714 "Element <%s> may not appear below <%s>\n",
1715 element_name, "Move");
1716 }
1717 }
1718}
1719
1720static void
1721start_element_handler (GMarkupParseContext *context,
1722 const char *element_name,
1723 const char **attribute_names,
1724 const char **attribute_values,
1725 gpointer user_data,
1726 GError **error)
1727{
1728 MenuParser *parser = user_data;
1729
1730 if (ELEMENT_IS ("Menu")(strcmp (element_name, ("Menu")) == 0))
1731 {
1732 if (parser->stack_top == parser->root &&
1733 has_child_of_type (parser->root, MENU_LAYOUT_NODE_MENU))
1734 {
1735 set_error (error, context,
1736 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1737 "Multiple root elements in menu file, only one toplevel <Menu> is allowed\n");
1738 return;
1739 }
1740
1741 start_menu_element (parser, context, element_name,
1742 attribute_names, attribute_values,
1743 error);
1744 }
1745 else if (parser->stack_top == parser->root)
1746 {
1747 set_error (error, context,
1748 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1749 "Root element in a menu file must be <Menu>, not <%s>\n",
1750 element_name);
1751 }
1752 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MENU)
1753 {
1754 start_menu_child_element (parser, context, element_name,
1755 attribute_names, attribute_values,
1756 error);
1757 }
1758 else if (parser->stack_top->type == MENU_LAYOUT_NODE_INCLUDE ||
1759 parser->stack_top->type == MENU_LAYOUT_NODE_EXCLUDE ||
1760 parser->stack_top->type == MENU_LAYOUT_NODE_AND ||
1761 parser->stack_top->type == MENU_LAYOUT_NODE_OR ||
1762 parser->stack_top->type == MENU_LAYOUT_NODE_NOT)
1763 {
1764 start_matching_rule_element (parser, context, element_name,
1765 attribute_names, attribute_values,
1766 error);
1767 }
1768 else if (parser->stack_top->type == MENU_LAYOUT_NODE_MOVE)
1769 {
1770 start_move_child_element (parser, context, element_name,
1771 attribute_names, attribute_values,
1772 error);
1773 }
1774 else if (parser->stack_top->type == MENU_LAYOUT_NODE_LAYOUT ||
1775 parser->stack_top->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)
1776 {
1777 start_layout_child_element (parser, context, element_name,
1778 attribute_names, attribute_values,
1779 error);
1780 }
1781 else
1782 {
1783 set_error (error, context,
1784 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1785 "Element <%s> may not appear in this context\n",
1786 element_name);
1787 }
1788
1789 add_context_to_error (error, context);
1790}
1791
1792/* we want to make sure that the <Layout> or <DefaultLayout> is either empty,
1793 * or contain one <Merge> of type "all", or contain one <Merge> of type "menus"
1794 * and one <Merge> of type "files". If this is not the case, we try to clean up
1795 * things:
1796 * + if there is at least one <Merge> of type "all", then we only keep the
1797 * last <Merge> of type "all" and remove all others <Merge>
1798 * + if there is no <Merge> with type "all", we keep only the last <Merge> of
1799 * type "menus" and the last <Merge> of type "files". If there's no <Merge>
1800 * of type "menus" we append one, and then if there's no <Merge> of type
1801 * "files", we append one. (So menus are before files)
1802 */
1803static gboolean
1804fixup_layout_node (GMarkupParseContext *context,
1805 MenuParser *parser,
1806 MenuLayoutNode *node,
1807 GError **error)
1808{
1809 MenuLayoutNode *child;
1810 MenuLayoutNode *last_all;
1811 MenuLayoutNode *last_menus;
1812 MenuLayoutNode *last_files;
1813 int n_all;
1814 int n_menus;
1815 int n_files;
1816
1817 if (!node->children)
4
Assuming field 'children' is non-null
5
Taking false branch
1818 {
1819 return TRUE(!(0));
1820 }
1821
1822 last_all = NULL((void*)0);
1823 last_menus = NULL((void*)0);
1824 last_files = NULL((void*)0);
1825 n_all = 0;
1826 n_menus = 0;
1827 n_files = 0;
1828
1829 child = node->children;
1830 while (child
5.1
'child' is not equal to NULL
!= NULL((void*)0)
)
6
Loop condition is true. Entering loop body
11
Assuming 'child' is not equal to NULL
12
Loop condition is true. Entering loop body
17
Assuming 'child' is equal to NULL
1831 {
1832 switch (child->type)
7
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1834
13
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1834
1833 {
1834 case MENU_LAYOUT_NODE_MERGE:
1835 switch (menu_layout_node_merge_get_type (child))
8
Control jumps to 'case MENU_LAYOUT_MERGE_ALL:' at line 1850
14
Control jumps to 'case MENU_LAYOUT_MERGE_MENUS:' at line 1840
1836 {
1837 case MENU_LAYOUT_MERGE_NONE:
1838 break;
1839
1840 case MENU_LAYOUT_MERGE_MENUS:
1841 last_menus = child;
1842 n_menus++;
1843 break;
15
Execution continues on line 1859
1844
1845 case MENU_LAYOUT_MERGE_FILES:
1846 last_files = child;
1847 n_files++;
1848 break;
1849
1850 case MENU_LAYOUT_MERGE_ALL:
1851 last_all = child;
1852 n_all++;
1853 break;
9
Execution continues on line 1859
1854
1855 default:
1856 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1857 break;
1858 }
1859 break;
1860
1861 default:
1862 break;
1863 }
1864
1865 child = node_next (child);
10
Execution continues on line 1865
16
Execution continues on line 1865
1866 }
1867
1868 if ((n_all
17.1
'n_all' is equal to 1
== 1 && n_menus
17.2
'n_menus' is not equal to 0
== 0 && n_files == 0) ||
1869 (n_all
17.3
'n_all' is not equal to 0
== 0 && n_menus == 1 && n_files == 1))
1870 {
1871 return TRUE(!(0));
1872 }
1873 else if (n_all
17.4
'n_all' is <= 1
> 1 || n_menus
17.5
'n_menus' is <= 1
> 1 || n_files
17.6
'n_files' is <= 1
> 1 ||
1874 (n_all
17.7
'n_all' is equal to 1
== 1 && (n_menus
17.8
'n_menus' is not equal to 0
!= 0 || n_files != 0)))
1875 {
1876 child = node->children;
1877 while (child
17.9
'child' is not equal to NULL
23.1
'child' is not equal to NULL
!= NULL((void*)0))
18
Loop condition is true. Entering loop body
24
Loop condition is true. Entering loop body
1878 {
1879 MenuLayoutNode *next;
1880
1881 next = node_next (child);
1882
1883 switch (child->type)
19
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1885
25
Control jumps to 'case MENU_LAYOUT_NODE_MERGE:' at line 1885
1884 {
1885 case MENU_LAYOUT_NODE_MERGE:
1886 switch (menu_layout_node_merge_get_type (child))
20
Control jumps to 'case MENU_LAYOUT_MERGE_ALL:' at line 1907
26
Control jumps to 'case MENU_LAYOUT_MERGE_MENUS:' at line 1891
1887 {
1888 case MENU_LAYOUT_MERGE_NONE:
1889 break;
1890
1891 case MENU_LAYOUT_MERGE_MENUS:
1892 if (n_all
26.1
'n_all' is 1
|| last_menus != child)
1893 {
1894 menu_verbose ("removing duplicated merge menus element\n");
1895 menu_layout_node_unlink (child);
27
Calling 'menu_layout_node_unlink'
1896 }
1897 break;
1898
1899 case MENU_LAYOUT_MERGE_FILES:
1900 if (n_all || last_files != child)
1901 {
1902 menu_verbose ("removing duplicated merge files element\n");
1903 menu_layout_node_unlink (child);
1904 }
1905 break;
1906
1907 case MENU_LAYOUT_MERGE_ALL:
1908 if (last_all
20.1
'last_all' is equal to 'child'
!= child)
21
Taking false branch
1909 {
1910 menu_verbose ("removing duplicated merge all element\n");
1911 menu_layout_node_unlink (child);
1912 }
1913 break;
22
Execution continues on line 1919
1914
1915 default:
1916 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1917 break;
1918 }
1919 break;
23
Execution continues on line 1925
1920
1921 default:
1922 break;
1923 }
1924
1925 child = next;
1926 }
1927 }
1928
1929 if (n_all == 0 && n_menus == 0)
1930 {
1931 last_menus = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1932 menu_layout_node_merge_set_type (last_menus, "menus");
1933 menu_verbose ("appending missing merge menus element\n");
1934 menu_layout_node_append_child (node, last_menus);
1935 }
1936
1937 if (n_all == 0 && n_files == 0)
1938 {
1939 last_files = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE);
1940 menu_layout_node_merge_set_type (last_files, "files");
1941 menu_verbose ("appending missing merge files element\n");
1942 menu_layout_node_append_child (node, last_files);
1943 }
1944
1945 return TRUE(!(0));
1946}
1947
1948/* we want to a) check that we have old-new pairs and b) canonicalize
1949 * such that each <Move> has exactly one old-new pair
1950 */
1951static gboolean
1952fixup_move_node (GMarkupParseContext *context,
1953 MenuParser *parser,
1954 MenuLayoutNode *node,
1955 GError **error)
1956{
1957 MenuLayoutNode *child;
1958 int n_old;
1959 int n_new;
1960
1961 n_old = 0;
1962 n_new = 0;
1963
1964 child = node->children;
1965 while (child != NULL((void*)0))
1966 {
1967 switch (child->type)
1968 {
1969 case MENU_LAYOUT_NODE_OLD:
1970 if (n_new != n_old)
1971 {
1972 set_error (error, context,
1973 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1974 "<Old>/<New> elements not paired properly\n");
1975 return FALSE(0);
1976 }
1977
1978 n_old += 1;
1979
1980 break;
1981
1982 case MENU_LAYOUT_NODE_NEW:
1983 n_new += 1;
1984
1985 if (n_new != n_old)
1986 {
1987 set_error (error, context,
1988 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
1989 "<Old>/<New> elements not paired properly\n");
1990 return FALSE(0);
1991 }
1992
1993 break;
1994
1995 default:
1996 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
1997 break;
1998 }
1999
2000 child = node_next (child);
2001 }
2002
2003 if (n_new == 0 || n_old == 0)
2004 {
2005 set_error (error, context,
2006 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2007 "<Old>/<New> elements missing under <Move>\n");
2008 return FALSE(0);
2009 }
2010
2011 g_assert (n_new == n_old)do { (void) 0; } while (0);
2012 g_assert ((n_new + n_old) % 2 == 0)do { (void) 0; } while (0);
2013
2014 if (n_new > 1)
2015 {
2016 MenuLayoutNode *prev;
2017 MenuLayoutNode *append_after;
2018
2019 /* Need to split the <Move> into multiple <Move> */
2020
2021 n_old = 0;
2022 n_new = 0;
2023 prev = NULL((void*)0);
2024 append_after = node;
2025
2026 child = node->children;
2027 while (child != NULL((void*)0))
2028 {
2029 MenuLayoutNode *next;
2030
2031 next = node_next (child);
2032
2033 switch (child->type)
2034 {
2035 case MENU_LAYOUT_NODE_OLD:
2036 n_old += 1;
2037 break;
2038
2039 case MENU_LAYOUT_NODE_NEW:
2040 n_new += 1;
2041 break;
2042
2043 default:
2044 g_assert_not_reached ()do { (void) 0; __builtin_unreachable (); } while (0);
2045 break;
2046 }
2047
2048 if (n_old == n_new &&
2049 n_old > 1)
2050 {
2051 /* Move the just-completed pair */
2052 MenuLayoutNode *new_move;
2053
2054 g_assert (prev != NULL)do { (void) 0; } while (0);
2055
2056 new_move = menu_layout_node_new (MENU_LAYOUT_NODE_MOVE);
2057 menu_verbose ("inserting new_move after append_after\n");
2058 menu_layout_node_insert_after (append_after, new_move);
2059 append_after = new_move;
2060
2061 menu_layout_node_steal (prev);
2062 menu_layout_node_steal (child);
2063
2064 menu_verbose ("appending prev to new_move\n");
2065 menu_layout_node_append_child (new_move, prev);
2066 menu_verbose ("appending child to new_move\n");
2067 menu_layout_node_append_child (new_move, child);
2068
2069 menu_verbose ("Created new move element old = %s new = %s\n",
2070 menu_layout_node_move_get_old (new_move),
2071 menu_layout_node_move_get_new (new_move));
2072
2073 menu_layout_node_unref (new_move);
2074 menu_layout_node_unref (prev);
2075 menu_layout_node_unref (child);
2076
2077 prev = NULL((void*)0);
2078 }
2079 else
2080 {
2081 prev = child;
2082 }
2083
2084 prev = child;
2085 child = next;
2086 }
2087 }
2088
2089 return TRUE(!(0));
2090}
2091
2092static void
2093end_element_handler (GMarkupParseContext *context,
2094 const char *element_name,
2095 gpointer user_data,
2096 GError **error)
2097{
2098 MenuParser *parser = user_data;
2099
2100 g_assert (parser->stack_top != NULL)do { (void) 0; } while (0);
1
Loop condition is false. Exiting loop
2101
2102 switch (parser->stack_top->type)
2
Control jumps to 'case MENU_LAYOUT_NODE_LAYOUT:' at line 2156
2103 {
2104 case MENU_LAYOUT_NODE_APP_DIR:
2105 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2106 case MENU_LAYOUT_NODE_NAME:
2107 case MENU_LAYOUT_NODE_DIRECTORY:
2108 case MENU_LAYOUT_NODE_FILENAME:
2109 case MENU_LAYOUT_NODE_CATEGORY:
2110 case MENU_LAYOUT_NODE_MERGE_DIR:
2111 case MENU_LAYOUT_NODE_LEGACY_DIR:
2112 case MENU_LAYOUT_NODE_OLD:
2113 case MENU_LAYOUT_NODE_NEW:
2114 case MENU_LAYOUT_NODE_MENUNAME:
2115 if (menu_layout_node_get_content (parser->stack_top) == NULL((void*)0))
2116 {
2117 set_error (error, context,
2118 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_INVALID_CONTENT,
2119 "Element <%s> is required to contain text and was empty\n",
2120 element_name);
2121 goto out;
2122 }
2123 break;
2124
2125 case MENU_LAYOUT_NODE_MENU:
2126 if (!has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME))
2127 {
2128 set_error (error, context,
2129 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2130 "<Menu> elements are required to contain a <Name> element\n");
2131 goto out;
2132 }
2133 break;
2134
2135 case MENU_LAYOUT_NODE_ROOT:
2136 case MENU_LAYOUT_NODE_PASSTHROUGH:
2137 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2138 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2139 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2140 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2141 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2142 case MENU_LAYOUT_NODE_INCLUDE:
2143 case MENU_LAYOUT_NODE_EXCLUDE:
2144 case MENU_LAYOUT_NODE_ALL:
2145 case MENU_LAYOUT_NODE_AND:
2146 case MENU_LAYOUT_NODE_OR:
2147 case MENU_LAYOUT_NODE_NOT:
2148 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2149 case MENU_LAYOUT_NODE_DELETED:
2150 case MENU_LAYOUT_NODE_NOT_DELETED:
2151 case MENU_LAYOUT_NODE_SEPARATOR:
2152 case MENU_LAYOUT_NODE_MERGE:
2153 case MENU_LAYOUT_NODE_MERGE_FILE:
2154 break;
2155
2156 case MENU_LAYOUT_NODE_LAYOUT:
2157 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2158 if (!fixup_layout_node (context, parser, parser->stack_top, error))
3
Calling 'fixup_layout_node'
2159 goto out;
2160 break;
2161
2162 case MENU_LAYOUT_NODE_MOVE:
2163 if (!fixup_move_node (context, parser, parser->stack_top, error))
2164 goto out;
2165 break;
2166 default:
2167 g_assert_not_reached()do { (void) 0; __builtin_unreachable (); } while (0);
2168 }
2169
2170 out:
2171 parser->stack_top = parser->stack_top->parent;
2172}
2173
2174static gboolean
2175all_whitespace (const char *text,
2176 gsize text_len)
2177{
2178 const char *p;
2179 const char *end;
2180
2181 p = text;
2182 end = text + text_len;
2183
2184 while (p != end)
2185 {
2186 if (!g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
2187 return FALSE(0);
2188
2189 p = g_utf8_next_char (p)(char *)((p) + g_utf8_skip[*(const guchar *)(p)]);
2190 }
2191
2192 return TRUE(!(0));
2193}
2194
2195static void
2196text_handler (GMarkupParseContext *context,
2197 const char *text,
2198 gsize text_len,
2199 gpointer user_data,
2200 GError **error)
2201{
2202 MenuParser *parser = user_data;
2203
2204 switch (parser->stack_top->type)
2205 {
2206 case MENU_LAYOUT_NODE_APP_DIR:
2207 case MENU_LAYOUT_NODE_DIRECTORY_DIR:
2208 case MENU_LAYOUT_NODE_NAME:
2209 case MENU_LAYOUT_NODE_DIRECTORY:
2210 case MENU_LAYOUT_NODE_FILENAME:
2211 case MENU_LAYOUT_NODE_CATEGORY:
2212 case MENU_LAYOUT_NODE_MERGE_FILE:
2213 case MENU_LAYOUT_NODE_MERGE_DIR:
2214 case MENU_LAYOUT_NODE_LEGACY_DIR:
2215 case MENU_LAYOUT_NODE_OLD:
2216 case MENU_LAYOUT_NODE_NEW:
2217 case MENU_LAYOUT_NODE_MENUNAME:
2218 g_assert (menu_layout_node_get_content (parser->stack_top) == NULL)do { (void) 0; } while (0);
2219
2220 menu_layout_node_set_content (parser->stack_top, text);
2221 break;
2222
2223 case MENU_LAYOUT_NODE_ROOT:
2224 case MENU_LAYOUT_NODE_PASSTHROUGH:
2225 case MENU_LAYOUT_NODE_MENU:
2226 case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS:
2227 case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS:
2228 case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS:
2229 case MENU_LAYOUT_NODE_ONLY_UNALLOCATED:
2230 case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED:
2231 case MENU_LAYOUT_NODE_INCLUDE:
2232 case MENU_LAYOUT_NODE_EXCLUDE:
2233 case MENU_LAYOUT_NODE_ALL:
2234 case MENU_LAYOUT_NODE_AND:
2235 case MENU_LAYOUT_NODE_OR:
2236 case MENU_LAYOUT_NODE_NOT:
2237 case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS:
2238 case MENU_LAYOUT_NODE_MOVE:
2239 case MENU_LAYOUT_NODE_DELETED:
2240 case MENU_LAYOUT_NODE_NOT_DELETED:
2241 case MENU_LAYOUT_NODE_LAYOUT:
2242 case MENU_LAYOUT_NODE_DEFAULT_LAYOUT:
2243 case MENU_LAYOUT_NODE_SEPARATOR:
2244 case MENU_LAYOUT_NODE_MERGE:
2245 if (!all_whitespace (text, text_len))
2246 {
2247 set_error (error, context,
2248 G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2249 "No text is allowed inside element <%s>",
2250 g_markup_parse_context_get_element (context));
2251 }
2252 break;
2253 default:
2254 g_assert_not_reached()do { (void) 0; __builtin_unreachable (); } while (0);
2255 }
2256
2257 add_context_to_error (error, context);
2258}
2259
2260static void
2261passthrough_handler (GMarkupParseContext *context,
2262 const char *passthrough_text,
2263 gsize text_len,
2264 gpointer user_data,
2265 GError **error)
2266{
2267 MenuParser *parser = user_data;
2268 MenuLayoutNode *node;
2269
2270 /* don't push passthrough on the stack, it's not an element */
2271
2272 node = menu_layout_node_new (MENU_LAYOUT_NODE_PASSTHROUGH);
2273 menu_layout_node_set_content (node, passthrough_text);
2274
2275 menu_layout_node_append_child (parser->stack_top, node);
2276 menu_layout_node_unref (node);
2277
2278 add_context_to_error (error, context);
2279}
2280
2281static void
2282menu_parser_init (MenuParser *parser)
2283{
2284 parser->root = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT);
2285 parser->stack_top = parser->root;
2286}
2287
2288static void
2289menu_parser_free (MenuParser *parser)
2290{
2291 if (parser->root)
2292 menu_layout_node_unref (parser->root);
2293}
2294
2295MenuLayoutNode *
2296menu_layout_load (const char *filename,
2297 const char *non_prefixed_basename,
2298 GError **err)
2299{
2300 GMainContext *main_context;
2301 GMarkupParseContext *context;
2302 MenuLayoutNodeRoot *root;
2303 MenuLayoutNode *retval;
2304 MenuParser parser;
2305 GError *error;
2306 GString *str;
2307 char *text;
2308 char *s;
2309 gsize length;
2310
2311 text = NULL((void*)0);
2312 length = 0;
2313 retval = NULL((void*)0);
2314 context = NULL((void*)0);
2315
2316 main_context = g_main_context_get_thread_default ();
2317
2318 menu_verbose ("Loading \"%s\" from disk\n", filename);
2319
2320 if (!g_file_get_contents (filename,
2321 &text,
2322 &length,
2323 err))
2324 {
2325 menu_verbose ("Failed to load \"%s\"\n",
2326 filename);
2327 return NULL((void*)0);
2328 }
2329
2330 g_assert (text != NULL)do { (void) 0; } while (0);
2331
2332 menu_parser_init (&parser);
2333
2334 root = (MenuLayoutNodeRoot *) parser.root;
2335
2336 root->basedir = g_path_get_dirname (filename);
2337 menu_verbose ("Set basedir \"%s\"\n", root->basedir);
2338
2339 if (non_prefixed_basename)
2340 s = g_strdup (non_prefixed_basename)g_strdup_inline (non_prefixed_basename);
2341 else
2342 s = g_path_get_basename (filename);
2343 str = g_string_new (s);
2344 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") )
)
2345 g_string_truncate (str, str->len - strlen (".menu"))g_string_truncate_inline (str, str->len - strlen (".menu")
)
;
2346
2347 root->name = str->str;
2348 menu_verbose ("Set menu name \"%s\"\n", root->name);
2349
2350 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))))
;
2351 g_free (s);
2352
2353 context = g_markup_parse_context_new (&menu_funcs, 0, &parser, NULL((void*)0));
2354
2355 error = NULL((void*)0);
2356 if (!g_markup_parse_context_parse (context,
2357 text,
2358 (gssize) length,
2359 &error))
2360 goto out;
2361
2362 error = NULL((void*)0);
2363 g_markup_parse_context_end_parse (context, &error);
2364
2365 root->main_context = main_context ? g_main_context_ref (main_context) : NULL((void*)0);
2366
2367 out:
2368 if (context)
2369 g_markup_parse_context_free (context);
2370 g_free (text);
2371
2372 if (error)
2373 {
2374 menu_verbose ("Error \"%s\" loading \"%s\"\n",
2375 error->message, filename);
2376 g_propagate_error (err, error);
2377 }
2378 else if (has_child_of_type (parser.root, MENU_LAYOUT_NODE_MENU))
2379 {
2380 menu_verbose ("File loaded OK\n");
2381 retval = parser.root;
2382 parser.root = NULL((void*)0);
2383 }
2384 else
2385 {
2386 menu_verbose ("Did not have a root element in file\n");
2387 g_set_error (err, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE,
2388 "Menu file %s did not contain a root <Menu> element",
2389 filename);
2390 }
2391
2392 menu_parser_free (&parser);
2393
2394 return retval;
2395}
diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-a1f4b3.html b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-a1f4b3.html new file mode 100644 index 0000000..27635e7 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-a1f4b3.html @@ -0,0 +1,1113 @@ + + + +menu-monitor.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:menu-monitor.c
Warning:line 161, column 3
Value stored to 'event' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name menu-monitor.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 -fcoverage-compilation-dir=/rootdir/libmenu -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D MATEMENU_I_KNOW_THIS_IS_UNSTABLE -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmenu -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-15-162655-4954-1 -x c menu-monitor.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/*
2 * Copyright (C) 2005 Red Hat, Inc.
3 * Copyright (C) 2006 Mark McLoughlin
4 * Copyright (C) 2007 Sebastian Dröge
5 * Copyright (C) 2008 Vincent Untz
6 * Copyright (C) 2012-2021 MATE Developers
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include <config.h>
25
26#include "menu-monitor.h"
27
28#include <gio/gio.h>
29
30#include "menu-util.h"
31
32struct MenuMonitor {
33 char* path;
34 guint refcount;
35
36 GSList* notifies;
37
38 GFileMonitor* monitor;
39
40 guint is_directory: 1;
41};
42
43typedef struct {
44 MenuMonitor* monitor;
45 MenuMonitorEvent event;
46 char* path;
47} MenuMonitorEventInfo;
48
49typedef struct {
50 MenuMonitorNotifyFunc notify_func;
51 gpointer user_data;
52 guint refcount;
53} MenuMonitorNotify;
54
55static MenuMonitorNotify* mate_menu_monitor_notify_refmenu_monitor_notify_ref(MenuMonitorNotify* notify);
56static void mate_menu_monitor_notify_unrefmenu_monitor_notify_unref(MenuMonitorNotify* notify);
57
58static GHashTable* monitors_registry = NULL((void*)0);
59static guint events_idle_handler = 0;
60static GSList* pending_events = NULL((void*)0);
61
62static void invoke_notifies(MenuMonitor* monitor, MenuMonitorEvent event, const char* path)
63{
64 GSList *copy;
65 GSList *tmp;
66
67 copy = g_slist_copy (monitor->notifies);
68 g_slist_foreach (copy,
69 (GFunc) mate_menu_monitor_notify_refmenu_monitor_notify_ref,
70 NULL((void*)0));
71
72 tmp = copy;
73 while (tmp != NULL((void*)0))
74 {
75 MenuMonitorNotify *notify = tmp->data;
76 GSList *next = tmp->next;
77
78 if (notify->notify_func)
79 {
80 notify->notify_func (monitor, event, path, notify->user_data);
81 }
82
83 mate_menu_monitor_notify_unrefmenu_monitor_notify_unref(notify);
84
85 tmp = next;
86 }
87
88 g_slist_free (copy);
89}
90
91static gboolean emit_events_in_idle(void)
92{
93 GSList *events_to_emit;
94 GSList *tmp;
95
96 events_to_emit = pending_events;
97
98 pending_events = NULL((void*)0);
99 events_idle_handler = 0;
100
101 tmp = events_to_emit;
102 while (tmp != NULL((void*)0))
103 {
104 MenuMonitorEventInfo *event_info = tmp->data;
105
106 mate_menu_monitor_refmenu_monitor_ref(event_info->monitor);
107
108 tmp = tmp->next;
109 }
110
111 tmp = events_to_emit;
112 while (tmp != NULL((void*)0))
113 {
114 MenuMonitorEventInfo *event_info = tmp->data;
115
116 invoke_notifies (event_info->monitor,
117 event_info->event,
118 event_info->path);
119
120 menu_monitor_unref (event_info->monitor);
121 event_info->monitor = NULL((void*)0);
122
123 g_free (event_info->path);
124 event_info->path = NULL((void*)0);
125
126 event_info->event = MENU_MONITOR_EVENT_INVALID;
127
128 g_free (event_info);
129
130 tmp = tmp->next;
131 }
132
133 g_slist_free (events_to_emit);
134
135 return FALSE(0);
136}
137
138static void menu_monitor_queue_event(MenuMonitorEventInfo* event_info)
139{
140 pending_events = g_slist_append (pending_events, event_info);
141
142 if (events_idle_handler == 0)
143 {
144 events_idle_handler = g_idle_add ((GSourceFunc) emit_events_in_idle, NULL((void*)0));
145 }
146}
147
148static inline char* get_registry_key(const char* path, gboolean is_directory)
149{
150 return g_strdup_printf ("%s:%s",
151 path,
152 is_directory ? "<dir>" : "<file>");
153}
154
155static gboolean monitor_callback (GFileMonitor* monitor, GFile* child, GFile* other_file, GFileMonitorEvent eflags, gpointer user_data)
156{
157 MenuMonitorEventInfo *event_info;
158 MenuMonitorEvent event;
159 MenuMonitor *menu_monitor = (MenuMonitor *) user_data;
160
161 event = MENU_MONITOR_EVENT_INVALID;
Value stored to 'event' is never read
162 switch (eflags)
163 {
164 case G_FILE_MONITOR_EVENT_CHANGED:
165 event = MENU_MONITOR_EVENT_CHANGED;
166 break;
167 case G_FILE_MONITOR_EVENT_CREATED:
168 event = MENU_MONITOR_EVENT_CREATED;
169 break;
170 case G_FILE_MONITOR_EVENT_DELETED:
171 event = MENU_MONITOR_EVENT_DELETED;
172 break;
173 default:
174 return TRUE(!(0));
175 }
176
177 event_info = g_new0 (MenuMonitorEventInfo, 1)((MenuMonitorEventInfo *) g_malloc0_n ((1), sizeof (MenuMonitorEventInfo
)))
;
178
179 event_info->path = g_file_get_path (child);
180 event_info->event = event;
181 event_info->monitor = menu_monitor;
182
183 menu_monitor_queue_event (event_info);
184
185 return TRUE(!(0));
186}
187
188static MenuMonitor* register_monitor(const char* path, gboolean is_directory)
189{
190 MenuMonitor *retval;
191 GFile *file;
192
193 retval = g_new0 (MenuMonitor, 1)((MenuMonitor *) g_malloc0_n ((1), sizeof (MenuMonitor)));
194
195 retval->path = g_strdup (path)g_strdup_inline (path);
196 retval->refcount = 1;
197 retval->is_directory = is_directory != FALSE(0);
198
199 file = g_file_new_for_path (retval->path);
200
201 if (file == NULL((void*)0))
202 {
203 menu_verbose ("Not adding monitor on '%s', failed to create GFile\n",
204 retval->path);
205 return retval;
206 }
207
208 if (retval->is_directory)
209 retval->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE,
210 NULL((void*)0), NULL((void*)0));
211 else
212 retval->monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE,
213 NULL((void*)0), NULL((void*)0));
214
215 g_object_unref (G_OBJECT (file)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((file)), (((GType) ((20) << (2))))))))
);
216
217 if (retval->monitor == NULL((void*)0))
218 {
219 menu_verbose ("Not adding monitor on '%s', failed to create monitor\n",
220 retval->path);
221 return retval;
222 }
223
224 g_signal_connect (retval->monitor, "changed",g_signal_connect_data ((retval->monitor), ("changed"), (((
GCallback) (monitor_callback))), (retval), ((void*)0), (GConnectFlags
) 0)
225 G_CALLBACK (monitor_callback), retval)g_signal_connect_data ((retval->monitor), ("changed"), (((
GCallback) (monitor_callback))), (retval), ((void*)0), (GConnectFlags
) 0)
;
226
227 return retval;
228}
229
230static MenuMonitor* lookup_monitor(const char* path, gboolean is_directory)
231{
232 MenuMonitor *retval;
233 char *registry_key;
234
235 retval = NULL((void*)0);
236
237 registry_key = get_registry_key (path, is_directory);
238
239 if (monitors_registry == NULL((void*)0))
240 {
241 monitors_registry = g_hash_table_new_full (g_str_hash,
242 g_str_equal,
243 g_free,
244 NULL((void*)0));
245 }
246 else
247 {
248 retval = g_hash_table_lookup (monitors_registry, registry_key);
249 }
250
251 if (retval == NULL((void*)0))
252 {
253 retval = register_monitor (path, is_directory);
254 g_hash_table_insert (monitors_registry, registry_key, retval);
255
256 return retval;
257 }
258 else
259 {
260 g_free (registry_key);
261
262 return mate_menu_monitor_refmenu_monitor_ref(retval);
263 }
264}
265
266MenuMonitor* mate_menu_monitor_file_getmenu_get_file_monitor(const char* path)
267{
268 g_return_val_if_fail(path != NULL, NULL)do{ (void)0; }while (0);
269
270 return lookup_monitor(path, FALSE(0));
271}
272
273MenuMonitor* menu_get_directory_monitor(const char* path)
274{
275 g_return_val_if_fail (path != NULL, NULL)do{ (void)0; }while (0);
276
277 return lookup_monitor (path, TRUE(!(0)));
278}
279
280MenuMonitor* mate_menu_monitor_refmenu_monitor_ref(MenuMonitor* monitor)
281{
282 g_return_val_if_fail(monitor != NULL, NULL)do{ (void)0; }while (0);
283 g_return_val_if_fail(monitor->refcount > 0, NULL)do{ (void)0; }while (0);
284
285 monitor->refcount++;
286
287 return monitor;
288}
289
290static void menu_monitor_clear_pending_events(MenuMonitor* monitor)
291{
292 GSList *tmp;
293
294 tmp = pending_events;
295 while (tmp != NULL((void*)0))
296 {
297 MenuMonitorEventInfo *event_info = tmp->data;
298 GSList *next = tmp->next;
299
300 if (event_info->monitor == monitor)
301 {
302 pending_events = g_slist_delete_link (pending_events, tmp);
303
304 g_free (event_info->path);
305 event_info->path = NULL((void*)0);
306
307 event_info->monitor = NULL((void*)0);
308 event_info->event = MENU_MONITOR_EVENT_INVALID;
309
310 g_free (event_info);
311 }
312
313 tmp = next;
314 }
315}
316
317void menu_monitor_unref(MenuMonitor* monitor)
318{
319 char *registry_key;
320
321 g_return_if_fail (monitor != NULL)do{ (void)0; }while (0);
322 g_return_if_fail (monitor->refcount > 0)do{ (void)0; }while (0);
323
324 if (--monitor->refcount > 0)
325 return;
326
327 registry_key = get_registry_key (monitor->path, monitor->is_directory);
328 g_hash_table_remove (monitors_registry, registry_key);
329 g_free (registry_key);
330
331 if (g_hash_table_size (monitors_registry) == 0)
332 {
333 g_hash_table_destroy (monitors_registry);
334 monitors_registry = NULL((void*)0);
335 }
336
337 if (monitor->monitor)
338 {
339 g_file_monitor_cancel (monitor->monitor);
340 g_object_unref (monitor->monitor);
341 monitor->monitor = NULL((void*)0);
342 }
343
344 g_slist_foreach (monitor->notifies, (GFunc) mate_menu_monitor_notify_unrefmenu_monitor_notify_unref, NULL((void*)0));
345 g_slist_free (monitor->notifies);
346 monitor->notifies = NULL((void*)0);
347
348 menu_monitor_clear_pending_events (monitor);
349
350 g_free (monitor->path);
351 monitor->path = NULL((void*)0);
352
353 g_free (monitor);
354}
355
356static MenuMonitorNotify* mate_menu_monitor_notify_refmenu_monitor_notify_ref(MenuMonitorNotify* notify)
357{
358 g_return_val_if_fail(notify != NULL, NULL)do{ (void)0; }while (0);
359 g_return_val_if_fail(notify->refcount > 0, NULL)do{ (void)0; }while (0);
360
361 notify->refcount++;
362
363 return notify;
364}
365
366static void mate_menu_monitor_notify_unrefmenu_monitor_notify_unref(MenuMonitorNotify* notify)
367{
368 g_return_if_fail(notify != NULL)do{ (void)0; }while (0);
369 g_return_if_fail(notify->refcount > 0)do{ (void)0; }while (0);
370
371 if (--notify->refcount > 0)
372 {
373 return;
374 }
375
376 g_free(notify);
377}
378
379void menu_monitor_add_notify(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data)
380{
381 GSList* tmp;
382 MenuMonitorNotify* notify;
383
384 g_return_if_fail(monitor != NULL)do{ (void)0; }while (0);
385 g_return_if_fail(notify_func != NULL)do{ (void)0; }while (0);
386
387 tmp = monitor->notifies;
388
389 while (tmp != NULL((void*)0))
390 {
391 notify = tmp->data;
392
393 if (notify->notify_func == notify_func && notify->user_data == user_data)
394 {
395 break;
396 }
397
398 tmp = tmp->next;
399 }
400
401 if (tmp == NULL((void*)0))
402 {
403 notify = g_new0(MenuMonitorNotify, 1)((MenuMonitorNotify *) g_malloc0_n ((1), sizeof (MenuMonitorNotify
)))
;
404 notify->notify_func = notify_func;
405 notify->user_data = user_data;
406 notify->refcount = 1;
407
408 monitor->notifies = g_slist_append(monitor->notifies, notify);
409 }
410}
411
412void mate_menu_monitor_notify_removemenu_monitor_remove_notify(MenuMonitor* monitor, MenuMonitorNotifyFunc notify_func, gpointer user_data)
413{
414 GSList* tmp = monitor->notifies;
415
416 while (tmp != NULL((void*)0))
417 {
418 MenuMonitorNotify* notify = tmp->data;
419 GSList* next = tmp->next;
420
421 if (notify->notify_func == notify_func && notify->user_data == user_data)
422 {
423 notify->notify_func = NULL((void*)0);
424 notify->user_data = NULL((void*)0);
425
426 mate_menu_monitor_notify_unrefmenu_monitor_notify_unref(notify);
427
428 monitor->notifies = g_slist_delete_link(monitor->notifies, tmp);
429 }
430
431 tmp = next;
432 }
433}
diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-fb6164.html b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-fb6164.html new file mode 100644 index 0000000..d2572a8 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/report-fb6164.html @@ -0,0 +1,1417 @@ + + + +/rootdir/libmenu/tmp-introspectwsrdc1ky/MateMenu-2.0.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:tmp-introspectwsrdc1ky/MateMenu-2.0.c
Warning:line 181, column 11
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name MateMenu-2.0.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 static -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 -fcoverage-compilation-dir=/rootdir/libmenu -resource-dir /usr/bin/../lib/clang/17 -D MATEMENU_I_KNOW_THIS_IS_UNSTABLE -D G_DISABLE_ASSERT -D G_DISABLE_CHECKS -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-deprecated-declarations -fdebug-compilation-dir=/rootdir/libmenu -ferror-limit 19 -fgnuc-version=4.2.1 -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.core.SizeofPtr -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-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-15-162655-4954-1 -x c /rootdir/libmenu/tmp-introspectwsrdc1ky/MateMenu-2.0.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* This file is generated, do not edit */
2
3#undef GLIB_VERSION_MIN_REQUIRED((((2) << 16 | (78) << 8)))
4#undef GLIB_VERSION_MAX_ALLOWED((((2) << 16 | (78) << 8)))
5
6#include <glib.h>
7#include <string.h>
8#include <stdlib.h>
9
10/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
11 * GObject introspection: Dump introspection data
12 *
13 * Copyright (C) 2008 Colin Walters <walters@verbum.org>
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the
27 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 * Boston, MA 02111-1307, USA.
29 */
30
31#include <stdlib.h>
32
33#include <glib.h>
34#include <glib-object.h>
35#include <gio/gio.h>
36
37/* This file is both compiled into libgirepository.so, and installed
38 * on the filesystem. But for the dumper, we want to avoid linking
39 * to libgirepository; see
40 * https://bugzilla.gnome.org/show_bug.cgi?id=630342
41 */
42#ifdef G_IREPOSITORY_COMPILATION
43#include "config.h"
44#include "girepository.h"
45#endif
46
47#include <string.h>
48
49static void
50escaped_printf (GOutputStream *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
51
52static void
53escaped_printf (GOutputStream *out, const char *fmt, ...)
54{
55 char *str;
56 va_list args;
57 gsize written;
58 GError *error = NULL((void*)0);
59
60 va_start (args, fmt)__builtin_va_start(args, fmt);
61
62 str = g_markup_vprintf_escaped (fmt, args);
63 if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL((void*)0), &error))
64 {
65 g_critical ("failed to write to iochannel: %s", error->message);
66 g_clear_error (&error);
67 }
68 g_free (str);
69
70 va_end (args)__builtin_va_end(args);
71}
72
73static void
74goutput_write (GOutputStream *out, const char *str)
75{
76 gsize written;
77 GError *error = NULL((void*)0);
78 if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL((void*)0), &error))
79 {
80 g_critical ("failed to write to iochannel: %s", error->message);
81 g_clear_error (&error);
82 }
83}
84
85typedef GType (*GetTypeFunc)(void);
86typedef GQuark (*ErrorQuarkFunc)(void);
87
88static GType
89invoke_get_type (GModule *self, const char *symbol, GError **error)
90{
91 GetTypeFunc sym;
92 GType ret;
93
94 if (!g_module_symbol (self, symbol, (void**)&sym))
95 {
96 g_set_error (error,
97 G_IO_ERRORg_io_error_quark(),
98 G_IO_ERROR_FAILED,
99 "Failed to find symbol '%s'", symbol);
100 return G_TYPE_INVALID((GType) ((0) << (2)));
101 }
102
103 ret = sym ();
104 if (ret == G_TYPE_INVALID((GType) ((0) << (2))))
105 {
106 g_set_error (error,
107 G_IO_ERRORg_io_error_quark(),
108 G_IO_ERROR_FAILED,
109 "Function '%s' returned G_TYPE_INVALID", symbol);
110 }
111 return ret;
112}
113
114static GQuark
115invoke_error_quark (GModule *self, const char *symbol, GError **error)
116{
117 ErrorQuarkFunc sym;
118
119 if (!g_module_symbol (self, symbol, (void**)&sym))
120 {
121 g_set_error (error,
122 G_IO_ERRORg_io_error_quark(),
123 G_IO_ERROR_FAILED,
124 "Failed to find symbol '%s'", symbol);
125 return G_TYPE_INVALID((GType) ((0) << (2)));
126 }
127
128 return sym ();
129}
130
131static char *
132value_transform_to_string (const GValue *value)
133{
134 GValue tmp = G_VALUE_INIT{ 0, { { 0 } } };
135 char *s = NULL((void*)0);
136
137 g_value_init (&tmp, G_TYPE_STRING((GType) ((16) << (2))));
138
139 if (g_value_transform (value, &tmp))
140 {
141 const char *str = g_value_get_string (&tmp);
142
143 if (str != NULL((void*)0))
144 s = g_strescape (str, NULL((void*)0));
145 }
146
147 g_value_unset (&tmp);
148
149 return s;
150}
151
152/* A simpler version of g_strdup_value_contents(), but with stable
153 * output and less complex semantics
154 */
155static char *
156value_to_string (const GValue *value)
157{
158 if (value == NULL((void*)0))
159 return NULL((void*)0);
160
161 if (G_VALUE_HOLDS_STRING (value)(((__extension__ ({ const GValue *__val = (const GValue*) ((value
)); GType __t = (((GType) ((16) << (2)))); gboolean __r
; if (!__val) __r = (0); else if (__val->g_type == __t) __r
= (!(0)); else __r = g_type_check_value_holds (__val, __t); __r
; }))))
)
162 {
163 const char *s = g_value_get_string (value);
164
165 if (s == NULL((void*)0))
166 return g_strdup ("NULL")g_strdup_inline ("NULL");
167
168 return g_strescape (s, NULL((void*)0));
169 }
170 else
171 {
172 GType value_type = G_VALUE_TYPE (value)(((GValue*) (value))->g_type);
173
174 switch (G_TYPE_FUNDAMENTAL (value_type)(g_type_fundamental (value_type)))
175 {
176 case G_TYPE_BOXED((GType) ((18) << (2))):
177 if (g_value_get_boxed (value) == NULL((void*)0))
178 return NULL((void*)0);
179 else
180 return value_transform_to_string (value);
181 break;
This statement is never executed
182
183 case G_TYPE_OBJECT((GType) ((20) << (2))):
184 if (g_value_get_object (value) == NULL((void*)0))
185 return NULL((void*)0);
186 else
187 return value_transform_to_string (value);
188 break;
189
190 case G_TYPE_POINTER((GType) ((17) << (2))):
191 return NULL((void*)0);
192
193 default:
194 return value_transform_to_string (value);
195 }
196 }
197
198 return NULL((void*)0);
199}
200
201static void
202dump_properties (GType type, GOutputStream *out)
203{
204 guint i;
205 guint n_properties;
206 GParamSpec **props;
207
208 if (G_TYPE_FUNDAMENTAL (type)(g_type_fundamental (type)) == G_TYPE_OBJECT((GType) ((20) << (2))))
209 {
210 GObjectClass *klass;
211 klass = g_type_class_ref (type);
212 props = g_object_class_list_properties (klass, &n_properties);
213 }
214 else
215 {
216 void *klass;
217 klass = g_type_default_interface_ref (type);
218 props = g_object_interface_list_properties (klass, &n_properties);
219 }
220
221 for (i = 0; i < n_properties; i++)
222 {
223 GParamSpec *prop;
224
225 prop = props[i];
226 if (prop->owner_type != type)
227 continue;
228
229 const GValue *v = g_param_spec_get_default_value (prop);
230 char *default_value = value_to_string (v);
231
232 if (v != NULL((void*)0) && default_value != NULL((void*)0))
233 {
234 escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\" default-value=\"%s\"/>\n",
235 prop->name,
236 g_type_name (prop->value_type),
237 prop->flags,
238 default_value);
239 }
240 else
241 {
242 escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\"/>\n",
243 prop->name,
244 g_type_name (prop->value_type),
245 prop->flags);
246 }
247
248 g_free (default_value);
249 }
250
251 g_free (props);
252}
253
254static void
255dump_signals (GType type, GOutputStream *out)
256{
257 guint i;
258 guint n_sigs;
259 guint *sig_ids;
260
261 sig_ids = g_signal_list_ids (type, &n_sigs);
262 for (i = 0; i < n_sigs; i++)
263 {
264 guint sigid;
265 GSignalQuery query;
266 guint j;
267
268 sigid = sig_ids[i];
269 g_signal_query (sigid, &query);
270
271 escaped_printf (out, " <signal name=\"%s\" return=\"%s\"",
272 query.signal_name, g_type_name (query.return_type));
273
274 if (query.signal_flags & G_SIGNAL_RUN_FIRST)
275 escaped_printf (out, " when=\"first\"");
276 else if (query.signal_flags & G_SIGNAL_RUN_LAST)
277 escaped_printf (out, " when=\"last\"");
278 else if (query.signal_flags & G_SIGNAL_RUN_CLEANUP)
279 escaped_printf (out, " when=\"cleanup\"");
280#if GLIB_CHECK_VERSION(2, 29, 15)(2 > (2) || (2 == (2) && 78 > (29)) || (2 == (2
) && 78 == (29) && 3 >= (15)))
281 else if (query.signal_flags & G_SIGNAL_MUST_COLLECT)
282 escaped_printf (out, " when=\"must-collect\"");
283#endif
284 if (query.signal_flags & G_SIGNAL_NO_RECURSE)
285 escaped_printf (out, " no-recurse=\"1\"");
286
287 if (query.signal_flags & G_SIGNAL_DETAILED)
288 escaped_printf (out, " detailed=\"1\"");
289
290 if (query.signal_flags & G_SIGNAL_ACTION)
291 escaped_printf (out, " action=\"1\"");
292
293 if (query.signal_flags & G_SIGNAL_NO_HOOKS)
294 escaped_printf (out, " no-hooks=\"1\"");
295
296 goutput_write (out, ">\n");
297
298 for (j = 0; j < query.n_params; j++)
299 {
300 escaped_printf (out, " <param type=\"%s\"/>\n",
301 g_type_name (query.param_types[j]));
302 }
303 goutput_write (out, " </signal>\n");
304 }
305 g_free (sig_ids);
306}
307
308static void
309dump_object_type (GType type, const char *symbol, GOutputStream *out)
310{
311 guint n_interfaces;
312 guint i;
313 GType *interfaces;
314
315 escaped_printf (out, " <class name=\"%s\" get-type=\"%s\"",
316 g_type_name (type), symbol);
317 if (type != G_TYPE_OBJECT((GType) ((20) << (2))))
318 {
319 GString *parent_str;
320 GType parent;
321 gboolean first = TRUE(!(0));
322
323 parent = g_type_parent (type);
324 parent_str = g_string_new ("");
325 while (parent != G_TYPE_INVALID((GType) ((0) << (2))))
326 {
327 if (first)
328 first = FALSE(0);
329 else
330 g_string_append_c (parent_str, ',')g_string_append_c_inline (parent_str, ',');
331 g_string_append (parent_str, g_type_name (parent))(__builtin_constant_p (g_type_name (parent)) ? __extension__ (
{ const char * const __val = (g_type_name (parent)); g_string_append_len_inline
(parent_str, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(parent_str, g_type_name (parent), (gssize) -1))
;
332 parent = g_type_parent (parent);
333 }
334
335 escaped_printf (out, " parents=\"%s\"", parent_str->str);
336
337 g_string_free (parent_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(parent_str), ((!(0)))) : g_string_free_and_steal (parent_str
)) : (g_string_free) ((parent_str), ((!(0)))))
;
338 }
339
340 if (G_TYPE_IS_ABSTRACT (type)(g_type_test_flags ((type), G_TYPE_FLAG_ABSTRACT)))
341 escaped_printf (out, " abstract=\"1\"");
342
343#if GLIB_CHECK_VERSION (2, 70, 0)(2 > (2) || (2 == (2) && 78 > (70)) || (2 == (2
) && 78 == (70) && 3 >= (0)))
344 if (G_TYPE_IS_FINAL (type)(g_type_test_flags ((type), G_TYPE_FLAG_FINAL)))
345 escaped_printf (out, " final=\"1\"");
346#endif
347
348 goutput_write (out, ">\n");
349
350 interfaces = g_type_interfaces (type, &n_interfaces);
351 for (i = 0; i < n_interfaces; i++)
352 {
353 GType itype = interfaces[i];
354 escaped_printf (out, " <implements name=\"%s\"/>\n",
355 g_type_name (itype));
356 }
357 g_free (interfaces);
358
359 dump_properties (type, out);
360 dump_signals (type, out);
361 goutput_write (out, " </class>\n");
362}
363
364static void
365dump_interface_type (GType type, const char *symbol, GOutputStream *out)
366{
367 guint n_interfaces;
368 guint i;
369 GType *interfaces;
370
371 escaped_printf (out, " <interface name=\"%s\" get-type=\"%s\">\n",
372 g_type_name (type), symbol);
373
374 interfaces = g_type_interface_prerequisites (type, &n_interfaces);
375 for (i = 0; i < n_interfaces; i++)
376 {
377 GType itype = interfaces[i];
378 if (itype == G_TYPE_OBJECT((GType) ((20) << (2))))
379 {
380 /* Treat this as implicit for now; in theory GInterfaces are
381 * supported on things like GstMiniObject, but right now
382 * the introspection system only supports GObject.
383 * http://bugzilla.gnome.org/show_bug.cgi?id=559706
384 */
385 continue;
386 }
387 escaped_printf (out, " <prerequisite name=\"%s\"/>\n",
388 g_type_name (itype));
389 }
390 g_free (interfaces);
391
392 dump_properties (type, out);
393 dump_signals (type, out);
394 goutput_write (out, " </interface>\n");
395}
396
397static void
398dump_boxed_type (GType type, const char *symbol, GOutputStream *out)
399{
400 escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
401 g_type_name (type), symbol);
402}
403
404static void
405dump_flags_type (GType type, const char *symbol, GOutputStream *out)
406{
407 guint i;
408 GFlagsClass *klass;
409
410 klass = g_type_class_ref (type);
411 escaped_printf (out, " <flags name=\"%s\" get-type=\"%s\">\n",
412 g_type_name (type), symbol);
413
414 for (i = 0; i < klass->n_values; i++)
415 {
416 GFlagsValue *value = &(klass->values[i]);
417
418 escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%u\"/>\n",
419 value->value_name, value->value_nick, value->value);
420 }
421 goutput_write (out, " </flags>\n");
422}
423
424static void
425dump_enum_type (GType type, const char *symbol, GOutputStream *out)
426{
427 guint i;
428 GEnumClass *klass;
429
430 klass = g_type_class_ref (type);
431 escaped_printf (out, " <enum name=\"%s\" get-type=\"%s\">\n",
432 g_type_name (type), symbol);
433
434 for (i = 0; i < klass->n_values; i++)
435 {
436 GEnumValue *value = &(klass->values[i]);
437
438 escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n",
439 value->value_name, value->value_nick, value->value);
440 }
441 goutput_write (out, " </enum>");
442}
443
444static void
445dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
446{
447 guint n_interfaces;
448 guint i;
449 GType *interfaces;
450 GString *parent_str;
451 GType parent;
452 gboolean first = TRUE(!(0));
453
454
455 escaped_printf (out, " <fundamental name=\"%s\" get-type=\"%s\"",
456 g_type_name (type), symbol);
457
458 if (G_TYPE_IS_ABSTRACT (type)(g_type_test_flags ((type), G_TYPE_FLAG_ABSTRACT)))
459 escaped_printf (out, " abstract=\"1\"");
460
461#if GLIB_CHECK_VERSION (2, 70, 0)(2 > (2) || (2 == (2) && 78 > (70)) || (2 == (2
) && 78 == (70) && 3 >= (0)))
462 if (G_TYPE_IS_FINAL (type)(g_type_test_flags ((type), G_TYPE_FLAG_FINAL)))
463 escaped_printf (out, " final=\"1\"");
464#endif
465
466 if (G_TYPE_IS_INSTANTIATABLE (type)(g_type_test_flags ((type), G_TYPE_FLAG_INSTANTIATABLE)))
467 escaped_printf (out, " instantiatable=\"1\"");
468
469 parent = g_type_parent (type);
470 parent_str = g_string_new ("");
471 while (parent != G_TYPE_INVALID((GType) ((0) << (2))))
472 {
473 if (first)
474 first = FALSE(0);
475 else
476 g_string_append_c (parent_str, ',')g_string_append_c_inline (parent_str, ',');
477 if (!g_type_name (parent))
478 break;
479 g_string_append (parent_str, g_type_name (parent))(__builtin_constant_p (g_type_name (parent)) ? __extension__ (
{ const char * const __val = (g_type_name (parent)); g_string_append_len_inline
(parent_str, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(parent_str, g_type_name (parent), (gssize) -1))
;
480 parent = g_type_parent (parent);
481 }
482
483 if (parent_str->len > 0)
484 escaped_printf (out, " parents=\"%s\"", parent_str->str);
485 g_string_free (parent_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(parent_str), ((!(0)))) : g_string_free_and_steal (parent_str
)) : (g_string_free) ((parent_str), ((!(0)))))
;
486
487 goutput_write (out, ">\n");
488
489 interfaces = g_type_interfaces (type, &n_interfaces);
490 for (i = 0; i < n_interfaces; i++)
491 {
492 GType itype = interfaces[i];
493 escaped_printf (out, " <implements name=\"%s\"/>\n",
494 g_type_name (itype));
495 }
496 g_free (interfaces);
497 goutput_write (out, " </fundamental>\n");
498}
499
500static void
501dump_type (GType type, const char *symbol, GOutputStream *out)
502{
503 switch (g_type_fundamental (type))
504 {
505 case G_TYPE_OBJECT((GType) ((20) << (2))):
506 dump_object_type (type, symbol, out);
507 break;
508 case G_TYPE_INTERFACE((GType) ((2) << (2))):
509 dump_interface_type (type, symbol, out);
510 break;
511 case G_TYPE_BOXED((GType) ((18) << (2))):
512 dump_boxed_type (type, symbol, out);
513 break;
514 case G_TYPE_FLAGS((GType) ((13) << (2))):
515 dump_flags_type (type, symbol, out);
516 break;
517 case G_TYPE_ENUM((GType) ((12) << (2))):
518 dump_enum_type (type, symbol, out);
519 break;
520 case G_TYPE_POINTER((GType) ((17) << (2))):
521 /* GValue, etc. Just skip them. */
522 break;
523 default:
524 dump_fundamental_type (type, symbol, out);
525 break;
526 }
527}
528
529static void
530dump_error_quark (GQuark quark, const char *symbol, GOutputStream *out)
531{
532 escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
533 symbol, g_quark_to_string (quark));
534}
535
536/**
537 * g_irepository_dump:
538 * @arg: Comma-separated pair of input and output filenames
539 * @error: a %GError
540 *
541 * Argument specified is a comma-separated pair of filenames; i.e. of
542 * the form "input.txt,output.xml". The input file should be a
543 * UTF-8 Unix-line-ending text file, with each line containing either
544 * "get-type:" followed by the name of a GType _get_type function, or
545 * "error-quark:" followed by the name of an error quark function. No
546 * extra whitespace is allowed.
547 *
548 * The output file should already exist, but be empty. This function will
549 * overwrite its contents.
550 *
551 * Returns: %TRUE on success, %FALSE on error
552 */
553#ifndef G_IREPOSITORY_COMPILATION
554static gboolean
555dump_irepository (const char *arg, GError **error) G_GNUC_UNUSED__attribute__ ((__unused__));
556static gboolean
557dump_irepository (const char *arg, GError **error)
558#else
559gboolean
560g_irepository_dump (const char *arg, GError **error)
561#endif
562{
563 GHashTable *output_types;
564 char **args;
565 GFile *input_file;
566 GFile *output_file;
567 GFileInputStream *input;
568 GFileOutputStream *output;
569 GDataInputStream *in;
570 GModule *self;
571 gboolean caught_error = FALSE(0);
572
573 self = g_module_open (NULL((void*)0), 0);
574 if (!self)
575 {
576 g_set_error (error,
577 G_IO_ERRORg_io_error_quark(),
578 G_IO_ERROR_FAILED,
579 "failed to open self: %s",
580 g_module_error ());
581 return FALSE(0);
582 }
583
584 args = g_strsplit (arg, ",", 2);
585
586 input_file = g_file_new_for_path (args[0]);
587 output_file = g_file_new_for_path (args[1]);
588
589 g_strfreev (args);
590
591 input = g_file_read (input_file, NULL((void*)0), error);
592 g_object_unref (input_file);
593
594 if (input == NULL((void*)0))
595 {
596 g_object_unref (output_file);
597 return FALSE(0);
598 }
599
600 output = g_file_replace (output_file, NULL((void*)0), FALSE(0), 0, NULL((void*)0), error);
601 g_object_unref (output_file);
602
603 if (output == NULL((void*)0))
604 {
605 g_input_stream_close (G_INPUT_STREAM (input)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((input)), ((g_input_stream_get_type ()))))))
, NULL((void*)0), NULL((void*)0));
606 g_object_unref (input);
607 return FALSE(0);
608 }
609
610 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "<?xml version=\"1.0\"?>\n");
611 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "<dump>\n");
612
613 output_types = g_hash_table_new (NULL((void*)0), NULL((void*)0));
614
615 in = g_data_input_stream_new (G_INPUT_STREAM (input)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((input)), ((g_input_stream_get_type ()))))))
);
616 g_object_unref (input);
617
618 while (TRUE(!(0)))
619 {
620 gsize len;
621 char *line = g_data_input_stream_read_line (in, &len, NULL((void*)0), NULL((void*)0));
622 const char *function;
623
624 if (line == NULL((void*)0) || *line == '\0')
625 {
626 g_free (line);
627 break;
628 }
629
630 g_strchomp (line);
631
632 if (strncmp (line, "get-type:", strlen ("get-type:")) == 0)
633 {
634 GType type;
635
636 function = line + strlen ("get-type:");
637
638 type = invoke_get_type (self, function, error);
639
640 if (type == G_TYPE_INVALID((GType) ((0) << (2))))
641 {
642 g_printerr ("Invalid GType function: '%s'\n", function);
643 caught_error = TRUE(!(0));
644 g_free (line);
645 break;
646 }
647
648 if (g_hash_table_lookup (output_types, (gpointer) type))
649 goto next;
650 g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
651
652 dump_type (type, function, G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
);
653 }
654 else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
655 {
656 GQuark quark;
657 function = line + strlen ("error-quark:");
658 quark = invoke_error_quark (self, function, error);
659
660 if (quark == 0)
661 {
662 g_printerr ("Invalid error quark function: '%s'\n", function);
663 caught_error = TRUE(!(0));
664 g_free (line);
665 break;
666 }
667
668 dump_error_quark (quark, function, G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
);
669 }
670
671
672 next:
673 g_free (line);
674 }
675
676 g_hash_table_destroy (output_types);
677
678 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "</dump>\n");
679
680 {
681 /* Avoid overwriting an earlier set error */
682 caught_error |= !g_input_stream_close (G_INPUT_STREAM (in)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((in)), ((g_input_stream_get_type ()))))))
, NULL((void*)0),
683 caught_error ? NULL((void*)0) : error);
684 caught_error |= !g_output_stream_close (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, NULL((void*)0),
685 caught_error ? NULL((void*)0) : error);
686 }
687
688 g_object_unref (in);
689 g_object_unref (output);
690
691 return !caught_error;
692}
693
694
695int
696main(int argc, char **argv)
697{
698 GError *error = NULL((void*)0);
699 const char *introspect_dump_prefix = "--introspect-dump=";
700
701#if !GLIB_CHECK_VERSION(2,35,0)(2 > (2) || (2 == (2) && 78 > (35)) || (2 == (2
) && 78 == (35) && 3 >= (0)))
702 g_type_init ();
703#endif
704
705
706
707 if (argc != 2 || !g_str_has_prefix (argv[1], introspect_dump_prefix)(__builtin_constant_p (introspect_dump_prefix)? __extension__
({ const char * const __str = (argv[1]); const char * const __prefix
= (introspect_dump_prefix); gboolean __result = (0); if (__str
== ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix
) (__str, __prefix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __prefix_len = strlen (((
__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (argv[1], introspect_dump_prefix
) )
)
708 {
709 g_printerr ("Usage: %s --introspect-dump=input,output", argv[0]);
710 exit (1);
711 }
712
713 if (!dump_irepository (argv[1] + strlen(introspect_dump_prefix), &error))
714 {
715 g_printerr ("%s\n", error->message);
716 exit (1);
717 }
718 exit (0);
719}
720extern GType matemenu_tree_get_type(void);
721extern GType matemenu_tree_iter_get_type(void);
722extern GType matemenu_tree_directory_get_type(void);
723extern GType matemenu_tree_entry_get_type(void);
724extern GType matemenu_tree_separator_get_type(void);
725extern GType matemenu_tree_header_get_type(void);
726extern GType matemenu_tree_alias_get_type(void);
727extern GType matemenu_tree_flags_get_type(void);
728G_MODULE_EXPORT__attribute__((visibility("default"))) GType (*GI_GET_TYPE_FUNCS_[])(void) = {
729 matemenu_tree_get_type,
730 matemenu_tree_iter_get_type,
731 matemenu_tree_directory_get_type,
732 matemenu_tree_entry_get_type,
733 matemenu_tree_separator_get_type,
734 matemenu_tree_header_get_type,
735 matemenu_tree_alias_get_type,
736 matemenu_tree_flags_get_type
737};
diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/scanview.css b/2024-02-15-162655-4954-1@29e36d7cf10c_master/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2024-02-15-162655-4954-1@29e36d7cf10c_master/sorttable.js b/2024-02-15-162655-4954-1@29e36d7cf10c_master/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2024-02-15-162655-4954-1@29e36d7cf10c_master/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write("