8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / cmd / svr4pkg / libinst / sml.c
blobbf74432cbc28539a2d1ed118c7e7f1120d771aed
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * Module: sml.c
30 * Synopsis: simplified markup language (SML) support
31 * Taxonomy: project private
32 * Debug flag: sml
33 * Description:
35 * This module implements methods that support the processing of a
36 * simplified markup language (SML). Objects that contain SML data
37 * can be created and manipulated, and SML can be imported into
38 * internal SML objects or exported from internal SML objects.
40 * Public Methods:
42 * smlAddTag - Add new tag object into existing tag object
43 * smlConvertStringToTag - Convert string into tag object
44 * smlConvertTagToString - Convert a tag object into a string
45 * representation of the XML
46 * smlDbgPrintTag - Print a representation of an XML tag if debugging
47 * smlDelParam - Delete a parameter from a tag object
48 * smlDelTag - Delete element from tag object
49 * smlDup - Duplicate a tag object
50 * smlFindAndDelTag - Delete a tag if found in tag object
51 * smlFreeTag - Free a tag object and all its contents when no
52 * longer needed
53 * smlFstatCompareEq - Compare file status information
54 * smlGetElementName - Return a tag's element name
55 * smlGetNumParams - Get number of parameters set in tag
56 * smlGetParam - Get a parameter from a tag
57 * smlGetParamF - Get a formatted parameter from a tag
58 * smlGetParamByTag - Get a parameter by tag and index
59 * smlGetParamByTagParam Get parameter given tag name, index,
60 * parameter name, and value
61 * smlGetParamName - Get the name of a tag parameter given its index
62 * smlGetParam_r - Get a parameter from a tag into fixed buffer
63 * smlGetTag - Get an element from a tag
64 * smlGetTagByName - Get an element given a name and an index
65 * smlGetTagByTagParam - Get element given tag name, index, parameter name,
66 * and value
67 * smlGetVerbose - get current verbose mode setting
68 * smlLoadTagFromFile - Load a file into a tag object
69 * smlNewTag - Create a new (empty) tag object
70 * smlParamEq - Determine if parameter is equal to a specified value
71 * smlParamEqF - Determine if parameter is equal to a specified value
72 * smlPrintTag - Print a simple XML representation of a tag to stderr
73 * smlReadOneTag - read one complete tag from a datastream
74 * smlReadTagFromDs - read tag object from datastream
75 * smlSetFileStatInfo - encode file status information into tag
76 * smlSetVerbose - set/clear verbose mode for debugging output
77 * smlSetParam - Set parameter value in tag object
78 * smlSetParamF - Set parameter value in tag object
79 * smlWriteTagToDs - Write an XML representation of a tag to a datastream
80 * smlWriteTagToFd - Write an XML representation of a tag to an open file
81 * descriptor
82 * smlWriteTagToFile - Write an XML representation of a tag to a file
86 * Unix includes
89 #include <locale.h>
90 #include <signal.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <libintl.h>
94 #include <stdarg.h>
95 #include <string.h>
96 #include <unistd.h>
97 #include <sys/statvfs.h>
98 #include <errno.h>
99 #include <assert.h>
100 #include <sys/types.h>
101 #include <sys/stat.h>
102 #include <fcntl.h>
103 #include <limits.h>
104 #include <strings.h>
107 * liblu Includes
110 #include "libinst.h"
111 #include "messages.h"
113 /* Should be defined by cc -D */
114 #if !defined(TEXT_DOMAIN)
115 #define TEXT_DOMAIN "SYS_TEST"
116 #endif
119 * Private Method Forward Declarations
122 /*PRINTFLIKE2*/
123 static void _smlLogMsg(LogMsgType a_type, const char *a_format, ...);
125 static int _smlReadTag(SML_TAG **r_tag, char **a_str, char *parent);
127 static int _smlWriteSimpleTag(char **a_str,
128 SML_TAG *tag);
130 static int _smlWriteParamValue(char **a_str, char *value);
132 static void _smlFreeTag(SML_TAG *tag);
134 static char *_sml_fileStatInfoTag = "File-Stat-Info";
136 static boolean_t verbose = B_FALSE;
140 * This definition controls the maximum size of any individual sml
141 * component, such as a tag name, tag *value*, etc. The code should
142 * someday be revised to dynamically allocate whatever memory is needed
143 * to hold such components while parsing, but that exercise is left for
144 * another day. Any component that exceeds this length is silently
145 * truncated...
148 #define MAX_SML_COMPONENT_LENGTH 16384
151 * Public Methods
155 * Name: smlAddTag
156 * Description: Add new tag object into existing tag object
157 * Arguments: r_tag - [RO, *RW] - (SML_TAG **)
158 * Pointer to handle to the tag object to update
159 * The handle may be updated if the tag object is
160 * moved in memory
161 * a_index - [RO] - (int)
162 * Add the tag after the "n"th tag in the tag object
163 * -1 == add the tag to the end of the tag object
164 * 0 == add the tag to the beginning of the tag object
165 * a_subTag - [RO, *RW] - (SML_TAG *)
166 * The tag to add to 'tag'
167 * Returns: SML_TAG *
168 * The location within "r_tag" where "a_subTag"
169 * has been added - this is the handle into the r_tag
170 * object to the tag that was just added
171 * Errors: If the tag object cannot be updated, the process exits
174 SML_TAG *
175 smlAddTag(SML_TAG **r_tag, int a_index, SML_TAG *a_subTag)
177 SML_TAG *tag;
179 /* entry assertions */
181 assert(SML_TAG__ISVALID(a_subTag));
182 assert(SML_TAG__R_ISVALID(r_tag));
184 /* if no tag to update specified, ignore request */
186 tag = *r_tag;
187 if (tag == SML_TAG__NULL) {
188 return (tag);
191 /* entry debugging info */
193 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_ADD_TAG,
194 a_subTag->name, tag->name);
196 /* if index is out of range or -1, append to tag object */
198 if ((a_index > tag->tags_num) || (a_index == -1)) {
199 a_index = tag->tags_num;
202 /* bump number of tags in tag object */
204 tag->tags_num++;
206 /* expand tag object to hold new subtag */
208 tag->tags = (SML_TAG *)realloc(tag->tags,
209 sizeof (SML_TAG) * tag->tags_num);
211 /* if not appending, adjust tag object to hold new subtag */
213 if (a_index < (tag->tags_num - 1)) {
214 (void) memmove(&(tag->tags[a_index + 1]), &(tag->tags[a_index]),
215 sizeof (SML_TAG) * (tag->tags_num - a_index - 1));
218 /* copy new subtag into correct location in tag object */
220 (void) memcpy(&(tag->tags[a_index]), a_subTag,
221 sizeof (SML_TAG));
223 return (&(tag->tags[a_index]));
227 * Name: smlDelTag
228 * Description: Delete element from tag object
229 * Arguments: tag - [RO, *RW] - (SML_TAG *)
230 * The tag object to update
231 * sub_tag - [RO, *RW] - (SML_TAG *)
232 * Element to be removed from the tag object
233 * Returns: void
234 * The sub_tag is removed from the tag object
235 * NOTE: The sub-tag and all elements contained within it are deallocated
236 * the sub-tag is no longer valid when this method returns
239 void
240 smlDelTag(SML_TAG *tag, SML_TAG *sub_tag)
242 int index;
244 /* entry assertions */
246 assert(SML_TAG__ISVALID(sub_tag));
248 /* if no tag to update specified, ignore request */
250 if (tag == SML_TAG__NULL) {
251 return;
254 /* entry debugging info */
256 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_DEL_TAG,
257 sub_tag->name, tag->name);
259 /* if tag object is empty, ignore request */
261 if (tag->tags_num == 0) {
262 return;
265 /* determine index into tag object of element to remove */
266 for (index = 0; index < tag->tags_num; index++) {
267 if (sub_tag == &tag->tags[index]) {
268 break;
272 /* if element not found in tag, ignore request */
274 if (index >= tag->tags_num) {
275 return;
278 /* free up the subtag to be deleted */
280 _smlFreeTag(sub_tag);
283 * if not removing last element, collapse tag object removing
284 * target element
287 if (index < (tag->tags_num - 1)) {
288 (void) memmove(&(tag->tags[index]), &(tag->tags[index + 1]),
289 sizeof (SML_TAG) *(tag->tags_num - index - 1));
292 /* one less tag object in tag */
294 tag->tags_num --;
297 * If only one tag left, then delete entire tag structure
298 * otherwise reallocate removing unneeded entry
301 if (tag->tags_num > 0) {
302 /* realloc removing last element in tag object */
304 tag->tags = (SML_TAG *)realloc(tag->tags,
305 sizeof (SML_TAG) *tag->tags_num);
306 } else {
307 tag->tags = SML_TAG__NULL;
312 * Name: smlFreeTag
313 * Description: Free a tag object and all its contents when no longer needed
314 * Arguments: tag - [RO, *RW] - (SML_TAG *)
315 * The tag object to be deleted
316 * Returns: void
317 * The tag object and all its contents are deallocated
320 void
321 smlFreeTag(SML_TAG *tag)
323 /* entry assertions */
325 assert(SML_TAG__ISVALID(tag));
327 /* entry debugging info */
329 if (tag->name != (char *)NULL) {
330 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_FREE_TAG,
331 (unsigned long)tag, tag->name);
334 /* free the tag object contents */
336 _smlFreeTag(tag);
338 /* free the tag object handle */
340 bzero(tag, sizeof (SML_TAG));
341 free(tag);
345 * Name: smlGetNumParams
346 * Synopsis: Get number of parameters set in tag
347 * Description: Return the number of parameters set in a tag
348 * Arguments: a_tag - [RO, *RO] - (SML_TAG *)
349 * The tag object to obtain the # params from
350 * Returns: int
351 * Number of parameters set in tag
352 * 0 = no parameters are set
356 smlGetNumParams(SML_TAG *a_tag)
358 return (a_tag ? a_tag->params_num : 0);
363 * Name: smlGetParam_r
364 * Description: Get a parameter from a tag into a buffer of fixed size
365 * Arguments: tag - [RO, *RO] - (SML_TAG *)
366 * The tag object to obtain the parameter from
367 * name - [RO, *RO] - (char *)
368 * Name of the parameter to retrieve
369 * buf - [RO, *RW] - (char *)
370 * Location of buffer to contain results
371 * bufLen - [RO, *RO] - (int)
372 * Maximum bytes available in buffer to contain results
373 * Returns: void
376 void
377 smlGetParam_r(SML_TAG *tag, char *name, char *buf, int bufLen)
379 int k;
381 /* entry assertions */
383 assert(name != (char *)NULL);
384 assert(*name != '\0');
385 assert(buf != (char *)NULL);
386 assert(bufLen > 0);
388 /* terminate the buffer */
390 buf[0] = '\0';
391 buf[bufLen-1] = '\0';
393 bzero(buf, bufLen);
395 /* if no tag specified, return NULL */
397 if (tag == SML_TAG__NULL) {
398 return;
401 /* if no parameters in tag, return NULL */
403 if (tag->params == NULL) {
404 return;
407 /* entry debugging info */
409 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GET_PARAM,
410 name, tag->name);
412 /* scan tag object looking for specified parameter */
414 for (k = 0; k < tag->params_num; k++) {
415 assert(tag->params[k].name != (char *)NULL);
416 assert(tag->params[k].value != (char *)NULL);
417 if (streq(tag->params[k].name, name)) {
418 _smlLogMsg(LOG_MSG_DEBUG,
419 DBG_SML_GOT_PARAM,
420 tag->name, name, tag->params[k].value);
421 (void) strncpy(buf, tag->params[k].value, bufLen-1);
422 return;
426 /* parameter not found - return */
430 * Name: smlGetParam
431 * Description: Get a parameter from a tag
432 * Arguments: tag - [RO, *RO] - (SML_TAG *)
433 * The tag object to obtain the parameter from
434 * name - [RO, *RO] - (char *)
435 * Name of the parameter to retrieve
436 * Returns: char *
437 * Value of the specified parameter
438 * == (char *)NULL if the parameter does not exist
439 * NOTE: Any parameter returned is placed in new storage for the
440 * calling method. The caller must use 'free' to dispose
441 * of the storage once the parameter is no longer needed.
444 char *
445 smlGetParam(SML_TAG *tag, char *name)
447 int k;
449 /* entry assertions */
451 assert(name != (char *)NULL);
452 assert(*name != '\0');
454 /* entry debugging info */
456 _smlLogMsg(LOG_MSG_DEBUG, "get param param <%s>", name);
458 /* if no tag specified, return NULL */
460 if (tag == SML_TAG__NULL) {
461 return ((char *)NULL);
464 /* if no parameters in tag, return NULL */
466 if (tag->params == NULL) {
467 return ((char *)NULL);
470 /* entry debugging info */
472 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GET_PARAM,
473 name, tag->name);
475 /* scan tag object looking for specified parameter */
477 for (k = 0; k < tag->params_num; k++) {
478 assert(tag->params[k].name != (char *)NULL);
479 assert(tag->params[k].value != (char *)NULL);
480 if (streq(tag->params[k].name, name)) {
481 _smlLogMsg(LOG_MSG_DEBUG,
482 DBG_SML_GOT_PARAM,
483 tag->name, name, tag->params[k].value);
484 return (strdup(tag->params[k].value));
488 /* parameter not found - return NULL */
490 return ((char *)NULL);
494 * Name: smlGetParamName
495 * Description: Get the name of a tag parameter given its index
496 * Arguments: tag - [RO, *RO] - (SML_TAG *)
497 * The tag object to obtain the parameter name from
498 * index - [RO] - (int)
499 * Index of parameter name to return
500 * Returns: char *
501 * Name of 'index'th parameter
502 * == (char *)NULL if no such parameter exists in tag
503 * NOTE: Any parameter name returned is placed in new storage for the
504 * calling method. The caller must use 'free' to dispose
505 * of the storage once the parameter name is no longer needed.
508 char *
509 smlGetParamName(SML_TAG *tag, int index)
511 /* if no tag specified, return NULL */
513 if (tag == NULL) {
514 return ((char *)NULL);
517 /* entry debugging info */
519 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GET_PARAM_NAME,
520 tag->name, index);
522 /* if no parameters in tag, return NULL */
524 if (tag->params == NULL) {
525 return ((char *)NULL);
528 /* if index not within range, return NULL */
530 if (index >= tag->params_num) {
531 return ((char *)NULL);
534 /* index within range - return parameter name */
536 assert(tag->params[index].name != (char *)NULL);
537 assert(tag->params[index].value != (char *)NULL);
539 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GOT_PARAM_NAME,
540 tag->name, index, tag->params[index].name);
542 return (strdup(tag->params[index].name));
546 * Name: smlGetParamByTag
547 * Synopsis: Get a parameter value from a tag by name and index
548 * Description: Call to look for a parameter value from a tag with
549 * a given name with a parameter of a given name
550 * Arguments: tag - [RO, *RO] - (SML_TAG *)
551 * The tag object to obtain the parameter
552 * index - [RO] - (int)
553 * Index of nth tag by name to look for
554 * tagName - [RO, *RO] - (char *)
555 * Name of tag to look for
556 * paramName - [RO, *RO] - (char *)
557 * Name of parameter to return value of
558 * Returns: char *
559 * == (char *)NULL - no parameter value set
560 * != (char *)NULL - value of parameter set
563 char *
564 smlGetParamByTag(SML_TAG *tag, int index,
565 char *tagName, char *paramName)
567 SML_TAG *rtag;
569 /* entry assertions */
571 assert(SML_TAG__ISVALID(tag));
572 assert(tagName != (char *)NULL);
573 assert(*tagName != '\0');
574 assert(paramName != (char *)NULL);
575 assert(*paramName != '\0');
577 /* entry debugging info */
579 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GET_PARAM_BY_TAG,
580 tagName, index, paramName);
582 /* find the requested tag by name and index */
584 rtag = smlGetTagByName(tag, index, tagName);
585 if (rtag == SML_TAG__NULL) {
586 return ((char *)NULL);
589 return (smlGetParam(rtag, paramName));
593 * Name: smlGetTagByTagParam
594 * Synopsis: Get element given tag name, index, parameter name, and value
595 * Description: Call to look for a tag with a given nae, that has a parameter
596 * of a given name with a specified value
597 * Arguments: tag - [RO, *RO] - (SML_TAG *)
598 * The tag object to obtain the element from
599 * index - [RO] - (int)
600 * Index of nth name to return
601 * tagName - [RO, *RO] - (char *)
602 * Tag name to look up
603 * paramName - [RO, *RO] - (char *)
604 * Parameter name to look up
605 * paramValue - [RO, *RO] - (char *)
606 * Parameter value to match
607 * Returns: SML_TAG *
608 * The 'index'th occurance of element 'name' with
609 * a parameter 'name' with value specified
610 * == SML_TAG__NULL if no such element exists
613 SML_TAG *
614 smlGetTagByTagParam(SML_TAG *tag, int index,
615 char *tagName, char *paramName, char *paramValue)
617 int ti; /* tag structure index */
619 /* entry assertions */
621 assert(SML_TAG__ISVALID(tag));
622 assert(tagName != (char *)NULL);
623 assert(*tagName != '\0');
624 assert(paramName != (char *)NULL);
625 assert(*paramName != '\0');
626 assert(paramValue != (char *)NULL);
627 assert(*paramValue != '\0');
629 /* if tag has no elements, return NULL */
631 if (tag->tags == NULL) {
632 return (SML_TAG__NULL);
636 * Search algorithm:
637 * -> search tag structure; for each tag with element == "tagName":
638 * -> search tag parameters; if parameter name == "paramName"
639 * -> if parameter value != "paramValue"; to next tag
640 * -> if parameter value == "paramValue":
641 * -> if not the "index"th paramValue found; to next tag
642 * -> return tag found
645 for (ti = 0; ti < tag->tags_num; ti++) {
646 int pi; /* parameter structure index */
648 /* if tag element does not match, go on to next tag */
650 if (strcmp(tag->tags[ti].name, tagName)) {
651 continue;
654 /* element matches: search for specified parameter name/value */
656 for (pi = 0; pi < tag->tags[ti].params_num; pi++) {
657 assert(tag->tags[ti].params[pi].name != (char *)NULL);
658 assert(tag->tags[ti].params[pi].value != (char *)NULL);
660 /* if parameter name doesnt match to next parameter */
662 if (strcmp(tag->tags[ti].params[pi].name, paramName)) {
663 continue;
666 /* if parameter value doesnt match to next tag */
668 if (strcmp(tag->tags[ti].params[pi].value,
669 paramValue)) {
670 break;
674 * found element/paramname/paramvalue:
675 * -> if this is not the 'index'th one, go to next tag
678 if (index-- != 0) {
679 break;
683 * found specified element/paramname/paramvalue:
684 * -> return the tag found
687 return (&tag->tags[ti]);
692 /* no such element found - return NULL */
694 return (SML_TAG__NULL);
698 * Name: smlGetParamByTagParam
699 * Synopsis: Get parameter given tag name, index, parameter name, and value
700 * Description: Call to return the value of a parameter from a tag of a
701 * given name, with a parameter of a given name with a
702 * specified value
703 * Arguments: tag - [RO, *RO] - (SML_TAG *)
704 * The tag object to obtain the element from
705 * index - [RO] - (int)
706 * Index of nth name to return
707 * tagName - [RO, *RO] - (char *)
708 * Tag name to look up
709 * paramName - [RO, *RO] - (char *)
710 * Parameter name to look up
711 * paramValue - [RO, *RO] - (char *)
712 * Parameter value to match
713 * paramReturn - [RO, *RO] - (char *)
714 * Parameter name to return the value of
715 * Returns: char *
716 * The value of parameter 'paramReturn' from the
717 * The 'index'th occurance of element 'name' with
718 * a parameter 'name' with value specified
719 * == (char *)NULL if no such parameter exists
722 char *
723 smlGetParamByTagParam(SML_TAG *tag, int index,
724 char *tagName, char *paramName, char *paramValue, char *paramReturn)
726 int ti; /* tag structure index */
728 /* entry assertions */
730 assert(SML_TAG__ISVALID(tag));
731 assert(tagName != (char *)NULL);
732 assert(*tagName != '\0');
733 assert(paramName != (char *)NULL);
734 assert(*paramName != '\0');
735 assert(paramValue != (char *)NULL);
736 assert(*paramValue != '\0');
737 assert(paramReturn != (char *)NULL);
738 assert(*paramReturn != '\0');
740 /* if tag has no elements, return NULL */
742 if (tag->tags == NULL) {
743 return ((char *)NULL);
747 * Search algorithm:
748 * -> search tag structure; for each tag with element == "tagName":
749 * -> search tag parameters; if parameter name == "paramName"
750 * -> if parameter value != "paramValue"; to next tag
751 * -> if parameter value == "paramValue":
752 * -> if not the "index"th paramValue found; to next tag
753 * -> return value of "paramReturn"
756 for (ti = 0; ti < tag->tags_num; ti++) {
757 int pi; /* parameter structure index */
759 /* if tag element does not match, go on to next tag */
761 if (strcmp(tag->tags[ti].name, tagName)) {
762 continue;
765 /* element matches: search for specified parameter name/value */
767 for (pi = 0; pi < tag->tags[ti].params_num; pi++) {
768 assert(tag->tags[ti].params[pi].name != (char *)NULL);
769 assert(tag->tags[ti].params[pi].value != (char *)NULL);
771 /* if parameter name doesnt match to next parameter */
773 if (strcmp(tag->tags[ti].params[pi].name, paramName)) {
774 continue;
777 /* if parameter value doesnt match to next tag */
779 if (strcmp(tag->tags[ti].params[pi].value,
780 paramValue)) {
781 break;
785 * found element/paramname/paramvalue:
786 * -> if this is not the 'index'th one, go to next tag
789 if (index-- != 0) {
790 break;
794 * found specified element/paramname/paramvalue:
795 * -> return parameter requested
798 return (smlGetParam(&tag->tags[ti], paramReturn));
803 /* no such element found - return NULL */
805 return ((char *)NULL);
809 * Name: smlGetElementName
810 * Description: Return the name of a given tag
811 * Arguments: a_tag - [RO, *RO] - (SML_TAG *)
812 * The tag object to obtain the element name from
813 * Returns: char *
814 * Value of name of specified tag
815 * NOTE: Any name string returned is placed in new storage for the
816 * calling method. The caller must use 'free' to dispose
817 * of the storage once the name string is no longer needed.
820 char *
821 smlGetElementName(SML_TAG *a_tag)
823 /* entry assertions */
825 assert(SML_TAG__ISVALID(a_tag));
826 assert(a_tag->name != (char *)NULL);
827 assert(*a_tag->name != '\0');
829 /* return the tag name */
831 return (strdup(a_tag->name));
835 * Name: smlGetTag
836 * Description: Get an element from a tag
837 * Arguments: tag - [RO, *RO] - (SML_TAG *)
838 * The tag object to obtain the element from
839 * index - [RO] - (int)
840 * Index of element to return
841 * Returns: SML_TAG *
842 * The 'index'th element from the specified tag
843 * == SML_TAG__NULL if no such tag or element
846 SML_TAG *
847 smlGetTag(SML_TAG *tag, int index)
849 /* if no tag specified, return NULL */
851 if (tag == NULL) {
852 return (SML_TAG__NULL);
855 /* if tag has no elements, return NULL */
857 if (tag->tags == NULL) {
858 return (SML_TAG__NULL);
861 /* if index not within range, return NULL */
863 if (tag->tags_num <= index) {
864 return (SML_TAG__NULL);
867 /* index within range, return element specified */
869 assert(SML_TAG__ISVALID(&tag->tags[index]));
871 return (&tag->tags[index]);
875 * Name: smlGetTagByName
876 * Description: Get an element given a name and an index
877 * Arguments: tag - [RO, *RO] - (SML_TAG *)
878 * The tag object to obtain the element from
879 * index - [RO] - (int)
880 * Index of nth name to return
881 * name - [RO, *RO] - (char *)
882 * Tag name to look up
883 * Returns: SML_TAG *
884 * The 'index'th occurance of element 'name'
885 * == SML_TAG__NULL if no such element exists
888 SML_TAG *
889 smlGetTagByName(SML_TAG *tag, int index, char *name)
891 int k;
893 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_GET_TAG_BY_NAME, name, index);
895 /* if no tag specified, return NULL */
897 if (tag == NULL) {
898 return (SML_TAG__NULL);
901 /* if this tag is the one mentioned, return it */
903 if (streq(tag->name, name) && (index == 0)) {
904 return (tag);
907 /* if tag has no elements, return NULL */
909 if (tag->tags == NULL) {
910 return (SML_TAG__NULL);
913 /* if index out of range, return NULL */
915 if (tag->tags_num <= index) {
916 return (SML_TAG__NULL);
919 /* index within range - search for specified element */
921 for (k = 0; k < tag->tags_num; k++) {
922 if (streq(tag->tags[k].name, name)) {
923 if (index == 0) {
924 assert(SML_TAG__ISVALID(&tag->tags[k]));
925 return (&tag->tags[k]);
926 } else {
927 index--;
932 /* no such element found - return NULL */
934 return (SML_TAG__NULL);
938 * Name: smlConvertStringToTag
939 * Description: Convert string into tag object
940 * Arguments: err - [RO, *RW] (LU_ERR)
941 * Error object - used to contain any errors encountered
942 * and return those errors to this methods caller
943 * r_tag - [RW, *RW] - (SML_TAG **)
944 * Pointer to handle to place new tag object
945 * str - [RO, *RO] - (char *)
946 * String object to convert to tag object
947 * Returns: int
948 * RESULT_OK - string converted to tag object
949 * RESULT_ERR - problem converting string to tag object
950 * NOTE: Any tag object returned is placed in new storage for the
951 * calling method. The caller must use 'smlFreeTag' to dispose
952 * of the storage once the tag object name is no longer needed.
956 smlConvertStringToTag(SML_TAG **r_tag, char *str)
958 int r;
959 SML_TAG *tag = SML_TAG__NULL;
960 SML_TAG *tmp_tag;
962 /* entry assertions */
964 assert(SML_TAG__R_ISVALID(r_tag));
965 assert(str != (char *)NULL);
966 assert(*str != '\0');
968 tag = smlNewTag("tagfile");
970 for (;;) {
971 r = _smlReadTag(&tmp_tag, &str, NULL);
972 if (r != RESULT_OK) {
973 smlFreeTag(tag);
974 return (r);
976 if (tmp_tag == SML_TAG__NULL) {
977 if (*str != '\0') {
978 continue;
980 _smlLogMsg(LOG_MSG_DEBUG,
981 DBG_SML_LOADED_TAGS_FROM_STR,
982 (unsigned long)tag, tag->name);
983 *r_tag = tag;
984 return (RESULT_OK);
986 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_READ_IN_TOP_TAG,
987 tmp_tag->name);
988 tag->tags_num++;
989 tag->tags = (SML_TAG *)realloc(tag->tags,
990 sizeof (SML_TAG) *tag->tags_num);
991 (void) memcpy(&(tag->tags[tag->tags_num - 1]), tmp_tag,
992 sizeof (SML_TAG));
997 * Name: smlReadOneTag
998 * Description: read one complete tag from a datastream
999 * Arguments: err - [RO, *RW] (LU_ERR)
1000 * Error object - used to contain any errors encountered
1001 * and return those errors to this methods caller
1002 * r_tag - [RW, *RW] - (SML_TAG **)
1003 * Pointer to handle to place new tag object
1004 * == SML_TAG__NULL if empty tag found (not an error)
1005 * ds - [RO, *RO] - (LU_DS)
1006 * Handle to datastream to read tag from
1007 * Returns: int
1008 * RESULT_OK - tag successfully read
1009 * RESULT_ERR - problem reading tag
1010 * NOTE: Any tag object returned is placed in new storage for the
1011 * calling method. The caller must use 'smlFreeTag' to dispose
1012 * of the storage once the tag object name is no longer needed.
1016 smlReadOneTag(SML_TAG **r_tag, char *a_str)
1018 int r;
1020 /* entry assertions */
1022 assert(SML_TAG__R_ISVALID(r_tag));
1023 assert(a_str != (char *)NULL);
1025 /* entry debugging info */
1027 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_READ_ONE_TAG, a_str);
1029 /* reset return tag */
1031 *r_tag = SML_TAG__NULL;
1033 /* read tag from datastream, no parent tag to attach it to */
1035 r = _smlReadTag(r_tag, &a_str, NULL);
1036 if (r != RESULT_OK) {
1037 _smlLogMsg(LOG_MSG_ERR, ERR_SML_CANNOT_READ_TAG);
1038 return (r);
1041 if (*r_tag != SML_TAG__NULL) {
1042 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_ONE_TAG_READ,
1043 (unsigned long)*r_tag,
1044 (*r_tag)->name ? (*r_tag)->name : "<no name>");
1045 } else {
1046 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_READ_ONE_TAG_NOTAG);
1049 /* exit debugging info */
1051 return (RESULT_OK);
1055 * Name: smlNewTag
1056 * Description: Create a new (empty) tag object
1057 * Arguments: name - [RO, *RO] - (char *)
1058 * Name of tag; NULL to give the tag no name
1059 * Returns: SML_TAG *
1060 * Tag object created
1061 * NOTE: Any tag object returned is placed in new storage for the
1062 * calling method. The caller must use 'smlFreeTag' to dispose
1063 * of the storage once the tag object name is no longer needed.
1064 * Errors: If the tag object cannot be created, the process exits
1067 SML_TAG *
1068 smlNewTag(char *name)
1070 SML_TAG *tag;
1072 /* entry assertions */
1074 assert((name == (char *)NULL) || (*name != '\0'));
1076 /* entry debugging info */
1078 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_CREATE_NEW_TAG_OBJECT,
1079 name ? name : "<no name>");
1081 /* allocate zeroed storage for the tag object */
1083 tag = (SML_TAG *)calloc(1, sizeof (SML_TAG));
1084 assert(tag != SML_TAG__NULL);
1086 /* if name is provided, duplicate and assign it */
1088 if (name != (char *)NULL) {
1089 tag->name = strdup(name);
1092 /* exit assertions */
1094 assert(SML_TAG__ISVALID(tag));
1096 /* exit debugging info */
1098 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_CREATED_NEW_TAG_OBJECT,
1099 (unsigned long)tag, name ? name : "<no name>");
1101 return (tag);
1105 * Name: smlConvertTagToString
1106 * Description: Convert a tag object into a string representation of the XML
1107 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1108 * The tag object to convert to a string
1109 * Returns: char *
1110 * String representation (in XML) of tag object
1111 * == (char *)NULL if conversion is not possible
1112 * NOTE: Any string returned is placed in new storage for the
1113 * calling method. The caller must use 'free' to dispose
1114 * of the storage once the string is no longer needed.
1117 char *
1118 smlConvertTagToString(SML_TAG *tag)
1120 char *str = (char *)NULL;
1122 /* entry assertions */
1124 assert(SML_TAG__ISVALID(tag));
1126 /* convert the tag object into the datastream */
1128 (void) _smlWriteSimpleTag(&str, tag);
1130 assert(str != (char *)NULL);
1131 assert(*str != '\0');
1133 /* return the results */
1135 return (str);
1139 * Name: smlDbgPrintTag
1140 * Synopsis: Print a representation of an XML tag if debugging
1141 * Arguments: a_tag - [RO, *RO] - (SML_TAG *)
1142 * Pointer to tag structure to dump
1143 * a_format - [RO, RO*] (char *)
1144 * printf-style format for debugging message to be output
1145 * VARG_LIST - [RO] (?)
1146 * arguments as appropriate to 'format' specified
1147 * Returns: void
1148 * If one of the debugging flags is set, the hexdump
1149 * is output.
1152 /*PRINTFLIKE2*/
1153 void
1154 smlDbgPrintTag(SML_TAG *a_tag, char *a_format, ...)
1156 va_list ap;
1157 size_t vres = 0;
1158 char bfr[1];
1159 char *rstr = (char *)NULL;
1161 /* entry assertions */
1163 assert(a_format != (char *)NULL);
1164 assert(*a_format != '\0');
1165 assert(SML_TAG__ISVALID(a_tag));
1168 * output the message header
1171 /* determine size of the message in bytes */
1173 va_start(ap, a_format);
1174 vres = vsnprintf(bfr, 1, a_format, ap);
1175 va_end(ap);
1177 assert(vres > 0);
1179 /* allocate storage to hold the message */
1181 rstr = (char *)calloc(1, vres+2);
1182 assert(rstr != (char *)NULL);
1184 /* generate the results of the printf conversion */
1186 va_start(ap, a_format);
1187 vres = vsnprintf(rstr, vres+1, a_format, ap);
1188 va_end(ap);
1190 assert(vres > 0);
1191 assert(*rstr != '\0');
1193 _smlLogMsg(LOG_MSG_DEBUG, "%s", rstr);
1194 free(rstr);
1196 /* convert the tag into a string to be printed */
1198 rstr = smlConvertTagToString(a_tag);
1199 if (rstr != (char *)NULL) {
1200 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_PRINTTAG, a_tag->name,
1201 strlen(rstr), rstr);
1203 free(rstr);
1207 * Name: smlDelParam
1208 * Description: Delete a parameter from a tag object
1209 * Arguments: tag - [RO, *RW] - (SML_TAG *)
1210 * The tag object to delete the parameter from
1211 * name - [RO, *RO] - (char *)
1212 * The parameter to delete from the tag object
1213 * Returns: void
1214 * If the parameter exists, it is deleted from the tag
1217 void
1218 smlDelParam(SML_TAG *tag, char *name)
1220 int k;
1222 /* entry assertions */
1224 assert(SML_TAG__ISVALID(tag));
1225 assert(tag->name != (char *)NULL);
1226 assert(name != NULL);
1227 assert(*name != '\0');
1229 /* entry debugging info */
1231 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_DELETE_PARAM,
1232 tag->name, name);
1234 /* if tag has no parameters, nothing to delete */
1236 if (tag->params == NULL) {
1237 _smlLogMsg(LOG_MSG_DEBUG,
1238 DBG_SML_DELETE_PARAM_NO_PARAMS);
1239 return;
1242 assert(tag->params_num > 0);
1244 /* search the tag for the parameter */
1246 for (k = 0; k < tag->params_num; k++) {
1247 if (streq(tag->params[k].name, name)) {
1248 break;
1252 /* if the parameter was not found, nothing to delete */
1254 if (k >= tag->params_num) {
1255 _smlLogMsg(LOG_MSG_DEBUG,
1256 DBG_SML_DELETE_PARAM_NOT_FOUND,
1257 name);
1258 return;
1261 /* parameter found - indicate deleted */
1263 assert(tag->params[k].name != (char *)NULL);
1264 assert(tag->params[k].value != (char *)NULL);
1266 _smlLogMsg(LOG_MSG_DEBUG,
1267 DBG_SML_DELETE_PARAM_FOUND,
1268 name, tag->params[k].value);
1270 /* free up storage fro parameter */
1272 free(tag->params[k].name);
1273 free(tag->params[k].value);
1275 /* if not at end, compact parameter storage */
1277 if (k < (tag->params_num -1)) {
1278 (void) memmove(&(tag->params[k]), &(tag->params[k + 1]),
1279 sizeof (SML_PARAM) *(tag->params_num - k - 1));
1282 /* one less parameter object in tag */
1284 tag->params_num --;
1287 * If only one parameter left, then delete entire parameter storage,
1288 * otherwise reallocate removing unneeded entry
1291 if (tag->params_num > 0) {
1292 /* realloc removing last element in tag object */
1294 tag->params = (SML_PARAM *)
1295 realloc(tag->params,
1296 sizeof (SML_PARAM) *tag->params_num);
1297 } else {
1298 tag->params = (SML_PARAM *)NULL;
1303 * Name: smlSetParamF
1304 * Description: Set formatted parameter value in tag object
1305 * Arguments: tag - [RO, *RW] - (SML_TAG *)
1306 * The tag object to set the parameter in
1307 * name - [RO, *RO] - (char *)
1308 * The parameter to add to the tag object
1309 * format - [RO, RO*] (char *)
1310 * printf-style format to create parameter value from
1311 * ... - [RO] (?)
1312 * arguments as appropriate to 'format' specified
1313 * Returns: void
1314 * The parameter value is set in the tag object
1315 * according to the results of the format string
1316 * and arguments
1319 /*PRINTFLIKE3*/
1320 void
1321 smlSetParamF(SML_TAG *tag, char *name, char *format, ...)
1323 va_list ap;
1324 size_t vres = 0;
1325 char *bfr = NULL;
1326 char fbfr[1];
1328 /* entry assertions */
1330 assert(SML_TAG__ISVALID(tag));
1331 assert(name != (char *)NULL);
1332 assert(*name != '\0');
1333 assert(format != NULL);
1334 assert(*format != '\0');
1336 /* determine size of the parameter name in bytes */
1338 va_start(ap, format);
1339 vres = vsnprintf(fbfr, 1, format, ap);
1340 va_end(ap);
1342 assert(vres > 0);
1344 /* allocate storage to hold the message */
1346 bfr = (char *)calloc(1, vres+2);
1347 assert(bfr != (char *)NULL);
1349 /* generate the parameter name and store it in the allocated storage */
1351 va_start(ap, format);
1352 vres = vsnprintf(bfr, vres+1, format, ap);
1353 va_end(ap);
1355 assert(vres > 0);
1356 assert(*bfr != '\0');
1358 /* add the parameter to the tag */
1360 smlSetParam(tag, name, bfr);
1362 /* free up temporary storage and return */
1364 free(bfr);
1368 * Name: smlGetParam
1369 * Description: Get a format-generated parameter from a tag
1370 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1371 * The tag object to obtain the parameter from
1372 * format - [RO, RO*] (char *)
1373 * printf-style format for parameter name to be
1374 * looked up to be formatted
1375 * ... - [RO] (?)
1376 * arguments as appropriate to 'format' specified
1377 * Returns: char *
1378 * Value of the specified parameter
1379 * == (char *)NULL if the parameter does not exist
1380 * NOTE: Any parameter returned is placed in new storage for the
1381 * calling method. The caller must use 'free' to dispose
1382 * of the storage once the parameter is no longer needed.
1385 /*PRINTFLIKE2*/
1386 char *
1387 smlGetParamF(SML_TAG *tag, char *format, ...)
1389 va_list ap;
1390 size_t vres = 0;
1391 char *bfr = NULL;
1392 char fbfr[1];
1393 char *p;
1395 /* entry assertions */
1397 assert(SML_TAG__ISVALID(tag));
1398 assert(format != NULL);
1399 assert(*format != '\0');
1401 /* determine size of the parameter name in bytes */
1403 va_start(ap, format);
1404 vres = vsnprintf(fbfr, 1, format, ap);
1405 va_end(ap);
1407 assert(vres > 0);
1409 /* allocate storage to hold the message */
1411 bfr = (char *)calloc(1, vres+2);
1412 assert(bfr != (char *)NULL);
1414 /* generate the parameter name and store it in the allocated storage */
1416 va_start(ap, format);
1417 vres = vsnprintf(bfr, vres+1, format, ap);
1418 va_end(ap);
1420 assert(vres > 0);
1421 assert(*bfr != '\0');
1423 /* add the parameter to the tag */
1425 p = smlGetParam(tag, bfr);
1427 /* free up temporary storage and return */
1429 free(bfr);
1431 return (p);
1435 * Name: smlSetParam
1436 * Description: Set parameter value in tag object
1437 * Arguments: tag - [RO, *RW] - (SML_TAG *)
1438 * The tag object to set the parameter in
1439 * name - [RO, *RO] - (char *)
1440 * The parameter to add to the tag object
1441 * value - [RO, *RO] - (char *)
1442 * The value of the parameter to set in the tag object
1443 * Returns: void
1444 * The parameter value is set in the tag object
1447 void
1448 smlSetParam(SML_TAG *tag, char *name, char *value)
1450 SML_PARAM *parameter;
1452 /* entry assertions */
1454 assert(SML_TAG__ISVALID(tag));
1455 assert(name != (char *)NULL);
1456 assert(*name != '\0');
1457 assert(value != (char *)NULL);
1459 /* entry debugging info */
1461 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_SET_PARAM,
1462 tag->name, name, value);
1464 /* if parameters exist, see if modifying existing parameter */
1466 if (tag->params != NULL) {
1467 int k;
1468 for (k = 0; k < tag->params_num; k++) {
1469 assert(tag->params[k].name != (char *)NULL);
1470 assert(tag->params[k].value != (char *)NULL);
1472 /* if name does not match, skip */
1474 if (!streq(tag->params[k].name, name)) {
1475 continue;
1478 /* found parameter - if value is same, leave alone */
1480 if (streq(tag->params[k].value, value)) {
1481 _smlLogMsg(LOG_MSG_DEBUG,
1482 DBG_SML_SET_PARAM_LEAVE_ALONE,
1483 tag->params[k].value);
1484 return;
1487 /* exists and has different value - change */
1489 _smlLogMsg(LOG_MSG_DEBUG,
1490 DBG_SML_SET_PARAM_MODIFY,
1491 tag->params[k].value);
1492 free(tag->params[k].value);
1493 tag->params[k].value = strdup(value);
1494 return;
1498 /* not modifying existing - add new parameter */
1500 _smlLogMsg(LOG_MSG_DEBUG,
1501 DBG_SML_SET_PARAM_CREATE_NEW);
1503 parameter = (SML_PARAM *)calloc(1, sizeof (SML_PARAM));
1504 bzero(parameter, sizeof (SML_PARAM));
1505 parameter->name = strdup(name);
1506 parameter->value = strdup(value);
1508 tag->params_num++;
1509 tag->params = (SML_PARAM *)realloc(tag->params,
1510 sizeof (SML_PARAM) *tag->params_num);
1511 (void) memcpy(&(tag->params[tag->params_num - 1]), parameter,
1512 sizeof (SML_PARAM));
1513 free(parameter);
1517 * Name: smlParamEqF
1518 * Description: Determine if parameter is equal to a specified formatted value
1519 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1520 * The tag object to look for the parameter to compare
1521 * findTag - [RO, *RO] - (char *)
1522 * Tag within tag object to look for the parameter in
1523 * findParam - [RO, *RO] - (char *)
1524 * Parameter within tag to look for
1525 * format - [RO, RO*] (char *)
1526 * printf-style format for value to be compared against
1527 * parameter value
1528 * ... - [RO] (?)
1529 * arguments as appropriate to 'format' specified to
1530 * generate the value to compare parameter with
1531 * Returns: boolean_t
1532 * B_TRUE - the parameter exists and matches given value
1533 * B_FALSE - parameter does not exist or does not match
1536 /*PRINTFLIKE4*/
1537 boolean_t
1538 smlParamEqF(SML_TAG *tag, char *findTag, char *findParam, char *format, ...)
1540 va_list ap;
1541 size_t vres = 0;
1542 char *bfr = NULL;
1543 char fbfr[1];
1544 boolean_t b;
1546 /* entry assertions */
1548 assert(SML_TAG__ISVALID(tag));
1549 assert(format != NULL);
1550 assert(*format != '\0');
1552 /* determine size of the parameter value in bytes */
1554 va_start(ap, format);
1555 vres = vsnprintf(fbfr, 1, format, ap);
1556 va_end(ap);
1558 assert(vres > 0);
1560 /* allocate storage to hold the message */
1562 bfr = (char *)calloc(1, vres+2);
1563 assert(bfr != (char *)NULL);
1565 /* generate the parameter value and store it in the allocated storage */
1567 va_start(ap, format);
1568 vres = vsnprintf(bfr, vres+1, format, ap);
1569 va_end(ap);
1571 assert(vres > 0);
1572 assert(*bfr != '\0');
1574 /* add the parameter to the tag */
1576 b = smlParamEq(tag, findTag, findParam, bfr);
1578 /* free up temporary storage and return */
1580 free(bfr);
1582 return (b);
1586 * Name: smlParamEq
1587 * Description: Determine if parameter is equal to a specified value
1588 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1589 * The tag object to look for the parameter to compare
1590 * findTag - [RO, *RO] - (char *)
1591 * Tag within tag object to look for the parameter in
1592 * findParam - [RO, *RO] - (char *)
1593 * Parameter within tag to look for
1594 * str - [RO, *RO] - (char *)
1595 * Value to compare parameter with
1596 * Returns: boolean_t
1597 * B_TRUE - the parameter exists and matches given value
1598 * B_FALSE - parameter does not exist or does not match
1601 boolean_t
1602 smlParamEq(SML_TAG *tag, char *findTag, char *findParam, char *str)
1604 SML_TAG *rtag;
1605 char *rparm;
1606 boolean_t answer;
1608 /* entry assertions */
1610 assert(str != (char *)NULL);
1611 assert(findParam != (char *)NULL);
1612 assert(findTag != (char *)NULL);
1613 assert(SML_TAG__ISVALID(tag));
1615 /* look for the specified tag - if not found, return false */
1617 rtag = smlGetTagByName(tag, 0, findTag);
1618 if (rtag == SML_TAG__NULL) {
1619 return (B_FALSE);
1622 /* look for the specified parameter - if not found, return false */
1624 rparm = smlGetParam(rtag, findParam);
1625 if (rparm == (char *)NULL) {
1626 return (B_FALSE);
1629 /* parameter found - compare against given value */
1631 answer = strcasecmp(str, rparm);
1633 /* free up parameter storage */
1635 free(rparm);
1637 /* return results of comparison */
1639 return (answer == 0 ? B_TRUE : B_FALSE);
1643 * Name: smlFindAndDelTag
1644 * Description: Delete a tag if found in tag object
1645 * Arguments: tag - [RO, *RW] - (SML_TAG *)
1646 * The tag object to delete the tag from
1647 * findTag - [RO, *RO] - (char *)
1648 * Tag within tag object to delete
1649 * Returns: boolean_t
1650 * B_TRUE - tag found and deleted
1651 * B_FALSE - tag not found
1654 boolean_t
1655 smlFindAndDelTag(SML_TAG *tag, char *findTag)
1657 SML_TAG *rtag = SML_TAG__NULL;
1659 /* entry assertions */
1661 assert(SML_TAG__ISVALID(tag));
1662 assert(findTag != (char *)NULL);
1663 assert(*findTag != '\0');
1665 /* find the specified tag - if not found, return false */
1667 rtag = smlGetTagByName(tag, 0, findTag);
1668 if (rtag == SML_TAG__NULL) {
1669 return (B_FALSE);
1672 /* tag found - delete it and return true */
1674 smlDelTag(tag, rtag);
1676 return (B_TRUE);
1680 * Name: smlDup
1681 * Description: Duplicate a tag object
1682 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1683 * The tag object to duplicate
1684 * Returns: SML_TAG *
1685 * A handle to a complete duplicate of the tag provided
1686 * NOTE: Any tag object returned is placed in new storage for the
1687 * calling method. The caller must use 'smlFreeTag' to dispose
1688 * of the storage once the tag object name is no longer needed.
1689 * Errors: If the tag object cannot be duplicated, the process exits
1692 SML_TAG *
1693 smlDup(SML_TAG *tag)
1695 SML_TAG *rtag = SML_TAG__NULL;
1696 int i;
1698 /* entry assertions */
1700 assert(SML_TAG__ISVALID(tag));
1702 /* allocate zeroed storage for the tag object */
1704 rtag = (SML_TAG *)calloc(1, sizeof (SML_TAG));
1705 assert(rtag != SML_TAG__NULL);
1707 /* duplicate all parameters of the tag */
1709 rtag->name = (tag->name ? strdup(tag->name) : (char *)NULL);
1710 rtag->params_num = tag->params_num;
1711 if (tag->params != (SML_PARAM *)NULL) {
1712 rtag->params = (SML_PARAM *)
1713 calloc(1, sizeof (SML_PARAM)*rtag->params_num);
1714 bzero(rtag->params, sizeof (SML_PARAM)*rtag->params_num);
1715 for (i = 0; i < rtag->params_num; i++) {
1716 rtag->params[i].name = tag->params[i].name ?
1717 strdup(tag->params[i].name) :
1718 (char *)NULL;
1719 rtag->params[i].value = tag->params[i].value ?
1720 strdup(tag->params[i].value) :
1721 (char *)NULL;
1725 /* duplicate all elements of the tag */
1727 rtag->tags_num = tag->tags_num;
1729 if (tag->tags != SML_TAG__NULL) {
1730 rtag->tags = (SML_TAG *)
1731 calloc(1, sizeof (SML_TAG)*rtag->tags_num);
1732 bzero(rtag->tags, sizeof (SML_TAG)*rtag->tags_num);
1733 for (i = 0; i < rtag->tags_num; i++) {
1734 SML_TAG *stag;
1735 stag = smlDup(&tag->tags[i]);
1736 (void) memcpy(&rtag->tags[i], stag,
1737 sizeof (SML_TAG));
1738 free(stag);
1742 /* exit assertions */
1744 assert(SML_TAG__ISVALID(rtag));
1746 /* return */
1748 return (rtag);
1752 * Name: smlSetFileStatInfo
1753 * Description; Given a file status structure and path name, encode the
1754 * structure and place it and the name into the specified tag
1755 * in a "_sml_fileStatInfoTag" (private) element
1756 * Arguments: tag - [RO, *RO] - (SML_TAG *)
1757 * The tag object to deposit the information into
1758 * statbuf - [RO, *RO] - (struct stat *)
1759 * Pointer to file status structure to encode
1760 * path - [RO, *RO] - (char *)
1761 * Pointer to path name of file to encode
1762 * Returns: void
1763 * The information is placed into the specified tag object
1766 void
1767 smlSetFileStatInfo(SML_TAG **tag, struct stat *statbuf, char *path)
1769 SML_TAG *rtag;
1771 /* entry assertions */
1773 assert(SML_TAG__R_ISVALID(tag));
1774 assert(SML_TAG__ISVALID(*tag));
1775 assert(statbuf != (struct stat *)NULL);
1777 /* if stat info exists, delete it */
1779 (void) smlFindAndDelTag(*tag, _sml_fileStatInfoTag);
1781 /* create the file stat info inside of the top level tag */
1783 assert(smlGetTagByName(*tag, 0, _sml_fileStatInfoTag)
1784 == SML_TAG__NULL);
1785 rtag = smlNewTag(_sml_fileStatInfoTag);
1786 assert(SML_TAG__ISVALID(rtag));
1787 (void) smlAddTag(tag, 0, rtag);
1788 free(rtag);
1790 /* obtain handle on newly created file stat info tag */
1792 rtag = smlGetTagByName(*tag, 0, _sml_fileStatInfoTag);
1793 assert(SML_TAG__ISVALID(rtag));
1795 /* add file info as parameters to the tag */
1797 if (path != (char *)NULL) {
1798 smlSetParam(rtag, "st_path", path);
1801 smlSetParamF(rtag, "st_ino", "0x%llx",
1802 (unsigned long long)statbuf->st_ino);
1803 smlSetParamF(rtag, "st_mode", "0x%llx",
1804 (unsigned long long)statbuf->st_mode);
1805 smlSetParamF(rtag, "st_mtime", "0x%llx",
1806 (unsigned long long)statbuf->st_mtime);
1807 smlSetParamF(rtag, "st_ctime", "0x%llx",
1808 (unsigned long long)statbuf->st_ctime);
1809 smlSetParamF(rtag, "st_size", "0x%llx",
1810 (unsigned long long)statbuf->st_size);
1814 * Name: smlFstatCompareEQ
1815 * Description: Given a file status structure and path name, look for the
1816 * information placed into a tag object via smlSetFileStatInfo
1817 * and if present compare the encoded information with the
1818 * arguments provided
1819 * Arguments: statbuf - [RO, *RO] - (struct stat *)
1820 * Pointer to file status structure to compare
1821 * tag - [RO, *RO] - (SML_TAG *)
1822 * The tag object to compare against
1823 * path - [RO, *RO] - (char *)
1824 * Pointer to path name of file to compare
1825 * Returns: boolean_t
1826 * B_TRUE - both status structures are identical
1827 * B_FALSE - the status structures are not equal
1830 boolean_t
1831 smlFstatCompareEq(struct stat *statbuf, SML_TAG *tag, char *path)
1833 if (tag == SML_TAG__NULL) {
1834 return (B_FALSE);
1837 assert(SML_TAG__ISVALID(tag));
1839 if (statbuf == (struct stat *)NULL) {
1840 return (B_FALSE);
1843 if (path != (char *)NULL) {
1844 if (smlParamEq(tag,
1845 _sml_fileStatInfoTag, "st_path", path) != B_TRUE) {
1846 return (B_FALSE);
1850 if (smlParamEqF(tag, _sml_fileStatInfoTag, "st_ino",
1851 "0x%llx", (unsigned long long)statbuf->st_ino) != B_TRUE) {
1852 return (B_FALSE);
1855 if (smlParamEqF(tag, _sml_fileStatInfoTag, "st_mode",
1856 "0x%llx", (unsigned long long)statbuf->st_mode) != B_TRUE) {
1857 return (B_FALSE);
1860 if (smlParamEqF(tag, _sml_fileStatInfoTag, "st_mtime",
1861 "0x%llx", (unsigned long long)statbuf->st_mtime) != B_TRUE) {
1862 return (B_FALSE);
1865 if (smlParamEqF(tag, _sml_fileStatInfoTag, "st_ctime",
1866 "0x%llx", (unsigned long long)statbuf->st_ctime) != B_TRUE) {
1867 return (B_FALSE);
1870 if (smlParamEqF(tag, _sml_fileStatInfoTag, "st_size",
1871 "0x%llx", (unsigned long long)statbuf->st_size) != B_TRUE) {
1872 return (B_FALSE);
1875 return (B_TRUE);
1879 * Name: set_verbose
1880 * Description: Turns on verbose output
1881 * Scope: public
1882 * Arguments: verbose = B_TRUE indicates verbose mode
1883 * Returns: none
1885 void
1886 smlSetVerbose(boolean_t setting)
1888 verbose = setting;
1892 * Name: get_verbose
1893 * Description: Returns whether or not to output verbose messages
1894 * Scope: public
1895 * Arguments: none
1896 * Returns: B_TRUE - verbose messages should be output
1898 boolean_t
1899 smlGetVerbose()
1901 return (verbose);
1905 * Name: sml_strPrintf
1906 * Synopsis: Create string from printf style format and arguments
1907 * Description: Call to convert a printf style format and arguments into a
1908 * string of characters placed in allocated storage
1909 * Arguments: format - [RO, RO*] (char *)
1910 * printf-style format for string to be formatted
1911 * ... - [RO] (?)
1912 * arguments as appropriate to 'format' specified
1913 * Returns: char *
1914 * A string representing the printf conversion results
1915 * NOTE: Any string returned is placed in new storage for the
1916 * calling method. The caller must use 'free' to dispose
1917 * of the storage once the string is no longer needed.
1918 * Errors: If the string cannot be created, the process exits
1921 /*PRINTFLIKE1*/
1922 char *
1923 sml_strPrintf(char *a_format, ...)
1925 va_list ap;
1926 size_t vres = 0;
1927 char bfr[1];
1928 char *rstr = (char *)NULL;
1930 /* entry assertions */
1932 assert(a_format != (char *)NULL);
1933 assert(*a_format != '\0');
1935 /* determine size of the message in bytes */
1937 va_start(ap, a_format);
1938 vres = vsnprintf(bfr, 1, a_format, ap);
1939 va_end(ap);
1941 assert(vres > 0);
1943 /* allocate storage to hold the message */
1945 rstr = (char *)calloc(1, vres+2);
1946 assert(rstr != (char *)NULL);
1948 /* generate the results of the printf conversion */
1950 va_start(ap, a_format);
1951 vres = vsnprintf(rstr, vres+1, a_format, ap);
1952 va_end(ap);
1954 assert(vres > 0);
1955 assert(*rstr != '\0');
1957 /* return the results */
1959 return (rstr);
1963 * Name: sml_strPrintf_r
1964 * Synopsis: Create string from printf style format and arguments
1965 * Description: Call to convert a printf style format and arguments into a
1966 * string of characters placed in allocated storage
1967 * Arguments: a_buf - [RO, *RW] - (char *)
1968 * - Pointer to buffer used as storage space for the
1969 * returned string created
1970 * a_bufLen - [RO, *RO] - (int)
1971 * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1'
1972 * bytes will be placed in 'a_buf' - the returned
1973 * string is always null terminated
1974 * a_format - [RO, RO*] (char *)
1975 * printf-style format for string to be formatted
1976 * VARG_LIST - [RO] (?)
1977 * arguments as appropriate to 'format' specified
1978 * Returns: void
1981 /*PRINTFLIKE3*/
1982 void
1983 sml_strPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...)
1985 va_list ap;
1986 size_t vres = 0;
1988 /* entry assertions */
1990 assert(a_format != (char *)NULL);
1991 assert(*a_format != '\0');
1992 assert(a_buf != (char *)NULL);
1993 assert(a_bufLen > 1);
1995 /* generate the results of the printf conversion */
1997 va_start(ap, a_format);
1998 vres = vsnprintf(a_buf, a_bufLen-1, a_format, ap);
1999 va_end(ap);
2001 assert(vres > 0);
2002 assert(vres < a_bufLen);
2004 a_buf[a_bufLen-1] = '\0';
2008 * Name: sml_XmlEncodeString
2009 * Description: Given a plain text string, convert that string into one that
2010 * encoded using the XML character reference encoding format.
2011 * Arguments: a_plain_text_string - [RO, *RO] (char *)
2012 * The plain text string to convert (encode)
2013 * Returns: char *
2014 * The encoded form of the plain text string provided
2015 * NOTE: Any string returned is placed in new storage for the
2016 * calling method. The caller must use 'lu_memFree' to dispose
2017 * of the storage once the string is no longer needed.
2020 char *
2021 sml_XmlEncodeString(char *a_plainTextString)
2023 char *stringHead; /* -> start of string containing encoded data */
2024 long stringTail; /* byte pos of first free byte in stringHead */
2025 long stringLength; /* total bytes allocd starting at stringHead */
2026 char *p; /* temp -> to retrieve bytes from src string */
2027 long textLength = 0; /* length of the string to convert */
2029 /* entry assertions */
2031 assert(a_plainTextString != (char *)NULL);
2033 textLength = strlen(a_plainTextString);
2035 /* Allocate initial string buffer to hold results */
2037 stringLength = textLength*2;
2038 stringTail = 0;
2039 stringHead = (char *)calloc(1, (size_t)stringLength+2);
2040 assert(stringHead != (char *)NULL);
2042 /* Add in the encoded message text */
2044 for (p = a_plainTextString; textLength > 0; p++, textLength--) {
2046 * Must have at least 12 bytes: this must be at least the
2047 * maximum number of bytes that can be added for a single
2048 * byte as the last byte of the stream. Assuming the byte
2049 * needs to be encoded, it could be:
2050 * &#xxxxxxxx;\0
2051 * If not that many bytes left, grow the buffer.
2054 if ((stringLength-stringTail) < 12) {
2055 stringLength += (textLength*2)+12;
2056 stringHead =
2057 realloc(stringHead,
2058 (size_t)stringLength+2);
2059 assert(stringHead != (char *)NULL);
2063 * See if this byte is a 'printable 7-bit ascii value'.
2064 * If so just add it to the new string; otherwise, must
2065 * output an XML character value encoding for the byte.
2068 switch (*p) {
2069 case '!':
2070 case '#':
2071 case '%':
2072 case '\'':
2073 case '(':
2074 case ')':
2075 case '*':
2076 case '+':
2077 case ',':
2078 case '-':
2079 case '.':
2080 case '/':
2081 case '0':
2082 case '1':
2083 case '2':
2084 case '3':
2085 case '4':
2086 case '5':
2087 case '6':
2088 case '7':
2089 case '8':
2090 case '9':
2091 case ':':
2092 case ';':
2093 case '<':
2094 case '=':
2095 case '>':
2096 case '?':
2097 case '@':
2098 case 'A':
2099 case 'B':
2100 case 'C':
2101 case 'D':
2102 case 'E':
2103 case 'F':
2104 case 'G':
2105 case 'H':
2106 case 'I':
2107 case 'J':
2108 case 'K':
2109 case 'L':
2110 case 'M':
2111 case 'N':
2112 case 'O':
2113 case 'P':
2114 case 'Q':
2115 case 'R':
2116 case 'S':
2117 case 'T':
2118 case 'U':
2119 case 'V':
2120 case 'W':
2121 case 'X':
2122 case 'Y':
2123 case 'Z':
2124 case '[':
2125 case ']':
2126 case '^':
2127 case '_':
2128 case 'a':
2129 case 'b':
2130 case 'c':
2131 case 'd':
2132 case 'e':
2133 case 'f':
2134 case 'g':
2135 case 'h':
2136 case 'i':
2137 case 'j':
2138 case 'k':
2139 case 'l':
2140 case 'm':
2141 case 'n':
2142 case 'o':
2143 case 'p':
2144 case 'q':
2145 case 'r':
2146 case 's':
2147 case 't':
2148 case 'u':
2149 case 'v':
2150 case 'w':
2151 case 'x':
2152 case 'y':
2153 case 'z':
2154 case '{':
2155 case '|':
2156 case '}':
2157 case '~':
2158 case ' ':
2160 * It is a printable 7-bit ascii character:
2161 * just add it to the end of the new string.
2164 stringHead[stringTail++] = *p;
2165 break;
2166 default:
2168 * It is not a printable 7-bit ascii character:
2169 * add it as an xml character value encoding.
2172 stringTail += sprintf(&stringHead[stringTail], "&#%x;",
2173 (*p)&0xFF);
2174 break;
2178 /* Terminate the new string */
2180 stringHead[stringTail] = '\0';
2182 /* realloc the string so it is only as big as it needs to be */
2184 stringHead = realloc(stringHead, stringTail+1);
2185 assert(stringHead != (char *)NULL);
2187 return (stringHead);
2191 * Name: sml_XmlDecodeString
2192 * Description: Given a string encoded using the XML character reference format,
2193 * convert that string into a plain text (unencoded) string.
2194 * Arguments: a_xml_encoded_string - [RO, *RO] (char *)
2195 * The XML encoded string to convert to plain text
2196 * Returns: char *
2197 * The unencoded (plain text) form of the encoded string
2198 * NOTE: Any string returned is placed in new storage for the
2199 * calling method. The caller must use 'lu_memFree' to dispose
2200 * of the storage once the string is no longer needed.
2203 char *
2204 sml_XmlDecodeString(char *a_xmlEncodedString)
2206 char *s = NULL; /* -> index into encoded bytes string */
2207 char *d = NULL; /* -> index into decoded bytes string */
2208 char *rs = NULL; /* -> string holding ref bytes allocated */
2209 char *ri = NULL; /* -> index into string holding reference */
2210 long textLength = 0; /* length of encoded string to decode */
2211 unsigned long rv = 0; /* temp to hold scanf results of byte conv */
2212 char *i = NULL; /* temp to hold strchr results */
2213 char *stringHead = NULL; /* -> plain test buffer */
2214 ptrdiff_t tmpdiff;
2217 * A finite state machine is used to convert the xml encoded string
2218 * into plain text. The states of the machine are defined below.
2221 int fsmsState = -1; /* Finite state machine state */
2222 #define fsms_text 0 /* Decoding plain text */
2223 #define fsms_seenAmp 1 /* Found & */
2224 #define fsms_seenPound 2 /* Found # following & */
2225 #define fsms_collect 3 /* Collecting character reference bytes */
2227 /* entry assertions */
2229 assert(a_xmlEncodedString != (char *)NULL);
2231 textLength = strlen(a_xmlEncodedString);
2234 * Allocate string that can contain the decoded string.
2235 * Since decoding always results in a shorter string (bytes encoded
2236 * using the XML character reference are larger in the encoded form)
2237 * we can allocate a string the same size as the encoded string.
2240 stringHead = (char *)calloc(1, textLength+1);
2241 assert(stringHead != (char *)NULL);
2244 * Convert all bytes.
2247 /* Decoding plain text */
2248 fsmsState = fsms_text;
2250 for (s = a_xmlEncodedString, d = stringHead; textLength > 0;
2251 s++, textLength--) {
2252 switch (fsmsState) {
2253 case fsms_text: /* Decoding plain text */
2254 if (rs != NULL) {
2255 free(rs);
2256 rs = NULL;
2257 ri = NULL;
2259 if (*s == '&') {
2260 /* Found & */
2261 fsmsState = fsms_seenAmp;
2262 continue;
2264 *d++ = *s;
2265 continue;
2267 case fsms_seenAmp: /* Found & */
2268 if (*s == '#') {
2269 /* Found # following & */
2270 fsmsState = fsms_seenPound;
2271 continue;
2273 fsmsState = fsms_text; /* Decoding plain text */
2274 *d++ = '&';
2275 *d++ = *s;
2276 continue;
2278 case fsms_seenPound: /* Found # following & */
2279 i = strchr(s, ';');
2280 if (i == NULL) {
2281 /* Decoding plain text */
2282 fsmsState = fsms_text;
2283 *d++ = '&';
2284 *d++ = '#';
2285 *d++ = *s;
2286 continue;
2288 tmpdiff = (ptrdiff_t)i - (ptrdiff_t)s;
2289 rs = (char *)calloc(1, tmpdiff + 1);
2290 assert(rs != (char *)NULL);
2291 ri = rs;
2292 /* Collecting character reference bytes */
2293 fsmsState = fsms_collect;
2295 /*FALLTHRU*/
2297 /* Collecting character reference bytes */
2298 case fsms_collect:
2299 if (*s != ';') {
2300 switch (*s) {
2301 case '0':
2302 case '1':
2303 case '2':
2304 case '3':
2305 case '4':
2306 case '5':
2307 case '6':
2308 case '7':
2309 case '8':
2310 case '9':
2311 case 'a':
2312 case 'b':
2313 case 'c':
2314 case 'd':
2315 case 'e':
2316 case 'f':
2317 case 'A':
2318 case 'B':
2319 case 'C':
2320 case 'D':
2321 case 'E':
2322 case 'F':
2323 *ri++ = *s;
2324 break;
2325 default:
2326 *ri = '\0';
2327 *d++ = '&';
2328 *d++ = '#';
2329 tmpdiff = (ptrdiff_t)ri - (ptrdiff_t)rs;
2330 (void) strncpy(d, rs, tmpdiff-1);
2331 *d++ = *s;
2332 /* Decoding plain text */
2333 fsmsState = fsms_text;
2334 break;
2336 continue;
2338 *ri = '\0';
2339 if (sscanf(rs, "%lx", &rv) != 1) {
2340 *d++ = '?';
2341 } else {
2342 *d++ = (rv & 0xFF);
2344 /* Decoding plain text */
2345 fsmsState = fsms_text;
2349 /* Done converting bytes - deallocate reference byte storage */
2351 free(rs);
2353 /* terminate the converted (plain text) string */
2355 *d = '\0';
2357 /* exit assertions */
2359 assert(stringHead != (char *)NULL);
2361 return (stringHead);
2365 * Private Methods
2369 * Name: _smlReadTag
2370 * Description: read complete tag from a datastream
2371 * Arguments: err - [RO, *RW] (LU_ERR)
2372 * Error object - used to contain any errors encountered
2373 * and return those errors to this methods caller
2374 * r_tag - [RW, *RW] - (SML_TAG **)
2375 * Pointer to handle to place new tag object
2376 * == SML_TAG__NULL if empty tag found (not an error)
2377 * ds - [RO, *RO] - (LU_DS)
2378 * Handle to datastream to read tag from
2379 * parent - [RO, *RO] - (char *)
2380 * Name for parent of tag (NONE if top of tag)
2381 * Returns: int
2382 * RESULT_OK - tag successfully read
2383 * RESULT_ERR - problem reading tag
2384 * NOTE: Any tag object returned is placed in new storage for the
2385 * calling method. The caller must use 'smlFreeTag' to dispose
2386 * of the storage once the tag object name is no longer needed.
2387 * Errors: If the tag object cannot be duplicated, the process exits
2390 static int
2391 _smlReadTag(SML_TAG **r_tag, char **a_str, char *parent)
2393 int r;
2394 SML_TAG *tag;
2395 SML_TAG *tmp_tag;
2396 char name[MAX_SML_COMPONENT_LENGTH];
2397 int pos = 0;
2398 int c;
2399 char *p = *a_str;
2401 /* entry assertions */
2403 assert(SML_TAG__R_ISVALID(r_tag));
2404 assert(a_str != (char **)NULL);
2406 /* entry debugging info */
2408 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_READ_TAG,
2409 parent ? parent : "<<TOP TAG>>");
2411 /* reset return tag */
2413 *r_tag = SML_TAG__NULL;
2415 /* allocate zeroed storage for the tag object */
2417 tag = (SML_TAG *)calloc(1, sizeof (SML_TAG));
2418 assert(tag != SML_TAG__NULL);
2420 /* reset name accumulator storage */
2422 bzero(name, sizeof (name));
2424 /* ignore delimters before tag */
2426 for (;;) {
2427 /* read tag character - handle failure/EOF */
2429 if ((*p == '\0') || ((c = (*p++)) == '\0')) {
2430 if (parent == NULL) {
2431 _smlLogMsg(LOG_MSG_DEBUG,
2432 DBG_SML_READTAG_EXPECTED_EOF,
2433 p ? p : "?");
2434 smlFreeTag(tag);
2435 *a_str = p;
2436 return (RESULT_OK);
2439 /* EOF in middle of processing tag */
2441 _smlLogMsg(LOG_MSG_ERR,
2442 DBG_SML_READTAG_UNEXPECTED_EOF,
2443 p ? p : "?");
2444 smlFreeTag(tag);
2445 *a_str = p;
2446 return (RESULT_ERR);
2449 /* if beginning of tag, break out */
2451 if (c == '<') {
2452 break;
2455 /* not tag beginning: ignore delimiters if not inside tag yet */
2457 if (parent == (char *)NULL) {
2458 /* ignore delimters */
2460 if (strchr(" \t", c) != (char *)NULL) {
2461 continue;
2464 /* on blank lines, return no tag object */
2466 if (c == '\n') {
2467 _smlLogMsg(LOG_MSG_DEBUG,
2468 DBG_SML_READTAG_BLANKLINE,
2469 p ? p : "?");
2470 smlFreeTag(tag);
2471 *a_str = p;
2472 return (RESULT_OK);
2475 /* invalid character before tag start */
2477 _smlLogMsg(LOG_MSG_ERR, ERR_SML_READTAG_BAD_START_CHAR,
2478 c, (unsigned int)c);
2479 *a_str = p;
2480 return (RESULT_ERR);
2485 * all delimiters have been ignored and opening tag character seen;
2486 * process tag
2489 assert(c == '<');
2491 c = *p;
2492 if (*p != '\0') {
2493 p++;
2496 /* handle EOF after tag opening character found */
2498 if (c == '\0') {
2499 _smlLogMsg(LOG_MSG_ERR,
2500 ERR_SML_EOF_BEFORE_TAG_NAME,
2501 parent ? parent : "<<NONE>>");
2502 smlFreeTag(tag);
2503 *a_str = p;
2504 return (RESULT_ERR);
2507 /* is this a tag closure? */
2509 if (c == '/') {
2510 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_START_CLOSE_TAG,
2511 parent ? parent : "<<NONE>>");
2513 for (;;) {
2514 /* get next character of tag name */
2516 c = *p;
2517 if (*p != '\0') {
2518 p++;
2521 /* EOF inside tag name? */
2523 if (c == '\0') {
2524 _smlLogMsg(LOG_MSG_ERR,
2525 ERR_SML_READTAG_CLOSE_TAG_EOF,
2526 parent ? parent : "<<NONE>>");
2527 smlFreeTag(tag);
2528 *a_str = p;
2529 return (RESULT_ERR);
2532 /* tag close: break out of collection loop */
2534 if (c == '>') {
2535 break;
2538 /* see if illegal character in tag name */
2540 /* CSTYLED */
2541 if (strchr("/ \t\n\":<?$'\\`!@#%^&*()+=|[]{};,", c)
2542 != NULL) {
2543 _smlLogMsg(LOG_MSG_ERR,
2544 ERR_SML_READTAG_CLOSE_TAG_ILLCHAR,
2545 c, (unsigned int)c, name);
2546 smlFreeTag(tag);
2547 *a_str = p;
2548 return (RESULT_ERR);
2551 /* valid character - add to name if room left */
2553 if (pos < sizeof (name)-1) {
2554 name[pos] = (c&0xFF);
2555 pos++;
2558 assert(pos < sizeof (name));
2561 /* close of tag found */
2563 assert(c == '>');
2565 /* is the tag empty? If so that's an error */
2567 if (*name == '\0') {
2568 _smlLogMsg(LOG_MSG_ERR,
2569 ERR_SML_READTAG_CLOSE_EMPTY_TAG);
2570 smlFreeTag(tag);
2571 *a_str = p;
2572 return (RESULT_ERR);
2575 /* if no parent, a close tag outside of any open tag */
2577 if (parent == (char *)NULL) {
2578 _smlLogMsg(LOG_MSG_ERR,
2579 ERR_SML_READTAG_CLOSE_NO_PARENT,
2580 name);
2581 smlFreeTag(tag);
2582 *a_str = p;
2583 return (RESULT_ERR);
2586 /* if not close to current parent, error */
2588 if (!streq(parent, name)) {
2589 _smlLogMsg(LOG_MSG_ERR,
2590 ERR_SML_READTAG_CLOSE_WRONG_TAG,
2591 name, parent);
2592 smlFreeTag(tag);
2593 *a_str = p;
2594 return (RESULT_ERR);
2597 /* close of current tag found - success */
2599 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_READTAG_CLOSE_TAG,
2600 name);
2601 smlFreeTag(tag);
2602 *a_str = p;
2603 return (RESULT_OK);
2606 /* not starting a close tag */
2608 assert(c != '/');
2609 assert(c != '<');
2611 /* at start of tag - input tag name */
2613 bzero(name, sizeof (name));
2614 pos = 0;
2616 for (;;) {
2618 /* EOF inside of tag name? */
2620 if (c == '\0') {
2621 _smlLogMsg(LOG_MSG_ERR,
2622 ERR_SML_READTAG_TAG_EOF,
2623 name, parent ? parent : "<<NONE>>");
2624 smlFreeTag(tag);
2625 *a_str = p;
2626 return (RESULT_ERR);
2629 /* if separator or end of line then tag name collected */
2631 if (strchr(" >\t\n", c) != NULL) {
2632 break;
2635 /* see if illegal character in tag name */
2637 /*CSTYLED*/
2638 if (strchr("\":<>?$'\\`!@#%^&*()+=|[]{};,", c) != NULL) {
2639 _smlLogMsg(LOG_MSG_ERR,
2640 ERR_SML_READTAG_TAG_ILLCHAR,
2641 c, (unsigned int)c, name);
2642 smlFreeTag(tag);
2643 *a_str = p;
2644 return (RESULT_ERR);
2647 /* close current tag? */
2649 if (c == '/') {
2650 /* get next character of tag name */
2652 c = *p;
2653 if (*p != '\0') {
2654 p++;
2657 /* tag close not found? */
2659 if (c != '>') {
2660 _smlLogMsg(LOG_MSG_ERR,
2661 ERR_SML_READTAG_BADTAG_CLOSE,
2662 name, parent ? parent : "<<NONE>>");
2663 smlFreeTag(tag);
2664 *a_str = p;
2665 return (RESULT_ERR);
2668 /* is the tag empty? If so that's an error */
2670 if (*name == '\0') {
2671 _smlLogMsg(LOG_MSG_ERR,
2672 ERR_SML_READTAG_EMPTY_TAG,
2673 parent ? parent : "<<NONE>>");
2674 smlFreeTag(tag);
2675 *a_str = p;
2676 return (RESULT_ERR);
2679 /* tag closed */
2681 _smlLogMsg(LOG_MSG_DEBUG,
2682 DBG_SML_READTAG_CLOSED_TAG,
2683 name, parent ? parent : "<<NONE>>");
2685 tag->name = strdup(name);
2686 *r_tag = tag;
2687 *a_str = p;
2688 return (RESULT_OK);
2691 /* valid character - add to name if room left */
2693 if (pos < sizeof (name)-1) {
2694 name[pos] = (c&0xFF);
2695 pos++;
2698 assert(pos < sizeof (name));
2700 /* get next character to parse */
2702 c = *p;
2703 if (*p != '\0') {
2704 p++;
2708 /* have a valid tag name: <tagname */
2710 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_HAVE_TAG_NAME,
2711 name, parent ? parent : "<<NONE>>");
2713 assert(*name != '\0');
2715 /* place tag name inside of tag object */
2717 tag->name = strdup(name);
2719 /* clear out name accumulator to get parameters */
2721 bzero(name, sizeof (name));
2722 pos = 0;
2724 /* input parameters */
2726 if (c != '>')
2727 for (;;) {
2729 char *pname;
2730 char *pvalue;
2731 SML_PARAM *parameter;
2733 /* pass spaces before parameter name */
2735 for (;;) {
2737 /* get next character of parameter name */
2739 c = *p;
2740 if (*p != '\0') {
2741 p++;
2744 /* EOF inside parameter name? */
2746 if (c == '\0') {
2747 _smlLogMsg(LOG_MSG_ERR,
2748 ERR_SML_READTAG_PARM_EOF,
2749 tag->name,
2750 parent ? parent : "<<NONE>>");
2751 smlFreeTag(tag);
2752 *a_str = p;
2753 return (RESULT_ERR);
2756 /* if separator/end of line tag parameter collected */
2758 if (strchr(" \t\n", c) != NULL) {
2759 continue;
2762 /* see if illegal character in parameter name */
2764 /*CSTYLED*/
2765 if (strchr("\":<?$'\\`!@#%^&*()+=|[]{};,.", c) !=
2766 (char *)NULL) {
2767 _smlLogMsg(LOG_MSG_ERR,
2768 ERR_SML_READTAG_PARMNAME_ILLCHAR,
2769 c, (unsigned int)c, name, tag->name,
2770 parent ? parent : "<<NONE>>");
2771 smlFreeTag(tag);
2772 *a_str = p;
2773 return (RESULT_ERR);
2776 /* tag close found? */
2778 if (c == '>') {
2779 break;
2782 /* close tag found ? */
2784 if (c == '/') {
2785 c = *p;
2786 if (*p != '\0') {
2787 p++;
2789 if (c == '>') {
2790 _smlLogMsg(LOG_MSG_DEBUG,
2791 DBG_SML_TAG_ONLY,
2792 tag->name);
2793 *r_tag = tag;
2794 *a_str = p;
2795 return (RESULT_OK);
2798 /* / not followed by > */
2799 _smlLogMsg(LOG_MSG_ERR,
2800 ERR_SML_READTAG_BADPARMNAME_CLOSE,
2801 name, tag->name,
2802 parent ? parent : "<<NONE>>");
2803 smlFreeTag(tag);
2804 *a_str = p;
2805 return (RESULT_ERR);
2808 /* valid character - add to name if room left */
2810 if (pos < sizeof (name)-1) {
2811 name[pos] = (c&0xFF);
2812 pos++;
2815 assert(pos < sizeof (name));
2816 break;
2819 if (c == '>') {
2820 break;
2823 /* input parameter name */
2825 for (;;) {
2826 c = *p;
2827 if (*p != '\0') {
2828 p++;
2831 /* EOF inside of parameter name? */
2833 if (c == '\0') {
2834 _smlLogMsg(LOG_MSG_ERR,
2835 ERR_SML_READTAG_PARM_EOF,
2836 tag->name,
2837 parent ? parent : "<<NONE>>");
2838 smlFreeTag(tag);
2839 *a_str = p;
2840 return (RESULT_ERR);
2843 /*CSTYLED*/
2844 if (strchr("\t \n\":<>?$'\\`!@%^*()+|[]{},./", c) != NULL) {
2845 _smlLogMsg(LOG_MSG_ERR,
2846 ERR_SML_READTAG_PARMNAME_ILLCHAR,
2847 c, (unsigned int)c, name, tag->name,
2848 parent ? parent : "<<NONE>>");
2849 smlFreeTag(tag);
2850 *a_str = p;
2851 return (RESULT_ERR);
2854 /* name - value separator found ? */
2856 if (c == '=') {
2857 break;
2860 /* valid character - add to name if room left */
2862 if (pos < sizeof (name)-1) {
2863 name[pos] = (c&0xFF);
2864 pos++;
2867 assert(pos < sizeof (name));
2870 /* is the parameter name empty? If so that's an error */
2872 if (*name == '\0') {
2873 _smlLogMsg(LOG_MSG_ERR,
2874 ERR_SML_READTAG_EMPTY_PARMNAME,
2875 tag->name, parent ? parent : "<<NONE>>");
2876 smlFreeTag(tag);
2877 *a_str = p;
2878 return (RESULT_ERR);
2881 /* have a parameter name */
2883 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_HAVE_PARM_NAME,
2884 name, tag->name);
2886 /* duplicate (save) parameter name */
2888 pname = strdup(name);
2890 /* clear out name accumulator to get parameters */
2892 bzero(name, sizeof (name));
2893 pos = 0;
2895 c = *p;
2896 if (*p != '\0') {
2897 p++;
2900 if (c != '"') {
2901 _smlLogMsg(LOG_MSG_ERR,
2902 ERR_SML_PARM_SEP_BAD,
2903 c, (unsigned int)c);
2904 free(pname);
2905 smlFreeTag(tag);
2906 *a_str = p;
2907 return (RESULT_ERR);
2910 /* input parameter value */
2912 for (;;) {
2913 c = *p;
2914 if (*p != '\0') {
2915 p++;
2918 /* EOF inside of parameter value? */
2920 if (c == '\0') {
2921 _smlLogMsg(LOG_MSG_ERR,
2922 ERR_SML_READTAG_PARMVAL_EOF,
2923 pname, tag->name,
2924 parent ? parent : "<<NONE>>");
2925 smlFreeTag(tag);
2926 free(pname);
2927 *a_str = p;
2928 return (RESULT_ERR);
2931 /* close of parameter value? */
2933 if (c == '"') {
2934 break;
2937 if (strchr("\n", c) != NULL) {
2938 _smlLogMsg(LOG_MSG_ERR,
2939 ERR_SML_READTAG_PARMVAL_NL,
2940 pname, tag->name,
2941 parent ? parent : "<<NONE>>");
2942 free(pname);
2943 smlFreeTag(tag);
2944 *a_str = p;
2945 return (RESULT_ERR);
2948 /* valid character - add to value if room left */
2950 if (pos < sizeof (name)-1) {
2951 name[pos] = (c&0xFF);
2952 pos++;
2955 assert(pos < sizeof (name));
2958 /* got the value */
2960 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_HAVE_PARM_VALUE,
2961 pname, name, tag->name);
2963 pvalue = sml_XmlDecodeString(name);
2964 bzero(name, sizeof (name));
2965 pos = 0;
2967 parameter = (SML_PARAM *)calloc(1, sizeof (SML_PARAM));
2968 bzero(parameter, sizeof (SML_PARAM));
2969 parameter->name = pname;
2970 parameter->value = pvalue;
2971 tag->params_num++;
2972 tag->params = (SML_PARAM *)
2973 realloc(tag->params,
2974 sizeof (SML_PARAM) *tag->params_num);
2975 (void) memcpy(&(tag->params[tag->params_num - 1]), parameter,
2976 sizeof (SML_PARAM));
2978 free(parameter);
2979 if (c == '>') {
2980 break;
2984 /* finished processing this tag element entry */
2986 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_TAG_HEAD_DONE,
2987 tag->name, parent ? parent : "<<NULL>>");
2989 tag->tags = NULL;
2991 while (((r = _smlReadTag(&tmp_tag, &p, tag->name))
2992 == RESULT_OK) && (tmp_tag != NULL)) {
2993 tag->tags_num++;
2994 tag->tags = (SML_TAG *)realloc(tag->tags,
2995 sizeof (SML_TAG) *tag->tags_num);
2996 (void) memcpy(&(tag->tags[tag->tags_num - 1]), tmp_tag,
2997 sizeof (SML_TAG));
2998 free(tmp_tag);
3001 c = *p;
3002 if (*p != '\0') {
3003 p++;
3006 *r_tag = tag;
3007 *a_str = p;
3008 return (r);
3012 * Name: _smlWriteParamValue
3013 * Description: XML Encode a plain text parameter value and write to datastream
3014 * Arguments: ds - [RO, *RO] - (LU_DS)
3015 * Handle to datastream to write parameter value to
3016 * value - [RO, *RO] - (char *)
3017 * Parameter value to be encoded and written
3018 * Returns: int
3019 * RESULT_OK - tag successfully read
3020 * RESULT_ERR - problem reading tag
3023 static int
3024 _smlWriteParamValue(char **a_str, char *value)
3026 char *ns;
3027 char *p;
3029 /* entry assertions */
3031 assert(a_str != (char **)NULL);
3032 assert(value != (char *)NULL);
3034 /* xml encode the plain text string */
3036 p = sml_XmlEncodeString(value);
3037 assert(p != (char *)NULL);
3039 /* write the xml encoded parameter value to the datastream */
3041 ns = sml_strPrintf("%s\"%s\"", *a_str ? *a_str : "", p);
3043 /* free up xml encoded value storage */
3045 free(p);
3047 if (ns == NULL) {
3048 return (RESULT_ERR);
3051 if (*a_str != NULL) {
3052 free(*a_str);
3054 *a_str = ns;
3056 /* return results */
3058 return (RESULT_OK);
3061 static int
3062 _smlWriteSimpleTag(char **a_str, SML_TAG *tag)
3064 int r;
3065 int k;
3066 char *ns;
3067 char *np0;
3068 char *np1;
3070 if (tag == NULL) {
3071 return (RESULT_OK);
3074 if (*a_str == NULL) {
3075 *a_str = strdup("");
3078 if (tag->params_num == 0) {
3079 if (tag->tags_num == 0) {
3080 ns = sml_strPrintf("%s<%s/>\n", *a_str, tag->name);
3081 free(*a_str);
3082 *a_str = ns;
3083 return (RESULT_OK);
3084 } else {
3085 ns = sml_strPrintf("%s<%s>\n", *a_str, tag->name);
3086 if (ns == NULL) {
3087 return (RESULT_ERR);
3089 free(*a_str);
3090 *a_str = ns;
3092 } else {
3093 ns = sml_strPrintf("%s<%s %s=", *a_str ? *a_str : "", tag->name,
3094 tag->params[0].name);
3095 if (ns == NULL) {
3096 return (RESULT_ERR);
3098 free(*a_str);
3099 *a_str = ns;
3101 np0 = NULL;
3102 r = _smlWriteParamValue(&np0, tag->params[0].value);
3103 if ((np0 == NULL) || (r != RESULT_OK)) {
3104 return (RESULT_ERR);
3107 ns = sml_strPrintf("%s%s", *a_str, np0);
3108 if (ns == NULL) {
3109 return (RESULT_ERR);
3112 free(np0);
3113 free(*a_str);
3114 *a_str = ns;
3116 for (k = 1; k < tag->params_num; k++) {
3117 np0 = sml_strPrintf(" %s=", tag->params[k].name);
3118 if (np0 == NULL) {
3119 return (RESULT_ERR);
3121 np1 = NULL;
3122 r = _smlWriteParamValue(&np1, tag->params[k].value);
3123 if ((np1 == NULL) || (r != RESULT_OK)) {
3124 return (RESULT_ERR);
3127 ns = sml_strPrintf("%s%s%s", *a_str, np0, np1);
3128 if (ns == NULL) {
3129 return (RESULT_ERR);
3132 free(np0);
3133 free(np1);
3134 free(*a_str);
3135 *a_str = ns;
3138 if (tag->tags_num == 0) {
3139 np0 = sml_strPrintf("/>\n");
3140 if (np0 == NULL) {
3141 return (RESULT_ERR);
3143 ns = sml_strPrintf("%s%s", *a_str, np0);
3144 if (ns == NULL) {
3145 return (RESULT_ERR);
3147 free(np0);
3148 free(*a_str);
3149 *a_str = ns;
3150 } else {
3151 np0 = sml_strPrintf(">\n");
3152 if (np0 == NULL) {
3153 return (RESULT_ERR);
3155 ns = sml_strPrintf("%s%s", *a_str, np0);
3156 if (ns == NULL) {
3157 return (RESULT_ERR);
3159 free(np0);
3160 free(*a_str);
3161 *a_str = ns;
3165 for (k = 0; k < tag->tags_num; k++) {
3166 r = _smlWriteSimpleTag(a_str, &(tag->tags[k]));
3167 if (r != RESULT_OK) {
3168 return (r);
3172 if (tag->tags_num > 0) {
3173 np0 = sml_strPrintf("</%s>\n", tag->name);
3174 if (np0 == NULL) {
3175 return (RESULT_ERR);
3177 ns = sml_strPrintf("%s%s", *a_str ? *a_str : "", np0);
3178 if (ns == NULL) {
3179 return (RESULT_ERR);
3181 free(np0);
3182 free(*a_str);
3183 *a_str = ns;
3186 return (RESULT_OK);
3189 static void
3190 _smlFreeTag(SML_TAG *tag)
3192 int k;
3194 /* entry assertions */
3196 assert(tag != SML_TAG__NULL);
3198 /* entry debugging info */
3200 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_TAG,
3201 (unsigned long)tag,
3202 tag->name ? tag->name : "<<NONE>>",
3203 tag->params_num, tag->tags_num);
3205 for (k = 0; k < tag->params_num; k++) {
3206 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_PARAM_NAME,
3207 (unsigned long)(&tag->params[k]),
3208 (unsigned long)(tag->params[k].name),
3209 tag->params[k].name);
3210 free(tag->params[k].name);
3211 tag->params[k].name = (char *)NULL;
3212 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_PARAM_VALUE,
3213 (unsigned long)(&tag->params[k]),
3214 (unsigned long)(tag->params[k].value),
3215 tag->params[k].value);
3216 free(tag->params[k].value);
3217 tag->params[k].value = (char *)NULL;
3220 for (k = 0; k < tag->tags_num; k++) {
3221 _smlFreeTag(&tag->tags[k]);
3224 if (tag->name != NULL) {
3225 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_TAG_NAME,
3226 (unsigned long)tag->name, tag->name);
3227 free(tag->name);
3228 tag->name = NULL;
3232 if (tag->params != NULL) {
3233 assert(tag->params_num > 0);
3234 bzero(tag->params, sizeof (SML_PARAM)*tag->params_num);
3235 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_PARAMS,
3236 (unsigned long)tag->params);
3237 free(tag->params);
3238 tag->params = NULL;
3239 tag->params_num = 0;
3242 if (tag->tags != NULL) {
3243 assert(tag->tags_num > 0);
3244 bzero(tag->tags, sizeof (SML_TAG)*tag->tags_num);
3245 _smlLogMsg(LOG_MSG_DEBUG, DBG_SML_INT_FREE_TAGS,
3246 (unsigned long)tag->tags);
3247 free(tag->tags);
3248 tag->tags = NULL;
3249 tag->tags_num = 0;
3254 * Name: log_msg
3255 * Description: Outputs messages to logging facility.
3256 * Scope: public
3257 * Arguments: type - the severity of the message
3258 * out - where to output the message.
3259 * fmt - the printf format, plus its arguments
3260 * Returns: none
3263 /*PRINTFLIKE2*/
3264 static void
3265 _smlLogMsg(LogMsgType a_type, const char *a_format, ...)
3267 va_list ap;
3268 size_t vres = 0;
3269 char bfr[1];
3270 char *rstr = (char *)NULL;
3271 FILE *out;
3272 char *prefix;
3274 switch (a_type) {
3275 case LOG_MSG_ERR:
3276 default:
3277 out = stderr;
3278 prefix = MSG_LOG_ERROR;
3279 break;
3280 case LOG_MSG_WRN:
3281 out = stderr;
3282 prefix = MSG_LOG_WARNING;
3283 break;
3284 case LOG_MSG_INFO:
3285 out = stdout;
3286 prefix = NULL;
3287 break;
3288 case LOG_MSG_DEBUG:
3289 if (!smlGetVerbose()) {
3290 /* no debug messages if not verbose mode */
3291 return;
3293 out = stderr;
3294 prefix = MSG_LOG_DEBUG;
3295 break;
3298 if (prefix != NULL) {
3299 (void) fprintf(out, "%s: ", prefix);
3302 /* determine size of the message in bytes */
3304 va_start(ap, a_format);
3305 vres = vsnprintf(bfr, 1, a_format, ap);
3306 va_end(ap);
3308 /* allocate storage to hold the message */
3310 rstr = (char *)malloc(vres+2);
3312 /* generate the results of the printf conversion */
3314 va_start(ap, a_format);
3315 vres = vsnprintf(rstr, vres+1, a_format, ap);
3316 va_end(ap);
3318 if (fprintf(out, "%s\n", rstr) < 0) {
3320 * nothing output, try stderr as a
3321 * last resort
3323 (void) fprintf(stderr, ERR_LOG_FAIL, a_format);
3326 free(rstr);