diff options
Diffstat (limited to 'libglusterfs/src/parse-utils.c')
| -rw-r--r-- | libglusterfs/src/parse-utils.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/libglusterfs/src/parse-utils.c b/libglusterfs/src/parse-utils.c new file mode 100644 index 00000000000..4531d5f0170 --- /dev/null +++ b/libglusterfs/src/parse-utils.c @@ -0,0 +1,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; +} |
