// // 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; }