/* Copyright 2014-present Facebook. All Rights Reserved This file is part of GlusterFS. Author : Shreyas Siravara 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 #include #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; }