util: fix possible buffer overrun in the function that create L2 menus (Coverity...
[wmaker-crm.git] / util / wmgenmenu.c
blob95c20e5c11a1cb247ff9259c6f7ffc9490f64d46
1 /* Copyright (C) 2010 Carlos R. Mafra */
3 #ifdef __GLIBC__
4 #define _GNU_SOURCE /* getopt_long */
5 #endif
7 #include "config.h"
9 #include <ctype.h>
10 #include <getopt.h>
11 #include <limits.h>
12 #include <locale.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #ifdef HAVE_STDNORETURN
18 #include <stdnoreturn.h>
19 #endif
21 #include <WINGs/WUtil.h>
23 #include "../src/wconfig.h"
25 #define MAX_NR_APPS 128 /* Maximum number of entries in each apps list */
26 #define MAX_WMS 10 /* Maximum number of other window managers to check */
28 #include "wmgenmenu.h"
30 static void find_and_write(const char *group, char *list[][2], int this_is_terminals);
31 static void other_window_managers(void);
32 static void print_help(int print_usage, int exitval);
34 extern char *__progname;
36 char *path, *terminal = NULL;
38 WMPropList *RMenu, *L1Menu, *L2Menu, *L3Menu, *L4Menu;
40 int main(int argc, char *argv[])
42 char *t;
43 int ch;
44 char *tmp, *theme_paths, *style_paths, *icon_paths;
46 tmp = wstrconcat("-noext ", PKGDATADIR);
47 theme_paths = wstrconcat(tmp, "/Themes $HOME/GNUstep/Library/WindowMaker/Themes WITH setstyle");
48 style_paths = wstrconcat(tmp, "/Styles $HOME/GNUstep/Library/WindowMaker/Styles WITH setstyle");
49 icon_paths = wstrconcat(tmp, "/IconSets $HOME/GNUstep/Library/WindowMaker/IconSets WITH seticons");
51 struct option longopts[] = {
52 { "version", no_argument, NULL, 'v' },
53 { "help", no_argument, NULL, 'h' },
54 { NULL, 0, NULL, 0 }
57 while ((ch = getopt_long(argc, argv, "hv", longopts, NULL)) != -1)
58 switch (ch) {
59 case 'v':
60 printf("%s (Window Maker %s)\n", __progname, VERSION);
61 return 0;
62 /* NOTREACHED */
63 case 'h':
64 print_help(1, 0);
65 /* NOTREACHED */
66 default:
67 print_help(0, 1);
68 /* NOTREACHED */
71 argc -= optind;
72 argv += optind;
74 if (argc != 0)
75 print_help(0, 1);
77 path = getenv("PATH");
78 setlocale(LC_ALL, "");
80 #if defined(HAVE_LIBINTL_H) && defined(I18N)
81 if (getenv("NLSPATH"))
82 bindtextdomain("wmgenmenu", getenv("NLSPATH"));
83 else
84 bindtextdomain("wmgenmenu", LOCALEDIR);
86 bind_textdomain_codeset("wmgenmenu", "UTF-8");
87 textdomain("wmgenmenu");
88 #endif
91 * The menu generated is a five-level hierarchy, of which the
92 * top level (RMenu) is only used to hold the others (a single
93 * PLString, which will be the title of the root menu)
95 * RMenu Window Maker
96 * L1Menu Applications
97 * L2Menu Terminals
98 * L3Menu XTerm
99 * L3Menu RXVT
100 * L2Menu Internet
101 * L3Menu Firefox
102 * L2Menu E-mail
103 * L1Menu Appearance
104 * L2Menu Themes
105 * L2Menu Background
106 * L3Menu Solid
107 * L4Menu Indigo
108 * L1Menu Configure Window Maker
112 /* Root */
113 RMenu = WMCreatePLArray(WMCreatePLString("Window Maker"), NULL);
115 /* Root -> Applications */
116 L1Menu = WMCreatePLArray(WMCreatePLString(_("Applications")), NULL);
118 /* Root -> Applications -> <category> */
119 find_and_write(_("Terminals"), Terminals, 1); /* always keep terminals the top item */
120 find_and_write(_("Internet"), Internet, 0);
121 find_and_write(_("Email"), Email, 0);
122 find_and_write(_("Mathematics"), Mathematics, 0);
123 find_and_write(_("File Managers"), File_managers, 0);
124 find_and_write(_("Graphics"), Graphics, 0);
125 find_and_write(_("Multimedia"), Multimedia, 0);
126 find_and_write(_("Editors"), Editors, 0);
127 find_and_write(_("Development"), Development, 0);
128 find_and_write("Window Maker", WindowMaker, 0);
129 find_and_write(_("Office"), Office, 0);
130 find_and_write(_("Astronomy"), Astronomy, 0);
131 find_and_write(_("Sound"), Sound, 0);
132 find_and_write(_("Comics"), Comics, 0);
133 find_and_write(_("Viewers"), Viewers, 0);
134 find_and_write(_("Utilities"), Utilities, 0);
135 find_and_write(_("System"), System, 0);
136 find_and_write(_("Video"), Video, 0);
137 find_and_write(_("Chat and Talk"), Chat, 0);
138 find_and_write(_("P2P Network"), P2P, 0);
139 find_and_write(_("Games"), Games, 0);
140 find_and_write("OpenSUSE", OpenSUSE, 0);
141 find_and_write("Mandriva", Mandriva, 0);
143 WMAddToPLArray(RMenu, L1Menu);
145 /* Root -> `Run' dialog */
146 L1Menu = WMCreatePLArray(
147 WMCreatePLString(_("Run...")),
148 WMCreatePLString("SHEXEC"),
149 WMCreatePLString(_("%A(Run, Type command:)")),
150 NULL
152 WMAddToPLArray(RMenu, L1Menu);
154 /* Root -> Appearance */
155 L1Menu = WMCreatePLArray(WMCreatePLString(_("Appearance")), NULL);
157 /* Root -> Appearance -> Themes */
158 L2Menu = WMCreatePLArray(
159 WMCreatePLString(_("Themes")),
160 WMCreatePLString("OPEN_MENU"),
161 WMCreatePLString(theme_paths),
162 NULL
164 WMAddToPLArray(L1Menu, L2Menu);
166 /* Root -> Appearance -> Styles */
167 L2Menu = WMCreatePLArray(
168 WMCreatePLString(_("Styles")),
169 WMCreatePLString("OPEN_MENU"),
170 WMCreatePLString(style_paths),
171 NULL
173 WMAddToPLArray(L1Menu, L2Menu);
175 /* Root -> Appearance -> Icon Sets */
176 L2Menu = WMCreatePLArray(
177 WMCreatePLString(_("Icon Sets")),
178 WMCreatePLString("OPEN_MENU"),
179 WMCreatePLString(icon_paths),
180 NULL
182 WMAddToPLArray(L1Menu, L2Menu);
184 /* Root -> Appearance -> Background */
185 L2Menu = WMCreatePLArray(WMCreatePLString(_("Background")), NULL);
187 /* Root -> Appearance -> Background -> Solid */
188 L3Menu = WMCreatePLArray(WMCreatePLString(_("Solid")), NULL);
190 #define SOLID_BACK(label, colorspec) \
191 L4Menu = WMCreatePLArray( \
192 WMCreatePLString(label), \
193 WMCreatePLString("EXEC"), \
194 WMCreatePLString("wdwrite WindowMaker WorkspaceBack '(solid, \"" colorspec "\")'"), \
195 NULL \
196 ); \
197 WMAddToPLArray(L3Menu, L4Menu)
199 /* Root -> Appearance -> Background -> Solid -> <color> */
200 SOLID_BACK(_("Black"), "black");
201 SOLID_BACK(_("Blue"), "#505075");
202 SOLID_BACK(_("Indigo"), "#243e6c");
203 SOLID_BACK(_("Bluemarine"), "#243e6c");
204 SOLID_BACK(_("Purple"), "#554466");
205 SOLID_BACK(_("Wheat"), "wheat4");
206 SOLID_BACK(_("Dark Gray"), "#333340");
207 SOLID_BACK(_("Wine"), "#400020");
208 #undef SOLID_BACK
209 WMAddToPLArray(L2Menu, L3Menu);
211 /* Root -> Appearance -> Background -> Gradient */
212 L3Menu = WMCreatePLArray(WMCreatePLString(_("Gradient")), NULL);
214 #define GRADIENT_BACK(label, fcolorspec, tcolorspec) \
215 L4Menu = WMCreatePLArray( \
216 WMCreatePLString(label), \
217 WMCreatePLString("EXEC"), \
218 WMCreatePLString("wdwrite WindowMaker WorkspaceBack '(vgradient, \"" \
219 fcolorspec "\", \"" tcolorspec "\"'"), \
220 NULL \
221 ); \
222 WMAddToPLArray(L3Menu, L4Menu)
224 /* Root -> Appearance -> Background -> Gradient -> <color> */
225 L4Menu = WMCreatePLArray(
226 WMCreatePLString(_("Sunset")),
227 WMCreatePLString("EXEC"),
228 WMCreatePLString("wdwrite WindowMaker WorkspaceBack "
229 "'(mvgradient, deepskyblue4, black, deepskyblue4, tomato4)'"),
230 NULL
232 WMAddToPLArray(L3Menu, L4Menu);
233 GRADIENT_BACK(_("Sky"), "blue4", "white");
234 GRADIENT_BACK(_("Blue Shades"), "#7080a5", "#101020");
235 GRADIENT_BACK(_("Indigo Shades"), "#746ebc", "#242e4c");
236 GRADIENT_BACK(_("Purple Shades"), "#654c66", "#151426");
237 GRADIENT_BACK(_("Wheat Shades"), "#a09060", "#302010");
238 GRADIENT_BACK(_("Grey Shades"), "#636380", "#131318");
239 GRADIENT_BACK(_("Wine Shades"), "#600040", "#180010");
240 #undef GRADIENT_BACK
241 WMAddToPLArray(L2Menu, L3Menu);
243 /* Root -> Appearance -> Background -> Images */
244 L3Menu = WMCreatePLArray(
245 WMCreatePLString(_("Images")),
246 WMCreatePLString("OPEN_MENU"),
247 WMCreatePLString("-noext $HOME/GNUstep/Library/WindowMaker/Backgrounds WITH wmsetbg -u -t"),
248 NULL
250 WMAddToPLArray(L2Menu, L3Menu);
252 WMAddToPLArray(L1Menu, L2Menu);
254 /* Root -> Appearance -> Save Theme */
255 L2Menu = WMCreatePLArray(
256 WMCreatePLString(_("Save Theme")),
257 WMCreatePLString("SHEXEC"),
258 WMCreatePLString("getstyle -p \"%a(Theme name, Name to save theme as)\""),
259 NULL
261 WMAddToPLArray(L1Menu, L2Menu);
263 /* Root -> Appearance -> Save IconSet */
264 L2Menu = WMCreatePLArray(
265 WMCreatePLString(_("Save IconSet")),
266 WMCreatePLString("SHEXEC"),
267 WMCreatePLString("geticonset $HOME/GNUstep/Library/WindowMaker/IconSets/"
268 "\"%a(IconSet name,Name to save icon set as)\""),
269 NULL
271 WMAddToPLArray(L1Menu, L2Menu);
272 WMAddToPLArray(RMenu, L1Menu);
274 /* Root -> Workspaces */
275 L1Menu = WMCreatePLArray(
276 WMCreatePLString(_("Workspaces")),
277 WMCreatePLString("WORKSPACE_MENU"),
278 NULL
280 WMAddToPLArray(RMenu, L1Menu);
282 /* Root -> Workspace */
283 L1Menu = WMCreatePLArray(WMCreatePLString(_("Workspace")), NULL);
284 L2Menu = WMCreatePLArray(
285 WMCreatePLString(_("Hide Others")),
286 WMCreatePLString("HIDE_OTHERS"),
287 NULL
289 WMAddToPLArray(L1Menu, L2Menu);
291 /* Root -> Workspace -> Show All */
292 L2Menu = WMCreatePLArray(
293 WMCreatePLString(_("Show All")),
294 WMCreatePLString("SHOW_ALL"),
295 NULL
297 WMAddToPLArray(L1Menu, L2Menu);
299 /* Root -> Workspace -> Arrange Icons */
300 L2Menu = WMCreatePLArray(
301 WMCreatePLString(_("Arrange Icons")),
302 WMCreatePLString("ARRANGE_ICONS"),
303 NULL
305 WMAddToPLArray(L1Menu, L2Menu);
307 /* Root -> Workspace -> Refresh */
308 L2Menu = WMCreatePLArray(
309 WMCreatePLString(_("Refresh")),
310 WMCreatePLString("REFRESH"),
311 NULL
313 WMAddToPLArray(L1Menu, L2Menu);
315 /* Root -> Workspace -> Save Session */
316 L2Menu = WMCreatePLArray(
317 WMCreatePLString(_("Save Session")),
318 WMCreatePLString("SAVE_SESSION"),
319 NULL
321 WMAddToPLArray(L1Menu, L2Menu);
323 /* Root -> Workspace -> Clear Session */
324 L2Menu = WMCreatePLArray(
325 WMCreatePLString(_("Clear Session")),
326 WMCreatePLString("CLEAR_SESSION"),
327 NULL
329 WMAddToPLArray(L1Menu, L2Menu);
330 WMAddToPLArray(RMenu, L1Menu);
332 /* Root -> Configure Window Maker */
333 L1Menu = WMCreatePLArray(
334 WMCreatePLString(_("Configure Window Maker")),
335 WMCreatePLString("EXEC"),
336 WMCreatePLString("WPrefs"),
337 NULL
339 WMAddToPLArray(RMenu, L1Menu);
341 /* Root -> Info Panel */
342 L1Menu = WMCreatePLArray(
343 WMCreatePLString(_("Info Panel")),
344 WMCreatePLString("INFO_PANEL"),
345 NULL
347 WMAddToPLArray(RMenu, L1Menu);
349 /* Root -> Restart Window Maker */
350 L1Menu = WMCreatePLArray(
351 WMCreatePLString(_("Restart Window Maker")),
352 WMCreatePLString("RESTART"),
353 NULL
355 WMAddToPLArray(RMenu, L1Menu);
357 /* Root -> Other Window Managers [-> <other window manager> ...] */
358 other_window_managers();
360 /* Root -> Lock Screen */
361 t = wfindfile(path, "xlock");
362 if (t) {
363 L1Menu = WMCreatePLArray(
364 WMCreatePLString(_("Lock Screen")),
365 WMCreatePLString("EXEC"),
366 WMCreatePLString("xlock -allowroot -usefirst -mode matrix"),
367 NULL
369 WMAddToPLArray(RMenu, L1Menu);
370 wfree(t);
373 /* Root -> Exit Window Maker */
374 L1Menu = WMCreatePLArray(
375 WMCreatePLString(_("Exit Window Maker")),
376 WMCreatePLString("EXIT"),
377 NULL
379 WMAddToPLArray(RMenu, L1Menu);
381 printf("%s", WMGetPropListDescription(RMenu, True));
382 puts("");
384 return 0;
388 * Creates an L2Menu made of L3Menu items
389 * Attaches to L1Menu
390 * - make sure previous menus of these levels are
391 * attached to their parent before calling
393 static void find_and_write(const char *group, char *list[][2], int this_is_terminals)
395 int i, argc;
396 char *t, **argv, buf[PATH_MAX];
398 /* or else pre-existing menus of these levels
399 * will badly disturb empty group detection */
400 L2Menu = NULL;
401 L3Menu = NULL;
403 i = 0;
404 while (list[i][0]) {
405 /* Before checking if app exists, split its options */
406 wtokensplit(list[i][1], &argv, &argc);
407 t = wfindfile(path, argv[0]);
408 if (t) {
409 /* find a terminal to be used for cmnds that need a terminal */
410 if (this_is_terminals && !terminal)
411 terminal = wstrdup(list[i][1]);
412 if (*(argv[argc-1]) != '!') {
413 L3Menu = WMCreatePLArray(
414 WMCreatePLString(_(list[i][0])),
415 WMCreatePLString("EXEC"),
416 WMCreatePLString(list[i][1]),
417 NULL
419 } else {
420 char comm[PATH_MAX], *ptr;
422 strncpy(comm, list[i][1], sizeof(comm) - 1);
423 comm[sizeof(comm) - 1] = '\0';
425 /* delete character " !" from the command */
426 ptr = strchr(comm, '!');
427 while (ptr >= comm && (*ptr == '!' || isspace(*ptr)))
428 *ptr-- = '\0';
429 snprintf(buf, sizeof(buf), "%s -e %s", terminal ? terminal : "xterm" , comm);
430 /* Root -> Applications -> <category> -> <application> */
431 L3Menu = WMCreatePLArray(
432 WMCreatePLString(_(list[i][0])),
433 WMCreatePLString("EXEC"),
434 WMCreatePLString(buf),
435 NULL
438 if (!L2Menu)
439 L2Menu = WMCreatePLArray(
440 WMCreatePLString(group),
441 NULL
443 WMAddToPLArray(L2Menu, L3Menu);
444 wfree(t);
446 i++;
448 if (L2Menu)
449 WMAddToPLArray(L1Menu, L2Menu);
453 * Creates an L1Menu made of L2Menu items
454 * - make sure previous menus of these levels are
455 * attached to their parent before calling
456 * Attaches to RMenu
458 static void other_window_managers(void)
460 int i;
461 char *t, buf[PATH_MAX];
463 /* or else pre-existing menus of these levels
464 * will badly disturb empty group detection */
465 L1Menu = NULL;
466 L2Menu = NULL;
468 i = 0;
469 while (other_wm[i][0]) {
470 t = wfindfile(path, other_wm[i][1]);
471 if (t) {
472 snprintf(buf, sizeof(buf), _("Start %s"), _(other_wm[i][0]));
473 /* Root -> Other Window Managers -> <other window manager> */
474 L2Menu = WMCreatePLArray(
475 WMCreatePLString(buf),
476 WMCreatePLString("RESTART"),
477 WMCreatePLString(other_wm[i][1]),
478 NULL
480 if (!L1Menu)
481 L1Menu = WMCreatePLArray(
482 WMCreatePLString(_("Other Window Managers")),
483 NULL
485 WMAddToPLArray(L1Menu, L2Menu);
486 wfree(t);
488 i++;
490 if (L1Menu)
491 WMAddToPLArray(RMenu, L1Menu);
494 noreturn void print_help(int print_usage, int exitval)
496 printf("Usage: %s [-h] [-v]\n", __progname);
497 if (print_usage) {
498 puts("Writes a menu structure usable as ~/GNUstep/Defaults/WMRootMenu to stdout");
499 puts("");
500 puts(" -h, --help display this help and exit");
501 puts(" -v, --version output version information and exit");
503 exit(exitval);