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