aboutsummaryrefslogtreecommitdiff
path: root/section-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'section-parse.c')
-rw-r--r--section-parse.c120
1 files changed, 120 insertions, 0 deletions
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 <stdlib.h> // exit()
+#include <stdio.h> // fgets(), feof()
+#include <string.h> // memcmp(), strlen()
+#include <stdbool.h> // 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;
+}