1 /*
2  * Copyright (C) 2001 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 #ifdef _WIN32
19 #include "win32/config.h"
20 #else
21 #include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <limits.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #ifdef HAVE_STDDEF_H
35 #include <stddef.h>
36 #endif
37 #ifdef HAVE_STDARG_H
38 #include <stdarg.h>
39 #endif
40 #include <sys/stat.h>
41 #ifdef __APPLE_API_PRIVATE
42 #undef __APPLE_API_PRIVATE
43 #endif
44 #if HAVE_DIRENT_H
45 # include <dirent.h>
46 # define NAMLEN(dirent) strlen((dirent)->d_name)
47 #else
48 # if HAVE_SYS_DIRENT_H
49 #  include <sys/dirent.h>
50 #  define NAMLEN(dirent) strlen((dirent)->d_name)
51 # else
52 #  define dirent direct
53 #  define NAMLEN(dirent) (dirent)->d_namlen
54 #  if HAVE_SYS_NDIR_H
55 #   include <sys/ndir.h>
56 #  endif
57 #  if HAVE_SYS_DIR_H
58 #   include <sys/dir.h>
59 #  endif
60 #  if HAVE_NDIR_H
61 #   include <ndir.h>
62 #  endif
63 # endif
64 #endif
65 
66 #ifdef _WIN32
67 #include "win32/afterbase.h"
68 #include <io.h>
69 #include <windows.h>
70 #define access _access
71 #else
72 #include "afterbase.h"
73 #endif
74 #include "asimage.h"
75 
76 #ifdef X_DISPLAY_MISSING
77 #include "colornames.h"
78 #endif
79 
80 /*#include <X11/Xlib.h>*/
81 
82 char    *asim_ApplicationName = NULL ;
83 
84 void
asim_set_application_name(char * argv0)85 asim_set_application_name (char *argv0)
86 {
87 	char *temp = &(argv0[0]);
88 	do
89 	{	/* Save our program name - for error messages */
90 		register int i = 1 ;                   /* we don't use standard strrchr since there
91 												* seems to be some wierdness in
92 												* CYGWIN implementation of it. */
93 		asim_ApplicationName =  temp ;
94 		while( temp[i] && temp[i] != '/' ) ++i ;
95 		temp = temp[i] ? &(temp[i+1]): NULL ;
96 	}while( temp != NULL );
97 }
98 
99 const char *
asim_get_application_name()100 asim_get_application_name()
101 {
102 	return asim_ApplicationName;
103 }
104 
105 static unsigned int asim_as_output_threshold = OUTPUT_DEFAULT_THRESHOLD ;
106 
107 unsigned int
asim_get_output_threshold()108 asim_get_output_threshold()
109 {
110 	return asim_as_output_threshold ;
111 }
112 
113 unsigned int
asim_set_output_threshold(unsigned int threshold)114 asim_set_output_threshold( unsigned int threshold )
115 {
116     unsigned int old = asim_as_output_threshold;
117     asim_as_output_threshold = threshold ;
118     return old;
119 }
120 
121 
122 /* from libAfterBase/output.c : */
asim_show_error(const char * error_format,...)123 Bool asim_show_error( const char *error_format, ...)
124 {
125     if( OUTPUT_LEVEL_ERROR <= get_output_threshold())
126     {
127         va_list ap;
128         fprintf (stderr, "%s ERROR: ", get_application_name() );
129         va_start (ap, error_format);
130         vfprintf (stderr, error_format, ap);
131         va_end (ap);
132         fprintf (stderr, "\n" );
133         return True;
134     }
135     return False;
136 }
137 
asim_show_warning(const char * warning_format,...)138 Bool asim_show_warning( const char *warning_format, ...)
139 {
140     if( OUTPUT_LEVEL_WARNING <= get_output_threshold())
141     {
142         va_list ap;
143         fprintf (stderr, "%s warning: ", get_application_name() );
144         va_start (ap, warning_format);
145         vfprintf (stderr, warning_format, ap);
146         va_end (ap);
147         fprintf (stderr, "\n" );
148         return True;
149     }
150     return False;
151 }
152 
asim_show_progress(const char * msg_format,...)153 Bool asim_show_progress( const char *msg_format, ...)
154 {
155     if( OUTPUT_LEVEL_PROGRESS <= get_output_threshold())
156     {
157         va_list ap;
158         fprintf (stderr, "%s : ", get_application_name() );
159         va_start (ap, msg_format);
160         vfprintf (stderr, msg_format, ap);
161         va_end (ap);
162         fprintf (stderr, "\n" );
163         return True;
164     }
165     return False;
166 }
167 
168 
asim_show_debug(const char * file,const char * func,int line,const char * msg_format,...)169 Bool asim_show_debug( const char *file, const char *func, int line, const char *msg_format, ...)
170 {
171     if( OUTPUT_LEVEL_DEBUG <= get_output_threshold())
172     {
173         va_list ap;
174         fprintf (stderr, "%s debug msg: %s:%s():%d: ", get_application_name(), file, func, line );
175         va_start (ap, msg_format);
176         vfprintf (stderr, msg_format, ap);
177         va_end (ap);
178         fprintf (stderr, "\n" );
179         return True;
180     }
181     return False;
182 }
183 
184 
asim_nonGNUC_debugout(const char * format,...)185 void asim_nonGNUC_debugout( const char *format, ...)
186 {
187     va_list ap;
188     fprintf (stderr, "%s: ", get_application_name() );
189     va_start (ap, format);
190     vfprintf (stderr, format, ap);
191     va_end (ap);
192     fprintf (stderr, "\n" );
193 }
194 
asim_nonGNUC_debugout_stub(const char * format,...)195 void asim_nonGNUC_debugout_stub( const char *format, ...)
196 {}
197 
198 /* from libAfterBase/fs.c : */
199 
asim_check_file_mode(const char * file,int mode)200 int		asim_check_file_mode (const char *file, int mode)
201 {
202 	struct stat   st;
203 
204 	if ((stat (file, &st) == -1) || (st.st_mode & S_IFMT) != mode)
205 		return (-1);
206 	else
207 		return (0);
208 }
209 
210 char         *
asim_put_file_home(const char * path_with_home)211 asim_put_file_home (const char *path_with_home)
212 {
213 	static char  *home = NULL;				   /* the HOME environment variable */
214 	static char   default_home[3] = "./";
215 	static int    home_len = 0;
216 	char         *str = NULL, *ptr;
217 	register int  i;
218 	if (path_with_home == NULL)
219 		return NULL;
220 	/* home dir ? */
221 	if ( strncmp(  path_with_home, "$HOME/", 6 ) == 0 )
222 		path_with_home += 5 ;
223 	else if (path_with_home[0] == '~' && path_with_home[1] == '/')
224 		path_with_home += 1 ;
225 	else
226 		return mystrdup(path_with_home);
227 
228 	if (home == NULL)
229 	{
230 		if ((home = getenv ("HOME")) == NULL)
231 			home = &(default_home[0]);
232 		home_len = strlen (home);
233 	}
234 
235 	for (i = 0; path_with_home[i]; i++);
236 	str = safemalloc (home_len + i + 1);
237 	for (ptr = str + home_len; i >= 0; i--)
238 		ptr[i] = path_with_home[i];
239 	for (i = 0; i < home_len; i++)
240 		str[i] = home[i];
241 	return str;
242 }
243 
244 char*
asim_load_binary_file(const char * realfilename,long * file_size_return)245 asim_load_binary_file(const char* realfilename, long *file_size_return)
246 {
247 	struct stat st;
248 	FILE* fp;
249 	char* data = NULL ;
250 
251 	/* Get the file size. */
252 	if (stat(realfilename, &st)) return NULL;
253 	/* Open the file. */
254 	fp = fopen(realfilename, "rb");
255 	if ( fp != NULL )
256 	{
257 		long len ;
258 		/* Read in the file. */
259 		data = safecalloc(1, st.st_size + 1);
260 		len = fread(data, 1, st.st_size, fp);
261 		if( file_size_return )
262 			*file_size_return = len ;
263 		fclose(fp);
264 	}
265 	return data;
266 }
267 
268 char*
asim_load_file(const char * realfilename)269 asim_load_file(const char* realfilename)
270 {
271 	long len;
272 	char* str = load_binary_file( realfilename, &len );
273 
274 	if (str != NULL && len >= 0)
275 		str[len] = '\0';
276 
277 	return str;
278 }
279 
280 
281 /****************************************************************************
282  *
283  * Find the specified icon file somewhere along the given path.
284  *
285  * There is a possible race condition here:  We check the file and later
286  * do something with it.  By then, the file might not be accessible.
287  * Oh well.
288  *
289  ****************************************************************************/
290 /* supposedly pathlist should not include any environment variables
291    including things like ~/
292  */
293 void
unix_path2dos_path(char * path)294 unix_path2dos_path( char *path )
295 {
296 	int i = strlen(path) ;
297 	while( --i >= 0 )
298 		if( path[i] == '/' && ( i == 0 || path[i-1] != '/' ) )
299 			path[i] = '\\' ;
300 }
301 
302 
303 char         *
asim_find_file(const char * file,const char * pathlist,int type)304 asim_find_file (const char *file, const char *pathlist, int type)
305 {
306 	char 		  *path;
307 	register int   len;
308 	int            max_path = 0;
309 	register char *ptr;
310 	register int   i;
311 	Bool local = False ;
312 
313 	if (file == NULL)
314 		return NULL;
315 #ifdef _WIN32
316 #define PATH_SEPARATOR_CHAR ';'
317 #define PATH_CHAR '\\'
318 #else
319 #define PATH_SEPARATOR_CHAR ':'
320 #define PATH_CHAR '/'
321 #endif
322 
323 	if (*file == PATH_CHAR || *file == '~' || ((pathlist == NULL) || (*pathlist == '\0')))
324 		local = True ;
325 	else if( file[0] == '.' && (file[1] == PATH_CHAR || (file[1] == '.' && file[2] == PATH_CHAR)))
326 		local = True ;
327 	else if( strncmp( file, "$HOME", 5) == 0 )
328 		local = True ;
329 	if( local )
330 	{
331 		path = put_file_home (file);
332 		if ( access (path, type) == 0 )
333 		{
334 			return path;
335 		}
336 		free (path);
337 		return NULL;
338 	}
339 /*	return put_file_home(file); */
340 	for (i = 0; file[i]; i++);
341 	len = i ;
342 	for (ptr = (char *)pathlist; *ptr; ptr += i)
343 	{
344 		if (*ptr == PATH_SEPARATOR_CHAR )
345 			ptr++;
346 		for (i = 0; ptr[i] && ptr[i] != PATH_SEPARATOR_CHAR; i++);
347 		if (i > max_path)
348 			max_path = i;
349 	}
350 
351 	path = safecalloc (1, max_path + 1 + len + 1);
352 	strcpy( path+max_path+1, file );
353 	path[max_path] = PATH_CHAR ;
354 
355 	ptr = (char*)&(pathlist[0]) ;
356 	while( ptr[0] != '\0' )
357 	{
358 		int skip ;
359 		for( i = 0 ; ptr[i] == PATH_SEPARATOR_CHAR; ++i );
360 		ptr += i ;
361 		for( i = 0 ; ptr[i] != PATH_SEPARATOR_CHAR && ptr[i] != '\0'; ++i );
362 		skip = i ;
363 		if( i > 0 && ptr[i-1] == PATH_CHAR )
364 			i-- ;
365 		if( i > 0 )
366 		{
367 			register char *try_path = path+max_path-i;
368 			strncpy( try_path, ptr, i );
369 			if (access(try_path, type) == 0)
370 			{
371 				char* res = mystrdup(try_path);
372 				free( path );
373 				return res;
374 			}
375 		}
376 		ptr += skip ;
377 	}
378 	free (path);
379 	return NULL;
380 }
381 
382 static char         *
find_envvar(char * var_start,int * end_pos)383 find_envvar (char *var_start, int *end_pos)
384 {
385 	char          backup, *name_start = var_start;
386 	register int  i;
387 	char         *var = NULL;
388 
389 	if (var_start[0] == '{')
390 	{
391 		name_start++;
392 		for (i = 1; var_start[i] && var_start[i] != '}'; i++);
393 	} else
394 		for (i = 0; isalnum ((int)var_start[i]) || var_start[i] == '_'; i++);
395 
396 	backup = var_start[i];
397 	var_start[i] = '\0';
398 	var = getenv (name_start);
399 	var_start[i] = backup;
400 
401 	*end_pos = i;
402 	if (backup == '}')
403 		(*end_pos)++;
404 	return var;
405 }
406 
407 static char *
do_replace_envvar(char * path)408 do_replace_envvar (char *path)
409 {
410 	char         *data = path, *tmp;
411 	char         *home = getenv ("HOME");
412 	int           pos = 0, len, home_len = 0;
413 
414 	if (path == NULL)
415 		return NULL;
416 	if (*path == '\0')
417 		return path;
418 	len = strlen (path);
419 	if (home)
420 		home_len = strlen (home);
421 
422 	while (*(data + pos))
423 	{
424 		char         *var;
425 		int           var_len, end_pos;
426 
427 		while (*(data + pos) != '$' && *(data + pos))
428 		{
429 			if (*(data + pos) == '~' && *(data + pos + 1) == '/')
430 			{
431 				if (pos > 0)
432 					if (*(data + pos - 1) != ':')
433 					{
434 						pos += 2;
435 						continue;
436 					}
437 				if (home == NULL)
438 					*(data + (pos++)) = '.';
439 				else
440 				{
441 					len += home_len;
442 					tmp = safecalloc (1, len);
443 					strncpy (tmp, data, pos);
444 					strcpy (tmp + pos, home);
445 					strcpy (tmp + pos + home_len, data + pos + 1);
446 					if( data != path )
447 						free (data);
448 					data = tmp;
449 					pos += home_len;
450 				}
451 			}
452 			pos++;
453 		}
454 		if (*(data + pos) == '\0')
455 			break;
456 		/* found $ sign - trying to replace var */
457 		if ((var = find_envvar (data + pos + 1, &end_pos)) == NULL)
458 		{
459 			++pos;
460 			continue;
461 		}
462 		var_len = strlen (var);
463 		len += var_len;
464 		tmp = safecalloc (1, len);
465 		strncpy (tmp, data, pos);
466 		strcpy (tmp + pos, var);
467 		strcpy (tmp + pos + var_len, data + pos + end_pos + 1);
468 		if( data != path )
469 			free (data);
470 		data = tmp;
471 	}
472 	return data;
473 }
474 
475 char*
asim_copy_replace_envvar(char * path)476 asim_copy_replace_envvar (char *path)
477 {
478 	char         *res = do_replace_envvar( path );
479 	return ( res == path )?mystrdup( res ):res;
480 }
481 
482 
483 /*******************************************************************/
484 /* from mystring.c : */
485 char         *
asim_mystrndup(const char * str,size_t n)486 asim_mystrndup (const char *str, size_t n)
487 {
488 	char         *c = NULL;
489 	if (str)
490 	{
491 		c = calloc (1, n + 1);
492 		strncpy (c, str, n);
493 	}
494 	return c;
495 }
496 
497 char         *
asim_mystrdup(const char * str)498 asim_mystrdup (const char *str)
499 {
500 	char         *c = NULL;
501 
502 	if (str)
503 	{
504 		c = malloc (strlen (str) + 1);
505 		strcpy (c, str);
506 	}
507 	return c;
508 }
509 
510 int
asim_mystrcasecmp(const char * s1,const char * s2)511 asim_mystrcasecmp (const char *s1, const char *s2)
512 {
513 	int          c1, c2;
514 	register int i = 0 ;
515 
516 	if (s1 == NULL || s2 == NULL)
517 		return (s1 == s2) ? 0 : ((s1==NULL)?1:-1);
518 	while (s1[i])
519 	{
520 		/* in some BSD implementations, tolower(c) is not defined
521 		 * unless isupper(c) is true */
522 		c1 = s1[i];
523 		if (isupper (c1))
524 			c1 = tolower (c1);
525 		c2 = s2[i];
526 		if (isupper (c2))
527 			c2 = tolower (c2);
528 
529 		++i ;
530 		if (c1 != c2)
531 			return (c1 - c2);
532 	}
533 	return -s2[i];
534 }
535 
536 int
asim_mystrncasecmp(const char * s1,const char * s2,size_t n)537 asim_mystrncasecmp (const char *s1, const char *s2, size_t n)
538 {
539 	register int  c1, c2;
540 	register int i = 0 ;
541 
542 	if (s1 == NULL || s2 == NULL)
543 		return (s1 == s2) ? 0 : ((s1==NULL)?1:-1);
544 	while( i < n )
545 	{
546 		c1 = s1[i], c2 = s2[i];
547 		++i ;
548 		if (c1==0)
549 			return -c2;
550 		if (isupper (c1))
551 			c1 = tolower(c1);
552 		if (isupper (c2))
553 			c2 = tolower(c2);
554 		if (c1 != c2)
555 			return (c1 - c2);
556 	}
557 	return 0;
558 }
559 
560 #ifdef X_DISPLAY_MISSING
compare_xcolor_entries(const void * a,const void * b)561 static int compare_xcolor_entries(const void *a, const void *b)
562 {
563    return strcmp((const char *) a, ((const XColorEntry *) b)->name);
564 }
565 
FindColor(const char * name,CARD32 * colorPtr)566 static int FindColor(const char *name, CARD32 *colorPtr)
567 {
568    XColorEntry *found;
569 
570    found = bsearch(name, xColors, numXColors, sizeof(XColorEntry),
571                    compare_xcolor_entries);
572    if (found == NULL)
573       return 0;
574 
575    *colorPtr = 0xFF000000|((found->red<<16)&0x00FF0000)|((found->green<<8)&0x0000FF00)|((found->blue)&0x000000FF);
576    return 1;
577 }
578 #endif
579 
580 /*******************************************************************/
581 /* from parse,c : */
asim_parse_argb_color(const char * color,CARD32 * pargb)582 const char *asim_parse_argb_color( const char *color, CARD32 *pargb )
583 {
584 #define hextoi(h)   (isdigit(h)?((h)-'0'):(isupper(h)?((h)-'A'+10):((h)-'a'+10)))
585 	if( color )
586 	{
587 		if( *color == '#' )
588 		{
589 			CARD32 argb = 0 ;
590 			int len = 0 ;
591 			register const char *ptr = color+1 ;
592 			while( isxdigit((int)ptr[len]) ) len++;
593 			if( len >= 3)
594 			{
595 				if( (len&0x3) == 0 && len != 12 )
596 				{  /* we do have alpha channel !!! */
597 					len = len>>2 ;
598 					argb = (hextoi((int)ptr[0])<<28)&0xF0000000 ;
599 					if( len > 1 )
600 						argb |= (hextoi((int)ptr[1])<<24)&0x0F000000 ;
601 					else
602 						argb |= 0x0F000000;
603 					ptr += len ;
604 				}else
605 				{
606 					len = len/3 ;
607 					argb = 0xFF000000;
608 				}
609 				/* processing rest of the channels : */
610 				if( len == 1 )
611 				{
612 					argb |= 0x000F0F0F;
613 					argb |= (hextoi((int)ptr[0])<<20)&0x00F00000 ;
614 					argb |= (hextoi((int)ptr[1])<<12)&0x0000F000 ;
615 					argb |= (hextoi((int)ptr[2])<<4 )&0x000000F0 ;
616 					ptr += 3 ;
617 				}else
618 				{
619 					argb |= (hextoi((int)ptr[0])<<20)&0x00F00000 ;
620 					argb |= (hextoi((int)ptr[1])<<16)&0x000F0000 ;
621 					ptr += len ;
622 					argb |= (hextoi((int)ptr[0])<<12)&0x0000F000 ;
623 					argb |= (hextoi((int)ptr[1])<<8) &0x00000F00 ;
624 					ptr += len ;
625 					argb |= (hextoi((int)ptr[0])<<4 )&0x000000F0 ;
626 					argb |= (hextoi((int)ptr[1]))    &0x0000000F ;
627 					ptr += len ;
628 				}
629 				*pargb = argb ;
630 				return ptr;
631 			}
632 		}else if( *color )
633 		{
634 			/* does not really matter here what screen to use : */
635 			Display *dpy = get_default_asvisual()->dpy;
636 #ifdef X_DISPLAY_MISSING
637 			register const char *ptr = &(color[0]);
638             if(!FindColor(color, pargb))
639                 return color;
640     		while( !isspace((int)*ptr) && *ptr != '\0' ) ptr++;
641 			return ptr;
642 #else
643 			if( dpy == NULL )
644 				return color ;
645 			else
646 			{
647 				register const char *ptr = &(color[0]);
648 #ifndef X_DISPLAY_MISSING
649 				XColor xcol, xcol_scr ;
650 /* XXX Not sure if Scr.asv->colormap is always defined here.  If not,
651 ** change back to DefaultColormap(dpy,DefaultScreen(dpy)). */
652 				if( XLookupColor( dpy, DefaultColormap(dpy,DefaultScreen(dpy)), color, &xcol, &xcol_scr) )
653 					*pargb = 0xFF000000|((xcol.red<<8)&0x00FF0000)|(xcol.green&0x0000FF00)|((xcol.blue>>8)&0x000000FF);
654 #endif
655 				while( !isspace((int)*ptr) && *ptr != '\0' ) ptr++;
656 				return ptr;
657 			}
658 #endif
659 		}
660 	}
661 	return color;
662 }
663 
664 
665 static int asim_asxml_var_nget(char* name, int n);
666 
667 
668 /* Math expression parsing algorithm. */
asim_parse_math(const char * str,char ** endptr,double size)669 double asim_parse_math(const char* str, char** endptr, double size) {
670 	double total = 0;
671 	char op = '+';
672 	char minus = 0;
673 	char logical_not = 0;
674 /*	const char* startptr = str; */
675 	if( str == NULL )
676 		return 0 ;
677 
678 	while (isspace((int)*str)) str++;
679 	if( *str == '!' )
680 	{
681 		logical_not = 1;
682 		++str ;
683 	}else if( *str == '-' )
684 	{
685 		minus = 1 ;
686 		++str ;
687 	}
688 
689 	while (*str)
690 	{
691 		while (isspace((int)*str)) str++;
692 		if (!op)
693 		{
694 			if (*str == '+' || *str == '-' || *str == '*' || *str == '/') op = *str++;
695 			else if (*str == '-') { minus = 1; str++; }
696 			else if (*str == '!') { logical_not = 1; str++; }
697 			else if (*str == ')') { str++; break; }
698 			else break;
699 		} else
700 		{
701 			char* ptr;
702 			double num;
703 
704 			if (*str == '(')
705 				num = asim_parse_math(str + 1, &ptr, size);
706             else if (*str == '$')
707 			{
708             	for (ptr = (char*)str + 1 ; *ptr && !isspace(*ptr) && *ptr != '+' && *ptr != '-' && *ptr != '*' && *ptr != '!' && *ptr != '/' && *ptr != ')' ; ptr++);
709                	num = asim_asxml_var_nget((char*)str + 1, ptr - (str + 1));
710             }else
711 				num = strtod(str, &ptr);
712 
713 			if (str != ptr)
714 			{
715 				if (*ptr == '%') num *= size / 100.0, ptr++;
716 				if (minus) num = -num;
717 				if (logical_not) num = !num;
718 
719 				if (op == '+') total += num;
720 				else if (op == '-') total -= num;
721 				else if (op == '*') total *= num;
722 				else if (op == '/' && num) total /= num;
723 			} else
724 				break;
725 			str = ptr;
726 			op = '\0';
727 			minus = logical_not = 0;
728 		}
729 	}
730 	if (endptr) *endptr = (char*)str;
731 /* 	show_debug(__FILE__,"parse_math",__LINE__,"Parsed math [%s] with reference [%.2f] into number [%.2f].", startptr, size, total); */
732 	return total;
733 }
734 
735 /*******************************************************************/
736 /* from ashash,c : */
asim_default_hash_func(ASHashableValue value,ASHashKey hash_size)737 ASHashKey asim_default_hash_func (ASHashableValue value, ASHashKey hash_size)
738 {
739 	return (ASHashKey)(value % hash_size);
740 }
741 
742 long
asim_default_compare_func(ASHashableValue value1,ASHashableValue value2)743 asim_default_compare_func (ASHashableValue value1, ASHashableValue value2)
744 {
745 	return ((long)value1 - (long)value2);
746 }
747 
748 long
asim_desc_long_compare_func(ASHashableValue value1,ASHashableValue value2)749 asim_desc_long_compare_func (ASHashableValue value1, ASHashableValue value2)
750 {
751     return ((long)value2 - (long)value1);
752 }
753 
754 void
asim_init_ashash(ASHashTable * hash,Bool freeresources)755 asim_init_ashash (ASHashTable * hash, Bool freeresources)
756 {
757 LOCAL_DEBUG_CALLER_OUT( " has = %p, free ? %d", hash, freeresources );
758 	if (hash)
759 	{
760 		if (freeresources)
761 			if (hash->buckets)
762 				free (hash->buckets);
763 		memset (hash, 0x00, sizeof (ASHashTable));
764 	}
765 }
766 
767 ASHashTable  *
asim_create_ashash(ASHashKey size,ASHashKey (* hash_func)(ASHashableValue,ASHashKey),long (* compare_func)(ASHashableValue,ASHashableValue),void (* item_destroy_func)(ASHashableValue,void *))768 asim_create_ashash (ASHashKey size,
769 			   ASHashKey (*hash_func) (ASHashableValue, ASHashKey),
770 			   long (*compare_func) (ASHashableValue, ASHashableValue),
771 			   void (*item_destroy_func) (ASHashableValue, void *))
772 {
773 	ASHashTable  *hash;
774 
775 	if (size <= 0)
776 		size = 63;
777 
778 	hash = safecalloc (1, sizeof (ASHashTable));
779 	init_ashash (hash, False);
780 
781 	hash->buckets = safecalloc (size, sizeof (ASHashBucket));
782 
783 	hash->size = size;
784 
785 	if (hash_func)
786 		hash->hash_func = hash_func;
787 	else
788 		hash->hash_func = asim_default_hash_func;
789 
790 	if (compare_func)
791 		hash->compare_func = compare_func;
792 	else
793 		hash->compare_func = asim_default_compare_func;
794 
795 	hash->item_destroy_func = item_destroy_func;
796 
797 	return hash;
798 }
799 
800 static void
destroy_ashash_bucket(ASHashBucket * bucket,void (* item_destroy_func)(ASHashableValue,void *))801 destroy_ashash_bucket (ASHashBucket * bucket, void (*item_destroy_func) (ASHashableValue, void *))
802 {
803 	register ASHashItem *item, *next;
804 
805 	for (item = *bucket; item != NULL; item = next)
806 	{
807 		next = item->next;
808 		if (item_destroy_func)
809 			item_destroy_func (item->value, item->data);
810 		free (item);
811 	}
812 	*bucket = NULL;
813 }
814 
815 void
asim_destroy_ashash(ASHashTable ** hash)816 asim_destroy_ashash (ASHashTable ** hash)
817 {
818 LOCAL_DEBUG_CALLER_OUT( " hash = %p, *hash = %p", hash, *hash  );
819 	if (*hash)
820 	{
821 		register int  i;
822 
823 		for (i = (*hash)->size - 1; i >= 0; i--)
824 			if ((*hash)->buckets[i])
825 				destroy_ashash_bucket (&((*hash)->buckets[i]), (*hash)->item_destroy_func);
826 
827 		asim_init_ashash (*hash, True);
828 		free (*hash);
829 		*hash = NULL;
830 	}
831 }
832 
833 static        ASHashResult
add_item_to_bucket(ASHashBucket * bucket,ASHashItem * item,long (* compare_func)(ASHashableValue,ASHashableValue))834 add_item_to_bucket (ASHashBucket * bucket, ASHashItem * item, long (*compare_func) (ASHashableValue, ASHashableValue))
835 {
836 	ASHashItem  **tmp;
837 
838 	/* first check if we already have this item */
839 	for (tmp = bucket; *tmp != NULL; tmp = &((*tmp)->next))
840 	{
841 		register long res = compare_func ((*tmp)->value, item->value);
842 
843 		if (res == 0)
844 			return ((*tmp)->data == item->data) ? ASH_ItemExistsSame : ASH_ItemExistsDiffer;
845 		else if (res > 0)
846 			break;
847 	}
848 	/* now actually add this item */
849 	item->next = (*tmp);
850 	*tmp = item;
851 	return ASH_Success;
852 }
853 
854 #define DEALLOC_CACHE_SIZE      1024
855 static ASHashItem*  deallocated_mem[DEALLOC_CACHE_SIZE+10] ;
856 static unsigned int deallocated_used = 0 ;
857 
858 ASHashResult
asim_add_hash_item(ASHashTable * hash,ASHashableValue value,void * data)859 asim_add_hash_item (ASHashTable * hash, ASHashableValue value, void *data)
860 {
861 	ASHashKey     key;
862 	ASHashItem   *item;
863 	ASHashResult  res;
864 
865 	if (hash == NULL)
866         return ASH_BadParameter;
867 
868 	key = hash->hash_func (value, hash->size);
869 	if (key >= hash->size)
870         return ASH_BadParameter;
871 
872     if( deallocated_used > 0 )
873         item = deallocated_mem[--deallocated_used];
874     else
875         item = safecalloc (1, sizeof (ASHashItem));
876 
877 	item->next = NULL;
878 	item->value = value;
879 	item->data = data;
880 
881 	res = add_item_to_bucket (&(hash->buckets[key]), item, hash->compare_func);
882 	if (res == ASH_Success)
883 	{
884 		hash->most_recent = item ;
885 		hash->items_num++;
886 		if (hash->buckets[key]->next == NULL)
887 			hash->buckets_used++;
888 	} else
889 		free (item);
890 	return res;
891 }
892 
893 static ASHashItem **
find_item_in_bucket(ASHashBucket * bucket,ASHashableValue value,long (* compare_func)(ASHashableValue,ASHashableValue))894 find_item_in_bucket (ASHashBucket * bucket,
895 					 ASHashableValue value, long (*compare_func) (ASHashableValue, ASHashableValue))
896 {
897 	register ASHashItem **tmp;
898 	register long res;
899 
900 	/* first check if we already have this item */
901 	for (tmp = bucket; *tmp != NULL; tmp = &((*tmp)->next))
902 	{
903 		res = compare_func ((*tmp)->value, value);
904 		if (res == 0)
905 			return tmp;
906 		else if (res > 0)
907 			break;
908 	}
909 	return NULL;
910 }
911 
912 ASHashResult
asim_get_hash_item(ASHashTable * hash,ASHashableValue value,void ** trg)913 asim_get_hash_item (ASHashTable * hash, ASHashableValue value, void **trg)
914 {
915 	ASHashKey     key;
916 	ASHashItem  **pitem = NULL;
917 
918 	if (hash)
919 	{
920 		key = hash->hash_func (value, hash->size);
921 		if (key < hash->size)
922 			pitem = find_item_in_bucket (&(hash->buckets[key]), value, hash->compare_func);
923 	}
924 	if (pitem)
925 		if (*pitem)
926 		{
927 			if (trg)
928 				*trg = (*pitem)->data;
929 			return ASH_Success;
930 		}
931 	return ASH_ItemNotExists;
932 }
933 
934 ASHashResult
asim_remove_hash_item(ASHashTable * hash,ASHashableValue value,void ** trg,Bool destroy)935 asim_remove_hash_item (ASHashTable * hash, ASHashableValue value, void **trg, Bool destroy)
936 {
937 	ASHashKey     key = 0;
938 	ASHashItem  **pitem = NULL;
939 
940 	if (hash)
941 	{
942 		key = hash->hash_func (value, hash->size);
943 		if (key < hash->size)
944 			pitem = find_item_in_bucket (&(hash->buckets[key]), value, hash->compare_func);
945 	}
946 	if (pitem)
947 		if (*pitem)
948 		{
949 			ASHashItem   *next;
950 
951 			if( hash->most_recent == *pitem )
952 				hash->most_recent = NULL ;
953 
954 			if (trg)
955 				*trg = (*pitem)->data;
956 
957 			next = (*pitem)->next;
958 			if (hash->item_destroy_func && destroy)
959 				hash->item_destroy_func ((*pitem)->value, (trg) ? NULL : (*pitem)->data);
960 
961             if( deallocated_used < DEALLOC_CACHE_SIZE )
962             {
963                 deallocated_mem[deallocated_used++] = *pitem ;
964             }else
965                 free( *pitem );
966 
967             *pitem = next;
968 			if (hash->buckets[key] == NULL)
969 				hash->buckets_used--;
970 			hash->items_num--;
971 
972 			return ASH_Success;
973 		}
974 	return ASH_ItemNotExists;
975 }
976 
asim_flush_ashash_memory_pool()977 void asim_flush_ashash_memory_pool()
978 {
979 	/* we better disable errors as some of this data will belong to memory audit : */
980 	while( deallocated_used > 0 )
981 		free( deallocated_mem[--deallocated_used] );
982 }
983 
984 /************************************************************************/
985 /************************************************************************/
986 /* 	Some useful implementations 					*/
987 /************************************************************************/
asim_pointer_hash_value(ASHashableValue value,ASHashKey hash_size)988 ASHashKey asim_pointer_hash_value (ASHashableValue value, ASHashKey hash_size)
989 {
990     union
991     {
992         void *ptr;
993         ASHashKey key[2];
994     } mix;
995     register  ASHashKey key;
996 
997     mix.ptr = (void*)value;
998     key = mix.key[0]^mix.key[1] ;
999     if( hash_size == 256 )
1000 		return (key>>4)&0x0FF;
1001     return (key>>4) % hash_size;
1002 }
1003 
1004 /* case sensitive strings hash */
1005 ASHashKey
asim_string_hash_value(ASHashableValue value,ASHashKey hash_size)1006 asim_string_hash_value (ASHashableValue value, ASHashKey hash_size)
1007 {
1008 	ASHashKey     hash_key = 0;
1009 	register int  i = 0;
1010 	char         *string = (char*)value;
1011 	register char c;
1012 
1013 	do
1014 	{
1015 		c = string[i];
1016 		if (c == '\0')
1017 			break;
1018 		hash_key += (((ASHashKey) c) << i);
1019 		++i ;
1020 	}while( i < ((sizeof (ASHashKey) - sizeof (char)) << 3) );
1021 	return hash_key % hash_size;
1022 }
1023 
1024 long
asim_string_compare(ASHashableValue value1,ASHashableValue value2)1025 asim_string_compare (ASHashableValue value1, ASHashableValue value2)
1026 {
1027 	register char *str1 = (char*)value1;
1028 	register char *str2 = (char*)value2;
1029 	register int   i = 0 ;
1030 
1031 	if (str1 == str2)
1032 		return 0;
1033 	if (str1 == NULL)
1034 		return -1;
1035 	if (str2 == NULL)
1036 		return 1;
1037 	do
1038 	{
1039 		if (str1[i] != str2[i])
1040 			return (long)(str1[i]) - (long)(str2[i]);
1041 
1042 	}while( str1[i++] );
1043 	return 0;
1044 }
1045 
1046 void
asim_string_destroy_without_data(ASHashableValue value,void * data)1047 asim_string_destroy_without_data (ASHashableValue value, void *data)
1048 {
1049 	if ((char*)value != NULL)
1050 		free ((char*)value);
1051 }
1052 
1053 /* variation for case-unsensitive strings */
1054 ASHashKey
asim_casestring_hash_value(ASHashableValue value,ASHashKey hash_size)1055 asim_casestring_hash_value (ASHashableValue value, ASHashKey hash_size)
1056 {
1057 	ASHashKey     hash_key = 0;
1058 	register int  i = 0;
1059 	char         *string = (char*)value;
1060 	register int c;
1061 
1062 	do
1063 	{
1064 		c = string[i];
1065 		if (c == '\0')
1066 			break;
1067 		if (isupper (c))
1068 			c = tolower (c);
1069 		hash_key += (((ASHashKey) c) << i);
1070 		++i;
1071 	}while(i < ((sizeof (ASHashKey) - sizeof (char)) << 3));
1072 
1073 	return hash_key % hash_size;
1074 }
1075 
1076 long
asim_casestring_compare(ASHashableValue value1,ASHashableValue value2)1077 asim_casestring_compare (ASHashableValue value1, ASHashableValue value2)
1078 {
1079 	register char *str1 = (char*)value1;
1080 	register char *str2 = (char*)value2;
1081 	register int   i = 0;
1082 
1083 	if (str1 == str2)
1084 		return 0;
1085 	if (str1 == NULL)
1086 		return -1;
1087 	if (str2 == NULL)
1088 		return 1;
1089 	do
1090 	{
1091 		int          u1, u2;
1092 
1093 		u1 = str1[i];
1094 		u2 = str2[i];
1095 		if (islower (u1))
1096 			u1 = toupper (u1);
1097 		if (islower (u2))
1098 			u2 = toupper (u2);
1099 		if (u1 != u2)
1100 			return (long)u1 - (long)u2;
1101 	}while( str1[i++] );
1102 	return 0;
1103 }
1104 
1105 int
asim_get_drawable_size(Drawable d,unsigned int * ret_w,unsigned int * ret_h)1106 asim_get_drawable_size (Drawable d, unsigned int *ret_w, unsigned int *ret_h)
1107 {
1108 	Display *dpy = get_default_asvisual()->dpy;
1109 	*ret_w = 0;
1110 	*ret_h = 0;
1111 #ifndef X_DISPLAY_MISSING
1112 	if( dpy && d )
1113 	{
1114 		Window        root;
1115 		unsigned int  ujunk;
1116 		int           junk;
1117 		if (XGetGeometry (dpy, d, &root, &junk, &junk, ret_w, ret_h, &ujunk, &ujunk) != 0)
1118 			return 1;
1119 	}
1120 #endif
1121 	return 0;
1122 }
1123 
1124 #ifdef X_DISPLAY_MISSING
XParseGeometry(char * string,int * x,int * y,unsigned int * width,unsigned int * height)1125 int XParseGeometry (  char *string,int *x,int *y,
1126                       unsigned int *width,    /* RETURN */
1127 					  unsigned int *height)    /* RETURN */
1128 {
1129 	show_error( "Parsing of geometry is not supported without either Xlib opr libAfterBase" );
1130 	return 0;
1131 }
XDestroyImage(void * d)1132 void XDestroyImage( void* d){}
XGetWindowAttributes(void * d,Window w,unsigned long m,void * s)1133 int XGetWindowAttributes( void*d, Window w, unsigned long m, void* s){  return 0;}
XGetImage(void * dpy,Drawable d,int x,int y,unsigned int width,unsigned int height,unsigned long m,int t)1134 void *XGetImage( void* dpy,Drawable d,int x,int y,unsigned int width,unsigned int height, unsigned long m,int t)
1135 {return NULL ;}
XGetPixel(void * d,int x,int y)1136 unsigned long XGetPixel(void* d, int x, int y){return 0;}
XQueryColors(void * a,Colormap c,void * x,int m)1137 int XQueryColors(void* a,Colormap c,void* x,int m){return 0;}
1138 #endif
1139 
1140 
1141 /***************************************/
1142 /* from sleep.c                        */
1143 /***************************************/
1144 #if TIME_WITH_SYS_TIME
1145 # include <sys/time.h>
1146 # include <time.h>
1147 #else
1148 # if HAVE_SYS_TIME_H
1149 #  include <sys/time.h>
1150 # else
1151 #  include <time.h>
1152 # endif
1153 #endif
1154 #ifndef _WIN32
1155 # include <sys/times.h>
1156 #endif
1157 static clock_t _as_ticker_last_tick = 0;
1158 static clock_t _as_ticker_tick_size = 1;
1159 static clock_t _as_ticker_tick_time = 0;
1160 
1161 /**************************************************************************
1162  * Sleep for n microseconds
1163  *************************************************************************/
1164 void
sleep_a_little(int n)1165 sleep_a_little (int n)
1166 {
1167 #ifndef _WIN32
1168 	struct timeval value;
1169 
1170 	if (n <= 0)
1171 		return;
1172 
1173 	value.tv_usec = n % 1000000;
1174 	value.tv_sec = n / 1000000;
1175 
1176 #ifndef PORTABLE_SELECT
1177 #ifdef __hpux
1178 #define PORTABLE_SELECT(w,i,o,e,t)	select((w),(int *)(i),(int *)(o),(e),(t))
1179 #else
1180 #define PORTABLE_SELECT(w,i,o,e,t)	select((w),(i),(o),(e),(t))
1181 #endif
1182 #endif
1183 	PORTABLE_SELECT (1, 0, 0, 0, &value);
1184 #else /* win32 : */
1185 	Sleep(n);
1186 #endif
1187 }
1188 
1189 void
asim_start_ticker(unsigned int size)1190 asim_start_ticker (unsigned int size)
1191 {
1192 #ifndef _WIN32
1193 	struct tms    t;
1194 
1195 	_as_ticker_last_tick = times (&t);		   /* in system ticks */
1196 	if (_as_ticker_tick_time == 0)
1197 	{
1198 		register clock_t delta = _as_ticker_last_tick;
1199 		/* calibrating clock - how many ms per cpu tick ? */
1200 		sleep_a_little (100);
1201 		_as_ticker_last_tick = times (&t);
1202 		delta = _as_ticker_last_tick - delta ;
1203 		if( delta <= 0 )
1204 			_as_ticker_tick_time = 100;
1205 		else
1206 			_as_ticker_tick_time = 101 / delta;
1207 	}
1208 #else
1209 	_as_ticker_tick_time = 1000;
1210 	_as_ticker_last_tick = time(NULL) ;
1211 #endif
1212 	_as_ticker_tick_size = size;			   /* in ms */
1213 
1214 }
1215 
1216 void
asim_wait_tick()1217 asim_wait_tick ()
1218 {
1219 #ifndef _WIN32
1220 	struct tms    t;
1221 	register clock_t curr = (times (&t) - _as_ticker_last_tick) * _as_ticker_tick_time;
1222 #else
1223 	register int curr = (time(NULL) - _as_ticker_last_tick) * _as_ticker_tick_time;
1224 #endif
1225 
1226 	if (curr < _as_ticker_tick_size)
1227 		sleep_a_little (_as_ticker_tick_size - curr);
1228 
1229 #ifndef _WIN32
1230 	_as_ticker_last_tick = times (&t);
1231 #else
1232 	_as_ticker_last_tick = time(NULL) ;
1233 #endif
1234 }
1235 
1236 #ifndef _WIN32
1237 /*
1238  * Non-NULL select and dcomp pointers are *NOT* tested, but should be OK.
1239  * They are not used by afterstep however, so this implementation should
1240  * be good enough.
1241  *
1242  * c.ridd@isode.com
1243  */
1244 int
asim_my_scandir_ext(const char * dirname,int (* filter_func)(const char *),Bool (* handle_direntry_func)(const char * fname,const char * fullname,struct stat * stat_info,void * aux_data),void * aux_data)1245 asim_my_scandir_ext ( const char *dirname, int (*filter_func) (const char *),
1246 				 Bool (*handle_direntry_func)( const char *fname, const char *fullname, struct stat *stat_info, void *aux_data),
1247 				 void *aux_data)
1248 {
1249 	DIR          *d;
1250 	struct dirent *e;						   /* Pointer to static struct inside readdir() */
1251 	int           n = 0;					   /* Count of nl used so far */
1252 	char         *filename;					   /* For building filename to pass to stat */
1253 	char         *p;						   /* Place where filename starts */
1254 	struct stat   stat_info;
1255 
1256 	d = opendir (dirname);
1257 
1258 	if (d == NULL)
1259 		return -1;
1260 
1261 	filename = (char *)safecalloc (1, strlen (dirname) + PATH_MAX + 2);
1262 	if (filename == NULL)
1263 	{
1264 		closedir (d);
1265 		return -1;
1266 	}
1267 	strcpy (filename, dirname);
1268 	p = filename + strlen (filename);
1269 	if( *p != '/' )
1270 	{
1271 		*p++ = '/';
1272 		*p = 0;									   /* Just in case... */
1273 	}
1274 
1275 	while ((e = readdir (d)) != NULL)
1276 	{
1277 		if ((filter_func == NULL) || filter_func (&(e->d_name[0])))
1278 		{
1279 			int i = 0;
1280 			/* Fill in the fields using stat() */
1281 			do{ p[i] = e->d_name[i]; ++i ; }while(  e->d_name[i] && i < PATH_MAX );
1282 			p[i] ='\0' ;
1283 			if (stat (filename, &stat_info) != -1)
1284 			{
1285 				if( handle_direntry_func( e->d_name, filename, &stat_info, aux_data) )
1286 					n++;
1287 			}
1288 		}
1289 	}
1290 	free (filename);
1291 
1292 	if (closedir (d) == -1)
1293 		return -1;
1294 	/* Return the count of the entries */
1295 	return n;
1296 }
1297 
1298 #endif /* #ifndef _WIN32 */
1299 
1300 /***************************************/
1301 /* from xml.c                          */
1302 /***************************************/
1303 static char* cdata_str = XML_CDATA_STR;
1304 static char* container_str = XML_CONTAINER_STR;
1305 static ASHashTable *asxml_var = NULL;
1306 
1307 void
asim_asxml_var_init(void)1308 asim_asxml_var_init(void)
1309 {
1310 	if ( asxml_var == NULL )
1311 	{
1312 		Display *dpy = get_default_asvisual()->dpy;
1313 
1314     	asxml_var = create_ashash(0, string_hash_value, string_compare, string_destroy_without_data);
1315     	if (!asxml_var) return;
1316 #ifndef X_DISPLAY_MISSING
1317     	if ( dpy != NULL )
1318 		{
1319         	asxml_var_insert("xroot.width",  XDisplayWidth (dpy, DefaultScreen(dpy)));
1320         	asxml_var_insert("xroot.height", XDisplayHeight(dpy, DefaultScreen(dpy)));
1321       	}
1322 #endif
1323 	}
1324 }
1325 
1326 void
asim_asxml_var_insert(const char * name,int value)1327 asim_asxml_var_insert(const char* name, int value)
1328 {
1329 	ASHashData hdata;
1330 
1331     if (!asxml_var) asxml_var_init();
1332     if (!asxml_var) return;
1333 
1334     /* Destroy any old data associated with this name. */
1335     remove_hash_item(asxml_var, AS_HASHABLE(name), NULL, True);
1336 
1337     show_progress("Defining var [%s] == %d.", name, value);
1338 
1339     hdata.i = value;
1340     add_hash_item(asxml_var, AS_HASHABLE(mystrdup(name)), hdata.vptr);
1341 }
1342 
1343 int
asim_asxml_var_get(const char * name)1344 asim_asxml_var_get(const char* name)
1345 {
1346 	ASHashData hdata = {0};
1347 
1348     if (!asxml_var) asxml_var_init();
1349     if (!asxml_var) return 0;
1350     if( get_hash_item(asxml_var, AS_HASHABLE(name), &hdata.vptr) != ASH_Success )
1351 	{
1352 		show_debug(__FILE__, "asxml_var_get", __LINE__, "Use of undefined variable [%s].", name);
1353 		return 0;
1354 	}
1355     return hdata.i;
1356 }
1357 
1358 static int
asim_asxml_var_nget(char * name,int n)1359 asim_asxml_var_nget(char* name, int n) {
1360       int value;
1361       char oldc = name[n];
1362       name[n] = '\0';
1363       value = asxml_var_get(name);
1364       name[n] = oldc;
1365       return value;
1366 }
1367 
1368 void
asim_asxml_var_cleanup(void)1369 asim_asxml_var_cleanup(void)
1370 {
1371 	if ( asxml_var != NULL )
1372     	destroy_ashash( &asxml_var );
1373 
1374 }
1375 
lcstring(char * str)1376 static char* lcstring(char* str)
1377 {
1378 	char* ptr = str;
1379 	for ( ; *ptr ; ptr++) if (isupper((int)*ptr)) *ptr = tolower((int)*ptr);
1380 	return str;
1381 }
1382 
1383 
xml_elem_new(void)1384 static xml_elem_t* xml_elem_new(void) {
1385 	xml_elem_t* elem = NEW(xml_elem_t);
1386 	elem->next = elem->child = NULL;
1387 	elem->parm = elem->tag = NULL;
1388 	elem->tag_id = XML_UNKNOWN_ID ;
1389 /*	LOCAL_DEBUG_OUT("elem = %p", elem); */
1390 	return elem;
1391 }
1392 
1393 static int
xml_name2id(const char * name,ASHashTable * vocabulary)1394 xml_name2id( const char *name, ASHashTable *vocabulary )
1395 {
1396 	ASHashData hdata;
1397 	hdata.i = 0 ;
1398     get_hash_item(vocabulary, AS_HASHABLE(name), &hdata.vptr);
1399 	return hdata.i;
1400 }
1401 
xml_elem_remove(xml_elem_t ** list,xml_elem_t * elem)1402 static xml_elem_t* xml_elem_remove(xml_elem_t** list, xml_elem_t* elem) {
1403 	/* Splice the element out of the list, if it's in one. */
1404 	if (list) {
1405 		if (*list == elem) {
1406 			*list = elem->next;
1407 		} else {
1408 			xml_elem_t* ptr;
1409 			for (ptr = *list ; ptr->next ; ptr = ptr->next) {
1410 				if (ptr->next == elem) {
1411 					ptr->next = elem->next;
1412 					break;
1413 				}
1414 			}
1415 		}
1416 	}
1417 	elem->next = NULL;
1418 	return elem;
1419 }
1420 
xml_insert(xml_elem_t * parent,xml_elem_t * child)1421 static void xml_insert(xml_elem_t* parent, xml_elem_t* child) {
1422 	child->next = NULL;
1423 	if (!parent->child) {
1424 		parent->child = child;
1425 		return;
1426 	}
1427 	for (parent = parent->child ; parent->next ; parent = parent->next);
1428 	parent->next = child;
1429 }
1430 
asim_xml_parse_parm(const char * parm,ASHashTable * vocabulary)1431 xml_elem_t* asim_xml_parse_parm(const char* parm, ASHashTable *vocabulary) {
1432 	xml_elem_t* list = NULL;
1433 	const char* eparm;
1434 
1435 	if (!parm) return NULL;
1436 
1437 	for (eparm = parm ; *eparm ; ) {
1438 		xml_elem_t* p;
1439 		const char* bname;
1440 		const char* ename;
1441 		const char* bval;
1442 		const char* eval;
1443 
1444 		/* Spin past any leading whitespace. */
1445 		for (bname = eparm ; isspace((int)*bname) ; bname++);
1446 
1447 		/* Check for a parm.  First is the parm name. */
1448 		for (ename = bname ; xml_tagchar((int)*ename) ; ename++);
1449 
1450 		/* No name equals no parm equals broken tag. */
1451 		if (!*ename) { eparm = NULL; break; }
1452 
1453 		/* No "=" equals broken tag.  We do not support HTML-style parms */
1454 		/* with no value.                                                */
1455 		for (bval = ename ; isspace((int)*bval) ; bval++);
1456 		if (*bval != '=') { eparm = NULL; break; }
1457 
1458 		while (isspace((int)*++bval));
1459 
1460 		/* If the next character is a quote, spin until we see another one. */
1461 		if (*bval == '"' || *bval == '\'') {
1462 			char quote = *bval;
1463 			bval++;
1464 			for (eval = bval ; *eval && *eval != quote ; eval++);
1465 		} else {
1466 			for (eval = bval ; *eval && !isspace((int)*eval) ; eval++);
1467 		}
1468 
1469 		for (eparm = eval ; *eparm && !isspace((int)*eparm) ; eparm++);
1470 
1471 		/* Add the parm to our list. */
1472 		p = xml_elem_new();
1473 		if (!list) list = p;
1474 		else { p->next = list; list = p; }
1475 		p->tag = lcstring(mystrndup(bname, ename - bname));
1476 		if( vocabulary )
1477 			p->tag_id = xml_name2id( p->tag, vocabulary );
1478 		p->parm = mystrndup(bval, eval - bval);
1479 	}
1480 
1481 	if (!eparm) {
1482 		while (list) {
1483 			xml_elem_t* p = list->next;
1484 			free(list->tag);
1485 			free(list->parm);
1486 			free(list);
1487 			list = p;
1488 		}
1489 	}
1490 
1491 	return list;
1492 }
1493 
1494 
asim_xml_elem_delete(xml_elem_t ** list,xml_elem_t * elem)1495 void asim_xml_elem_delete(xml_elem_t** list, xml_elem_t* elem) {
1496 /*	LOCAL_DEBUG_OUT("elem = %p", elem); */
1497 
1498 	if (list) xml_elem_remove(list, elem);
1499 	while (elem) {
1500 		xml_elem_t* ptr = elem;
1501 		elem = elem->next;
1502 		if (ptr->child) xml_elem_delete(NULL, ptr->child);
1503 		if (ptr->tag && ptr->tag != cdata_str && ptr->tag != container_str) free(ptr->tag);
1504 		if (ptr->parm) free(ptr->parm);
1505 		free(ptr);
1506 	}
1507 }
1508 
1509 static xml_elem_t *
create_CDATA_tag()1510 create_CDATA_tag()
1511 {
1512 	xml_elem_t *cdata = xml_elem_new();
1513 	cdata->tag = strdup(XML_CDATA_STR) ;
1514 	cdata->tag_id = XML_CDATA_ID ;
1515 	return cdata;
1516 }
1517 
1518 static xml_elem_t *
create_CONTAINER_tag()1519 create_CONTAINER_tag()
1520 {
1521 	xml_elem_t *container = xml_elem_new();
1522 	container->tag = strdup(XML_CONTAINER_STR) ;
1523 	container->tag_id = XML_CONTAINER_ID ;
1524 	return container;
1525 }
1526 
1527 
1528 
asim_xml_parse_doc(const char * str,ASHashTable * vocabulary)1529 xml_elem_t* asim_xml_parse_doc(const char* str, ASHashTable *vocabulary) {
1530 	xml_elem_t* elem = create_CONTAINER_tag();
1531 	xml_parse(str, elem, vocabulary);
1532 	return elem;
1533 }
1534 
asim_xml_parse(const char * str,xml_elem_t * current,ASHashTable * vocabulary)1535 int asim_xml_parse(const char* str, xml_elem_t* current, ASHashTable *vocabulary) {
1536 	const char* ptr = str;
1537 
1538 	/* Find a tag of the form <tag opts>, </tag>, or <tag opts/>. */
1539 	while (*ptr) {
1540 		const char* oab = ptr;
1541 
1542 		/* Look for an open oab bracket. */
1543 		for (oab = ptr ; *oab && *oab != '<' ; oab++);
1544 
1545 		/* If there are no oab brackets left, we're done. */
1546 		if (*oab != '<') return oab - str;
1547 
1548 		/* Does this look like a close tag? */
1549 		if (oab[1] == '/')
1550 		{
1551 			const char* etag;
1552 			/* Find the end of the tag. */
1553 			for (etag = oab + 2 ; xml_tagchar((int)*etag) ; etag++);
1554 
1555 			while (isspace((int)*etag)) ++etag;
1556 			/* If this is an end tag, and the tag matches the tag we're parsing, */
1557 			/* we're done.  If not, continue on blindly. */
1558 			if (*etag == '>')
1559 			{
1560 				if (!mystrncasecmp(oab + 2, current->tag, etag - (oab + 2)))
1561 				{
1562 					if (oab - ptr)
1563 					{
1564 						xml_elem_t* child = create_CDATA_tag();
1565 						child->parm = mystrndup(ptr, oab - ptr);
1566 						xml_insert(current, child);
1567 					}
1568 					return (etag + 1) - str;
1569 				}
1570 			}
1571 
1572 			/* This tag isn't interesting after all. */
1573 			ptr = oab + 1;
1574 		}
1575 
1576 		/* Does this look like a start tag? */
1577 		if (oab[1] != '/') {
1578 			int empty = 0;
1579 			const char* btag = oab + 1;
1580 			const char* etag;
1581 			const char* bparm;
1582 			const char* eparm;
1583 
1584 			/* Find the end of the tag. */
1585 			for (etag = btag ; xml_tagchar((int)*etag) ; etag++);
1586 
1587 			/* If we reached the end of the document, continue on. */
1588 			if (!*etag) { ptr = oab + 1; continue; }
1589 
1590 			/* Find the beginning of the parameters, if they exist. */
1591 			for (bparm = etag ; isspace((int)*bparm) ; bparm++);
1592 
1593 			/* From here on, we're looking for a sequence of parms, which have
1594 			 * the form [a-z0-9-]+=("[^"]"|'[^']'|[^ \t\n]), followed by either
1595 			 * a ">" or a "/>". */
1596 			for (eparm = bparm ; *eparm ; ) {
1597 				const char* tmp;
1598 
1599 				/* Spin past any leading whitespace. */
1600 				for ( ; isspace((int)*eparm) ; eparm++);
1601 
1602 				/* Are we at the end of the tag? */
1603 				if (*eparm == '>' || (*eparm == '/' && eparm[1] == '>')) break;
1604 
1605 				/* Check for a parm.  First is the parm name. */
1606 				for (tmp = eparm ; xml_tagchar((int)*tmp) ; tmp++);
1607 
1608 				/* No name equals no parm equals broken tag. */
1609 				if (!*tmp) { eparm = NULL; break; }
1610 
1611 				/* No "=" equals broken tag.  We do not support HTML-style parms
1612 				   with no value. */
1613 				for ( ; isspace((int)*tmp) ; tmp++);
1614 				if (*tmp != '=') { eparm = NULL; break; }
1615 
1616 				do { ++tmp; } while (isspace((int)*tmp));
1617 
1618 				/* If the next character is a quote, spin until we see another one. */
1619 				if (*tmp == '"' || *tmp == '\'') {
1620 					char quote = *tmp;
1621 					for (tmp++ ; *tmp && *tmp != quote ; tmp++);
1622 				}
1623 
1624 				/* Now look for a space or the end of the tag. */
1625 				for ( ; *tmp && !isspace((int)*tmp) && *tmp != '>' && !(*tmp == '/' && tmp[1] == '>') ; tmp++);
1626 
1627 				/* If we reach the end of the string, there cannot be a '>'. */
1628 				if (!*tmp) { eparm = NULL; break; }
1629 
1630 				/* End of the parm.  */
1631 				eparm = tmp;
1632 
1633 				if (!isspace((int)*tmp)) break;
1634 				for ( ; isspace((int)*tmp) ; tmp++);
1635 				if( *tmp == '>' || (*tmp == '/' && tmp[1] == '>') )
1636 					break;
1637 			}
1638 
1639 			/* If eparm is NULL, the parm string is invalid, and we should
1640 			 * abort processing. */
1641 			if (!eparm) { ptr = oab + 1; continue; }
1642 
1643 			/* Save CDATA, if there is any. */
1644 			if (oab - ptr) {
1645 				xml_elem_t* child = create_CDATA_tag();
1646 				child->parm = mystrndup(ptr, oab - ptr);
1647 				xml_insert(current, child);
1648 			}
1649 
1650 			/* We found a tag!  Advance the pointer. */
1651 			for (ptr = eparm ; isspace((int)*ptr) ; ptr++);
1652 			empty = (*ptr == '/');
1653 			ptr += empty + 1;
1654 
1655 			/* Add the tag to our children and parse it. */
1656 			{
1657 				xml_elem_t* child = xml_elem_new();
1658 				child->tag = lcstring(mystrndup(btag, etag - btag));
1659 				if( vocabulary )
1660 					child->tag_id = xml_name2id( child->tag, vocabulary );
1661 				if (eparm - bparm) child->parm = mystrndup(bparm, eparm - bparm);
1662 				xml_insert(current, child);
1663 				if (!empty) ptr += xml_parse(ptr, child, vocabulary);
1664 			}
1665 		}
1666 	}
1667 	return ptr - str;
1668 }
1669 
1670 
asim_interpret_ctrl_codes(char * text)1671 char *asim_interpret_ctrl_codes( char *text )
1672 {
1673 	register char *ptr = text ;
1674 	int len, curr = 0 ;
1675 	if( ptr == NULL )  return NULL ;
1676 
1677 	len = strlen(ptr);
1678 	while( ptr[curr] != '\0' )
1679 	{
1680 		if( ptr[curr] == '\\' && ptr[curr+1] != '\0' )
1681 		{
1682 			char subst = '\0' ;
1683 			switch( ptr[curr+1] )
1684 			{
1685 				case '\\': subst = '\\' ;  break ;
1686 				case 'a' : subst = '\a' ;  break ;
1687 				case 'b' : subst = '\b' ;  break ;
1688 				case 'f' : subst = '\f' ;  break ;
1689 				case 'n' : subst = '\n' ;  break ;
1690 				case 'r' : subst = '\r' ;  break ;
1691 				case 't' : subst = '\t' ;  break ;
1692 				case 'v' : subst = '\v' ;  break ;
1693 			}
1694 			if( subst )
1695 			{
1696 				register int i = curr ;
1697 				ptr[i] = subst ;
1698 				while( ++i < len )
1699 					ptr[i] = ptr[i+1] ;
1700 				--len ;
1701 			}
1702 		}
1703 		++curr ;
1704 	}
1705 	return text;
1706 }
1707 
asim_reset_xml_buffer(ASXmlBuffer * xb)1708 void asim_reset_xml_buffer( ASXmlBuffer *xb )
1709 {
1710 	if( xb )
1711 	{
1712 		xb->current = xb->used = 0 ;
1713 		xb->state = ASXML_Start	 ;
1714 		xb->level = 0 ;
1715 		xb->verbatim = False ;
1716 		xb->quoted = False ;
1717 		xb->tag_type = ASXML_OpeningTag ;
1718 		xb->tags_count = 0 ;
1719 	}
1720 }
1721 
1722 void
asim_free_xml_buffer_resources(ASXmlBuffer * xb)1723 asim_free_xml_buffer_resources (ASXmlBuffer *xb)
1724 {
1725 	if (xb && xb->buffer)
1726 	{
1727 		free (xb->buffer);
1728 		xb->allocated = xb->current = xb->used = 0 ;
1729 		xb->buffer = NULL;
1730 	}
1731 }
1732 
1733 static inline void
realloc_xml_buffer(ASXmlBuffer * xb,int len)1734 realloc_xml_buffer( ASXmlBuffer *xb, int len )
1735 {
1736 	if( xb->used + len > xb->allocated )
1737 	{
1738 		xb->allocated = xb->used + (((len>>11)+1)<<11) ;
1739 		xb->buffer = realloc( xb->buffer, xb->allocated );
1740 	}
1741 }
1742 
1743 void
asim_add_xml_buffer_chars(ASXmlBuffer * xb,char * tmp,int len)1744 asim_add_xml_buffer_chars( ASXmlBuffer *xb, char *tmp, int len )
1745 {
1746 	realloc_xml_buffer (xb, len);
1747 	memcpy( &(xb->buffer[xb->used]), tmp, len );
1748 	xb->used += len ;
1749 }
1750 
1751 static void
add_xml_buffer_spaces(ASXmlBuffer * xb,int len)1752 add_xml_buffer_spaces( ASXmlBuffer *xb, int len )
1753 {
1754 	if (len > 0)
1755 	{
1756 		realloc_xml_buffer (xb, len);
1757 		memset( &(xb->buffer[xb->used]), ' ', len );
1758 		xb->used += len ;
1759 	}
1760 }
1761 
1762 static void
add_xml_buffer_open_tag(ASXmlBuffer * xb,xml_elem_t * tag)1763 add_xml_buffer_open_tag( ASXmlBuffer *xb, xml_elem_t *tag )
1764 {
1765 	int tag_len = strlen (tag->tag);
1766 	int parm_len = 0;
1767 	xml_elem_t* parm = NULL ;
1768 
1769 	if (tag->parm)
1770 	{
1771 		xml_elem_t *t = parm = xml_parse_parm(tag->parm, NULL);
1772 		while (t)
1773 		{
1774 			parm_len += 1 + strlen(t->tag) + 1 + 1 + strlen(t->parm) + 1;
1775 			t = t->next;
1776 		}
1777 	}
1778 	realloc_xml_buffer (xb, 1+tag_len+1+parm_len+2);
1779 	xb->buffer[(xb->used)++] = '<';
1780 	memcpy (&(xb->buffer[xb->used]), tag->tag, tag_len);
1781 	xb->used += tag_len ;
1782 
1783 	while (parm)
1784 	{
1785 		xml_elem_t* p = parm->next;
1786 		int len;
1787 		xb->buffer[(xb->used)++] = ' ';
1788 		for (len = 0 ; parm->tag[len] ; ++len)
1789 			xb->buffer[xb->used+len] = parm->tag[len];
1790 		xb->used += len ;
1791 		xb->buffer[(xb->used)++] = '=';
1792 		xb->buffer[(xb->used)++] = '\"';
1793 		for (len = 0 ; parm->parm[len] ; ++len)
1794 			xb->buffer[xb->used+len] = parm->parm[len];
1795 		xb->used += len ;
1796 		xb->buffer[(xb->used)++] = '\"';
1797 		free(parm->tag);
1798 		free(parm->parm);
1799 		free(parm);
1800 		parm = p;
1801 	}
1802 
1803 	if (tag->child == NULL)
1804 		xb->buffer[(xb->used)++] = '/';
1805 	xb->buffer[(xb->used)++] = '>';
1806 }
1807 
1808 static void
add_xml_buffer_close_tag(ASXmlBuffer * xb,xml_elem_t * tag)1809 add_xml_buffer_close_tag( ASXmlBuffer *xb, xml_elem_t *tag )
1810 {
1811 	int tag_len = strlen (tag->tag);
1812 	realloc_xml_buffer (xb, tag_len+3);
1813 	xb->buffer[(xb->used)++] = '<';
1814 	xb->buffer[(xb->used)++] = '/';
1815 	memcpy (&(xb->buffer[xb->used]), tag->tag, tag_len);
1816 	xb->used += tag_len ;
1817 	xb->buffer[(xb->used)++] = '>';
1818 }
1819 
1820 int
asim_spool_xml_tag(ASXmlBuffer * xb,char * tmp,int len)1821 asim_spool_xml_tag( ASXmlBuffer *xb, char *tmp, int len )
1822 {
1823 	register int i = 0 ;
1824 
1825 	if( !xb->verbatim && !xb->quoted &&
1826 		(xb->state != ASXML_Start || xb->level == 0 ))
1827 	{	/* skip spaces if we are not in string */
1828 		while( i < len && isspace( (int)tmp[i] )) ++i;
1829 		if( i >= len )
1830 			return i;
1831 	}
1832 	if( xb->state == ASXML_Start )
1833 	{     /* we are looking for the opening '<' */
1834 		if( tmp[i] != '<' )
1835 		{
1836 			if( xb->level == 0 )
1837 				xb->state = ASXML_BadStart ;
1838 			else
1839 			{
1840 				int start = i ;
1841 				while( i < len && tmp[i] != '<' ) ++i ;
1842 				add_xml_buffer_chars( xb, &tmp[start], i - start );
1843 				return i;
1844 			}
1845 		}else
1846 		{
1847 			xb->state = ASXML_TagOpen;
1848 			xb->tag_type = ASXML_OpeningTag ;
1849 			add_xml_buffer_chars( xb, "<", 1 );
1850 			if( ++i >= len )
1851 				return i;
1852 		}
1853 	}
1854 
1855 	if( xb->state == ASXML_TagOpen )
1856 	{     /* we are looking for the beginning of tag name  or closing tag's slash */
1857 		if( tmp[i] == '/' )
1858 		{
1859 			xb->state = ASXML_TagName;
1860 			xb->verbatim = True ;
1861 			xb->tag_type = ASXML_ClosingTag ;
1862 			add_xml_buffer_chars( xb, "/", 1 );
1863 			if( ++i >= len )
1864 				return i;
1865 		}else if( isalnum((int)tmp[i]) )
1866 		{
1867 			xb->state = ASXML_TagName;
1868 			xb->verbatim = True ;
1869 		}else
1870 			xb->state = ASXML_BadTagName ;
1871 	}
1872 
1873 	if( xb->state == ASXML_TagName )
1874 	{     /* we are looking for the tag name */
1875 		int start = i ;
1876 		/* need to store attribute name in form : ' attr_name' */
1877 		while( i < len && isalnum((int)tmp[i]) ) ++i ;
1878 		if( i > start )
1879 			add_xml_buffer_chars( xb, &tmp[start], i - start );
1880 		if( i < len )
1881 		{
1882 			if( isspace( (int)tmp[i] ) || tmp[i] == '>' )
1883 			{
1884 				xb->state = ASXML_TagAttrOrClose;
1885 				xb->verbatim = False ;
1886 			}else
1887 				xb->state = ASXML_BadTagName ;
1888 		}
1889 		return i;
1890 	}
1891 
1892 	if( xb->state == ASXML_TagAttrOrClose )
1893 	{   /* we are looking for the atteribute or closing '/>' or '>' */
1894 		Bool has_slash = (xb->tag_type != ASXML_OpeningTag);
1895 
1896 		if( !has_slash && tmp[i] == '/' )
1897 		{
1898 			xb->tag_type = ASXML_SimpleTag ;
1899 			add_xml_buffer_chars( xb, "/", 1 );
1900 			++i ;
1901 			has_slash = True ;
1902 		}
1903 		if( i < len )
1904 		{
1905 			if( has_slash && tmp[i] != '>')
1906 				xb->state = ASXML_UnexpectedSlash ;
1907 			else if( tmp[i] == '>' )
1908 			{
1909 				++(xb->tags_count);
1910 				xb->state = ASXML_Start;
1911 	 			add_xml_buffer_chars( xb, ">", 1 );
1912 				++i ;
1913 				if( xb->tag_type == ASXML_OpeningTag )
1914 					++(xb->level);
1915 				else if( xb->tag_type == ASXML_ClosingTag )
1916 				{
1917 					if( xb->level <= 0 )
1918 					{
1919 				 		xb->state = ASXML_UnmatchedClose;
1920 						return i;
1921 					}else
1922 						--(xb->level);
1923 				}
1924 			}else if( !isalnum( (int)tmp[i] ) )
1925 				xb->state = ASXML_BadAttrName ;
1926 			else
1927 			{
1928 				xb->state = ASXML_AttrName;
1929 				xb->verbatim = True ;
1930 				add_xml_buffer_chars( xb, " ", 1);
1931 			}
1932 		}
1933 		return i;
1934 	}
1935 
1936 	if( xb->state == ASXML_AttrName )
1937 	{
1938 		int start = i ;
1939 		/* need to store attribute name in form : ' attr_name' */
1940 		while( i < len && isalnum((int)tmp[i]) ) ++i ;
1941 		if( i > start )
1942 			add_xml_buffer_chars( xb, &tmp[start], i - start );
1943 		if( i < len )
1944 		{
1945 			if( isspace( (int)tmp[i] ) || tmp[i] == '=' )
1946 			{
1947 				xb->state = ASXML_AttrEq;
1948 				xb->verbatim = False ;
1949 				/* should fall down to case below */
1950 			}else
1951 				xb->state = ASXML_BadAttrName ;
1952 		}
1953 	 	return i;
1954 	}
1955 
1956 	if( xb->state == ASXML_AttrEq )                   /* looking for '=' */
1957 	{
1958 		if( tmp[i] == '=' )
1959 		{
1960 			xb->state = ASXML_AttrValueStart;
1961 			add_xml_buffer_chars( xb, "=", 1 );
1962 			++i ;
1963 		}else
1964 			xb->state = ASXML_MissingAttrEq ;
1965 		return i;
1966 	}
1967 
1968 	if( xb->state == ASXML_AttrValueStart )/*looking for attribute value:*/
1969 	{
1970 		xb->state = ASXML_AttrValue ;
1971 		if( tmp[i] == '"' )
1972 		{
1973 			xb->quoted = True ;
1974 			add_xml_buffer_chars( xb, "\"", 1 );
1975 			++i ;
1976 		}else
1977 			xb->verbatim = True ;
1978 		return i;
1979 	}
1980 
1981 	if( xb->state == ASXML_AttrValue )  /* looking for attribute value : */
1982 	{
1983 		if( !xb->quoted && isspace((int)tmp[i]) )
1984 		{
1985 			add_xml_buffer_chars( xb, " ", 1 );
1986 			++i ;
1987 			xb->verbatim = False ;
1988 			xb->state = ASXML_TagAttrOrClose ;
1989 		}else if( xb->quoted && tmp[i] == '"' )
1990 		{
1991 			add_xml_buffer_chars( xb, "\"", 1 );
1992 			++i ;
1993 			xb->quoted = False ;
1994 			xb->state = ASXML_TagAttrOrClose ;
1995 		}else if( tmp[i] == '/' && !xb->quoted)
1996 		{
1997 			xb->state = ASXML_AttrSlash ;
1998 			add_xml_buffer_chars( xb, "/", 1 );
1999 			++i ;
2000 		}else if( tmp[i] == '>' )
2001 		{
2002 			xb->quoted = False ;
2003 			xb->verbatim = False ;
2004 			xb->state = ASXML_TagAttrOrClose ;
2005 		}else
2006 		{
2007 			add_xml_buffer_chars( xb, &tmp[i], 1 );
2008 			++i ;
2009 		}
2010 		return i;
2011 	}
2012 	if( xb->state == ASXML_AttrSlash )  /* looking for attribute value : */
2013 	{
2014 		if( tmp[i] == '>' )
2015 		{
2016 			xb->tag_type = ASXML_SimpleTag ;
2017 			add_xml_buffer_chars( xb, ">", 1 );
2018 			++i ;
2019 			++(xb->tags_count);
2020 			xb->state = ASXML_Start;
2021 			xb->quoted = False ;
2022 			xb->verbatim = False ;
2023 		}else
2024 		{
2025 			xb->state = ASXML_AttrValue ;
2026 		}
2027 		return i;
2028 	}
2029 
2030 	return (i==0)?1:i;
2031 }
2032 
2033 /* reverse transformation - put xml tags into a buffer */
2034 Bool
asim_xml_tags2xml_buffer(xml_elem_t * tags,ASXmlBuffer * xb,int tags_count,int depth)2035 asim_xml_tags2xml_buffer( xml_elem_t *tags, ASXmlBuffer *xb, int tags_count, int depth)
2036 {
2037 	Bool new_line = False;
2038 
2039 	while (tags && tags_count != 0) /* not a bug - negative tags_count means unlimited !*/
2040 	{
2041 		if (tags->tag_id == XML_CDATA_ID || !strcmp(tags->tag, cdata_str))
2042 		{
2043 			/* TODO : add handling for cdata with quotes, amps and gt, lt */
2044 			add_xml_buffer_chars( xb, tags->parm, strlen(tags->parm));
2045 		}else
2046 		{
2047 			if (depth >= 0 && (tags->child != NULL || tags->next != NULL))
2048 			{
2049 				add_xml_buffer_chars( xb, "\n", 1);
2050 				add_xml_buffer_spaces( xb, depth*2);
2051 				new_line = True ;
2052 			}
2053 			add_xml_buffer_open_tag( xb, tags);
2054 
2055 			if (tags->child)
2056 			{
2057 				if( xml_tags2xml_buffer( tags->child, xb, -1, (depth < 0)?-1:depth+1 ))
2058 				{
2059 					if (depth >= 0)
2060 					{
2061 						add_xml_buffer_chars( xb, "\n", 1);
2062 						add_xml_buffer_spaces( xb, depth*2);
2063 					}
2064 				}
2065 				add_xml_buffer_close_tag( xb, tags);
2066 			}
2067 		}
2068 		tags = tags->next;
2069 		--tags_count;
2070 	}
2071 	return new_line;
2072 }
2073 
asim_xml_print(xml_elem_t * root)2074 void asim_xml_print(xml_elem_t* root)
2075 {
2076 	ASXmlBuffer xb;
2077 	memset( &xb, 0x00, sizeof(xb));
2078 	xml_tags2xml_buffer( root, &xb, -1, 0);
2079 	add_xml_buffer_chars( &xb, "\0", 1 );
2080 	printf ("%s", xb.buffer);
2081 	free_xml_buffer_resources (&xb);
2082 }
2083 
2084 
2085 xml_elem_t *
asim_format_xml_buffer_state(ASXmlBuffer * xb)2086 asim_format_xml_buffer_state (ASXmlBuffer *xb)
2087 {
2088 	xml_elem_t *state_xml = NULL;
2089 	if (xb->state < 0)
2090 	{
2091 		state_xml = xml_elem_new();
2092 		state_xml->tag = strdup("error");
2093 		state_xml->parm = safemalloc (64);
2094 		sprintf(state_xml->parm, "code=%d level=%d tag_count=%d", xb->state, xb->level ,xb->tags_count );
2095 		state_xml->child = create_CDATA_tag();
2096 		switch( xb->state )
2097 		{
2098 			case ASXML_BadStart : state_xml->child->parm = strdup("Text encountered before opening tag bracket - not XML format"); break;
2099 			case ASXML_BadTagName : state_xml->child->parm = strdup("Invalid characters in tag name" );break;
2100 			case ASXML_UnexpectedSlash : state_xml->child->parm = strdup("Unexpected '/' encountered");break;
2101 			case ASXML_UnmatchedClose : state_xml->child->parm = strdup("Closing tag encountered without opening tag" );break;
2102 			case ASXML_BadAttrName : state_xml->child->parm = strdup("Invalid characters in attribute name" );break;
2103 			case ASXML_MissingAttrEq : state_xml->child->parm = strdup("Attribute name not followed by '=' character" );break;
2104 			default:
2105 				state_xml->child->parm = strdup("Premature end of the input");break;
2106 		}
2107 	}else if (xb->state == ASXML_Start)
2108 	{
2109 		if (xb->tags_count > 0)
2110 		{
2111 			state_xml = xml_elem_new();
2112 			state_xml->tag = strdup("success");
2113 			state_xml->parm = safemalloc(64);
2114 			sprintf(state_xml->parm, "tag_count=%d level=%d", xb->tags_count, xb->level );
2115 		}
2116 	}else
2117 	{
2118 		/* TODO */
2119 	}
2120 	return state_xml;
2121 }
2122