1 /*-
2 * Copyright (c) 2004-2008 os-cillation e.K.
3 *
4 * Written by Benedikt Meurer <benny@xfce.org>.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifdef HAVE_MEMORY_H
25 #include <memory.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33
34 #include <libxfce4util/libxfce4util.h>
35
36 #include <terminal/terminal-options.h>
37 #include <terminal/terminal-private.h>
38
39
40
41 /**
42 * terminal_option_cmp:
43 * @long_name : long option text or %NULL
44 * @short_name : short option character or 0
45 * @argv : pointer to the argument vector
46 * @argc : length of the argument vector
47 * @argv_offset : current offset in the argument vector
48 * @return_string : return location of a pointer to the option
49 * arguments, or %NULL to make this function
50 * behave for string comparison.
51 *
52 * Return value: %TRUE if @long_name or @short_name was found.
53 **/
54 static gboolean
terminal_option_cmp(const gchar * long_name,gchar short_name,gint argc,gchar ** argv,gint * argv_offset,gchar ** return_string)55 terminal_option_cmp (const gchar *long_name,
56 gchar short_name,
57 gint argc,
58 gchar **argv,
59 gint *argv_offset,
60 gchar **return_string)
61 {
62 gint len, offset;
63 gchar *arg = argv[*argv_offset];
64
65 if (long_name != NULL && *(arg + 1) == '-')
66 {
67 /* a boolean compare, check if the remaining string matches */
68 if (return_string == NULL)
69 return (strcmp (arg + 2, long_name) == 0);
70
71 len = strlen (long_name);
72 if (strncmp (arg + 2, long_name, len) != 0)
73 return FALSE;
74
75 offset = 2 + len;
76 }
77 else if (short_name != 0 && *(arg + 1) == short_name)
78 {
79 if (return_string == NULL)
80 return (*(arg + 2) == '\0');
81
82 offset = 2;
83 }
84 else
85 {
86 return FALSE;
87 }
88
89 terminal_assert (return_string != NULL);
90 if (*(arg + offset) == '=')
91 *return_string = arg + (offset + 1);
92 else if (*argv_offset + 1 > argc)
93 *return_string = NULL;
94 else
95 *return_string = argv[++*argv_offset];
96
97 return TRUE;
98 }
99
100
101
102 static gboolean
terminal_option_show_hide_cmp(const gchar * long_name,gint argc,gchar ** argv,gint * argv_offset,TerminalVisibility * return_visibility)103 terminal_option_show_hide_cmp (const gchar *long_name,
104 gint argc,
105 gchar **argv,
106 gint *argv_offset,
107 TerminalVisibility *return_visibility)
108 {
109 gchar *arg = argv[*argv_offset];
110 const size_t pref_len = strlen ("--show-");
111
112 terminal_return_val_if_fail (long_name != NULL, FALSE);
113 terminal_return_val_if_fail (return_visibility != NULL, FALSE);
114
115 if ((strncmp (arg, "--show-", pref_len) == 0 || strncmp (arg, "--hide-", pref_len) == 0)
116 && strcmp (arg + pref_len, long_name) == 0)
117 {
118 if (*(arg + 2) == 's')
119 *return_visibility = TERMINAL_VISIBILITY_SHOW;
120 else
121 *return_visibility = TERMINAL_VISIBILITY_HIDE;
122
123 return TRUE;
124 }
125
126 return FALSE;
127 }
128
129
130
131 void
terminal_options_parse(gint argc,gchar ** argv,TerminalOptions * options)132 terminal_options_parse (gint argc,
133 gchar **argv,
134 TerminalOptions *options)
135 {
136 gint n;
137
138 for (n = 1; n < argc; ++n)
139 {
140 /* all arguments should atleast start with a dash */
141 if (argv[n] == NULL || *argv[n] != '-')
142 continue;
143
144 /* everything after execute belongs to the command */
145 if (terminal_option_cmp ("execute", 'x', argc, argv, &n, NULL))
146 break;
147
148 if (terminal_option_cmp ("help", 'h', argc, argv, &n, NULL))
149 options->show_help = 1;
150 else if (terminal_option_cmp ("version", 'V', argc, argv, &n, NULL))
151 options->show_version = 1;
152 else if (terminal_option_cmp ("disable-server", 0, argc, argv, &n, NULL))
153 options->disable_server = 1;
154 else if (terminal_option_cmp ("color-table", 0, argc, argv, &n, NULL))
155 options->show_colors = 1;
156 else if (terminal_option_cmp ("preferences", 0, argc, argv, &n, NULL))
157 options->show_preferences = 1;
158 }
159 }
160
161
162
163 /**
164 * terminal_window_attr_parse:
165 * @argc :
166 * @argv :
167 * @error :
168 *
169 * Return value: %NULL on failure.
170 **/
171 GSList *
terminal_window_attr_parse(gint argc,gchar ** argv,gboolean can_reuse_tab,GError ** error)172 terminal_window_attr_parse (gint argc,
173 gchar **argv,
174 gboolean can_reuse_tab,
175 GError **error)
176 {
177 TerminalWindowAttr *win_attr;
178 TerminalTabAttr *tab_attr;
179 gchar *default_directory = NULL;
180 gchar *default_display = NULL;
181 gchar *s;
182 GSList *tp, *wp;
183 GSList *attrs;
184 gint n;
185 gchar *end_ptr = NULL;
186 TerminalVisibility visible;
187
188 win_attr = terminal_window_attr_new ();
189 tab_attr = win_attr->tabs->data;
190 attrs = g_slist_prepend (NULL, win_attr);
191
192 for (n = 1; n < argc; ++n)
193 {
194 /* all arguments should atleast start with a dash */
195 if (argv[n] == NULL || *argv[n] != '-')
196 goto unknown_option;
197
198 if (terminal_option_cmp ("default-display", 0, argc, argv, &n, &s))
199 {
200 if (G_UNLIKELY (s == NULL))
201 {
202 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
203 _("Option \"--default-display\" requires specifying "
204 "the default X display as its parameter"));
205 goto failed;
206 }
207 else
208 {
209 g_free (default_display);
210 default_display = g_strdup (s);
211 continue;
212 }
213 }
214 else if (terminal_option_cmp ("default-working-directory", 0, argc, argv, &n, &s))
215 {
216 if (G_UNLIKELY (s == NULL))
217 {
218 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
219 _("Option \"--default-working-directory\" requires "
220 "specifying the default working directory as its "
221 "parameter"));
222 goto failed;
223 }
224 else
225 {
226 g_free (default_directory);
227 default_directory = g_strdup (s);
228 continue;
229 }
230 }
231 else if (terminal_option_cmp ("execute", 'x', argc, argv, &n, NULL))
232 {
233 if (++n >= argc)
234 {
235 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
236 _("Option \"--execute/-x\" requires specifying the command "
237 "to run on the rest of the command line"));
238 goto failed;
239 }
240 else
241 {
242 g_strfreev (tab_attr->command);
243 tab_attr->command = g_strdupv (argv + n);
244 }
245
246 break;
247 }
248 else if (terminal_option_cmp ("command", 'e', argc, argv, &n, &s))
249 {
250 if (G_UNLIKELY (s == NULL))
251 {
252 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
253 _("Option \"--command/-e\" requires specifying "
254 "the command to run as its parameter"));
255 goto failed;
256 }
257 else
258 {
259 g_strfreev (tab_attr->command);
260 tab_attr->command = NULL;
261 if (!g_shell_parse_argv (s, NULL, &tab_attr->command, error))
262 goto failed;
263 }
264 }
265 else if (terminal_option_cmp ("working-directory", 0, argc, argv, &n, &s))
266 {
267 if (G_UNLIKELY (s == NULL))
268 {
269 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
270 _("Option \"--working-directory\" requires specifying "
271 "the working directory as its parameter"));
272 goto failed;
273 }
274 else
275 {
276 g_free (tab_attr->directory);
277 tab_attr->directory = g_strdup (s);
278 }
279 }
280 else if (terminal_option_cmp ("title", 'T', argc, argv, &n, &s))
281 {
282 if (G_UNLIKELY (s == NULL))
283 {
284 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
285 _("Option \"--title/-T\" requires specifying "
286 "the title as its parameter"));
287 goto failed;
288 }
289 else
290 {
291 g_free (tab_attr->title);
292 tab_attr->title = g_strdup (s);
293 }
294 }
295 else if (terminal_option_cmp ("dynamic-title-mode", 0, argc, argv, &n, &s))
296 {
297 if (G_UNLIKELY (s == NULL))
298 {
299 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
300 _("Option \"--dynamic-title-mode\" requires specifying "
301 "the dynamic title mode as its parameter"));
302 goto failed;
303 }
304 else if (g_ascii_strcasecmp (s, "replace") == 0)
305 tab_attr->dynamic_title_mode = TERMINAL_TITLE_REPLACE;
306 else if (g_ascii_strcasecmp (s, "before") == 0)
307 tab_attr->dynamic_title_mode = TERMINAL_TITLE_PREPEND;
308 else if (g_ascii_strcasecmp (s, "after") == 0)
309 tab_attr->dynamic_title_mode = TERMINAL_TITLE_APPEND;
310 else if (g_ascii_strcasecmp (s, "none") == 0)
311 tab_attr->dynamic_title_mode = TERMINAL_TITLE_HIDE;
312 else
313 {
314 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
315 _("Invalid argument for option \"--dynamic-title-mode\": %s"),
316 s);
317 goto failed;
318 }
319 }
320 else if (terminal_option_cmp ("initial-title", 0, argc, argv, &n, &s))
321 {
322 if (G_UNLIKELY (s == NULL))
323 {
324 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
325 _("Option \"--initial-title\" requires specifying "
326 "the initial title as its parameter"));
327 goto failed;
328 }
329 else
330 {
331 g_free (tab_attr->initial_title);
332 tab_attr->initial_title = g_strdup (s);
333 }
334 }
335 else if (terminal_option_cmp ("hold", 'H', argc, argv, &n, NULL))
336 {
337 tab_attr->hold = TRUE;
338 }
339 else if (terminal_option_cmp ("active-tab", 0, argc, argv, &n, NULL))
340 {
341 tab_attr->active = TRUE;
342 }
343 else if (terminal_option_cmp ("color-text", 0, argc, argv, &n, &s))
344 {
345 GdkRGBA color;
346 if (G_UNLIKELY (s == NULL))
347 {
348 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
349 _("Option \"%s\" requires specifying "
350 "the color as its parameter"), "--color-text");
351 goto failed;
352 }
353 else if (!gdk_rgba_parse (&color, s))
354 {
355 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
356 _("Unable to parse color: %s"), s);
357 goto failed;
358 }
359 g_free (tab_attr->color_text);
360 tab_attr->color_text = g_strdup (s);
361 }
362 else if (terminal_option_cmp ("color-bg", 0, argc, argv, &n, &s))
363 {
364 GdkRGBA color;
365 if (G_UNLIKELY (s == NULL))
366 {
367 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
368 _("Option \"%s\" requires specifying "
369 "the color as its parameter"), "--color-bg");
370 goto failed;
371 }
372 else if (!gdk_rgba_parse (&color, s))
373 {
374 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
375 _("Unable to parse color: %s"), s);
376 goto failed;
377 }
378 g_free (tab_attr->color_bg);
379 tab_attr->color_bg = g_strdup (s);
380 }
381 else if (terminal_option_cmp ("display", 0, argc, argv, &n, &s))
382 {
383 if (G_UNLIKELY (s == NULL))
384 {
385 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
386 _("Option \"--display\" requires specifying "
387 "the X display as its parameter"));
388 goto failed;
389 }
390 else
391 {
392 g_free (win_attr->display);
393 win_attr->display = g_strdup (s);
394 }
395 }
396 else if (terminal_option_cmp ("geometry", 0, argc, argv, &n, &s))
397 {
398 if (G_UNLIKELY (s == NULL))
399 {
400 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
401 _("Option \"--geometry\" requires specifying "
402 "the window geometry as its parameter"));
403 goto failed;
404 }
405 else
406 {
407 g_free (win_attr->geometry);
408 win_attr->geometry = g_strdup (s);
409 }
410 }
411 else if (terminal_option_cmp ("role", 0, argc, argv, &n, &s))
412 {
413 if (G_UNLIKELY (s == NULL))
414 {
415 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
416 _("Option \"--role\" requires specifying "
417 "the window role as its parameter"));
418 goto failed;
419 }
420 else
421 {
422 g_free (win_attr->role);
423 win_attr->role = g_strdup (s);
424 }
425 }
426 else if (terminal_option_cmp ("sm-client-id", 0, argc, argv, &n, &s))
427 {
428 if (G_UNLIKELY (s == NULL))
429 {
430 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
431 _("Option \"--sm-client-id\" requires specifying "
432 "the unique session id as its parameter"));
433 goto failed;
434 }
435 else
436 {
437 g_free (win_attr->sm_client_id);
438 win_attr->sm_client_id = g_strdup (s);
439 }
440 }
441 else if (terminal_option_cmp ("startup-id", 0, argc, argv, &n, &s))
442 {
443 if (G_UNLIKELY (s == NULL))
444 {
445 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
446 _("Option \"--startup-id\" requires specifying "
447 "the startup id as its parameter"));
448 goto failed;
449 }
450 else
451 {
452 g_free (win_attr->startup_id);
453 win_attr->startup_id = g_strdup (s);
454 continue;
455 }
456 }
457 else if (terminal_option_cmp ("icon", 'I', argc, argv, &n, &s))
458 {
459 if (G_UNLIKELY (s == NULL))
460 {
461 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
462 _("Option \"--icon/-I\" requires specifying "
463 "an icon name or filename as its parameter"));
464 goto failed;
465 }
466 else
467 {
468 g_free (win_attr->icon);
469 win_attr->icon = g_strdup (s);
470 }
471 }
472 else if (terminal_option_cmp ("drop-down", 0, argc, argv, &n, NULL))
473 {
474 win_attr->drop_down = TRUE;
475 }
476 else if (terminal_option_show_hide_cmp ("menubar", argc, argv, &n, &visible))
477 {
478 win_attr->menubar = visible;
479 }
480 else if (terminal_option_cmp ("fullscreen", 0, argc, argv, &n, NULL))
481 {
482 win_attr->fullscreen = TRUE;
483 }
484 else if (terminal_option_cmp ("maximize", 0, argc, argv, &n, NULL))
485 {
486 win_attr->maximize = TRUE;
487 }
488 else if (terminal_option_cmp ("minimize", 0, argc, argv, &n, NULL))
489 {
490 win_attr->minimize = TRUE;
491 }
492 else if (terminal_option_show_hide_cmp ("borders", argc, argv, &n, &visible))
493 {
494 win_attr->borders = visible;
495 }
496 else if (terminal_option_show_hide_cmp ("toolbar", argc, argv, &n, &visible))
497 {
498 win_attr->toolbar = visible;
499 }
500 else if (terminal_option_show_hide_cmp ("scrollbar", argc, argv, &n, &visible))
501 {
502 win_attr->scrollbar = visible;
503 }
504 else if (terminal_option_cmp ("tab", 0, argc, argv, &n, NULL))
505 {
506 if (can_reuse_tab)
507 {
508 /* tab is the first user option, reuse existing window */
509 win_attr->reuse_last_window = TRUE;
510 }
511 else
512 {
513 /* add new tab */
514 tab_attr = terminal_tab_attr_new ();
515 win_attr->tabs = g_slist_append (win_attr->tabs, tab_attr);
516 }
517 }
518 else if (terminal_option_cmp ("window", 0, argc, argv, &n, NULL))
519 {
520 /* multiple windows, don't reuse */
521 win_attr->reuse_last_window = FALSE;
522
523 /* setup new window */
524 win_attr = terminal_window_attr_new ();
525 tab_attr = win_attr->tabs->data;
526 attrs = g_slist_append (attrs, win_attr);
527 }
528 else if (terminal_option_cmp ("font", 0, argc, argv, &n, &s))
529 {
530 if (G_UNLIKELY (s == NULL))
531 {
532 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
533 _("Option \"--font\" requires specifying "
534 "the font name as its parameter"));
535 goto failed;
536 }
537 else
538 {
539 g_free (win_attr->font);
540 win_attr->font = g_strdup (s);
541 continue;
542 }
543 }
544 else if (terminal_option_cmp ("zoom", 0, argc, argv, &n, &s))
545 {
546 if (G_UNLIKELY (s == NULL) ||
547 strtol (s, &end_ptr, 0) < TERMINAL_ZOOM_LEVEL_MINIMUM ||
548 strtol (s, &end_ptr, 0) > TERMINAL_ZOOM_LEVEL_MAXIMUM)
549 {
550 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
551 _("Option \"--zoom\" requires specifying "
552 "the zoom (%d .. %d) as its parameter"),
553 TERMINAL_ZOOM_LEVEL_MINIMUM, TERMINAL_ZOOM_LEVEL_MAXIMUM);
554 goto failed;
555 }
556 else
557 {
558 win_attr->zoom = strtol (s, &end_ptr, 0);
559 continue;
560 }
561 }
562 else if (terminal_option_cmp ("disable-server", 0, argc, argv, &n, NULL)
563 || terminal_option_cmp ("sync", 0, argc, argv, &n, NULL)
564 || terminal_option_cmp ("g-fatal-warnings", 0, argc, argv, &n, NULL))
565 {
566 /* options we can ignore */
567 continue;
568 }
569 else
570 {
571 unknown_option:
572 g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_FAILED,
573 _("Unknown option \"%s\""), argv[n]);
574 goto failed;
575 }
576
577 /* not the first option anymore */
578 can_reuse_tab = FALSE;
579 }
580
581 /* substitute default working directory and default display if any */
582 if (default_display != NULL || default_directory != NULL)
583 {
584 for (wp = attrs; wp != NULL; wp = wp->next)
585 {
586 win_attr = wp->data;
587 for (tp = win_attr->tabs; tp != NULL; tp = tp->next)
588 {
589 tab_attr = tp->data;
590 if (tab_attr->directory == NULL && default_directory != NULL)
591 tab_attr->directory = g_strdup (default_directory);
592 }
593
594 if (win_attr->display == NULL && default_display != NULL)
595 win_attr->display = g_strdup (default_display);
596 }
597 }
598
599 g_free (default_directory);
600 g_free (default_display);
601
602 return attrs;
603
604 failed:
605
606 for (wp = attrs; wp != NULL; wp = wp->next)
607 terminal_window_attr_free (wp->data);
608 g_slist_free (attrs);
609
610 g_free (default_directory);
611 g_free (default_display);
612
613 return NULL;
614 }
615
616
617
618 /**
619 **/
620 TerminalWindowAttr*
terminal_window_attr_new(void)621 terminal_window_attr_new (void)
622 {
623 TerminalWindowAttr *win_attr = g_slice_new0 (TerminalWindowAttr);
624
625 win_attr->fullscreen = FALSE;
626 win_attr->menubar = TERMINAL_VISIBILITY_DEFAULT;
627 win_attr->borders = TERMINAL_VISIBILITY_DEFAULT;
628 win_attr->toolbar = TERMINAL_VISIBILITY_DEFAULT;
629 win_attr->scrollbar = TERMINAL_VISIBILITY_DEFAULT;
630 win_attr->zoom = TERMINAL_ZOOM_LEVEL_DEFAULT;
631 win_attr->tabs = g_slist_prepend (NULL, terminal_tab_attr_new ());
632
633 return win_attr;
634 }
635
636
637
638 /**
639 **/
640 TerminalTabAttr*
terminal_tab_attr_new(void)641 terminal_tab_attr_new (void)
642 {
643 TerminalTabAttr *tab_attr = g_slice_new0 (TerminalTabAttr);
644
645 tab_attr->dynamic_title_mode = TERMINAL_TITLE_DEFAULT;
646 tab_attr->position = -1;
647
648 return tab_attr;
649 }
650
651
652
653 /**
654 * terminal_tab_attr_free:
655 * @attr : A #TerminalTabAttr.
656 **/
657 void
terminal_tab_attr_free(TerminalTabAttr * attr)658 terminal_tab_attr_free (TerminalTabAttr *attr)
659 {
660 terminal_return_if_fail (attr != NULL);
661
662 g_strfreev (attr->command);
663 g_free (attr->directory);
664 g_free (attr->title);
665 g_free (attr->initial_title);
666 g_free (attr->color_text);
667 g_free (attr->color_bg);
668 g_free (attr->color_title);
669 g_slice_free (TerminalTabAttr, attr);
670 }
671
672
673
674 /**
675 * terminal_window_attr_free:
676 * @attr : A #TerminalWindowAttr.
677 **/
678 void
terminal_window_attr_free(TerminalWindowAttr * attr)679 terminal_window_attr_free (TerminalWindowAttr *attr)
680 {
681 terminal_return_if_fail (attr != NULL);
682
683 g_slist_free_full (attr->tabs, (GDestroyNotify) terminal_tab_attr_free);
684 g_free (attr->startup_id);
685 g_free (attr->sm_client_id);
686 g_free (attr->geometry);
687 g_free (attr->display);
688 g_free (attr->role);
689 g_free (attr->icon);
690 g_free (attr->font);
691 g_slice_free (TerminalWindowAttr, attr);
692 }
693