File: xml_comment.c

package info (click to toggle)
pacemaker 3.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 68,576 kB
  • sloc: xml: 160,564; ansic: 143,744; python: 5,670; sh: 2,969; makefile: 2,426
file content (120 lines) | stat: -rw-r--r-- 3,602 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * Copyright 2024-2025 the Pacemaker project contributors
 *
 * The version control history for this file may have further details.
 *
 * This source code is licensed under the GNU Lesser General Public License
 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
 */

#include <crm_internal.h>

#include <stdbool.h>                    // bool, false
#include <stdio.h>                      // NULL

#include <libxml/tree.h>                // xmlDoc, xmlNode, etc.
#include <libxml/xmlstring.h>           // xmlChar

#include "crmcommon_private.h"

/*!
 * \internal
 * \brief Create a new XML comment belonging to a given document
 *
 * \param[in] doc      Document that new comment will belong to
 * \param[in] content  Comment content
 *
 * \return Newly created XML comment (guaranteed not to be \c NULL)
 */
xmlNode *
pcmk__xc_create(xmlDoc *doc, const char *content)
{
    xmlNode *node = NULL;

    // Pacemaker typically assumes every xmlNode has a doc
    pcmk__assert(doc != NULL);

    node = xmlNewDocComment(doc, (const xmlChar *) content);
    pcmk__mem_assert(node);
    pcmk__xml_new_private_data(node);
    return node;
}

/*!
 * \internal
 * \brief Check whether two comments have matching content (case-insensitive)
 *
 * \param[in] comment1  First comment node to compare
 * \param[in] comment2  Second comment node to compare
 *
 * \return \c true if \p comment1 and \p comment2 have matching content (by
 *         case-insensitive string comparison), or \c false otherwise
 */
bool
pcmk__xc_matches(const xmlNode *comment1, const xmlNode *comment2)
{
    pcmk__assert((comment1 != NULL) && (comment1->type == XML_COMMENT_NODE)
                 && (comment2 != NULL) && (comment2->type == XML_COMMENT_NODE));

    return pcmk__str_eq((const char *) comment1->content,
                        (const char *) comment2->content, pcmk__str_casei);
}

/*!
 * \internal
 * \brief Find a comment with matching content among children of specified XML
 *
 * \param[in] parent  XML whose children to search
 * \param[in] search  Comment whose content should be searched for
 *
 * \return Matching comment, or \c NULL if no match is found
 */
static xmlNode *
match_xc_child(const xmlNode *parent, const xmlNode *search)
{
    pcmk__assert((search != NULL) && (search->type == XML_COMMENT_NODE));

    for (xmlNode *child = pcmk__xml_first_child(parent); child != NULL;
         child = pcmk__xml_next(child)) {

        if (child->type != XML_COMMENT_NODE) {
            continue;
        }

        if (pcmk__xc_matches(child, search)) {
            return child;
        }
    }

    return NULL;
}

/*!
 * \internal
 * \brief Make one XML comment match another (in content)
 *
 * \param[in,out] parent   If \p target is NULL and this is not, add or update
 *                         comment child of this XML node that matches \p update
 * \param[in,out] target   If not NULL, update this XML comment node
 * \param[in]     update   Make comment content match this (must not be NULL)
 *
 * \note At least one of \parent and \target must be non-NULL
 */
void
pcmk__xc_update(xmlNode *parent, xmlNode *target, xmlNode *update)
{
    CRM_CHECK(update != NULL, return);
    CRM_CHECK(update->type == XML_COMMENT_NODE, return);

    if (target == NULL) {
        target = match_xc_child(parent, update);
    }

    if (target == NULL) {
        pcmk__xml_copy(parent, update);

    } else if (!pcmk__str_eq((const char *)target->content, (const char *)update->content, pcmk__str_casei)) {
        xmlFree(target->content);
        target->content = xmlStrdup(update->content);
    }
}