1
0
Fork 0

Adding upstream version 3.1.0+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 08:00:08 +01:00
parent 64dbec996d
commit cfcebb1a7d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
569 changed files with 205393 additions and 0 deletions

20
tools/re/CMakeLists.txt Normal file
View file

@ -0,0 +1,20 @@
# yangre
set(resrc
main.c)
set(format_sources
${format_sources}
${CMAKE_CURRENT_SOURCE_DIR}/*.c
PARENT_SCOPE)
add_executable(yangre ${resrc} ${compatsrc})
target_link_libraries(yangre yang)
install(TARGETS yangre DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ${PROJECT_SOURCE_DIR}/tools/re/yangre.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
target_include_directories(yangre BEFORE PRIVATE ${PROJECT_BINARY_DIR})
if(WIN32)
target_include_directories(yangre PRIVATE ${GETOPT_INCLUDE_DIR})
target_link_libraries(yangre ${GETOPT_LIBRARY})
endif()

461
tools/re/main.c Normal file
View file

@ -0,0 +1,461 @@
/**
* @file main.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Adam Piecek <piecek@cesnet.cz>
* @brief libyang's YANG Regular Expression tool
*
* Copyright (c) 2017 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE /* asprintf, strdup */
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "libyang.h"
#include "compat.h"
#include "tools/config.h"
struct yr_pattern {
char *expr;
ly_bool invert;
};
void
help(void)
{
fprintf(stdout, "YANG Regular Expressions processor.\n");
fprintf(stdout, "Usage:\n");
fprintf(stdout, " yangre [-hv]\n");
fprintf(stdout, " yangre [-V] -p <regexp1> [-i] [-p <regexp2> [-i] ...] <string>\n");
fprintf(stdout, " yangre [-V] -f <file>\n");
fprintf(stdout, "Returns 0 if string matches the pattern(s) or if otherwise successful.\n");
fprintf(stdout, "Returns 1 on error.\n");
fprintf(stdout, "Returns 2 if string does not match the pattern(s).\n\n");
fprintf(stdout, "Options:\n"
" -h, --help Show this help message and exit.\n"
" -v, --version Show version number and exit.\n"
" -V, --verbose Print the processing information.\n"
" -i, --invert-match Invert-match modifier for the closest preceding\n"
" pattern.\n"
" -p, --pattern=\"REGEXP\" Regular expression including the quoting,\n"
" which is applied the same way as in a YANG module.\n"
" -f, --file=\"FILE\" List of patterns and the <string> (separated by an\n"
" empty line) are taken from <file>. Invert-match is\n"
" indicated by the single space character at the \n"
" beginning of the pattern line. YANG quotation around\n"
" patterns is still expected, but that avoids issues with\n"
" reading quotation by shell. Avoid newline at the end\n"
" of the string line to represent empty <string>.");
fprintf(stdout, "Examples:\n"
" pattern \"[0-9a-fA-F]*\"; -> yangre -p '\"[0-9a-fA-F]*\"' '1F'\n"
" pattern '[a-zA-Z0-9\\-_.]*'; -> yangre -p \"'[a-zA-Z0-9\\-_.]*'\" 'a-b'\n"
" pattern [xX][mM][lL].*; -> yangre -p '[xX][mM][lL].*' 'xml-encoding'\n\n");
fprintf(stdout, "Note that to pass YANG quoting through your shell, you are supposed to use\n"
"the other quotation around. For not-quoted patterns, use single quotes.\n\n");
}
void
version(void)
{
fprintf(stdout, "yangre %s\n", PROJECT_VERSION);
}
void
pattern_error(LY_LOG_LEVEL level, const char *msg, const char *UNUSED(data_path), const char *UNUSED(schema_path),
uint64_t UNUSED(line))
{
if (level == LY_LLERR) {
fprintf(stderr, "yangre error: %s\n", msg);
}
}
static int
add_pattern(struct yr_pattern **patterns, int *counter, char *pattern)
{
void *reallocated;
int orig_counter;
/* Store the original number of items. */
orig_counter = *counter;
/* Reallocate 'patterns' memory with additional space. */
reallocated = realloc(*patterns, (orig_counter + 1) * sizeof **patterns);
if (!reallocated) {
goto error;
}
(*patterns) = reallocated;
/* Allocated memory is now larger. */
(*counter)++;
/* Copy the pattern and store it to the additonal space. */
(*patterns)[orig_counter].expr = strdup(pattern);
if (!(*patterns)[orig_counter].expr) {
goto error;
}
(*patterns)[orig_counter].invert = 0;
return 0;
error:
fprintf(stderr, "yangre error: memory allocation error.\n");
return 1;
}
static int
create_empty_string(char **str)
{
free(*str);
*str = malloc(sizeof(char));
if (!(*str)) {
fprintf(stderr, "yangre error: memory allocation failed.\n");
return 1;
}
(*str)[0] = '\0';
return 0;
}
static ly_bool
file_is_empty(FILE *fp)
{
int c;
c = fgetc(fp);
if (c == EOF) {
return 1;
} else {
ungetc(c, fp);
return 0;
}
}
/**
* @brief Open the @p filepath, parse patterns and given string-argument.
*
* @param[in] filepath File to parse. Contains patterns and string.
* @param[out] infile The file descriptor of @p filepath.
* @param[out] patterns Storage of patterns.
* @param[out] patterns_count Number of items in @p patterns.
* @param[out] strarg The string-argument to check.
* @return 0 on success.
*/
static int
parse_patterns_file(const char *filepath, FILE **infile, struct yr_pattern **patterns, int *patterns_count, char **strarg)
{
int blankline = 0;
char *str = NULL;
size_t len = 0;
ssize_t l;
*infile = fopen(filepath, "rb");
if (!(*infile)) {
fprintf(stderr, "yangre error: unable to open input file %s (%s).\n", optarg, strerror(errno));
goto error;
}
if (file_is_empty(*infile)) {
if (create_empty_string(strarg)) {
goto error;
}
return 0;
}
while ((l = getline(&str, &len, *infile)) != -1) {
if (!blankline && ((str[0] == '\n') || ((str[0] == '\r') && (str[1] == '\n')))) {
/* blank line */
blankline = 1;
continue;
}
if ((str[0] != '\n') && (str[0] != '\r') && (str[l - 1] == '\n')) {
/* remove ending newline */
if ((l > 1) && (str[l - 2] == '\r') && (str[l - 1] == '\n')) {
str[l - 2] = '\0';
} else {
str[l - 1] = '\0';
}
}
if (blankline) {
/* done - str is now the string to check */
blankline = 0;
*strarg = str;
break;
/* else read the patterns */
} else if (add_pattern(patterns, patterns_count, (str[0] == ' ') ? &str[1] : str)) {
goto error;
}
if (str[0] == ' ') {
/* set invert-match */
(*patterns)[*patterns_count - 1].invert = 1;
}
}
if (!str || (blankline && (str[0] != '\0'))) {
/* corner case, no input after blankline meaning the pattern to check is empty */
if (create_empty_string(&str)) {
goto error;
}
}
*strarg = str;
return 0;
error:
free(str);
if (*infile) {
fclose(*infile);
*infile = NULL;
}
*strarg = NULL;
return 1;
}
static char *
modstr_init(void)
{
const char *module_start = "module yangre {"
"yang-version 1.1;"
"namespace urn:cesnet:libyang:yangre;"
"prefix re;"
"leaf pattern {"
" type string {";
return strdup(module_start);
}
static char *
modstr_add_pattern(char **modstr, const struct yr_pattern *pattern)
{
char *new;
const char *module_invertmatch = " { modifier invert-match; }";
const char *module_match = ";";
if (asprintf(&new, "%s pattern %s%s", *modstr, pattern->expr,
pattern->invert ? module_invertmatch : module_match) == -1) {
fprintf(stderr, "yangre error: memory allocation failed.\n");
return NULL;
}
free(*modstr);
*modstr = NULL;
return new;
}
static char *
modstr_add_ending(char **modstr)
{
char *new;
static const char *module_end = "}}}";
if (asprintf(&new, "%s%s", *modstr, module_end) == -1) {
fprintf(stderr, "yangre error: memory allocation failed.\n");
return NULL;
}
free(*modstr);
*modstr = NULL;
return new;
}
static int
create_module(struct yr_pattern *patterns, int patterns_count, char **mod)
{
int i;
char *new = NULL, *modstr;
if (!(modstr = modstr_init())) {
goto error;
}
for (i = 0; i < patterns_count; i++) {
if (!(new = modstr_add_pattern(&modstr, &patterns[i]))) {
goto error;
}
modstr = new;
}
if (!(new = modstr_add_ending(&modstr))) {
goto error;
}
*mod = new;
return 0;
error:
*mod = NULL;
free(new);
free(modstr);
return 1;
}
static void
print_verbose(struct yr_pattern *patterns, int patterns_count, char *str, LY_ERR match)
{
int i;
for (i = 0; i < patterns_count; i++) {
fprintf(stdout, "pattern %d: %s\n", i + 1, patterns[i].expr);
fprintf(stdout, "matching %d: %s\n", i + 1, patterns[i].invert ? "inverted" : "regular");
}
fprintf(stdout, "string : %s\n", str);
if (match == LY_SUCCESS) {
fprintf(stdout, "result : matching\n");
} else if (match == LY_EVALID) {
fprintf(stdout, "result : not matching\n");
} else {
fprintf(stdout, "result : error (%s)\n", ly_last_logmsg());
}
}
int
main(int argc, char *argv[])
{
LY_ERR match;
int i, opt_index = 0, ret = 1, verbose = 0;
struct option options[] = {
{"help", no_argument, NULL, 'h'},
{"file", required_argument, NULL, 'f'},
{"invert-match", no_argument, NULL, 'i'},
{"pattern", required_argument, NULL, 'p'},
{"version", no_argument, NULL, 'v'},
{"verbose", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
struct yr_pattern *patterns = NULL;
char *str = NULL, *modstr = NULL;
int patterns_count = 0;
struct ly_ctx *ctx = NULL;
struct lys_module *mod;
FILE *infile = NULL;
ly_bool info_printed = 0;
opterr = 0;
while ((i = getopt_long(argc, argv, "hf:ivVp:", options, &opt_index)) != -1) {
switch (i) {
case 'h':
help();
info_printed = 1;
break;
case 'f':
if (infile) {
help();
fprintf(stderr, "yangre error: multiple input files are not supported.\n");
goto cleanup;
} else if (patterns_count) {
help();
fprintf(stderr, "yangre error: command line patterns cannot be mixed with file input.\n");
goto cleanup;
}
if (parse_patterns_file(optarg, &infile, &patterns, &patterns_count, &str)) {
goto cleanup;
}
break;
case 'i':
if (!patterns_count || patterns[patterns_count - 1].invert) {
help();
fprintf(stderr, "yangre error: invert-match option must follow some pattern.\n");
goto cleanup;
}
patterns[patterns_count - 1].invert = 1;
break;
case 'p':
if (infile) {
help();
fprintf(stderr, "yangre error: command line patterns cannot be mixed with file input.\n");
goto cleanup;
}
if (add_pattern(&patterns, &patterns_count, optarg)) {
goto cleanup;
}
break;
case 'v':
version();
info_printed = 1;
break;
case 'V':
verbose = 1;
break;
default:
help();
if (optopt) {
fprintf(stderr, "yangre error: invalid option: -%c\n", optopt);
} else {
fprintf(stderr, "yangre error: invalid option: %s\n", argv[optind - 1]);
}
goto cleanup;
}
}
if (info_printed) {
ret = 0;
goto cleanup;
}
if (!str) {
/* check options compatibility */
if (optind >= argc) {
help();
fprintf(stderr, "yangre error: missing <string> parameter to process.\n");
goto cleanup;
} else if (!patterns_count) {
help();
fprintf(stderr, "yangre error: missing pattern parameter to use.\n");
goto cleanup;
}
str = argv[optind];
}
if (create_module(patterns, patterns_count, &modstr)) {
goto cleanup;
}
if (ly_ctx_new(NULL, 0, &ctx)) {
goto cleanup;
}
ly_set_log_clb(pattern_error);
if (lys_parse_mem(ctx, modstr, LYS_IN_YANG, &mod) || !mod->compiled || !mod->compiled->data) {
goto cleanup;
}
/* check the value */
match = lyd_value_validate(ctx, mod->compiled->data, str, strlen(str), NULL, NULL, NULL);
if (verbose) {
print_verbose(patterns, patterns_count, str, match);
}
if (match == LY_SUCCESS) {
ret = 0;
} else if (match == LY_EVALID) {
ret = 2;
} else {
ret = 1;
}
cleanup:
ly_ctx_destroy(ctx);
for (i = 0; i < patterns_count; i++) {
free(patterns[i].expr);
}
if (patterns_count) {
free(patterns);
}
free(modstr);
if (infile) {
fclose(infile);
free(str);
}
return ret;
}

118
tools/re/yangre.1 Normal file
View file

@ -0,0 +1,118 @@
.\" Manpage for yanglint.
.\" Process this file with
.\" groff -man -Tascii yangre.1
.\"
.TH YANGRE 1 "2018-11-09" "libyang"
.SH NAME
yangre \- YANG regular expression processor
.
.SH SYNOPSIS
.B yangre
[\-V] \-p \fIREGEXP\fP [\-i] [\-p \fIREGEXP\fP [\-i]...] \fISTRING\fP
.br
.B yangre
[\-V] \-f \fIFILE\fP
.
.SH DESCRIPTION
\fByangre\fP is a command-line tool to test and evaluate regular expressions
for use in YANG schemas. Supported regular expressions are defined by the
W3C's XML-Schema standard.
\fByangre\fP can be used either with regular expressions and a target string
on the command line or with input from a file. The latter is particularly
useful to avoid dealing with proper shell escaping of regular expression
patterns, which can be somewhat tricky.
.
.SH GENERAL OPTIONS
.TP
.BR "\-h\fR,\fP \-\^\-help"
.br
Outputs usage help and exits.
.TP
.BR "\-v\fR,\fP \-\^\-version"
.br
Outputs the version number and exits.
.TP
.BR "\-V\fR,\fP \-\^\-verbose"
Increases the verbosity level. If not specified, only errors are printed, with
each appearance it adds: warnings, verbose messages, debug messages (if compiled
with debug information).
.SH COMMAND LINE INPUT
.TP
.BR "\-p \fIREGEXP\fP\fR,\fP \-\^\-pattern=\fIREGEXP\fP"
.br
One or more regular expression patterns to be tested against the input
string. Supplied expressions are tested in the order they appear on the
command line. Testing is aborted when an expression does not match (or
does match, if the \fB-i\fP option is used.)
.TP
.BR "\-i\fR,\fP \-\^\-invert-match"
.br
Reverse match condition for the previous pattern. If the pattern matches,
an error is printed and evaluation is aborted.
.TP
.BR "\fISTRING\fP"
.br
Target text input to match the regular expression(s) against. The same
text is used for all regular expressions. Note that only the first
argument is used by \fByangre\fP, if it contains spaces or other shell
metacharacters they must be properly escaped. Additional arguments are
silently ignored.
.SH FILE INPUT
.TP
.BR "\-f \fIFILE\fP\fR,\fP \-\^\-file=\fIFILE\fP"
Read both patterns and target text from the specified input file.
\fIFILE\fP must consist of one or more YANG regular expressions, each on
their own line, followed by a blank line and one line of target text. No
preprocessing is done on file input, there are no comment lines and
whitespace is not stripped. A single space character at the beginning of
a pattern line inverts the match condition for the pattern on that line.
Patterns must still be properly quoted as mandated by the YANG standard.
.SH RETURN VALUES
.TP
0
.I Successful match
.br
The target text matched for all patterns.
.TP
1
.I Pattern mismatch
.br
One or more patterns did not match the target text. An error message is
printed to stderr describing which pattern was the first not to match.
.TP
255
.I Other error
.br
One or more patterns could not be processed or some other error occurred that
precluded processing.
.SH EXAMPLES
.IP \[bu] 2
Test a single pattern:
yangre -p 'te.*xt' text_text
.IP \[bu]
Test multiple patterns:
yangre -p '.*pat1' -p 'pat2.*' -p 'notpat' -i pat2testpat1
.IP \[bu]
Input from a file:
cat > /tmp/patterns <<EOF
.*pat1
pat2.*
notpat
pat2testpat1
EOF
yangre -f /tmp/patterns
.SH SEE ALSO
https://github.com/CESNET/libyang (libyang homepage and Git repository)
.
.SH AUTHORS
Radek Krejci <rkrejci@cesnet.cz>, Michal Vasko <mvasko@cesnet.cz>
.br
This man page was written by David Lamparter <equinox@diac24.net>
.
.SH COPYRIGHT
Copyright \(co 2015-2018 CESNET, a.l.e.