Add reminder to investigate recursive commands for 2.6
[fvwm.git] / fvwm / expand.c
blob9007f001da3f019628b73ba2a1af343fa86b5f87
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /* ---------------------------- included header files ---------------------- */
18 #include "config.h"
20 #include <stdio.h>
21 #include <limits.h>
23 #include "libs/fvwmlib.h"
24 #include "libs/Parse.h"
25 #include "libs/Strings.h"
26 #include "libs/ColorUtils.h"
27 #include "fvwm.h"
28 #include "externs.h"
29 #include "cursor.h"
30 #include "functions.h"
31 #include "misc.h"
32 #include "move_resize.h"
33 #include "screen.h"
34 #include "geometry.h"
35 #include "read.h"
36 #include "virtual.h"
37 #include "colorset.h"
38 #include "schedule.h"
39 #include "libs/FGettext.h"
40 #include "libs/charmap.h"
41 #include "libs/wcontext.h"
42 #include "libs/Fsvg.h"
44 /* ---------------------------- local definitions -------------------------- */
46 /* ---------------------------- local macros ------------------------------- */
48 /* ---------------------------- imports ------------------------------------ */
50 extern char const * const Fvwm_VersionInfo;
52 /* ---------------------------- included code files ------------------------ */
54 /* ---------------------------- local types -------------------------------- */
56 /* ---------------------------- forward declarations ----------------------- */
58 /* ---------------------------- local variables ---------------------------- */
60 static char *partial_function_vars[] =
62 "bg.cs",
63 "desk.name",
64 "fg.cs",
65 "fgsh.cs",
66 "gt.",
67 "hilight.cs",
68 "shadow.cs",
69 NULL
72 static char *function_vars[] =
74 "cond.rc",
75 "cw.height",
76 "cw.width",
77 "cw.x",
78 "cw.y",
79 "desk.height",
80 "desk.n",
81 "desk.pagesx",
82 "desk.pagesy",
83 "desk.width",
84 "func.context",
85 "i.height",
86 "i.width",
87 "i.x",
88 "i.y",
89 "ip.height",
90 "ip.width",
91 "ip.x",
92 "ip.y",
93 "it.height",
94 "it.width",
95 "it.x",
96 "it.y",
97 "page.nx",
98 "page.ny",
99 "pointer.cx",
100 "pointer.cy",
101 "pointer.wx",
102 "pointer.wy",
103 "pointer.x",
104 "pointer.y",
105 "schedule.last",
106 "schedule.next",
107 "screen",
108 "version.info",
109 "version.line",
110 "version.num",
111 "vp.height",
112 "vp.width",
113 "vp.x",
114 "vp.y",
115 "w.class",
116 "w.height",
117 "w.iconname",
118 "w.iconfile",
119 "w.miniiconfile",
120 "w.iconfile.svgopts",
121 "w.miniiconfile.svgopts",
122 "w.id",
123 "w.name",
124 "w.resource",
125 "w.visiblename",
126 "w.width",
127 "w.x",
128 "w.y",
129 "w.desk",
130 "w.layer",
131 NULL
134 enum
136 VAR_BG_CS,
137 VAR_DESK_NAME,
138 VAR_FG_CS,
139 VAR_FGSH_CS,
140 VAR_GT_,
141 VAR_HILIGHT_CS,
142 VAR_SHADOW_CS
143 } partial_extended_vars;
145 enum
147 VAR_COND_RC,
148 VAR_CW_HEIGHT,
149 VAR_CW_WIDTH,
150 VAR_CW_X,
151 VAR_CW_Y,
152 VAR_DESK_HEIGHT,
153 VAR_DESK_N,
154 VAR_DESK_PAGESX,
155 VAR_DESK_PAGESY,
156 VAR_DESK_WIDTH,
157 VAR_FUNC_CONTEXT,
158 VAR_I_HEIGHT,
159 VAR_I_WIDTH,
160 VAR_I_X,
161 VAR_I_Y,
162 VAR_IP_HEIGHT,
163 VAR_IP_WIDTH,
164 VAR_IP_X,
165 VAR_IP_Y,
166 VAR_IT_HEIGHT,
167 VAR_IT_WIDTH,
168 VAR_IT_X,
169 VAR_IT_Y,
170 VAR_PAGE_NX,
171 VAR_PAGE_NY,
172 VAR_POINTER_CX,
173 VAR_POINTER_CY,
174 VAR_POINTER_WX,
175 VAR_POINTER_WY,
176 VAR_POINTER_X,
177 VAR_POINTER_Y,
178 VAR_SCHEDULE_LAST,
179 VAR_SCHEDULE_NEXT,
180 VAR_SCREEN,
181 VAR_VERSION_INFO,
182 VAR_VERSION_LINE,
183 VAR_VERSION_NUM,
184 VAR_VP_HEIGHT,
185 VAR_VP_WIDTH,
186 VAR_VP_X,
187 VAR_VP_Y,
188 VAR_W_CLASS,
189 VAR_W_HEIGHT,
190 VAR_W_ICONNAME,
191 VAR_W_ICONFILE,
192 VAR_W_MINIICONFILE,
193 VAR_W_ICONFILE_SVGOPTS,
194 VAR_W_MINIICONFILE_SVGOPTS,
195 VAR_W_ID,
196 VAR_W_NAME,
197 VAR_W_RESOURCE,
198 VAR_W_VISIBLE_NAME,
199 VAR_W_WIDTH,
200 VAR_W_X,
201 VAR_W_Y,
202 VAR_W_DESK,
203 VAR_W_LAYER
204 } extended_vars;
206 /* ---------------------------- exported variables (globals) --------------- */
208 /* ---------------------------- local functions ---------------------------- */
210 int __eae_parse_range(char *input, int *lower, int *upper)
212 int rc;
213 int n;
215 *lower = 0;
216 *upper = INT_MAX;
217 if (*input == '*')
219 return 0;
221 if (!isdigit(*input))
223 return -1;
225 rc = sscanf(input, "%d-%d%n", lower, upper, &n);
226 if (rc < 2)
228 rc = sscanf(input, "%d%n", lower, &n);
229 if (rc < 1)
231 /* not a positional argument */
232 return -1;
234 if (input[n] == '-')
236 /* $[n- */
237 n++;
239 else
241 /* $[n */
242 *upper = *lower;
245 input += n;
246 if (*input != 0)
248 /* trailing characters - not good */
249 return -1;
251 if (*upper < *lower)
253 /* the range is reverse - not good */
254 return -1;
257 return 0;
260 static signed int expand_args_extended(
261 char *input, char *argument_string, char *output)
263 int rc;
264 int lower;
265 int upper;
266 int i;
267 size_t len;
269 rc = __eae_parse_range(input, &lower, &upper);
270 if (rc == -1)
272 return -1;
274 /* Skip to the start of the requested argument range */
275 if (lower > 0)
277 argument_string = SkipNTokens(argument_string, lower);
279 if (!argument_string)
281 /* replace with empty string */
282 return 0;
284 /* TODO: optimise handling of $[0] to $[9] which have already been
285 * parsed */
286 for (i = lower, len = 0; i <= upper; i++)
288 char *token;
289 size_t tlen;
291 token = PeekToken(argument_string, &argument_string);
292 if (token == NULL)
294 break;
296 /* copy the token */
297 if (i > lower)
299 if (output != NULL)
301 *output = ' ';
302 output++;
304 len++;
306 tlen = strlen(token);
307 if (output != NULL && tlen > 0)
309 memcpy(output, token, tlen);
310 output += tlen;
312 len += tlen;
315 return (int)len;
318 static signed int expand_vars_extended(
319 char *var_name, char *output, cond_rc_t *cond_rc,
320 const exec_context_t *exc)
322 char *rest;
323 char dummy[64] = "\0";
324 char *target = (output) ? output : dummy;
325 int cs = -1;
326 int n;
327 int i;
328 int l;
329 int x;
330 int y;
331 Pixel pixel = 0;
332 int val = -12345678;
333 const char *string = NULL;
334 char *allocated_string = NULL;
335 char *quoted_string = NULL;
336 Bool should_quote = False;
337 Bool is_numeric = False;
338 Bool is_target = False;
339 Bool is_x;
340 Window context_w = Scr.Root;
341 FvwmWindow *fw = exc->w.fw;
342 signed int len = -1;
344 /* allow partial matches for *.cs, gt, ... etc. variables */
345 switch ((i = GetTokenIndex(var_name, partial_function_vars, -1, &rest)))
347 case VAR_FG_CS:
348 case VAR_BG_CS:
349 case VAR_HILIGHT_CS:
350 case VAR_SHADOW_CS:
351 case VAR_FGSH_CS:
352 if (!isdigit(*rest) || (*rest == '0' && *(rest + 1) != 0))
354 /* not a non-negative integer without leading zeros */
355 return -1;
357 if (sscanf(rest, "%d%n", &cs, &n) < 1)
359 return -1;
361 if (*(rest + n) != 0)
363 /* trailing characters */
364 return -1;
366 if (cs < 0)
368 return -1;
370 alloc_colorset(cs);
371 switch (i)
373 case VAR_FG_CS:
374 pixel = Colorset[cs].fg;
375 break;
376 case VAR_BG_CS:
377 pixel = Colorset[cs].bg;
378 break;
379 case VAR_HILIGHT_CS:
380 pixel = Colorset[cs].hilite;
381 break;
382 case VAR_SHADOW_CS:
383 pixel = Colorset[cs].shadow;
384 break;
385 case VAR_FGSH_CS:
386 pixel = Colorset[cs].fgsh;
387 break;
389 is_target = True;
390 len = pixel_to_color_string(dpy, Pcmap, pixel, target, False);
391 goto GOT_STRING;
392 case VAR_GT_:
393 if (rest == NULL)
395 return -1;
397 string = _(rest);
398 goto GOT_STRING;
399 case VAR_DESK_NAME:
400 if (sscanf(rest, "%d%n", &cs, &n) < 1)
402 return -1;
404 if (*(rest + n) != 0)
406 /* trailing characters */
407 return -1;
409 string = GetDesktopName(cs);
410 if (string == NULL)
412 const char *ddn = _("Desk");
413 allocated_string = (char *)safemalloc(19 + strlen(ddn));
414 sprintf(allocated_string, "%s %i", ddn, cs);
415 string = allocated_string;
417 goto GOT_STRING;
418 default:
419 break;
422 /* only exact matches for all other variables */
423 switch ((i = GetTokenIndex(var_name, function_vars, 0, &rest)))
425 case VAR_DESK_N:
426 is_numeric = True;
427 val = Scr.CurrentDesk;
428 break;
429 case VAR_DESK_WIDTH:
430 is_numeric = True;
431 val = Scr.VxMax + Scr.MyDisplayWidth;
432 break;
433 case VAR_DESK_HEIGHT:
434 is_numeric = True;
435 val = Scr.VyMax + Scr.MyDisplayHeight;
436 break;
437 case VAR_DESK_PAGESX:
438 is_numeric = True;
439 val = (int)(Scr.VxMax / Scr.MyDisplayWidth) + 1;
440 break;
441 case VAR_DESK_PAGESY:
442 is_numeric = True;
443 val = (int)(Scr.VyMax / Scr.MyDisplayHeight) + 1;
444 break;
445 case VAR_VP_X:
446 is_numeric = True;
447 val = Scr.Vx;
448 break;
449 case VAR_VP_Y:
450 is_numeric = True;
451 val = Scr.Vy;
452 break;
453 case VAR_VP_WIDTH:
454 is_numeric = True;
455 val = Scr.MyDisplayWidth;
456 break;
457 case VAR_VP_HEIGHT:
458 is_numeric = True;
459 val = Scr.MyDisplayHeight;
460 break;
461 case VAR_PAGE_NX:
462 is_numeric = True;
463 val = (int)(Scr.Vx / Scr.MyDisplayWidth);
464 break;
465 case VAR_PAGE_NY:
466 is_numeric = True;
467 val = (int)(Scr.Vy / Scr.MyDisplayHeight);
468 break;
469 case VAR_W_ID:
470 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
472 is_target = True;
473 sprintf(target, "0x%x", (int)FW_W(fw));
475 break;
476 case VAR_W_NAME:
477 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
479 string = fw->name.name;
480 should_quote = True;
482 break;
483 case VAR_W_ICONNAME:
484 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
486 string = fw->icon_name.name;
487 should_quote = True;
489 break;
490 case VAR_W_ICONFILE:
491 case VAR_W_MINIICONFILE:
492 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
494 char *t;
496 t = (i == VAR_W_ICONFILE) ?
497 fw->icon_bitmap_file : fw->mini_pixmap_file;
498 /* expand the path if possible */
499 allocated_string = PictureFindImageFile(t, NULL, R_OK);
500 if (allocated_string == NULL)
502 string = t;
504 else if (USE_SVG && *allocated_string == ':' &&
505 (string = strchr(allocated_string + 1, ':')))
507 string++;
509 else
511 string = allocated_string;
514 break;
515 case VAR_W_ICONFILE_SVGOPTS:
516 case VAR_W_MINIICONFILE_SVGOPTS:
517 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
519 char *t;
521 if (!USE_SVG)
523 return -1;
525 t = (i == VAR_W_ICONFILE_SVGOPTS) ?
526 fw->icon_bitmap_file : fw->mini_pixmap_file;
527 /* expand the path if possible */
528 allocated_string = PictureFindImageFile(t, NULL, R_OK);
529 string = allocated_string;
530 if (string && *string == ':' &&
531 (t = strchr(string + 1, ':')))
533 *t = 0;
535 else
537 string = "";
540 break;
541 case VAR_W_CLASS:
542 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
544 string = fw->class.res_class;
545 should_quote = True;
547 break;
548 case VAR_W_RESOURCE:
549 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
551 string = fw->class.res_name;
552 should_quote = True;
554 break;
555 case VAR_W_VISIBLE_NAME:
556 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
558 string = fw->visible_name;
559 should_quote = True;
561 break;
562 case VAR_W_X:
563 case VAR_W_Y:
564 case VAR_W_WIDTH:
565 case VAR_W_HEIGHT:
566 if (!fw || IS_ICONIFIED(fw) || IS_EWMH_DESKTOP(FW_W(fw)))
568 return -1;
570 else
572 rectangle g;
574 is_numeric = True;
575 get_unshaded_geometry(fw, &g);
576 switch (i)
578 case VAR_W_X:
579 val = g.x;
580 break;
581 case VAR_W_Y:
582 val = g.y;
583 break;
584 case VAR_W_WIDTH:
585 val = g.width;
586 break;
587 case VAR_W_HEIGHT:
588 val = g.height;
589 break;
590 default:
591 return -1;
594 break;
595 case VAR_CW_X:
596 case VAR_CW_Y:
597 case VAR_CW_WIDTH:
598 case VAR_CW_HEIGHT:
599 if (!fw || IS_ICONIFIED(fw) || IS_EWMH_DESKTOP(FW_W(fw)))
601 return -1;
603 else
605 rectangle g;
607 is_numeric = True;
608 get_client_geometry(fw, &g);
609 switch (i)
611 case VAR_CW_X:
612 val = g.x;
613 break;
614 case VAR_CW_Y:
615 val = g.y;
616 break;
617 case VAR_CW_WIDTH:
618 val = g.width;
619 break;
620 case VAR_CW_HEIGHT:
621 val = g.height;
622 break;
623 default:
624 return -1;
627 break;
628 case VAR_IT_X:
629 case VAR_IT_Y:
630 case VAR_IT_WIDTH:
631 case VAR_IT_HEIGHT:
632 if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
634 return -1;
636 else
638 rectangle g;
640 if (get_visible_icon_title_geometry(fw, &g) == False)
642 return -1;
644 is_numeric = True;
645 switch (i)
647 case VAR_IT_X:
648 val = g.x;
649 break;
650 case VAR_IT_Y:
651 val = g.y;
652 break;
653 case VAR_IT_WIDTH:
654 val = g.width;
655 break;
656 case VAR_IT_HEIGHT:
657 val = g.height;
658 break;
659 default:
660 return -1;
663 break;
664 case VAR_IP_X:
665 case VAR_IP_Y:
666 case VAR_IP_WIDTH:
667 case VAR_IP_HEIGHT:
668 if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
670 return -1;
672 else
674 rectangle g;
676 if (get_visible_icon_picture_geometry(fw, &g) == False)
678 return -1;
680 is_numeric = True;
681 switch (i)
683 case VAR_IP_X:
684 val = g.x;
685 break;
686 case VAR_IP_Y:
687 val = g.y;
688 break;
689 case VAR_IP_WIDTH:
690 val = g.width;
691 break;
692 case VAR_IP_HEIGHT:
693 val = g.height;
694 break;
695 default:
696 return -1;
699 break;
700 case VAR_I_X:
701 case VAR_I_Y:
702 case VAR_I_WIDTH:
703 case VAR_I_HEIGHT:
704 if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
706 return -1;
708 else
710 rectangle g;
712 if (get_visible_icon_geometry(fw, &g) == False)
714 return -1;
716 is_numeric = True;
717 switch (i)
719 case VAR_I_X:
720 val = g.x;
721 break;
722 case VAR_I_Y:
723 val = g.y;
724 break;
725 case VAR_I_WIDTH:
726 val = g.width;
727 break;
728 case VAR_I_HEIGHT:
729 val = g.height;
730 break;
731 default:
732 return -1;
735 break;
736 case VAR_W_DESK:
737 if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
739 return -1;
741 is_numeric = True;
742 if (is_window_sticky_across_desks(fw))
744 val = Scr.CurrentDesk;
746 else
748 val = fw->Desk;
750 break;
751 case VAR_W_LAYER:
752 if (!fw || IS_EWMH_DESKTOP(FW_W(fw)))
754 return -1;
756 is_numeric = True;
757 val = fw->layer;
758 break;
759 case VAR_SCREEN:
760 is_numeric = True;
761 val = Scr.screen;
762 break;
763 case VAR_SCHEDULE_LAST:
764 is_numeric = True;
765 val = squeue_get_last_id();
766 break;
767 case VAR_SCHEDULE_NEXT:
768 is_numeric = True;
769 val = squeue_get_next_id();
770 break;
771 case VAR_COND_RC:
772 if (cond_rc == NULL)
774 return -1;
776 switch (cond_rc->rc)
778 case COND_RC_OK:
779 case COND_RC_NO_MATCH:
780 case COND_RC_ERROR:
781 case COND_RC_BREAK:
782 val = (int)(cond_rc->rc);
783 break;
784 default:
785 return -1;
787 is_numeric = True;
788 break;
789 case VAR_POINTER_X:
790 case VAR_POINTER_Y:
791 if (is_numeric == False)
793 is_numeric = True;
794 context_w = Scr.Root;
796 /* fall through */
797 case VAR_POINTER_WX:
798 case VAR_POINTER_WY:
799 if (is_numeric == False)
801 if (!fw || IS_ICONIFIED(fw)
802 || IS_EWMH_DESKTOP(FW_W(fw)))
804 return -1;
806 is_numeric = True;
807 context_w = FW_W_FRAME(fw);
809 /* fall through */
810 case VAR_POINTER_CX:
811 case VAR_POINTER_CY:
812 if (is_numeric == False)
814 if (!fw || IS_ICONIFIED(fw) || IS_SHADED(fw)
815 || IS_EWMH_DESKTOP(FW_W(fw)))
817 return -1;
819 is_numeric = True;
820 context_w = FW_W(fw);
822 is_x = False;
823 switch (i)
825 case VAR_POINTER_X:
826 case VAR_POINTER_WX:
827 case VAR_POINTER_CX:
828 is_x = True;
830 if (FQueryPointer(dpy, context_w, &JunkRoot, &JunkChild,
831 &JunkX, &JunkY, &x, &y, &JunkMask) == False)
833 /* pointer is on a different screen, don't expand */
834 return -1;
836 val = (is_x) ? x : y;
837 break;
838 case VAR_VERSION_NUM:
839 string = VERSION;
840 break;
841 case VAR_VERSION_INFO:
842 string = VERSIONINFO;
843 break;
844 case VAR_VERSION_LINE:
845 string = Fvwm_VersionInfo;
846 break;
847 case VAR_FUNC_CONTEXT:
848 is_target = True;
849 target[0] = wcontext_wcontext_to_char(exc->w.wcontext);
850 target[1] = '\0';
851 break;
852 default:
853 /* unknown variable - try to find it in the environment */
854 string = getenv(var_name);
855 if (!string)
857 /* Replace it with unexpanded variable. This is needed
858 * since var_name might have been expanded */
859 l = strlen(var_name) + 3;
860 if (output)
862 strcpy(output, "$[");
863 strcpy(output + 2, var_name);
864 output[l - 1] = ']';
865 output[l] = 0;
867 return l;
871 GOT_STRING:
872 if (is_numeric)
874 is_target = True;
875 sprintf(target, "%d", val);
877 if (is_target)
879 string = target;
881 else
883 if (!string)
885 return -1;
887 if (output)
889 strcpy(output, string);
892 if (len < 0)
894 len = strlen(string);
896 if (should_quote)
898 quoted_string = (char *)safemalloc(len * 2 + 3);
899 len = QuoteString(quoted_string, string) - quoted_string;
900 if (output)
902 strcpy(output, quoted_string);
904 free(quoted_string);
906 if (allocated_string)
908 free(allocated_string);
910 return len;
913 /* ---------------------------- interface functions ------------------------ */
915 char *expand_vars(
916 char *input, char *arguments[], Bool addto, Bool ismod,
917 cond_rc_t *cond_rc, const exec_context_t *exc)
919 int l, i, l2, n, k, j, m;
920 int xlen, xlevel;
921 Bool name_has_dollar;
922 char *out;
923 char *var;
924 const char *string = NULL;
925 Bool is_string = False;
926 FvwmWindow *fw = exc->w.fw;
928 l = strlen(input);
929 l2 = l;
931 if (input[0] == '+' && Scr.last_added_item.type == ADDED_FUNCTION)
933 addto = 1;
936 /* Calculate best guess at length of expanded string */
937 i = 0;
938 while (i < l)
940 if (input[i] == '$' && (!ismod || !isalpha(input[i + 1])))
942 switch (input[i + 1])
944 case '$':
945 /* skip the second $, it is not a part of
946 * variable */
947 i++;
948 break;
949 case '[':
950 /* extended variables */
951 m = i + 2;
952 var = &input[m];
953 xlevel = 1;
954 name_has_dollar = False;
955 while (m < l && xlevel && input[m])
957 /* handle nested variables */
958 if (input[m] == ']')
960 xlevel--;
962 else if (input[m] == '[')
964 xlevel++;
966 else if (input[m] == '$')
968 name_has_dollar = True;
970 if (xlevel)
972 m++;
975 if (input[m] == ']')
977 input[m] = 0;
978 /* handle variable name */
979 k = strlen(var);
980 if (addto)
982 i += k + 2;
983 input[m] = ']';
984 break;
986 if (name_has_dollar)
988 var = expand_vars(
989 var, arguments, addto,
990 ismod, cond_rc, exc);
992 xlen = expand_args_extended(
993 var, arguments ? arguments[0] :
994 NULL, NULL);
995 if (xlen < 0)
997 xlen = expand_vars_extended(
998 var, NULL, cond_rc,
999 exc);
1001 if (name_has_dollar)
1003 free(var);
1005 if (xlen >= 0)
1007 l2 += xlen - (k + 2);
1009 i += k + 2;
1010 input[m] = ']';
1012 break;
1013 case '0':
1014 case '1':
1015 case '2':
1016 case '3':
1017 case '4':
1018 case '5':
1019 case '6':
1020 case '7':
1021 case '8':
1022 case '9':
1023 case '*':
1024 if (input[i + 1] == '*')
1026 n = 0;
1028 else
1030 n = input[i + 1] - '0' + 1;
1032 if (arguments[n] != NULL)
1034 l2 += strlen(arguments[n]) - 2;
1035 i++;
1037 break;
1038 case '.':
1039 string = get_current_read_dir();
1040 break;
1041 case 'w':
1042 case 'd':
1043 case 'x':
1044 case 'y':
1045 l2 += 16;
1046 i++;
1047 break;
1048 case 'c':
1049 case 'r':
1050 case 'n':
1051 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
1053 switch(input[i + 1])
1055 case 'c':
1056 if (fw->class.res_class &&
1057 fw->class.res_class[0])
1059 string = fw->class.
1060 res_class;
1062 break;
1063 case 'r':
1064 if (fw->class.res_name &&
1065 fw->class.res_name[0])
1067 string = fw->class.
1068 res_name;
1070 break;
1071 case 'n':
1072 if (fw->name.name &&
1073 fw->name.name[0])
1075 string = fw->name.name;
1077 break;
1080 break;
1081 case 'v':
1082 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
1084 switch(input[i + 1])
1086 case 'v':
1087 if(fw->visible_name)
1089 string = fw->visible_name;
1091 break;
1095 if (Fvwm_VersionInfo)
1097 l2 += strlen(Fvwm_VersionInfo) + 2;
1099 break;
1101 if (string)
1103 for (k = 0; string[k] != 0; k++, l2++)
1105 if (string[k] == '\'')
1107 l2++;
1110 string = NULL;
1114 i++;
1117 /* Actually create expanded string */
1118 i = 0;
1119 out = safemalloc(l2 + 1);
1120 j = 0;
1121 while (i < l)
1123 if (input[i] == '$' && (!ismod || !isalpha(input[i + 1])))
1125 switch (input[i + 1])
1127 case '[':
1128 /* extended variables */
1129 if (addto)
1131 /* Don't expand these in an 'AddToFunc'
1132 * command */
1133 out[j++] = input[i];
1134 break;
1136 m = i + 2;
1137 var = &input[m];
1138 xlevel = 1;
1139 name_has_dollar = False;
1140 while (m < l && xlevel && input[m])
1142 /* handle nested variables */
1143 if (input[m] == ']')
1145 xlevel--;
1147 else if (input[m] == '[')
1149 xlevel++;
1151 else if (input[m] == '$')
1153 name_has_dollar = True;
1155 if (xlevel)
1157 m++;
1160 if (input[m] == ']')
1162 input[m] = 0;
1163 /* handle variable name */
1164 k = strlen(var);
1165 if (name_has_dollar)
1167 var = expand_vars(
1168 var, arguments, addto,
1169 ismod, cond_rc, exc);
1171 xlen = expand_args_extended(
1172 var, arguments ?
1173 arguments[0] : NULL,
1174 &out[j]);
1175 if (xlen < 0)
1177 xlen = expand_vars_extended(
1178 var, &out[j], cond_rc,
1179 exc);
1181 if (name_has_dollar)
1183 free(var);
1185 input[m] = ']';
1186 if (xlen >= 0)
1188 j += xlen;
1189 i += k + 2;
1191 else
1193 /* copy the whole string in
1194 * square brackets */
1195 for ( ; i <= m; i++, j++)
1197 out[j] = input[i];
1199 i--;
1202 else
1204 out[j++] = input[i];
1206 break;
1207 case '0':
1208 case '1':
1209 case '2':
1210 case '3':
1211 case '4':
1212 case '5':
1213 case '6':
1214 case '7':
1215 case '8':
1216 case '9':
1217 case '*':
1218 if (input[i + 1] == '*')
1220 n = 0;
1222 else
1224 n = input[i + 1] - '0' + 1;
1226 if (arguments[n] != NULL)
1228 for (k = 0; arguments[n][k]; k++)
1230 out[j++] = arguments[n][k];
1232 i++;
1234 else if (addto == 1)
1236 out[j++] = '$';
1238 else
1240 i++;
1242 break;
1243 case '.':
1244 string = get_current_read_dir();
1245 is_string = True;
1246 break;
1247 case 'w':
1248 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
1250 fvwm_msg(OLD, "expand_vars",
1251 "Use $[w.id] instead of $w");
1252 sprintf(&out[j], "0x%x",
1253 (int)FW_W(fw));
1255 else
1257 sprintf(&out[j], "$w");
1259 j += strlen(&out[j]);
1260 i++;
1261 break;
1262 case 'd':
1263 fvwm_msg(OLD, "expand_vars",
1264 "Use $[desk.n] instead of $d");
1265 sprintf(&out[j], "%d", Scr.CurrentDesk);
1266 j += strlen(&out[j]);
1267 i++;
1268 break;
1269 case 'x':
1270 fvwm_msg(OLD, "expand_vars",
1271 "Use $[vp.x] instead of $x");
1272 sprintf(&out[j], "%d", Scr.Vx);
1273 j += strlen(&out[j]);
1274 i++;
1275 break;
1276 case 'y':
1277 fvwm_msg(OLD, "expand_vars",
1278 "Use $[vp.y] instead of $y");
1279 sprintf(&out[j], "%d", Scr.Vy);
1280 j += strlen(&out[j]);
1281 i++;
1282 break;
1284 case 'c':
1285 case 'r':
1286 case 'n':
1287 if (fw && !IS_EWMH_DESKTOP(FW_W(fw)))
1289 switch(input[i + 1])
1291 case 'c':
1292 fvwm_msg(OLD, "expand_vars",
1293 "Use $[w.class] "
1294 "instead of $c");
1295 if (fw->class.res_class &&
1296 fw->class.res_class[0])
1298 string = fw->class.
1299 res_class;
1301 break;
1302 case 'r':
1303 fvwm_msg(OLD, "expand_vars",
1304 "Use $[w.resource] "
1305 "instead of $r");
1306 if (fw->class.res_name &&
1307 fw->class.res_name[0])
1309 string = fw->class.
1310 res_name;
1312 break;
1313 case 'n':
1314 fvwm_msg(OLD, "expand_vars",
1315 "Use $[w.name] "
1316 "instead of $n");
1317 if (fw->name.name &&
1318 fw->name.name[0])
1320 string = fw->name.name;
1322 break;
1325 is_string = True;
1326 break;
1327 case 'v':
1328 fvwm_msg(OLD, "expand_vars",
1329 "Use $[version.line] instead of $v");
1330 sprintf(&out[j], "%s", (Fvwm_VersionInfo) ?
1331 Fvwm_VersionInfo : "");
1332 j += strlen(&out[j]);
1333 i++;
1334 break;
1335 case '$':
1336 out[j++] = '$';
1337 i++;
1338 break;
1339 default:
1340 out[j++] = input[i];
1341 break;
1342 } /* switch */
1343 if (is_string && string)
1345 j = QuoteString(&out[j], string) - out;
1346 string = NULL;
1347 is_string = False;
1348 i++;
1350 else if (is_string)
1352 out[j++] = '$';
1353 is_string = False;
1355 } /* if '$' */
1356 else
1358 out[j++] = input[i];
1360 i++;
1362 out[j] = 0;
1364 return out;