diff --git a/sortstrings/Makefile b/sortstrings/Makefile new file mode 100644 index 0000000..1463bb2 --- /dev/null +++ b/sortstrings/Makefile @@ -0,0 +1,144 @@ +OBJECTS = sortstrings.o + +CFLAGS=-Wall -g +CXXFLAGS=-Wall -g + +SHELL=/bin/bash + +TIMEOUT=8 + +TESTS_DIR=tests + +TESTS_SH:=$(wildcard $(TESTS_DIR)/*.sh) +TESTS_SH_NAMES:=$(patsubst $(TESTS_DIR)/%.sh, %, $(TESTS_SH)) + +TESTS_IO:=$(wildcard $(TESTS_DIR)/*.in) +TESTS_IO_NAMES:=$(patsubst $(TESTS_DIR)/%.in, %, $(TESTS_IO)) + +TESTS_C:=$(wildcard $(TESTS_DIR)/*.c) +TESTS_CXX:=$(wildcard $(TESTS_DIR)/*.cc) +TESTS_BIN:=$(patsubst $(TESTS_DIR)/%.c, $(TESTS_DIR)/%, $(TESTS_C)) \ + $(patsubst $(TESTS_DIR)/%.cc, $(TESTS_DIR)/%, $(TESTS_CXX)) +TESTS_BIN_NAMES:=$(patsubst $(TESTS_DIR)/%.c, %, $(TESTS_C)) $(patsubst $(TESTS_DIR)/%.cc, %, $(TESTS_CXX)) + +.PHONY: all +all: compile check + +.PHONY: compile-program + +compile: $(PROGRAMS) $(OBJECTS) + +.PHONY: check +check: check-bin check-io-sh + +.PHONY: check-io-sh +check-io-sh: compile $(TESTS_IO) $(TESTS_SH) + @exec 2> /dev/null; \ + for p in $(foreach prog,$(PROGRAMS),$(dir $(prog))$(prog)); do \ + echo "Testing $${p}:" ; \ + for t in $(TESTS_IO_NAMES); do \ + echo -n "Running test $$t..." ; \ + "$$p" < "$(TESTS_DIR)/$$t.in" > "$$t.out" 2>&1 & \ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "see $(TESTS_DIR)/$$t.in" ;\ + echo "you may run $$p < $(TESTS_DIR)/$$t.in" ;\ + echo "to see what went wrong";\ + rm -f "$$t.out" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + if cmp -s "$$t.out" "$(TESTS_DIR)/$$t.expected"; \ + then \ + echo "PASS" ;\ + rm -f "$$t.out" ;\ + else \ + echo "FAIL" ;\ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "run diff $$t.out $(TESTS_DIR)/$$t.expected";\ + echo "to see the difference between the actual and expected output";\ + fi; \ + fi; \ + done; \ + for t in $(TESTS_SH_NAMES); do \ + echo -n "Running test $$t..." ; \ + $(SHELL) "$(TESTS_DIR)/$$t.sh" "$$p" > "$$t.out" 2>&1 & \ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "you may run $(TESTS_DIR)/$$t.sh $$p" ;\ + echo "to see what went wrong";\ + rm -f "$$t.out" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + if cmp -s "$$t.out" "$(TESTS_DIR)/$$t.expected"; \ + then \ + echo "PASS" ;\ + rm -f "$$t.out" ;\ + else \ + echo "FAIL" ;\ + echo "see $(TESTS_DIR)/$$t.sh" ;\ + echo "run diff $$t.out $(TESTS_DIR)/$$t.expected";\ + echo "to see the difference between the actual and expected output";\ + fi; \ + fi; \ + done; \ + done + +$(TESTS_DIR)/%: $(TESTS_DIR)/%.c $(OBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) $(TESTS_DIR)/$*.c $(OBJECTS) -o $@ + +$(TESTS_DIR)/%: $(TESTS_DIR)/%.cc $(OBJECTS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(TESTS_DIR)/$*.cc $(OBJECTS) -o $@ + +.PHONY: check-bin +check-bin: $(TESTS_BIN) + @exec 2> /dev/null; \ + for t in $(TESTS_BIN_NAMES); do \ + echo -n "Running test $$t..." ; \ + "$(TESTS_DIR)/$$t" &\ + prog_pid=$$!; \ + ( sleep $(TIMEOUT); kill $$prog_pid > /dev/null 2>&1 ) & \ + killer_pid=$$!; \ + wait $$prog_pid; \ + res=$$?; \ + if test $$res -gt 128; \ + then \ + case `kill -l $$(($$res - 128))` in \ + ABRT ) echo "FAIL"; ;; \ + TERM ) echo "TIME OUT"; ;; \ + * ) echo "UNKNOWN ERROR"; ;; \ + esac ; \ + echo "you may run $(TESTS_DIR)/$$t to see what went wrong" ;\ + else \ + kill $$killer_pid > /dev/null 2>&1 ;\ + wait $$killer_pid; \ + echo "PASS" ;\ + fi; \ + done + + +.PHONY: clean +clean: + rm -f $(PROGRAMS) $(OBJECTS) tests/*.o $(TESTS_BIN) diff --git a/sortstrings/sortstrings.c b/sortstrings/sortstrings.c new file mode 100644 index 0000000..eff4bb3 --- /dev/null +++ b/sortstrings/sortstrings.c @@ -0,0 +1,30 @@ +#include +#include +#include +#define MAX_N 1000 + +int compar(const void* string1, const void* string2) { + const char** s1 = (const char**) string1; + const char** s2 = (const char**) string2; + return strcmp(*s1, *s2); +} + +void sort_strings(const char* input, const char* output, unsigned int n) { + const char* strings[MAX_N]; + size_t i = 0; + size_t offset = 0; + for (i = 0; i < n; i++) { + strings[i] = input + offset; + offset += strlen(input + offset) + 1; // + 1 for NUL + } + + qsort(strings, n, sizeof(const char*), &compar); + + offset = 0; + for (i = 0; i < n; i++) { + const size_t len = strlen(strings[i]); + strncpy((char*) output + offset, (char*) strings[i], len + 1); + offset += len + 1; + } +} + diff --git a/sortstrings/tests/test0.c b/sortstrings/tests/test0.c new file mode 100644 index 0000000..6a4ecfd --- /dev/null +++ b/sortstrings/tests/test0.c @@ -0,0 +1,11 @@ +#include +#include + +extern void sort_strings(const char * input, char * output, unsigned int n); + +int main() { + char buf[100]; + sort_strings("", buf, 1); + assert(memcmp(buf, "", 1) == 0); + return 0; +} diff --git a/sortstrings/tests/test1.c b/sortstrings/tests/test1.c new file mode 100644 index 0000000..e15b91c --- /dev/null +++ b/sortstrings/tests/test1.c @@ -0,0 +1,15 @@ +#include +#include + +extern void sort_strings(const char * input, char * output, unsigned int n); + +int main() { + char buf[100]; + sort_strings("ciao", buf, 1); + assert(memcmp(buf, "ciao", 5) == 0); + + sort_strings("ciao\0blah", buf, 2); + assert(memcmp(buf, "blah\0ciao", 10) == 0); + + return 0; +} diff --git a/sortstrings/tests/test2.c b/sortstrings/tests/test2.c new file mode 100644 index 0000000..be680d0 --- /dev/null +++ b/sortstrings/tests/test2.c @@ -0,0 +1,37 @@ +#include +#include + +extern void sort_strings(const char * input, char * output, unsigned int n); + +int main() { + char buf[1000]; + + sort_strings("ciao\0ciao", buf, 2); + assert(memcmp(buf, "ciao\0ciao", 10) == 0); + + sort_strings("a\0b", buf, 2); + assert(memcmp(buf, "a\0b", 4) == 0); + + sort_strings("a\0b\0c", buf, 3); + assert(memcmp(buf, "a\0b\0c", 6) == 0); + + sort_strings("b\0c\0a", buf, 3); + assert(memcmp(buf, "a\0b\0c", 6) == 0); + + sort_strings("c\0a\0b", buf, 3); + assert(memcmp(buf, "a\0b\0c", 6) == 0); + + sort_strings("c\0a\0b", buf, 1); + assert(memcmp(buf, "c", 2) == 0); + + sort_strings("c\0a\0b", buf, 2); + assert(memcmp(buf, "a\0c", 2) == 0); + + sort_strings("a\0a", buf, 2); + assert(memcmp(buf, "a\0a", 4) == 0); + + sort_strings("b\0a\0a\0a\0b", buf, 5); + assert(memcmp(buf, "a\0a\0a\0b\0b", 10) == 0); + + return 0; +} diff --git a/sortstrings/tests/test4.c b/sortstrings/tests/test4.c new file mode 100644 index 0000000..23ab73a --- /dev/null +++ b/sortstrings/tests/test4.c @@ -0,0 +1,21 @@ +#include +#include + +extern void sort_strings(const char * input, char * output, unsigned int n); + +const char * S_sorted = "cfreq\0concatenate\0concatenate/tests\0coursesdb\0deletedigits\0deletedigits/tests\0findstrings\0flipline\0flipline/tests\0flipstream\0linkedlist\0redactdigits\0redactdigits/tests\0topcolor\0topcolor/tests\0volumes\0volumes/tests\0wordcount\0wordcount/tests"; + +const char * S = "concatenate/tests\0concatenate\0linkedlist\0topcolor/tests\0topcolor\0flipstream\0deletedigits/tests\0deletedigits\0coursesdb\0volumes/tests\0volumes\0cfreq\0wordcount/tests\0wordcount\0flipline/tests\0flipline\0findstrings\0redactdigits/tests\0redactdigits"; + + +int main() { + char buf[1000]; + + sort_strings("ciao\0cia", buf, 2); + assert(memcmp(buf, "cia\0ciao", 9) == 0); + + sort_strings(S, buf, 19); + assert(memcmp(buf, S_sorted, 239) == 0); + + return 0; +}