diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 04:20:26 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 04:20:26 +0000 |
commit | 044203039cebe3c05161f8f104a039d4744ca6d0 (patch) | |
tree | 1073c2308492e6aea4c66cb7436ee92db2abfd42 /tools/re/main.c | |
parent | Initial commit. (diff) | |
download | libyang2-044203039cebe3c05161f8f104a039d4744ca6d0.tar.xz libyang2-044203039cebe3c05161f8f104a039d4744ca6d0.zip |
Adding upstream version 2.1.30.upstream/2.1.30
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/re/main.c')
-rw-r--r-- | tools/re/main.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/tools/re/main.c b/tools/re/main.c new file mode 100644 index 0000000..2292b2a --- /dev/null +++ b/tools/re/main.c @@ -0,0 +1,309 @@ +/** + * @file main.c + * @author Radek Krejci <rkrejci@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" + +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), 1 if not and -1 on error.\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 *path) +{ + (void) path; /* unused */ + + if (level == LY_LLERR) { + fprintf(stderr, "yangre error: %s\n", msg); + } +} + +static const char *module_start = "module yangre {" + "yang-version 1.1;" + "namespace urn:cesnet:libyang:yangre;" + "prefix re;" + "leaf pattern {" + " type string {"; +static const char *module_invertmatch = " { modifier invert-match; }"; +static const char *module_match = ";"; +static const char *module_end = "}}}"; + +static int +add_pattern(char ***patterns, int **inverts, int *counter, char *pattern) +{ + void *reallocated1, *reallocated2; + + (*counter)++; + reallocated1 = realloc(*patterns, *counter * sizeof **patterns); + reallocated2 = realloc(*inverts, *counter * sizeof **inverts); + if (!reallocated1 || !reallocated2) { + fprintf(stderr, "yangre error: memory allocation error.\n"); + free(reallocated1); + free(reallocated2); + return EXIT_FAILURE; + } + (*patterns) = reallocated1; + (*patterns)[*counter - 1] = strdup(pattern); + (*inverts) = reallocated2; + (*inverts)[*counter - 1] = 0; + + return EXIT_SUCCESS; +} + +int +main(int argc, char *argv[]) +{ + LY_ERR match; + int i, opt_index = 0, ret = -1, verbose = 0, blankline = 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} + }; + char **patterns = NULL, *str = NULL, *modstr = NULL, *s; + int *invert_match = NULL; + int patterns_count = 0; + struct ly_ctx *ctx = NULL; + struct lys_module *mod; + FILE *infile = NULL; + size_t len = 0; + ssize_t l; + + opterr = 0; + while ((i = getopt_long(argc, argv, "hf:ivVp:", options, &opt_index)) != -1) { + switch (i) { + case 'h': + help(); + ret = -2; /* continue to allow printing version and help at once */ + 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; + } + infile = fopen(optarg, "rb"); + if (!infile) { + fprintf(stderr, "yangre error: unable to open input file %s (%s).\n", optarg, strerror(errno)); + goto cleanup; + } + + while ((l = getline(&str, &len, infile)) != -1) { + if (!blankline && (str[0] == '\n')) { + /* blank line */ + blankline = 1; + continue; + } + if ((str[0] != '\n') && (str[l - 1] == '\n')) { + /* remove ending newline */ + str[l - 1] = '\0'; + } + if (blankline) { + /* done - str is now the string to check */ + blankline = 0; + break; + /* else read the patterns */ + } else if (add_pattern(&patterns, &invert_match, &patterns_count, + (str[0] == ' ') ? &str[1] : str)) { + goto cleanup; + } + if (str[0] == ' ') { + /* set invert-match */ + invert_match[patterns_count - 1] = 1; + } + } + if (blankline) { + /* corner case, no input after blankline meaning the pattern to check is empty */ + if (str != NULL) { + free(str); + } + str = malloc(sizeof(char)); + str[0] = '\0'; + } + break; + case 'i': + if (!patterns_count || invert_match[patterns_count - 1]) { + help(); + fprintf(stderr, "yangre error: invert-match option must follow some pattern.\n"); + goto cleanup; + } + invert_match[patterns_count - 1] = 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, &invert_match, &patterns_count, optarg)) { + goto cleanup; + } + break; + case 'v': + version(); + ret = -2; /* continue to allow printing version and help at once */ + 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 (ret == -2) { + 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]; + } + + for (modstr = (char *)module_start, i = 0; i < patterns_count; i++) { + if (asprintf(&s, "%s pattern %s%s", modstr, patterns[i], invert_match[i] ? module_invertmatch : module_match) == -1) { + fprintf(stderr, "yangre error: memory allocation failed.\n"); + goto cleanup; + } + if (modstr != module_start) { + free(modstr); + } + modstr = s; + } + if (asprintf(&s, "%s%s", modstr, module_end) == -1) { + fprintf(stderr, "yangre error: memory allocation failed.\n"); + goto cleanup; + } + if (modstr != module_start) { + free(modstr); + } + modstr = s; + + if (ly_ctx_new(NULL, 0, &ctx)) { + goto cleanup; + } + + ly_set_log_clb(pattern_error, 0); + 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) { + for (i = 0; i < patterns_count; i++) { + fprintf(stdout, "pattern %d: %s\n", i + 1, patterns[i]); + fprintf(stdout, "matching %d: %s\n", i + 1, invert_match[i] ? "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_errmsg(ctx)); + } + } + if (match == LY_SUCCESS) { + ret = 0; + } else if (match == LY_EVALID) { + ret = 1; + } else { + ret = -1; + } + +cleanup: + ly_ctx_destroy(ctx); + for (i = 0; i < patterns_count; i++) { + free(patterns[i]); + } + free(patterns); + free(invert_match); + free(modstr); + if (infile) { + fclose(infile); + free(str); + } + + return ret; +} |