1 /*
2 * Copyright (c) 2000 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <ctype.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "config.h"
24 #include "astypes.h"
25 #include "audit.h"
26 #include "mystring.h"
27 #include "safemalloc.h"
28 #include "xwrap.h"
29 #include "parse.h"
30
31 /****************************************************************************
32 * parse_argb_color - should be used for all your color parsing needs
33 ***************************************************************************/
parse_argb_color(const char * color,CARD32 * pargb)34 const char *parse_argb_color( const char *color, CARD32 *pargb )
35 {
36 #define hextoi(h) (isdigit(h)?((h)-'0'):(isupper(h)?((h)-'A'+10):((h)-'a'+10)))
37 if( color )
38 {
39 if( *color == '#' )
40 {
41 CARD32 argb = 0 ;
42 int len = 0 ;
43 register const char *ptr = color+1 ;
44 while( isxdigit((int)ptr[len]) ) len++;
45 if( len >= 3)
46 {
47 if( (len&0x3) == 0 && len != 12 )
48 { /* we do have alpha channel !!! */
49 len = len>>2 ;
50 argb = (hextoi((int)ptr[0])<<28)&0xF0000000 ;
51 if( len > 1 )
52 argb |= (hextoi((int)ptr[1])<<24)&0x0F000000 ;
53 else
54 argb |= 0x0F000000;
55 ptr += len ;
56 }else
57 {
58 len = len/3 ;
59 argb = 0xFF000000;
60 }
61 /* processing rest of the channels : */
62 if( len == 1 )
63 {
64 argb |= 0x000F0F0F;
65 argb |= (hextoi((int)ptr[0])<<20)&0x00F00000 ;
66 argb |= (hextoi((int)ptr[1])<<12)&0x0000F000 ;
67 argb |= (hextoi((int)ptr[2])<<4 )&0x000000F0 ;
68 ptr += 3 ;
69 }else
70 {
71 argb |= (hextoi((int)ptr[0])<<20)&0x00F00000 ;
72 argb |= (hextoi((int)ptr[1])<<16)&0x000F0000 ;
73 ptr += len ;
74 argb |= (hextoi((int)ptr[0])<<12)&0x0000F000 ;
75 argb |= (hextoi((int)ptr[1])<<8) &0x00000F00 ;
76 ptr += len ;
77 argb |= (hextoi((int)ptr[0])<<4 )&0x000000F0 ;
78 argb |= (hextoi((int)ptr[1])) &0x0000000F ;
79 ptr += len ;
80 }
81 *pargb = argb ;
82 return ptr;
83 }
84 }else if( *color )
85 {
86 #ifndef X_DISPLAY_MISSING
87 XColor xcol, xcol_scr ;
88 register const char *ptr = &(color[0]);
89 /* does not really matter here what screen to use : */
90 if( AS_ASSERT(dpy) )
91 return color ;
92 if( XLookupColor( dpy, DefaultColormap(dpy,DefaultScreen(dpy)), color, &xcol, &xcol_scr) )
93 *pargb = 0xFF000000|((xcol.red<<8)&0x00FF0000)|(xcol.green&0x0000FF00)|((xcol.blue>>8)&0x000000FF);
94 while( !isspace((int)*ptr) && *ptr != '\0' ) ptr++;
95 return ptr;
96 #endif
97 }
98 }
99 return color;
100 }
101
102 /****************************************************************************
103 * Some usefull parsing functions
104 ****************************************************************************/
105 char *
find_doublequotes(char * ptr)106 find_doublequotes (char *ptr)
107 {
108 if (ptr)
109 {
110 if (*ptr == '"')
111 ptr++;
112
113 if (*ptr != '"')
114 {
115 while ((ptr = strchr (ptr, '"')))
116 if (*(ptr - 1) == '\\')
117 ptr++;
118 else
119 break;
120 }
121 }
122 return ptr;
123 }
124
125 /****************************************************************************
126 * Copies a string into a new, malloc'ed string
127 * Strips leading and trailing whitespace
128 ****************************************************************************/
129
130 char *
stripcpy(const char * source)131 stripcpy (const char *source)
132 {
133 const char *ptr;
134
135 for (; isspace ((int)*source); source++);
136 for (ptr = source + strlen (source); ptr > source && isspace ((int)*(ptr - 1)); ptr--);
137 return mystrndup (source, ptr - source);
138 }
139
140
141 /****************************************************************************
142 *
143 * Copies a string into a new, malloc'ed string
144 * Strips all data before the first quote and after the second
145 *
146 ****************************************************************************/
147
148 char *
stripcpy2(const char * source,int tab_sensitive)149 stripcpy2 (const char *source, int tab_sensitive)
150 {
151 char *ptr = (char *)source, *tail;
152
153 if (*ptr != '"')
154 ptr = find_doublequotes (ptr);
155 if (ptr != NULL)
156 {
157 if ((tail = find_doublequotes (ptr)) != NULL)
158 return mystrndup (ptr + 1, tail - ptr - 1);
159 return mystrdup (ptr + 1);
160 }
161 return mystrndup (source, 0);
162 }
163
164
165 /* here we'll strip comments and skip whitespaces */
166 char *
stripcomments(char * source)167 stripcomments (char *source)
168 {
169 register char *ptr;
170
171 /* remove comments from the line */
172 while (isspace ((int)*source))
173 source++;
174 for (ptr = (char *)source; *ptr; ptr++)
175 {
176 if (*ptr == '"')
177 {
178 if ((ptr = find_doublequotes (ptr)) == NULL)
179 {
180 ptr = source + strlen (source);
181 break;
182 }
183 }
184 if (*ptr == '#')
185 { /* checking if it is not a hex color code */
186 int i;
187
188 for (i = 1; isxdigit ((int)*(ptr + i)); i++);
189
190 if (i < 4 || i > 13 || (*(ptr + i) && !isspace ((int)*(ptr + i))))
191 {
192 for (ptr--; ptr > source && isspace ((int)*ptr); ptr--);
193 *(ptr + 1) = '\0';
194 /* we'll exit the loop automagically */
195 } else
196 ptr += i - 1;
197 }
198 }
199 for (ptr--; isspace ((int)*ptr) && ptr > source; ptr--);
200 *(ptr + 1) = '\0';
201 return source;
202 }
203
204 char *
strip_whitespace(char * str)205 strip_whitespace (char *str)
206 {
207 char *ptr;
208
209 /* strip trailing whitespace */
210 for (ptr = str + strlen (str); ptr > str && isspace ((int)*(ptr - 1)); ptr--)
211 *(ptr - 1) = '\0';
212 /* skip leading whitespace */
213 for (ptr = str; isspace ((int)*ptr); ptr++);
214 return ptr;
215 }
216
217
218 /****************************************************************************
219 *
220 * Copies a whitespace separated token into a new, malloc'ed string
221 * Strips leading and trailing whitespace
222 *
223 ****************************************************************************/
224
225 char *
tokencpy(const char * source)226 tokencpy (const char *source)
227 {
228 const char *ptr;
229
230 for (; isspace ((int)*source); source++);
231 for (ptr = source; !isspace ((int)*ptr) && *ptr; ptr++);
232 return mystrndup (source, ptr - source);
233 }
234
235 char *
tokenskip(char * start,unsigned int n_tokens)236 tokenskip( char *start, unsigned int n_tokens )
237 {
238 register int i ;
239 register char *cur = start ;
240
241 if( cur == NULL ) return cur ;
242 for (i = 0; i < n_tokens; i++)
243 {
244 while (!isspace ((int)*cur) && *cur)
245 { /* we have to match doublequotes if we encounter any, to allow for spaces in filenames */
246 if (*cur == '"')
247 {
248 register char *ptr = find_doublequotes (cur);
249
250 if (ptr)
251 while (cur != ptr)
252 cur++;
253 }
254 cur++;
255 }
256
257 while (isspace ((int)*cur) && *cur)
258 cur++;
259 if (*cur == '\0')
260 break;
261 }
262 return cur;
263 }
264
265 /****************************************************************************
266 *
267 * Matches text from config to a table of strings.
268 *
269 ****************************************************************************/
270
271 struct config *
find_config(struct config * table,const char * text)272 find_config (struct config *table, const char *text)
273 {
274 for (; strlen (table->keyword); table++)
275 if (!mystrncasecmp (text, table->keyword, strlen (table->keyword)))
276 return table;
277
278 return NULL;
279 }
280
281 /****************************************************************************
282 * copy src to dest, backslash-escaping all non-alphanumeric characters in
283 * src; write a maximum of maxlen chars to dest, including terminating zero
284 ****************************************************************************/
285 int
quotestr(char * dest,const char * src,int maxlen)286 quotestr (char *dest, const char *src, int maxlen)
287 {
288 int n = maxlen;
289
290 /* require at least enough space for the terminating zero */
291 if (maxlen < 1)
292 return maxlen - n;
293 n--;
294 while (n && *src)
295 {
296 if (!isalnum ((int)*src) && n > 1)
297 {
298 *dest++ = '\\';
299 n--;
300 }
301 *dest++ = *src++;
302 n--;
303 }
304 *dest = '\0';
305 return maxlen - n;
306 }
307
308 /****************************************************************************
309 *
310 * Copies a whitespace separated token into a new, malloc'ed string
311 * Strips leading and trailing whitespace
312 * returns pointer to the end of token in source string
313 ****************************************************************************/
314
315 char *
parse_token(const char * source,char ** trg)316 parse_token (const char *source, char **trg)
317 {
318 char *ptr;
319
320 for (; isspace ((int)*source); source++);
321 for (ptr = (char *)source; !isspace ((int)*ptr) && *ptr; ptr++);
322 *trg = mystrndup (source, ptr - source);
323 return ptr;
324 }
325
326 char *
parse_tab_token(const char * source,char ** trg)327 parse_tab_token (const char *source, char **trg)
328 {
329 char *ptr;
330
331 for (; isspace ((int)*source); source++);
332 for (ptr = (char *)source; *ptr != '\t' && *ptr; ptr++);
333 *trg = mystrndup (source, ptr - source);
334 return ptr;
335 }
336
337 char *
parse_filename(const char * source,char ** trg)338 parse_filename (const char *source, char **trg)
339 {
340 for (; isspace ((int)*source); source++);
341
342 if (*source == '"')
343 {
344 if ((*trg = stripcpy2 (source, 0)) != NULL)
345 source += strlen (*trg) + 2;
346 } else
347 source = parse_token (source, trg);
348 return (char *)source;
349 }
350
351 /* used in ParseMouse and in communication with modules */
352 char *
parse_signed_int(register char * tline,int * val_return,int * sign_return)353 parse_signed_int (register char *tline, int *val_return, int *sign_return)
354 {
355 int val = 0, sign = 0;
356 register int i = 0 ;
357
358 while (isspace ((int)tline[i])) ++i;
359
360 switch( tline[i] )
361 { /* handling constructs like --10 or -+10 which is equivalent to -0-10or -0+10 */
362 case '\0' : sign = 5 ; --i; break ;
363 case '-' : sign = -1;
364 if( tline[i+1] == '-' )
365 { ++i ; sign = -2 ; }
366 else if( tline[i+1] == '+' )
367 { ++i ; sign = 3 ; }
368 break;
369 case '+' : ++sign;
370 if( tline[i+1] == '-' )
371 { ++i ; sign = -3 ; }
372 else if( tline[i+1] == '+' )
373 { ++i ; sign = 2 ; }
374 break;
375 case '=' : break; /* skipping */
376 case 'x' :
377 case 'X' : sign = 4; break;
378 default : --i ;
379 }
380 while (isdigit ((int)tline[++i]))
381 val = val * 10 + (int)(tline[i] - '0');
382
383 if( val_return )
384 *val_return = (sign < 0)?-val:val ;
385 if( sign_return )
386 *sign_return = sign;
387 return tline+i;
388 }
389
390 char *
parse_func_args(char * tline,char * unit,int * func_val)391 parse_func_args (char *tline, char *unit, int *func_val)
392 {
393 tline = parse_signed_int( tline, func_val, NULL );
394
395 *unit = *tline;
396 if (isspace ((int)*tline))
397 *unit = '\0' ;
398 return tline[0]?tline+1:tline;
399 }
400
401 char *
parse_geometry(register char * tline,int * x_return,int * y_return,unsigned int * width_return,unsigned int * height_return,int * flags_return)402 parse_geometry (register char *tline,
403 int *x_return, int *y_return,
404 unsigned int *width_return,
405 unsigned int *height_return,
406 int* flags_return )
407 {
408 int flags = 0 ;
409 int sign, val ;
410
411 tline = parse_signed_int( tline, &val, &sign );
412 if( sign == 0 )
413 {
414 if( width_return )
415 {
416 *width_return = val ;
417 set_flags( flags, WidthValue );
418 }
419 tline = parse_signed_int( tline, &val, &sign );
420 }
421 if( sign == 4 )
422 {
423 if( height_return )
424 {
425 *height_return = val ;
426 set_flags( flags, HeightValue );
427 }
428 tline = parse_signed_int( tline, &val, &sign );
429 }
430 if( sign == 0 )
431 sign = 1 ;
432 if( sign == 1 || sign == -1)
433 {
434 if( x_return )
435 {
436 *x_return = val ;
437 set_flags( flags, ( sign < 0 )?XNegative|XValue:XValue );
438 }
439 tline = parse_signed_int( tline, &val, &sign );
440 }else if( sign != 5 )
441 {
442 if( x_return )
443 {
444 *x_return = 0 ;
445 set_flags( flags, ( sign == -2 || sign == 3 )?XNegative|XValue:XValue );
446 }
447 }
448
449 if( sign != 5 && y_return )
450 {
451 *y_return = val ;
452 set_flags( flags, ( sign < 0 )?YNegative|YValue:YValue );
453 }
454
455 if( flags_return )
456 *flags_return = flags ;
457
458 return tline;
459 }
460
461 char *
string_from_int(int param)462 string_from_int (int param)
463 {
464 char *mem;
465 register int i;
466 int neg = 0;
467
468 if (param == 0)
469 return mystrdup ("0");
470 if (param < 0)
471 {
472 param = -param;
473 neg = 1;
474 }
475 for (i = 1; param >> (i * 3); i++);
476 if (neg)
477 i++;
478 mem = safemalloc (i + 1);
479 if (neg)
480 mem[0] = '-';
481 sprintf (&(mem[neg]), "%u", param);
482 return mem;
483 }
484
485 static char _as_hex_to_char_table[] = "0123456789ABCDEF";
486
487 char *
hex_to_buffer_reverse(void * data,size_t bytes,char * buffer)488 hex_to_buffer_reverse(void *data, size_t bytes, char* buffer)
489 {
490
491 char *p = buffer;
492 unsigned char *d = data;
493 register int i = bytes, k = 0 ;
494
495 if( data == NULL || buffer == NULL )
496 return buffer ;
497
498 while( i > 0 )
499 {
500 i-- ;
501 p[k++] = _as_hex_to_char_table[d[i]>>4];
502 p[k++] = _as_hex_to_char_table[d[i]&0x0F];
503 }
504 return p+k;
505 }
506
507 char *
hex_to_buffer(void * data,size_t bytes,char * buffer)508 hex_to_buffer(void *data, size_t bytes, char* buffer)
509 {
510 char *p = buffer;
511 unsigned char *d = data;
512 register int i = bytes, k = 0 ;
513
514 if( data == NULL || buffer == NULL )
515 return buffer ;
516
517 while( i < bytes )
518 {
519 p[k++] = _as_hex_to_char_table[d[i]>>4];
520 p[k++] = _as_hex_to_char_table[d[i]&0x0F];
521 i++ ;
522 }
523 return p+k;
524 }
525
526 /***********************************************************************
527 * Procedure:
528 * scanForHotkeys - Look for hotkey markers in a function "name"
529 * Inputs:
530 * txt - string to scan
531 * Output: - hotkey found
532 ***********************************************************************/
533 char
scan_for_hotkey(char * txt)534 scan_for_hotkey (char *txt)
535 {
536 char hotkey = '\0';
537
538 if (txt != NULL)
539 for (; *txt != '\0'; txt++) /* Scan whole string */
540 if (*txt == '&')
541 { /* A hotkey marker? */
542 char *tmp; /* Copy the string down over it */
543
544 for (tmp = txt; *tmp != '\0'; tmp++)
545 *tmp = *(tmp + 1);
546 if (*txt != '&') /* Not Just an escaped & */
547 hotkey = *txt;
548 }
549 return hotkey;
550 }
551
552
553 /* Conversion of the coma separated values into a list of strings */
554 char *
get_comma_item(char * ptr,char ** item_start,char ** item_end)555 get_comma_item (char *ptr, char **item_start, char **item_end)
556 {
557
558 if (ptr == NULL)
559 return NULL;
560 while (*ptr && (isspace ((int)*ptr) || *ptr == ','))
561 ptr++;
562 if (*ptr == '\0')
563 return NULL;
564
565 *item_end = *item_start = ptr;
566 if (*ptr == '"')
567 {
568 if ((*item_end = find_doublequotes (ptr)) == NULL)
569 return NULL;
570 ptr = *item_end;
571 while (*ptr && !(isspace ((int)*ptr) || *ptr == ','))
572 ptr++;
573 } else
574 {
575 while (*ptr && *ptr != ',')
576 ptr++;
577 *item_end = ptr;
578 }
579 return ptr;
580 }
581
582 char **
comma_string2list(char * string)583 comma_string2list (char *string)
584 {
585 register char *ptr;
586 int items;
587 char **list = NULL, *item_start = NULL, *item_end = NULL;
588
589 if (string == NULL)
590 return NULL;
591
592 ptr = string;
593 items = 0;
594 while (*ptr)
595 {
596 if ((ptr = get_comma_item (ptr, &item_start, &item_end)) == NULL)
597 break;
598 items++;
599 }
600 if (items > 0)
601 {
602 register int i;
603
604 list = (char **)safemalloc (sizeof (char *) * (items + 1));
605 memset (list, 0x00, sizeof (char *) * (items + 1));
606
607 ptr = string;
608 for (i = 0; i < items; i++)
609 {
610 if ((ptr = get_comma_item (ptr, &item_start, &item_end)) == NULL)
611 break;
612 list[i] = mystrndup (item_start, (item_end - item_start));
613 }
614 }
615 return list;
616 }
617
618 char *
list2comma_string(char ** list)619 list2comma_string (char **list)
620 {
621 char *string = NULL;
622
623 if (list)
624 {
625 int len = 0;
626 register int i = 0;
627
628 for (i = 0; list[i]; i++)
629 if (*list[i])
630 len += strlen (list[i]) + 1;
631
632 if (len > 0)
633 {
634 register char *src, *dst;
635
636 dst = string = (char *)safemalloc (len);
637 for (i = 0; list[i]; i++)
638 {
639 src = list[i];
640 if (*src)
641 {
642 while (*src)
643 {
644 *(dst++) = *(src++);
645 }
646 *(dst++) = ',';
647 }
648 }
649 *(dst - 1) = '\0';
650 }
651 }
652 return string;
653 }
654
655 char *
make_tricky_text(char * src)656 make_tricky_text( char *src )
657 {
658 int len = 0, longest_line = 0;
659 int pos = 0;
660 char *trg ;
661 register int i, k ;
662
663 for( i = 0 ; src[i] ; i++ )
664 if( src[i] == '\n' )
665 {
666 if( len > longest_line )
667 longest_line = len;
668 len = 0 ;
669 pos++ ;
670 }else
671 len++ ;
672
673 if( len > longest_line )
674 longest_line = len;
675 pos++ ;
676 trg = safemalloc( longest_line*(pos+1)+1 );
677 i = 0 ;
678 for( pos = 0 ; pos < longest_line ; pos++ )
679 {
680 len = 0 ;
681 for( k = 0 ; src[k] ; k++ )
682 {
683 if( src[k] == '\n' )
684 {
685 if( len <= pos )
686 trg[i++] = ' ';
687 len = 0 ;
688 }else
689 {
690 if( len == pos )
691 trg[i++] = src[k] ;
692 len++ ;
693 }
694 }
695 trg[i++] = '\n' ;
696 }
697 if( i )
698 i-- ;
699 trg[i] = '\0' ;
700 return trg;
701 }
702
703