mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 10:09:17 +00:00
lib: add string utilities
I see lots of the same code being copy-pasted and slightly tweaked for string processing all over the codebase. Time to start aggregating these pieces into something consistent and correct. Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
a86dc99646
commit
fe011935cd
116
lib/command.c
116
lib/command.c
@ -25,17 +25,17 @@
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <lib/version.h>
|
||||
|
||||
|
||||
#include "command.h"
|
||||
#include "frrstr.h"
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "log_int.h"
|
||||
#include <lib/version.h>
|
||||
#include "thread.h"
|
||||
#include "vector.h"
|
||||
#include "linklist.h"
|
||||
#include "vty.h"
|
||||
#include "command.h"
|
||||
#include "workqueue.h"
|
||||
#include "vrf.h"
|
||||
#include "command_match.h"
|
||||
@ -46,7 +46,6 @@
|
||||
#include "jhash.h"
|
||||
|
||||
DEFINE_MTYPE(LIB, HOST, "Host config")
|
||||
DEFINE_MTYPE(LIB, STRVEC, "String vector")
|
||||
DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
|
||||
|
||||
#define item(x) \
|
||||
@ -259,30 +258,46 @@ void print_version(const char *progname)
|
||||
printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
|
||||
}
|
||||
|
||||
|
||||
/* Utility function to concatenate argv argument into a single string
|
||||
with inserting ' ' character between each argument. */
|
||||
char *argv_concat(struct cmd_token **argv, int argc, int shift)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
char *str;
|
||||
char *p;
|
||||
int cnt = argc - shift;
|
||||
const char *argstr[cnt];
|
||||
|
||||
len = 0;
|
||||
for (i = shift; i < argc; i++)
|
||||
len += strlen(argv[i]->arg) + 1;
|
||||
if (!len)
|
||||
for (int i = 0; i < cnt; i++)
|
||||
argstr[i] = argv[i + shift]->arg;
|
||||
|
||||
return frrstr_join(argstr, cnt, " ");
|
||||
}
|
||||
|
||||
vector cmd_make_strvec(const char *string)
|
||||
{
|
||||
if (!string)
|
||||
return NULL;
|
||||
p = str = XMALLOC(MTYPE_TMP, len);
|
||||
for (i = shift; i < argc; i++) {
|
||||
size_t arglen;
|
||||
memcpy(p, argv[i]->arg, (arglen = strlen(argv[i]->arg)));
|
||||
p += arglen;
|
||||
*p++ = ' ';
|
||||
|
||||
const char *copy = string;
|
||||
|
||||
/* skip leading whitespace */
|
||||
while (isspace((int)*copy) && *copy != '\0')
|
||||
copy++;
|
||||
|
||||
/* if the entire string was whitespace or a comment, return */
|
||||
if (*copy == '\0' || *copy == '!' || *copy == '#')
|
||||
return NULL;
|
||||
|
||||
vector result = frrstr_split_vec(copy, " \n\r\t");
|
||||
|
||||
for (unsigned int i = 0; i < vector_active(result); i++) {
|
||||
if (strlen(vector_slot(result, i)) == 0) {
|
||||
XFREE(MTYPE_TMP, vector_slot(result, i));
|
||||
vector_unset(result, i);
|
||||
}
|
||||
*(p - 1) = '\0';
|
||||
return str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void cmd_free_strvec(vector v)
|
||||
{
|
||||
frrstr_strvec_free(v);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,61 +347,6 @@ void install_node(struct cmd_node *node, int (*func)(struct vty *))
|
||||
"Command Hash");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a string, storing tokens in a vector.
|
||||
* Whitespace is ignored.
|
||||
*
|
||||
* Delimiter string = " \n\r\t".
|
||||
*
|
||||
* @param string to tokenize
|
||||
* @return tokenized string
|
||||
*/
|
||||
vector cmd_make_strvec(const char *string)
|
||||
{
|
||||
if (!string)
|
||||
return NULL;
|
||||
|
||||
char *copy, *copystart;
|
||||
copystart = copy = XSTRDUP(MTYPE_TMP, string);
|
||||
|
||||
// skip leading whitespace
|
||||
while (isspace((int)*copy) && *copy != '\0')
|
||||
copy++;
|
||||
|
||||
// if the entire string was whitespace or a comment, return
|
||||
if (*copy == '\0' || *copy == '!' || *copy == '#') {
|
||||
XFREE(MTYPE_TMP, copystart);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector strvec = vector_init(VECTOR_MIN_SIZE);
|
||||
const char *delim = " \n\r\t", *tok = NULL;
|
||||
while (copy) {
|
||||
tok = strsep(©, delim);
|
||||
if (*tok != '\0')
|
||||
vector_set(strvec, XSTRDUP(MTYPE_STRVEC, tok));
|
||||
}
|
||||
|
||||
XFREE(MTYPE_TMP, copystart);
|
||||
return strvec;
|
||||
}
|
||||
|
||||
/* Free allocated string vector. */
|
||||
void cmd_free_strvec(vector v)
|
||||
{
|
||||
unsigned int i;
|
||||
char *cp;
|
||||
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
for (i = 0; i < vector_active(v); i++)
|
||||
if ((cp = vector_slot(v, i)) != NULL)
|
||||
XFREE(MTYPE_STRVEC, cp);
|
||||
|
||||
vector_free(v);
|
||||
}
|
||||
|
||||
/* Return prompt character of specified node. */
|
||||
const char *cmd_prompt(enum node_type node)
|
||||
{
|
||||
|
@ -33,9 +33,6 @@
|
||||
DECLARE_MTYPE(HOST)
|
||||
DECLARE_MTYPE(COMPLETION)
|
||||
|
||||
/* for test-commands.c */
|
||||
DECLARE_MTYPE(STRVEC)
|
||||
|
||||
/* Host configuration variable */
|
||||
struct host {
|
||||
/* Host name of this router. */
|
||||
|
141
lib/frrstr.c
Normal file
141
lib/frrstr.c
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* FRR string processing utilities.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Quentin Young
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "frrstr.h"
|
||||
#include "memory.h"
|
||||
#include "vector.h"
|
||||
|
||||
void frrstr_split(const char *string, const char *delimiter, char ***result,
|
||||
int *argc)
|
||||
{
|
||||
if (!string)
|
||||
return;
|
||||
|
||||
unsigned int sz = 4, idx = 0;
|
||||
char *copy, *copystart;
|
||||
*result = XCALLOC(MTYPE_TMP, sizeof(char *) * sz);
|
||||
copystart = copy = XSTRDUP(MTYPE_TMP, string);
|
||||
*argc = 0;
|
||||
|
||||
const char *tok = NULL;
|
||||
while (copy) {
|
||||
tok = strsep(©, delimiter);
|
||||
(*result)[idx] = XSTRDUP(MTYPE_TMP, tok);
|
||||
if (++idx == sz)
|
||||
*result = XREALLOC(MTYPE_TMP, *result,
|
||||
(sz *= 2) * sizeof(char *));
|
||||
(*argc)++;
|
||||
}
|
||||
|
||||
XFREE(MTYPE_TMP, copystart);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
vector frrstr_split_vec(const char *string, const char *delimiter)
|
||||
{
|
||||
char **result;
|
||||
int argc;
|
||||
|
||||
frrstr_split(string, delimiter, &result, &argc);
|
||||
|
||||
vector v = array_to_vector((void **)result, argc);
|
||||
XFREE(MTYPE_TMP, result);
|
||||
return v;
|
||||
}
|
||||
|
||||
char *frrstr_join(const char **parts, int argc, const char *join)
|
||||
{
|
||||
int i;
|
||||
char *str;
|
||||
char *p;
|
||||
size_t len = 0;
|
||||
size_t joinlen = join ? strlen(join) : 0;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
len += strlen(parts[i]);
|
||||
len += argc * joinlen + 1;
|
||||
|
||||
if (!len)
|
||||
return NULL;
|
||||
|
||||
p = str = XMALLOC(MTYPE_TMP, len);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
size_t arglen = strlen(parts[i]);
|
||||
memcpy(p, parts[i], arglen);
|
||||
p += arglen;
|
||||
if (i + 1 != argc) {
|
||||
memcpy(p, join, joinlen);
|
||||
p += joinlen;
|
||||
}
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *frrstr_join_vec(vector v, const char *join)
|
||||
{
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
vector_to_array(v, (void ***)&argv, &argc);
|
||||
|
||||
char *ret = frrstr_join((const char **)argv, argc, join);
|
||||
|
||||
XFREE(MTYPE_TMP, argv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void frrstr_filter_vec(vector v, regex_t *filter)
|
||||
{
|
||||
regmatch_t ignored[1];
|
||||
for (unsigned int i = 0; i < vector_active(v); i++) {
|
||||
if (regexec(filter, vector_slot(v, i), 0, ignored, 0)) {
|
||||
XFREE(MTYPE_TMP, vector_slot(v, i));
|
||||
vector_unset(v, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frrstr_strvec_free(vector v)
|
||||
{
|
||||
unsigned int i;
|
||||
char *cp;
|
||||
|
||||
if (!v)
|
||||
return;
|
||||
|
||||
for (i = 0; i < vector_active(v); i++) {
|
||||
cp = vector_slot(v, i);
|
||||
XFREE(MTYPE_TMP, cp);
|
||||
}
|
||||
|
||||
vector_free(v);
|
||||
}
|
||||
|
86
lib/frrstr.h
Normal file
86
lib/frrstr.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* FRR string processing utilities.
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Quentin Young
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRRSTR_H_
|
||||
#define _FRRSTR_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
/*
|
||||
* Tokenizes a string, storing tokens in a vector. Whitespace is ignored.
|
||||
* Delimiter characters are not included.
|
||||
*
|
||||
* string
|
||||
* The string to split
|
||||
*
|
||||
* delimiter
|
||||
* Delimiter string, as used in strsep()
|
||||
*
|
||||
* Returns:
|
||||
* The split string. Each token is allocated with MTYPE_TMP.
|
||||
*/
|
||||
void frrstr_split(const char *string, const char *delimiter, char ***result,
|
||||
int *argc);
|
||||
vector frrstr_split_vec(const char *string, const char *delimiter);
|
||||
|
||||
/*
|
||||
* Concatenate string array into a single string.
|
||||
*
|
||||
* argv
|
||||
* array of string pointers to concatenate
|
||||
*
|
||||
* argc
|
||||
* array length
|
||||
*
|
||||
* join
|
||||
* string to insert between each part, or NULL for nothing
|
||||
*
|
||||
* Returns:
|
||||
* the joined string, allocated with MTYPE_TMP
|
||||
*/
|
||||
char *frrstr_join(const char **parts, int argc, const char *join);
|
||||
char *frrstr_join_vec(vector v, const char *join);
|
||||
|
||||
/*
|
||||
* Filter string vector.
|
||||
* Removes lines that do not contain a match for the provided regex.
|
||||
*
|
||||
* v
|
||||
* The vector to filter.
|
||||
*
|
||||
* filter
|
||||
* Regex to filter with.
|
||||
*/
|
||||
void frrstr_filter_vec(vector v, regex_t *filter);
|
||||
|
||||
/*
|
||||
* Free allocated string vector.
|
||||
* Assumes each item is allocated with MTYPE_TMP.
|
||||
*
|
||||
* v
|
||||
* the vector to free
|
||||
*/
|
||||
void frrstr_strvec_free(vector v);
|
||||
|
||||
|
||||
#endif /* _FRRSTR_H_ */
|
@ -21,6 +21,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/ferr.c \
|
||||
lib/filter.c \
|
||||
lib/frr_pthread.c \
|
||||
lib/frrstr.c \
|
||||
lib/getopt.c \
|
||||
lib/getopt1.c \
|
||||
lib/grammar_sandbox.c \
|
||||
@ -105,6 +106,7 @@ pkginclude_HEADERS += \
|
||||
lib/freebsd-queue.h \
|
||||
lib/frr_pthread.h \
|
||||
lib/frratomic.h \
|
||||
lib/frrstr.h \
|
||||
lib/getopt.h \
|
||||
lib/graph.h \
|
||||
lib/hash.h \
|
||||
|
15
lib/vector.c
15
lib/vector.c
@ -181,3 +181,18 @@ unsigned int vector_count(vector v)
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void vector_to_array(vector v, void ***dest, int *argc)
|
||||
{
|
||||
*dest = XCALLOC(MTYPE_TMP, sizeof(void *) * v->active);
|
||||
memcpy(*dest, v->index, sizeof(void *) * v->active);
|
||||
*argc = v->active;
|
||||
}
|
||||
|
||||
vector array_to_vector(void **src, int argc)
|
||||
{
|
||||
vector v = vector_init(VECTOR_MIN_SIZE);
|
||||
for (int i = 0; i < argc; i++)
|
||||
vector_set_index(v, i, src[i]);
|
||||
return v;
|
||||
}
|
||||
|
@ -59,5 +59,6 @@ extern vector vector_copy(vector v);
|
||||
|
||||
extern void *vector_lookup(vector, unsigned int);
|
||||
extern void *vector_lookup_ensure(vector, unsigned int);
|
||||
|
||||
extern void vector_to_array(vector v, void ***dest, int *argc);
|
||||
extern vector array_to_vector(void **src, int argc);
|
||||
#endif /* _ZEBRA_VECTOR_H */
|
||||
|
@ -130,7 +130,7 @@ static void test_load(void)
|
||||
line[strlen(line) - 1] = '\0';
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line));
|
||||
vector_set(test_cmds, XSTRDUP(MTYPE_TMP, line));
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ static void test_terminate(void)
|
||||
|
||||
vty_terminate();
|
||||
for (i = 0; i < vector_active(test_cmds); i++)
|
||||
XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i));
|
||||
XFREE(MTYPE_TMP, vector_slot(test_cmds, i));
|
||||
vector_free(test_cmds);
|
||||
cmd_terminate();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user