From 14419f066973d26192bea9b97707bd872af772c7 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Thu, 2 Mar 2023 17:09:02 -0500 Subject: initial commit --- section-parse.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 section-parse.c (limited to 'section-parse.c') diff --git a/section-parse.c b/section-parse.c new file mode 100644 index 0000000..78fda1f --- /dev/null +++ b/section-parse.c @@ -0,0 +1,120 @@ +// +// section-parse: scan standard input and do the following: +// +// 1. look for a section that begins with "test-text "STUFF/foo" and ends +// with a blank line. +// 2. print the "bar.DIGITS" suffix for each line in the section +// +// Build: +// cc -std=c17 -W -Wall -Wextra -Werror -pedantic -O2 -o section-parse{,.c} +// +// Example: +// > cc -std=c17 -W -Wall -Wextra -Werror -pedantic -O2 -o section-parse{,.c} +// > ./section-parse < input.txt +// bar.1 +// bar.2 +// bar.3 +// bar.4 +// + +#include // exit() +#include // fgets(), feof() +#include // memcmp(), strlen() +#include // bool + +// section header line prefix +// (used by is_header()) +static const char HEAD_PREFIX[] = "test-text \""; +static const size_t HEAD_PREFIX_LEN = sizeof(HEAD_PREFIX) - 1; + +// section footer line suffix +// (used by is_header()) +static const char HEAD_SUFFIX[] = "/foo\"\n"; +static const size_t HEAD_SUFFIX_LEN = sizeof(HEAD_SUFFIX) - 1; + +/** + * Return true if the given line is a section header, and false + * otherwise. + */ +static bool is_header(const char * const s) { + const size_t len = strlen(s); + + // check string length + if (len < (HEAD_PREFIX_LEN + HEAD_SUFFIX_LEN)) { + return false; + } + + // compare line prefix and suffix and return true if they both match + return !memcmp(s, HEAD_PREFIX, HEAD_PREFIX_LEN) && + !memcmp(s + len - HEAD_SUFFIX_LEN, HEAD_SUFFIX, HEAD_SUFFIX_LEN); +} + +/** + * Return true if the given line is a section footer, and false + * otherwise. + */ +static bool is_footer(const char * const s) { + const size_t len = strlen(s); + + for (size_t i = 0; i < len; i++) { + if (s[i] != ' ' && s[i] != '\n') { + // found non-space character, return false + return false; + } + } + + // return true + return true; +} + +/** + * Match ".DIGITS" suffix on given line and print "bar.DIGITS" to standard + * output. + * + * Exits with a non-zero error code if the given line is invalid. + */ +static void print_body_line(const char * const s) { + const size_t len = strlen(s); + + // check line length + if (len < 2) { + fprintf(stderr, "short line\n"); + exit(-1); + } + + // find trailing '.' + // (note: technically this should probably use isdigit() too) + size_t pos = len - 2; + while (pos > 0 && s[pos] != '.') { + pos--; + } + + // check to make sure we found trailing '.' + if (s[pos] != '.') { + fprintf(stderr, "invalid line: %s", s); + exit(-1); + } + + // print trailing digits + // (note: match also includes trailing newline) + printf("bar.%s", s + pos + 1); +} + +int main() { + char buf[1024]; // line buffer + bool in_body = false; // parse state + + // read lines from standard input + while (fgets(buf, sizeof(buf), stdin) && !feof(stdin)) { + if ((!in_body && is_header(buf)) || (in_body && is_footer(buf))) { + // toggle state + in_body = !in_body; + } else if (in_body) { + // print body line + print_body_line(buf); + } + } + + // return success + return 0; +} -- cgit v1.2.3