#include #include #include static int _remspace_internal(FILE* fin, FILE* fout, FILE* ferr, int pc) { int c = fgetc(fin); if (c == EOF) { // Should I still put EOF here? does it work with pipes or not? //fputc(c, fout); return 0; } if (c == ' ' && pc == ' ') { // skip it } else { fputc(c, fout); } __attribute__((musttail)) return _remspace_internal(fin, fout, ferr, c); } /* Copy stdin to stdout, replacing consecutive spaces with a single space Edge case: a leading space is retained if there are leading spaces. */ int remspace(FILE* fin, FILE* fout, FILE* ferr) { int res = _remspace_internal(fin, fout, ferr, -1); fflush(fout); fflush(ferr); return res; } #ifndef test int main(void) { return remspace(stdin, stdout, stderr); } #else #include "CuTest.h" void do_test(CuTest* tc, char* input, const char* expected, const char* err_expected) { char buf[100] = {0}; char err_buf[100] = {0}; FILE* tin = fmemopen(input, strlen(input), "r"); FILE* tout = fmemopen(buf, 100, "w"); FILE* terr = fmemopen(err_buf, 100, "w"); int res = remspace(tin, tout, terr); CuAssertIntEquals(tc, 0, res); CuAssertStrEquals(tc, expected, buf); CuAssertStrEquals(tc, err_expected, err_buf); } void test_remspace_empty(CuTest* tc) { do_test(tc, "", "", ""); } void test_remspace_oneword(CuTest* tc) { do_test(tc, "foobar", "foobar", ""); } void test_remspace_leadtrailspace(CuTest* tc) { do_test(tc, " foo bar ", " foo bar ", ""); } CuSuite* remspace_suite() { CuSuite* suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_remspace_empty); SUITE_ADD_TEST(suite, test_remspace_oneword); SUITE_ADD_TEST(suite, test_remspace_leadtrailspace); return suite; } int main(void) { CuString* output = CuStringNew(); CuSuite* suite = CuSuiteNew(); CuSuiteAddSuite(suite, remspace_suite()); CuSuiteRun(suite); CuSuiteSummary(suite, output); CuSuiteDetails(suite, output); printf("%s\n", output->buffer); return 0; } #endif