1/*
2 * "$Id: mxml-search.c,v 1.7 2004/09/17 18:38:21 rleigh Exp $"
3 *
4 * Search/navigation functions for mini-XML, a small XML-like file
5 * parsing library.
6 *
7 * Copyright 2003 by Michael Sweet.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * Contents:
20 *
21 *   stp_mxmlFindElement() - Find the named element.
22 *   stp_mxmlWalkNext()    - Walk to the next logical node in the tree.
23 *   stp_mxmlWalkPrev()    - Walk to the previous logical node in the tree.
24 */
25
26/*
27 * Include necessary headers...
28 */
29
30#include <gutenprint/mxml.h>
31#include "config.h"
32
33
34/*
35 * 'stp_mxmlFindElement()' - Find the named element.
36 *
37 * The search is constrained by the name, attribute name, and value; any
38 * NULL names or values are treated as wildcards, so different kinds of
39 * searches can be implemented by looking for all elements of a given name
40 * or all elements with a specific attribute. The descend argument determines
41 * whether the search descends into child nodes; normally you will use
42 * STP_MXML_DESCEND_FIRST for the initial search and STP_MXML_NO_DESCEND to find
43 * additional direct descendents of the node. The top node argument
44 * constrains the search to a particular node's children.
45 */
46
47stp_mxml_node_t *				/* O - Element node or NULL */
48stp_mxmlFindElement(stp_mxml_node_t *node,	/* I - Current node */
49                stp_mxml_node_t *top,	/* I - Top node */
50                const char  *name,	/* I - Element name or NULL for any */
51		const char  *attr,	/* I - Attribute name, or NULL for none */
52		const char  *value,	/* I - Attribute value, or NULL for any */
53		int         descend)	/* I - Descend into tree - STP_MXML_DESCEND, STP_MXML_NO_DESCEND, or STP_MXML_DESCEND_FIRST */
54{
55  const char	*temp;			/* Current attribute value */
56
57
58 /*
59  * Range check input...
60  */
61
62  if (!node || !top || (!attr && value))
63    return (NULL);
64
65 /*
66  * Start with the next node...
67  */
68
69  node = stp_mxmlWalkNext(node, top, descend);
70
71 /*
72  * Loop until we find a matching element...
73  */
74
75  while (node != NULL)
76  {
77   /*
78    * See if this node matches...
79    */
80
81    if (node->type == STP_MXML_ELEMENT &&
82        node->value.element.name &&
83	(!name || !strcmp(node->value.element.name, name)))
84    {
85     /*
86      * See if we need to check for an attribute...
87      */
88
89      if (!attr)
90        return (node);			/* No attribute search, return it... */
91
92     /*
93      * Check for the attribute...
94      */
95
96      if ((temp = stp_mxmlElementGetAttr(node, attr)) != NULL)
97      {
98       /*
99        * OK, we have the attribute, does it match?
100	*/
101
102	if (!value || !strcmp(value, temp))
103	  return (node);		/* Yes, return it... */
104      }
105    }
106
107   /*
108    * No match, move on to the next node...
109    */
110
111    if (descend == STP_MXML_DESCEND)
112      node = stp_mxmlWalkNext(node, top, STP_MXML_DESCEND);
113    else
114      node = node->next;
115  }
116
117  return (NULL);
118}
119
120
121/*
122 * 'stp_mxmlWalkNext()' - Walk to the next logical node in the tree.
123 *
124 * The descend argument controls whether the first child is considered
125 * to be the next node. The top node argument constrains the walk to
126 * the node's children.
127 */
128
129stp_mxml_node_t *				/* O - Next node or NULL */
130stp_mxmlWalkNext(stp_mxml_node_t *node,		/* I - Current node */
131             stp_mxml_node_t *top,		/* I - Top node */
132             int         descend)	/* I - Descend into tree - STP_MXML_DESCEND, STP_MXML_NO_DESCEND, or STP_MXML_DESCEND_FIRST */
133{
134  if (!node)
135    return (NULL);
136  else if (node->child && descend)
137    return (node->child);
138  else if (node->next)
139    return (node->next);
140  else if (node->parent && node->parent != top)
141  {
142    node = node->parent;
143
144    while (!node->next)
145      if (node->parent == top || !node->parent)
146        return (NULL);
147      else
148        node = node->parent;
149
150    return (node->next);
151  }
152  else
153    return (NULL);
154}
155
156
157/*
158 * 'stp_mxmlWalkPrev()' - Walk to the previous logical node in the tree.
159 *
160 * The descend argument controls whether the previous node's last child
161 * is considered to be the previous node. The top node argument constrains
162 * the walk to the node's children.
163 */
164
165stp_mxml_node_t *				/* O - Previous node or NULL */
166stp_mxmlWalkPrev(stp_mxml_node_t *node,		/* I - Current node */
167             stp_mxml_node_t *top,		/* I - Top node */
168             int         descend)	/* I - Descend into tree - STP_MXML_DESCEND, STP_MXML_NO_DESCEND, or STP_MXML_DESCEND_FIRST */
169{
170  if (!node)
171    return (NULL);
172  else if (node->prev)
173  {
174    if (node->prev->last_child && descend)
175    {
176     /*
177      * Find the last child under the previous node...
178      */
179
180      node = node->prev->last_child;
181
182      while (node->last_child)
183        node = node->last_child;
184
185      return (node);
186    }
187    else
188      return (node->prev);
189  }
190  else if (node->parent != top)
191    return (node->parent);
192  else
193    return (NULL);
194}
195
196
197/*
198 * End of "$Id: mxml-search.c,v 1.7 2004/09/17 18:38:21 rleigh Exp $".
199 */
200