done sortstrings
This commit is contained in:
parent
93c8c5f0d8
commit
7fb7197e75
6 changed files with 258 additions and 0 deletions
144
sortstrings/Makefile
Normal file
144
sortstrings/Makefile
Normal file
|
@ -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)
|
30
sortstrings/sortstrings.c
Normal file
30
sortstrings/sortstrings.c
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
sortstrings/tests/test0.c
Normal file
11
sortstrings/tests/test0.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
15
sortstrings/tests/test1.c
Normal file
15
sortstrings/tests/test1.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
37
sortstrings/tests/test2.c
Normal file
37
sortstrings/tests/test2.c
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
21
sortstrings/tests/test4.c
Normal file
21
sortstrings/tests/test4.c
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Reference in a new issue