Show misc_parse.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* misc_parse.c
*
* Some simple parsing functions
*
*/
#include <libmisc/misc.h>
#include <glib.h>
int misc_num_args(char *str, char esc)
{
char *ptr;
int arg = 0, retval = 0;
/* if null argument or null string passed, then we return 0 */
if ((str == NULL) || (*str == '\0'))
goto done;
for (ptr = str; *ptr; ptr++) {
/* every non-esc char is an arg */
if (*ptr != esc) {
arg = 1;
continue;
}
/* find first esc char after an arg */
if (arg && (*ptr == esc)) {
arg = 0;
/* we count args once we find the first esc after the arg */
retval++;
continue;
}
/* multiple consecutive esc after an arg are ignored,
* i.e.: arg == 0 && ptr == esc */
}
/* if string ended with an arg and no esc, then we add the last arg
* in the total count */
if (arg)
retval++;
done:
return retval;
}
char * misc_parse_string(char *str, char esc, char **val)
{
char *ptr;
int arg = 0;
int esc_mode = 0;
/* if null argument or null string passed, then we return NULL */
if ((str == NULL) || (*str == '\0'))
return NULL;
for (ptr = str; *ptr; ptr++) {
/* esc chars at the beginning of the string are ignored */
/* every non-esc char is an arg */
if ((*ptr != esc) && !esc_mode) {
/* get rid of the first esc chars, if any */
if (!arg) str = ptr;
arg = 1;
continue;
}
/* find first esc char after an arg */
if (arg && (*ptr == esc)) {
arg = 0;
/* terminate string */
*ptr = '\0';
esc_mode = 1;
continue;
}
/* get rid of multiple consecutive esc char after the arg */
if (esc_mode && (*ptr != esc))
break;
}
/* copy first argument if necessary */
if (val != NULL) {
if (esc_mode || arg)
*val = strdup(str);
else
*val = NULL;
}
return ptr;
}
void misc_parse_unescape(char *str, char esc)
{
char *ptr;
char *trail;
int esc_mode = 0;
if (str == NULL) return;
for (trail=str, ptr=str; *ptr; ptr++) {
if (!esc_mode && (*ptr == esc)) {
esc_mode = 1;
continue;
}
esc_mode = 0;
*trail = *ptr;
trail++;
}
/* null term */
*trail = 0;
}
void misc_parse_reset(parser_state_t *state)
{
if (state && state->_input) {
free(state->_input);
state->_input = NULL;
}
state->consumed = 0;
}
parser_state_t * misc_parse_init(char *input, int scheme)
{
parser_state_t *ps = g_new0(parser_state_t, 1);
ps->input = input;
switch (scheme) {
default:
case MISC_PARSE_COLON_SCHEME:
break;
case MISC_PARSE_SEMICOLON_SCHEME:
ps->pair_delimit_set = ";";
break;
case MISC_PARSE_SEMICOLON_KEY_SCHEME:
ps->pair_delimit_set = ";";
ps->pair_assign_set = "";
break;
case MISC_PARSE_COMMA_SCHEME:
ps->pair_delimit_set = ",";
break;
case MISC_PARSE_LF_SCHEME:
ps->pair_delimit_set = "\n";
ps->pair_assign_set = "";
break;
// dootcam returns strings with ampersands as delimiters
case MISC_PARSE_AMPERSAND_SCHEME:
ps->pair_delimit_set = "&";
break;
}
return ps;
}
void misc_parse_cleanup(parser_state_t *state)
{
misc_parse_reset(state);
free(state);
}
int misc_parse_n_args(parser_state_t *state, char **keys, char **vals, int n)
{
int i;
memset(vals, 0, sizeof(char*)*n);
for (i=0; i<n; i++) {
if (misc_parse_next_kvp(state) < 0)
return -1;
if (state->value) {
if (keys && strcmp(state->key, keys[i])) {
elog(LOG_WARNING, "Argument key mismatch: %s,%s",
keys[i], state->key);
return -1;
}
vals[i] = strdup(state->value);
}
else
vals[i] = strdup(state->key);
}
/* check for nothing left.. */
if (misc_parse_next_kvp(state) < 0)
return 0;
/* some kind of string remains.. */
if (state->key && state->key[0])
return -1;
/* ok */
return 0;
}
void misc_free_n_args(char **args, int n)
{
int i;
for (i=0; i<n; i++)
if (args[i]) free(args[i]);
}
char *misc_parse_get_raw_value(parser_state_t *state, int *remain)
{
int offset;
if (state->value == NULL)
return NULL;
offset = state->value - state->_input;
if (remain) *remain = state->input_len - offset;
return state->input + offset;
}
int misc_parse_next_kvp(parser_state_t *state)
{
char *pair_dset = NULL;
char *pair_aset = NULL;
int esc_mode = 0;
int found_pair = 0;
/*
* initialization with defaults
*/
/* default length */
if (state->input_len == 0)
state->input_len = strlen(state->input);
/* copy input if needed, force null term */
if (state->_input == NULL) {
state->_input = malloc(state->input_len+1);
memmove(state->_input, state->input, state->input_len);
state->_input[state->input_len] = 0;
//state->_input[state->input_len+1] = 0;
}
/* default delimiter set */
if (state->pair_delimit_set)
pair_dset = state->pair_delimit_set;
else
pair_dset = ":\n";
/* default assignment set */
if (state->pair_assign_set)
pair_aset = state->pair_assign_set;
else
pair_aset = "=";
/* default escape */
if (state->escape_char == 0)
state->escape_char = '\\';
/*
* parse buffer
*/
/* init */
state->key = state->_input + state->consumed;
state->value = NULL;
state->pair_delimit = 0;
state->pair_assign = 0;
/* if we're starting out with no data, we're done */
if (state->consumed == state->input_len)
goto check_reset;
/* otherwise scan for next key */
while (state->consumed <= state->input_len) {
char c = state->_input[state->consumed];
/* if last char, force out of esacpe mode */
if (state->consumed == state->input_len)
esc_mode = 0;
/* check for escape char */
if (c == state->escape_char) {
esc_mode = 1;
goto nextchar;
}
/* escape mode? */
if (esc_mode) {
esc_mode = 0;
goto nextchar;
}
/* check for pair delimiter */
if ((c == 0) || strchr(pair_dset, c))
goto got_pair;
/* check for assign delimiter, unless second one.. */
if ((state->value == NULL) && strchr(pair_aset, c))
goto got_assign;
/* ok, next char */
goto nextchar;
got_pair:
/* record delimiter */
state->pair_delimit = c;
/* we found a pair */
found_pair = 1;
/* null term, advance, done */
state->_input[state->consumed] = 0;
state->consumed++;
goto unescape;
got_assign:
/* record delimit and null */
state->pair_assign = c;
state->_input[state->consumed] = 0;
state->value = state->_input + state->consumed+1;
/* fall through */
nextchar:
state->consumed++;
}
check_reset:
/* no new pair.. reset */
if (found_pair == 0) {
misc_parse_reset(state);
return -1;
}
unescape:
misc_parse_unescape(state->key, state->escape_char);
misc_parse_unescape(state->value, state->escape_char);
return state->pair_delimit;
}
void misc_parse_dump_curr_to_buf(buf_t *buf, parser_state_t *state)
{
bufprintf(buf, "%s", state->key);
if ((state->pair_assign) && (state->value)) {
bufprintf(buf, "%c%s", state->pair_assign, state->value);
}
bufprintf(buf, "%c", state->pair_delimit);
}
char **misc_parse_csv_to_vector(char *str)
{
buf_t buf;
parser_state_t *ps = misc_parse_init(str, MISC_PARSE_COMMA_SCHEME);
buf_init(&buf);
while (misc_parse_next_kvp(ps) >= 0) {
char *dup = strdup(ps->key);
bufcpy(&buf, &dup, sizeof(dup));
}
{
int x=0;
bufcpy(&buf, &x, sizeof(x));
}
misc_parse_cleanup(ps);
return (char**)buf.buf;
}
void misc_usage_uniquify(buf_t *in, buf_t *out)
{
parser_state_t *ps = misc_parse_init(in->buf, MISC_PARSE_LF_SCHEME);
buf_t *strs = buf_new();
buf_iter_t *iter = buf_item_iter_new(strs);
int header = 1;
while (misc_parse_next_kvp(ps) >= 0) {
char *ptr;
/* keep only the first entry with no preceding whitespace */
if (!isspace(ps->key[0])) {
if (header) {
header = 0;
goto keep;
}
goto skip;
}
/* extract the key */
ptr = strpbrk(ps->key, ":=");
if (ptr) {
char save = *ptr;
*ptr = 0;
for (buf_item_iter_top(iter); buf_item_iter_valid(iter);
buf_item_iter_next(iter)) {
if (strncmp(buf_item_iter_get_pointer(iter, -1), ps->key,
buf_item_iter_length(iter)) == 0)
goto skip;
}
buf_item_iter_append_str(iter, ps->key, strlen(ps->key));
*ptr = save;
}
keep:
bufprintf(out, "%s\n", ps->key);
skip:
continue;
}
buf_item_iter_destroy(iter, 1);
misc_parse_cleanup(ps);
}
int misc_parse_test_key(parser_state_t *state, char *key)
{
return strcasecmp(state->key, key) == 0;
}
See more files for this project here