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