summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/parse-utils.c
blob: 4531d5f017012a1676d65011b92e26e5f6201000 (plain)
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
   Copyright 2014-present Facebook. All Rights Reserved

   This file is part of GlusterFS.

   Author :
   Shreyas Siravara <shreyas.siravara@gmail.com>

   This file is licensed to you under your choice of the GNU Lesser
   General Public License, version 3 or any later version (LGPLv3 or
   later), or the GNU General Public License, version 2 (GPLv2), in all
   cases as published by the Free Software Foundation.
*/

#include <regex.h>
#include <stdio.h>

#include "glusterfs/parse-utils.h"
#include "glusterfs/mem-pool.h"
#include "glusterfs/common-utils.h"
#include "glusterfs/libglusterfs-messages.h"

/**
 * parser_init: Initialize a parser with the a string to parse and
 * the regex we want to use to parse it.
 *
 * @complete_str: the string to parse
 * @regex       : the regex to use
 *
 * Notes        : It is up to the caller to call the parser_deinit () function
 *                to free the allocated parser.
 *
 * @return      : success: parser ptr (on successful compilation and allocation)
 *              : failure: NULL (on failure to compile regex or allocate memory)
 */
struct parser *
parser_init(const char *regex)
{
    int rc = 0;
    struct parser *parser = NULL;

    parser = GF_MALLOC(sizeof(*parser), gf_common_mt_parser_t);
    if (!parser)
        goto out;

    parser->regex = gf_strdup(regex);
    if (!parser->regex) {
        GF_FREE(parser);
        parser = NULL;
        goto out;
    }

    rc = regcomp(&parser->preg, parser->regex, REG_EXTENDED);
    if (rc != 0) {
        gf_msg(GF_PARSE, GF_LOG_INFO, 0, LG_MSG_REGEX_OP_FAILED,
               "Failed to compile regex pattern.");
        parser_deinit(parser);
        parser = NULL;
        goto out;
    }
    parser->complete_str = NULL;
out:
    return parser;
}

/**
 * parser_set_string -- Set the string in the parser that we want to parse.
 *                      Subsequent calls to get_next_match () will use this
 *                      string along with the regex that the parser was
 *                      initialized with.
 *
 * @parser      : The parser to use
 * @complete_str: The string to set in the parser (what we are going parse)
 *
 * @return: success: 0
 *          failure: -EINVAL for NULL args, -ENOMEM for allocation errors
 */
int
parser_set_string(struct parser *parser, const char *complete_str)
{
    int ret = -EINVAL;

    GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out);
    GF_VALIDATE_OR_GOTO(GF_PARSE, complete_str, out);

    parser->complete_str = gf_strdup(complete_str);
    GF_CHECK_ALLOC_AND_LOG(GF_PARSE, parser, ret, "Failed to duplicate string!",
                           out);

    /* Point the temp internal string to what we just dup'ed */
    parser->_rstr = (char *)parser->complete_str;
    ret = 0;
out:
    return ret;
}

/**
 * parser_unset_string -- Free the string that was set to be parsed.
 *                        This function needs to be called after
 *                        parser_set_string and parser_get_next_match
 *                        in order to free memory used by the string.
 *
 * @parser      : The parser to free memory in
 * @return      : success: 0
 *              : failure: -EINVAL on NULL args
 */
int
parser_unset_string(struct parser *parser)
{
    int ret = -EINVAL;

    GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out);

    GF_FREE(parser->complete_str);
    parser->complete_str = NULL; /* Avoid double frees in parser_deinit */
    ret = 0;
out:
    return ret;
}

/**
 * parser_deinit: Free the parser and all the memory allocated by it
 *
 * @parser    : Parser to free
 *
 * @return    : nothing
 */
void
parser_deinit(struct parser *ptr)
{
    if (!ptr)
        return;

    regfree(&ptr->preg);
    GF_FREE(ptr->complete_str);
    GF_FREE(ptr->regex);
    GF_FREE(ptr);
}

/**
 * parser_get_match: Given the parser that is configured with a compiled regex,
 * return the next match in the string.
 *
 * @parser    : Parser to use
 *
 * @return    : success: Pointer to matched character
 *            : failure: NULL
 */
char *
parser_get_next_match(struct parser *parser)
{
    int rc = -EINVAL;
    size_t copy_len = 0;
    char *match = NULL;

    GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out);

    rc = regexec(&parser->preg, parser->_rstr, 1, parser->pmatch, 0);
    if (rc != 0) {
        gf_msg_debug(GF_PARSE, 0, "Could not match %s with regex %s",
                     parser->_rstr, parser->regex);
        goto out;
    }

    copy_len = parser->pmatch[0].rm_eo - parser->pmatch[0].rm_so;

    match = gf_strndup(parser->_rstr + parser->pmatch[0].rm_so, copy_len);
    GF_CHECK_ALLOC_AND_LOG(GF_PARSE, match, rc, "Duplicating match failed!",
                           out);

    parser->_rstr = &parser->_rstr[parser->pmatch[0].rm_eo];
out:
    return match;
}