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.
6 *
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.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15
16 /*
17 ** Parse.c: routines for parsing in fvwm & modules
18 */
19
20 /* ---------------------------- included header files ---------------------- */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <ctype.h>
26
27 #include "fvwmlib.h"
28 #include "Strings.h"
29 #include "Parse.h"
30
31 /* ---------------------------- local definitions -------------------------- */
32
33 /* ---------------------------- local macros ------------------------------- */
34
35 /* ---------------------------- imports ------------------------------------ */
36
37 /* ---------------------------- included code files ------------------------ */
38
39 /* ---------------------------- local types -------------------------------- */
40
41 /* ---------------------------- forward declarations ----------------------- */
42
43 /* ---------------------------- local variables ---------------------------- */
44
45 /* ---------------------------- exported variables (globals) --------------- */
46
47 /* ---------------------------- local functions ---------------------------- */
48
49 /* Copies a token beginning at src to a previously allocated area dest. dest
50 * must be large enough to hold the token. Leading whitespace causes the token
51 * to be NULL. */
52 /* NOTE: CopyToken can be called with dest == src. The token will be copied
53 * back down over the src string. */
CopyToken(char * src,char * dest,char * spaces,int snum,char * delims,int dnum,char * out_delim)54 static char *CopyToken(
55 char *src, char *dest, char *spaces, int snum, char *delims, int dnum,
56 char *out_delim)
57 {
58 int len = 0;
59 char *t;
60
61 while (*src != 0 && !(isspace((unsigned char)*src) ||
62 (snum && strchr(spaces, *src)) ||
63 (dnum && strchr(delims, *src))))
64 {
65 /* Check for quoted text */
66 if (IsQuote(*src))
67 {
68 char c = *src;
69
70 src++;
71 while ((*src != c)&&(*src != 0))
72 {
73 if ((*src == '\\' && *(src+1) != 0))
74 {
75 /* Skip over backslashes */
76 src++;
77 }
78 if (len < MAX_TOKEN_LENGTH - 1)
79 {
80 len++;
81 *(dest++) = *(src++);
82 }
83 else
84 {
85 /* token too long, just skip rest */
86 src++;
87 }
88 }
89 if (*src == c)
90 {
91 src++;
92 }
93 }
94 else
95 {
96 if ((*src == '\\' && *(src+1) != 0))
97 {
98 /* Skip over backslashes */
99 src++;
100 }
101 if (len < MAX_TOKEN_LENGTH - 1)
102 {
103 len++;
104 *(dest++) = *(src++);
105 }
106 else
107 {
108 /* token too long, just skip rest of token */
109 src++;
110 }
111 }
112 }
113 if (out_delim)
114 {
115 *out_delim = *src;
116 }
117 *dest = 0;
118 t = SkipSpaces(src, spaces, snum);
119 if (*t != 0 && dnum && strchr(delims, *t) != NULL)
120 {
121 if (out_delim)
122 {
123 *out_delim = *t;
124 }
125 src = t + 1;
126 }
127 else if (*src != 0)
128 {
129 src++;
130 }
131
132 return src;
133 }
134
135 /* ---------------------------- interface functions ------------------------ */
136
137 /* This function escapes all occurences of the characters in the string qchars
138 * in the string as with a preceding echar character. The resulting string is
139 * returned in a malloced memory area. */
EscapeString(char * s,const char * qchars,char echar)140 char *EscapeString(char *s, const char *qchars, char echar)
141 {
142 char *t;
143 char *ret;
144 int len;
145
146 for (len = 1, t = s; *t ; t++, len++)
147 {
148 if (strchr(qchars, *t) != NULL)
149 {
150 len++;
151 }
152 }
153 ret = (char *)safemalloc(len);
154 for (t = ret; *s; s++, t++)
155 {
156 if (strchr(qchars, *s) != NULL)
157 {
158 *t = echar;
159 t++;
160 }
161 *t = *s;
162 }
163 *t = 0;
164
165 return ret;
166 }
167
168 /* If the string s begins with a quote chracter SkipQuote returns a pointer
169 * to the first unquoted character or to the final '\0'. If it does not, a
170 * pointer to the next character in the string is returned.
171 * There are three possible types of quoting: a backslash quotes the next
172 * character only. Long quotes like " " or ' ' quoting everything in
173 * between and quote pairs like ( ) or { }.
174 *
175 * precedence:
176 *
177 * 1) Backslashes are honoured always, even inside long or pair quotes.
178 * 2) long quotes do quote quoting pair characters but not simple quotes. All
179 * long quotes can quote all other types of long quotes).
180 * 3) pair quotes none of the above. Text between a pair of quotes is treated
181 * as a single token.
182 *
183 * qlong - string of long quoted (defaults to "'` )
184 * qstart - string of pair quote start characters (defaults to empty string)
185 * qend - string of pair quote end characters (defaults to empty string)
186 *
187 * The defaults are used if NULL is passed for the corresponding string.
188 */
SkipQuote(char * s,const char * qlong,const char * qstart,const char * qend)189 char *SkipQuote(
190 char *s, const char *qlong, const char *qstart, const char *qend)
191 {
192 char *t;
193
194 if (s == NULL || *s == 0)
195 {
196 return s;
197 }
198 if (!qlong)
199 {
200 qlong = "\"'`";
201 }
202 if (!qstart)
203 {
204 qstart = "";
205 }
206 if (!qend)
207 {
208 qend = "";
209 }
210
211 if (*s == '\\' && s[1] != 0)
212 {
213 return s+2;
214 }
215 else if (*qlong && (t = strchr(qlong, *s)))
216 {
217 char c = *t;
218
219 s++;
220 while (*s && *s != c)
221 {
222 /* Skip over escaped text, ie \quote */
223 if (*s == '\\' && *(s+1) != 0)
224 {
225 s++;
226 }
227 s++;
228 }
229 if (*s == c)
230 {
231 s++;
232 }
233 return s;
234 }
235 else if (*qstart && (t = strchr(qstart, *s)))
236 {
237 char c = *((t - qstart) + qend);
238
239 while (*s && *s != c)
240 {
241 s = SkipQuote(s, qlong, "", "");
242 }
243 return (*s == c) ? ++s : s;
244 }
245
246 return ++s;
247 }
248
249 /* Returns a string up to the first character from the string delims in a
250 * malloc'd area just like GetNextToken. Quotes are not removed from the
251 * returned string. The returned string is stored in *sout, the return value
252 * of this call is a pointer to the first character after the delimiter or
253 * to the terminating '\0'. Quoting is handled like in SkipQuote. If sin is
254 * NULL, the function returns NULL in *sout. */
GetQuotedString(char * sin,char ** sout,const char * delims,const char * qlong,const char * qstart,const char * qend)255 char *GetQuotedString(
256 char *sin, char **sout, const char *delims, const char *qlong,
257 const char *qstart, const char *qend)
258 {
259 char *t = sin;
260 unsigned int len;
261
262 if (!sout)
263 {
264 return NULL;
265 }
266 if (!sin)
267 {
268 *sout = NULL;
269 return NULL;
270 }
271
272 while (*t && !strchr(delims, *t))
273 {
274 t = SkipQuote(t, qlong, qstart, qend);
275 }
276 len = t - sin;
277 *sout = (char *)safemalloc(len + 1);
278 memcpy(*sout, sin, len);
279 (*sout)[len] = 0;
280 if (*t)
281 {
282 t++;
283 }
284
285 return t;
286 }
287
288 /* SkipSpaces: returns a pointer to the first character in indata that is
289 * neither a whitespace character nor contained in the string 'spaces'. snum
290 * is the number of characters in 'spaces'. You must not pass a NULL pointer
291 * in indata. */
SkipSpaces(char * indata,char * spaces,int snum)292 char *SkipSpaces(char *indata, char *spaces, int snum)
293 {
294 while (*indata != 0 && (isspace((unsigned char)*indata) ||
295 (snum && strchr(spaces, *indata))))
296 {
297 indata++;
298 }
299 return indata;
300 }
301
302 /*
303 ** DoPeekToken: returns next token from string, leaving string intact
304 ** (you must not free returned string)
305 **
306 ** WARNING: The returned pointer points to a static array that will be
307 ** overwritten in all functions in this file!
308 **
309 ** For a description of the parameters see DoGetNextToken below. DoPeekToken
310 ** is a bit faster.
311 */
312 /* NOTE: If indata is the pointer returned by a previous call to PeekToken or
313 * DoPeekToken, the input string will be destroyed. */
DoPeekToken(char * indata,char ** token,char * spaces,char * delims,char * out_delim)314 char *DoPeekToken(
315 char *indata, char **token, char *spaces, char *delims, char *out_delim)
316 {
317 char *end;
318 int snum;
319 int dnum;
320 static char tmptok[MAX_TOKEN_LENGTH];
321
322 snum = (spaces) ? strlen(spaces) : 0;
323 dnum = (delims) ? strlen(delims) : 0;
324 if (indata == NULL)
325 {
326 if (out_delim)
327 {
328 *out_delim = '\0';
329 }
330 *token = NULL;
331 return NULL;
332 }
333 indata = SkipSpaces(indata, spaces, snum);
334 end = CopyToken(indata, tmptok, spaces, snum, delims, dnum, out_delim);
335
336 if (tmptok[0] == 0)
337 {
338 *token = NULL;
339 }
340 else
341 {
342 *token = tmptok;
343 }
344
345 return end;
346 }
347
348 /*
349 * PeekToken takes the input string "indata" and returns a pointer to the
350 * token, stored in a static char array. The pointer is invalidated by
351 * the next call to PeekToken. If "outdata" is not NULL, the pointer
352 * to the first character after the token is returned through
353 * *outdata. (Note that outdata is a char **, not just a char *).
354 */
PeekToken(char * indata,char ** outdata)355 char *PeekToken(char *indata, char **outdata)
356 {
357 char *dummy;
358 char *token;
359
360 if (!outdata)
361 {
362 outdata = &dummy;
363 }
364 *outdata = DoPeekToken(indata, &token, NULL, NULL, NULL);
365
366 return token;
367 }
368
369
370 /**** SMR: Defined but not used -- is this for the future or a relic of the
371 **** past? ****/
372 /* domivogt (27-Jun-1999): It's intended for future use. I have no problem
373 * commenting it out if it's not used. */
374
375 /* Tries to seek up to n tokens in indata. Returns the number of tokens
376 * actually found (up to a maximum of n). */
377
378 #if 0
379 int CheckNTokens(char *indata, unsigned int n)
380 {
381 unsigned int i;
382 char *token;
383
384 for (i = 0, token = (char *)1; i < n && token != NULL; i++)
385 {
386 token = PeekToken(indata, NULL);
387 }
388
389 return i;
390 }
391 #endif
392
393 /*
394 ** MatchToken: does case-insensitive compare on next token in string, leaving
395 ** string intact (returns true if matches, false otherwise)
396 */
MatchToken(char * pstr,char * tok)397 int MatchToken(char *pstr,char *tok)
398 {
399 int rc=0;
400 char *ntok;
401
402 DoPeekToken(pstr, &ntok, NULL, NULL, NULL);
403 if (ntok)
404 {
405 rc = (strcasecmp(tok,ntok)==0);
406 }
407
408 return rc;
409 }
410
411 /* unused at the moment */
412 /*
413 function: XCmpToken
414 description: compare 1st word of s to 1st word of t
415 returns: < 0 if s < t
416 = 0 if s = t
417 > 0 if s > t
418 */
XCmpToken(const char * s,const char ** t)419 int XCmpToken(const char *s, const char **t)
420 {
421 register const char *w=*t;
422
423 if (w==NULL)
424 {
425 return 1;
426 }
427 if (s==NULL)
428 {
429 return -1;
430 }
431
432 while (*w && (*s==*w || toupper(*s)==toupper(*w)) )
433 {
434 s++;
435 w++;
436 }
437
438 if ((*s=='\0' && (ispunct(*w) || isspace(*w)))||
439 (*w=='\0' && (ispunct(*s) || isspace(*s))) )
440 {
441 return 0; /* 1st word equal */
442 }
443 else
444 {
445 return toupper(*s)-toupper(*w); /* smaller/greater */
446 }
447 }
448
449
450 /*
451 *
452 * Gets the next "word" of input from string indata.
453 * "word" is a string with no spaces, or a qouted string.
454 * Return value is ptr to indata,updated to point to text after the word
455 * which is extracted.
456 * token is the extracted word, which is copied into a malloced
457 * space, and must be freed after use. DoGetNextToken *never* returns an
458 * empty string or token. If the token consists only of whitespace or
459 * delimiters, the returned token is NULL instead. If out_delim is given,
460 * the character ending the string is returned therein.
461 *
462 * spaces = string of characters to treat as spaces
463 * delims = string of characters delimiting token
464 *
465 * Use "spaces" and "delims" to define additional space/delimiter
466 * characters (spaces are skipped before a token, delimiters are not).
467 *
468 */
DoGetNextToken(char * indata,char ** token,char * spaces,char * delims,char * out_delim)469 char *DoGetNextToken(
470 char *indata, char **token, char *spaces, char *delims, char *out_delim)
471 {
472 char *tmptok;
473 char *end;
474
475 end = DoPeekToken(indata, &tmptok, spaces, delims, out_delim);
476 if (tmptok == NULL)
477 {
478 *token = NULL;
479 }
480 else
481 {
482 *token = safestrdup(tmptok);
483 }
484
485 return end;
486 }
487
488 /*
489 * GetNextToken works similarly to PeekToken, but: stores the token in
490 * *token, & returns a pointer to the first character after the token
491 * in *token. The memory in *token is allocated with malloc and the
492 * calling function has to free() it.
493 *
494 * If possible, use PeekToken because it's faster and does not risk
495 * creating memory leaks.
496 */
GetNextToken(char * indata,char ** token)497 char *GetNextToken(char *indata, char **token)
498 {
499 return DoGetNextToken(indata, token, NULL, NULL, NULL);
500 }
501
502 /* fetch next token and stop at next ',' */
GetNextSimpleOption(char * indata,char ** option)503 char *GetNextSimpleOption(char *indata, char **option)
504 {
505 return DoGetNextToken(indata, option, NULL, ",", NULL);
506 }
507
508 /* read multiple tokens up to next ',' or end of line */
GetNextFullOption(char * indata,char ** option)509 char *GetNextFullOption(char *indata, char **option)
510 {
511 return GetQuotedString(indata, option, ",\n", NULL, NULL, NULL);
512 }
513
SkipNTokens(char * indata,unsigned int n)514 char *SkipNTokens(char *indata, unsigned int n)
515 {
516 for ( ; n > 0 && indata != NULL && *indata != 0; n--)
517 {
518 PeekToken(indata, &indata);
519 }
520
521 return indata;
522 }
523
524 /*
525 * convenience functions
526 */
527
528 /*
529 *
530 * Works like GetNextToken, but with the following differences:
531 *
532 * If *indata begins with a "*" followed by the string module_name,
533 * it returns the string following directly after module_name as the
534 * new token. Otherwise NULL is returned.
535 * e.g. GetModuleResource("*FvwmPagerGeometry", &token, "FvwmPager")
536 * returns "Geometry" in token.
537 *
538 */
GetModuleResource(char * indata,char ** resource,char * module_name)539 char *GetModuleResource(char *indata, char **resource, char *module_name)
540 {
541 char *tmp;
542 char *next;
543
544 if (!module_name)
545 {
546 *resource = NULL;
547 return indata;
548 }
549 tmp = PeekToken(indata, &next);
550 if (!tmp)
551 {
552 return next;
553 }
554
555 if (tmp[0] != '*' ||
556 strncasecmp(tmp+1, module_name, strlen(module_name)))
557 {
558 *resource = NULL;
559 return indata;
560 }
561 CopyString(resource, tmp+1+strlen(module_name));
562
563 return next;
564 }
565
566
567 /*
568 *
569 * This function uses GetNextToken to parse action for up to num integer
570 * arguments. The number of values actually found is returned.
571 * If ret_action is non-NULL, a pointer to the next token is returned there.
572 * The suffixlist parameter points to a string of possible suffixes for the
573 * integer values. The index of the matched suffix is returned in
574 * ret_suffixnum (0 = no suffix, 1 = first suffix in suffixlist ...).
575 *
576 */
_get_suffixed_integer_arguments(char * action,char ** ret_action,int * retvals,int num,char * suffixlist,int * ret_suffixnum,char * parsestring)577 static int _get_suffixed_integer_arguments(
578 char *action, char **ret_action, int *retvals, int num,
579 char *suffixlist, int *ret_suffixnum, char *parsestring)
580 {
581 int i;
582 int j;
583 int n;
584 char *token;
585 int suffixes;
586
587 /* initialize */
588 suffixes = 0;
589 if (suffixlist != 0)
590 {
591 /* if passed a suffixlist save its length */
592 suffixes = strlen(suffixlist);
593 }
594
595 for (i = 0; i < num && action; i++)
596 {
597 token = PeekToken(action, &action);
598 if (token == NULL)
599 {
600 break;
601 }
602 if (sscanf(token, parsestring, &(retvals[i]), &n) < 1)
603 {
604 break;
605 }
606 if (suffixes != 0 && ret_suffixnum != NULL)
607 {
608 int len;
609 char c;
610
611 len = strlen(token) - 1;
612 c = token[len];
613 if (isupper(c))
614 {
615 c = tolower(c);
616 }
617 for (j = 0; j < suffixes; j++)
618 {
619 char c2 = suffixlist[j];
620
621 if (isupper(c2))
622 {
623 c2 = tolower(c2);
624 }
625 if (c == c2)
626 {
627 ret_suffixnum[i] = j+1;
628 break;
629 }
630 }
631 if (j == suffixes)
632 {
633 ret_suffixnum[i] = 0;
634 }
635 }
636 else if (token[n] != 0 && !isspace(token[n]))
637 {
638 /* there is a suffix but no suffix list was specified */
639 break;
640 }
641 }
642 if (ret_action != NULL)
643 {
644 *ret_action = action;
645 }
646
647 return i;
648 }
649
GetSuffixedIntegerArguments(char * action,char ** ret_action,int * retvals,int num,char * suffixlist,int * ret_suffixnum)650 int GetSuffixedIntegerArguments(
651 char *action, char **ret_action, int *retvals, int num,
652 char *suffixlist, int *ret_suffixnum)
653 {
654 return _get_suffixed_integer_arguments(
655 action, ret_action, retvals, num, suffixlist, ret_suffixnum,
656 "%d%n");
657 }
658
659 /*
660 *
661 * This function converts the suffix/number pairs returned by
662 * GetSuffixedIntegerArguments into pixels. The unit_table is an array of
663 * integers that determine the factor to multiply with in hundredths of
664 * pixels. I.e. a unit of 100 means: translate the value into pixels,
665 * 50 means divide value by 2 to get the number of pixels and so on.
666 * The unit used is determined by the suffix which is taken as the index
667 * into the table. No size checking of the unit_table is done, so make sure
668 * it is big enough before calling this function.
669 *
670 */
SuffixToPercentValue(int value,int suffix,int * unit_table)671 int SuffixToPercentValue(int value, int suffix, int *unit_table)
672 {
673 return (value * unit_table[suffix]) / 100;
674 }
675
676 /*
677 *
678 * This function uses GetNextToken to parse action for up to num integer
679 * arguments. The number of values actually found is returned.
680 * If ret_action is non-NULL, a pointer to the next token is returned there.
681 *
682 */
GetIntegerArguments(char * action,char ** ret_action,int * retvals,int num)683 int GetIntegerArguments(char *action, char **ret_action, int *retvals,int num)
684 {
685 return _get_suffixed_integer_arguments(
686 action, ret_action, retvals, num, NULL, NULL, "%d%n");
687 }
688
689 /*
690 *
691 * Same as above, but supports hexadecimal and octal integers via 0x and 0
692 * prefixes.
693 *
694 */
GetIntegerArgumentsAnyBase(char * action,char ** ret_action,int * retvals,int num)695 int GetIntegerArgumentsAnyBase(
696 char *action, char **ret_action, int *retvals,int num)
697 {
698 return _get_suffixed_integer_arguments(
699 action, ret_action, retvals, num, NULL, NULL, "%i%n");
700 }
701
702 /*
703 *
704 * This function tries to match a token with a list of strings and returns
705 * the position of token in the array or -1 if no match is found. The last
706 * entry in the list must be NULL.
707 *
708 * len = 0 : only exact matches
709 * len < 0 : match, if token begins with one of the strings in list
710 * len > 0 : match, if the first len characters do match
711 *
712 * if next is non-NULL, *next will be set to point to the first character
713 * in token after the match.
714 *
715 */
GetTokenIndex(char * token,char ** list,int len,char ** next)716 int GetTokenIndex(char *token, char **list, int len, char **next)
717 {
718 int i;
719 int l;
720 int k;
721
722 if (!token || !list)
723 {
724 if (next)
725 {
726 *next = NULL;
727 }
728 return -1;
729 }
730 l = (len) ? len : strlen(token);
731 for (i = 0; list[i] != NULL; i++)
732 {
733 k = strlen(list[i]);
734 if (len < 0)
735 {
736 l = k;
737 }
738 else if (len == 0 && k != l)
739 {
740 continue;
741 }
742 if (!strncasecmp(token, list[i], l))
743 {
744 break;
745 }
746 }
747 if (next)
748 {
749 *next = (list[i]) ? token + l : token;
750 }
751
752 return (list[i]) ? i : -1;
753 }
754
755 /*
756 *
757 * This function does roughly the same as GetTokenIndex but reads the
758 * token from string action with GetNextToken. The index is returned
759 * in *index. The return value is a pointer to the character after the
760 * token (just like the return value of GetNextToken).
761 *
762 */
GetNextTokenIndex(char * action,char ** list,int len,int * index)763 char *GetNextTokenIndex(char *action, char **list, int len, int *index)
764 {
765 char *token;
766 char *next;
767
768 if (!index)
769 {
770 return action;
771 }
772
773 token = PeekToken(action, &next);
774 if (!token)
775 {
776 *index = -1;
777 return action;
778 }
779 *index = GetTokenIndex(token, list, len, NULL);
780
781 return (*index == -1) ? action : next;
782 }
783
784
785 /*
786 *
787 * Parses two integer arguments given in the form <int><character><int>.
788 * character can be ' ' or 'x', but any other character is allowed too
789 * (except 'p' or 'P').
790 *
791 */
GetRectangleArguments(char * action,int * width,int * height)792 int GetRectangleArguments(char *action, int *width, int *height)
793 {
794 char *token;
795 int n;
796
797 token = PeekToken(action, NULL);
798 if (!token)
799 {
800 return 0;
801 }
802 n = sscanf(token, "%d%*c%d", width, height);
803
804 return (n == 2) ? 2 : 0;
805 }
806
807 /* unit_io is input as well as output. If action has a postfix 'p' or 'P',
808 * *unit_io is set to 100, otherwise it is left untouched. */
GetOnePercentArgument(char * action,int * value,int * unit_io)809 int GetOnePercentArgument(char *action, int *value, int *unit_io)
810 {
811 unsigned int len;
812 char *token;
813 int n;
814
815 *value = 0;
816 if (!action)
817 {
818 return 0;
819 }
820 token = PeekToken(action, NULL);
821 if (!token)
822 {
823 return 0;
824 }
825 len = strlen(token);
826 /* token never contains an empty string, so this is ok */
827 if (token[len - 1] == 'p' || token[len - 1] == 'P')
828 {
829 *unit_io = 100;
830 token[len - 1] = '\0';
831 }
832 n = sscanf(token, "%d", value);
833
834 return n;
835 }
836
837
GetTwoPercentArguments(char * action,int * val1,int * val2,int * val1_unit,int * val2_unit)838 int GetTwoPercentArguments(
839 char *action, int *val1, int *val2, int *val1_unit, int *val2_unit)
840 {
841 char *tok1;
842 char *tok2;
843 char *next;
844 int n = 0;
845
846 *val1 = 0;
847 *val2 = 0;
848
849 tok1 = PeekToken(action, &next);
850 action = GetNextToken(action, &tok1);
851 if (!tok1)
852 {
853 return 0;
854 }
855 GetNextToken(action, &tok2);
856 if (GetOnePercentArgument(tok2, val2, val2_unit) == 1 &&
857 GetOnePercentArgument(tok1, val1, val1_unit) == 1)
858 {
859 free(tok1);
860 free(tok2);
861 return 2;
862 }
863
864 /* now try MxN style number, specifically for DeskTopSize: */
865 n = GetRectangleArguments(tok1, val1, val2);
866 free(tok1);
867 if (tok2)
868 {
869 free(tok2);
870 }
871
872 return n;
873 }
874
875
876 /* Parses the next token in action and returns 1 if it is "yes", "true", "y",
877 * "t" or "on", zero if it is "no", "false", "n", "f" or "off" and -1 if it is
878 * "toggle". A pointer to the first character in action behind the token is
879 * returned through ret_action in this case. ret_action may be NULL. If the
880 * token matches none of these strings the default_ret value is returned and
881 * the action itself is passed back in ret_action. If the no_toggle flag is
882 * non-zero, the "toggle" string is handled as no match. */
ParseToggleArgument(char * action,char ** ret_action,int default_ret,char no_toggle)883 int ParseToggleArgument(
884 char *action, char **ret_action, int default_ret, char no_toggle)
885 {
886 int index;
887 int rc;
888 char *next;
889 char *optlist[] = {
890 "toggle",
891 "yes", "no",
892 "true", "false",
893 "on", "off",
894 "t", "f",
895 "y", "n",
896 NULL
897 };
898
899 next = GetNextTokenIndex(action, optlist, 0, &index);
900 if (index == 0 && no_toggle == 0)
901 {
902 /* toggle requested explicitly */
903 rc = -1;
904 }
905 else if (index == -1 || (index == 0 && no_toggle))
906 {
907 /* nothing selected, use default and don't modify action */
908 rc = default_ret;
909 next = action;
910 }
911 else
912 {
913 /* odd numbers denote True, even numbers denote False */
914 rc = (index & 1);
915 }
916 if (ret_action)
917 {
918 *ret_action = next;
919 }
920
921 return rc;
922 }
923
924 /* Strips the path from 'path' and returns the last component in a malloc'ed
925 * area. */
GetFileNameFromPath(char * path)926 char *GetFileNameFromPath(char *path)
927 {
928 char *s;
929 char *name;
930
931 /* we get rid of the path from program name */
932 s = strrchr(path, '/');
933 if (s)
934 {
935 s++;
936 }
937 else
938 {
939 s = path;
940 }
941 name = (char *)safemalloc(strlen(s)+1);
942 strcpy(name, s);
943
944 return name;
945 }
946