summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/.gitignore12
-rw-r--r--src/Makefile50
-rw-r--r--src/chatprotocol.c15
-rw-r--r--src/doc.c32
-rw-r--r--src/doctest.abin0 -> 1580 bytes
-rw-r--r--src/doctest.c9
-rw-r--r--src/doctest.h66
7 files changed, 184 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..c1c7f87
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,12 @@
+# compilation results
+*.o
+*.doctest
+*.code
+/doctest.include
+/doctest.declare
+/doctestobj/
+
+# binaries
+/doc
+/doctest
+/chatprotocol
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..de6a9e7
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,50 @@
+.POSIX:
+
+# by default we use system nm but make does not provide nm
+NM= nm
+MKDIR= mkdir -p
+
+ALL_DOCTEST_O= chatprotocol.doctest
+ALL_CODE_O= chatprotocol.code
+
+.SUFFIXES:
+
+default: all
+
+all: chatprotocol doc doctest
+
+chatprotocol: $(ALL_CODE_O)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o chatprotocol $(ALL_CODE_O)
+
+doc: doc.o doctest.a
+ $(CC) $(CFLAGS) $(LDFLAGS) -o doc doc.o doctest.a
+
+doctest: doctest.o doctest.a
+ $(CC) $(CFLAGS) $(LDFLAGS) -o doctest doctest.o doctest.a
+
+doc.o: doc.c doctest.h doctest.declare doctest.include
+ $(CC) $(CFLAGS) -DDOCS -UDOCTEST -c doc.c
+
+doctest.o: doctest.c doc.c doctest.h doctest.declare doctest.include
+ $(CC) $(CFLAGS) -DDOCTEST -c doctest.c
+
+doctest.declare: doctest.a
+ $(NM) -P -g $? | sed -n -e 's/^\([^[:blank:]]*_mkdocs\)[[:blank:]]..*/extern void \1(struct docs *doc);/p' > $@
+
+doctest.include: doctest.a
+ $(NM) -P -g $? | sed -n -e 's/^\([^[:blank:]]*_mkdocs\)[[:blank:]]..*/\1(\&doc);/p' > $@
+
+doctest.a: $(ALL_DOCTEST_O)
+ $(MKDIR) $(@D)/doctestobj
+ for file in $(?:.doctest=); do cp -p $$file.doctest $(@D)/doctestobj/$$(basename $$file).o; done
+ cd $(@D)/doctestobj && $(AR) $(ARFLAGS) -u ../$(@F) $(ALL_DOCTEST_O:.doctest=.o)
+
+.SUFFIXES: .c .doctest .code
+
+.c.doctest:
+ $(CC) $(CFLAGS) -DDOCTEST -c $<
+ mv $*.o $*.doctest
+
+.c.code:
+ $(CC) $(CFLAGS) -UDOCS -UDOCTEST -c $<
+ mv $*.o $*.code
diff --git a/src/chatprotocol.c b/src/chatprotocol.c
new file mode 100644
index 0000000..f4725fc
--- /dev/null
+++ b/src/chatprotocol.c
@@ -0,0 +1,15 @@
+#include "doctest.h"
+#include <stdio.h>
+
+DOCF(int, main, int argc, char *argv[]) {
+#ifdef DOCS
+ D("Prints \"Hello, World!\" and args.");
+#else
+ int i = 0;
+ printf("Hello, World!\n");
+ for (i = 0; i < argc; i++) {
+ printf("%d: %s\n", i, argv[i]);
+ }
+#endif
+ DOCF_END;
+}
diff --git a/src/doc.c b/src/doc.c
new file mode 100644
index 0000000..33a283e
--- /dev/null
+++ b/src/doc.c
@@ -0,0 +1,32 @@
+/*
+ * Doc/test generation. See doctest.h for more information.
+ */
+#include "doctest.h"
+
+#ifdef DOCS
+#include <stdio.h>
+
+#include "doctest.declare"
+
+struct docs {
+ int dummy;
+};
+
+void docs_for( struct docs *doc, char *sig, char *name, char *params ) {
+ printf("docs_for: %s %s (%s)\n", sig, name, params);
+}
+
+void docs_line( struct docs *doc, char *s ) {
+ printf("docs_line: %s\n", s);
+}
+
+void docs_testline( struct docs *doc, int lineno, char *file, char *s) {
+ printf("docs_testline: %s:%d: %s\n", file, lineno, s);
+}
+
+int main(int argc, char *argv[]) {
+ struct docs doc = {0};
+#include "doctest.include"
+ return 0;
+}
+#endif
diff --git a/src/doctest.a b/src/doctest.a
new file mode 100644
index 0000000..3c80dbf
--- /dev/null
+++ b/src/doctest.a
Binary files differ
diff --git a/src/doctest.c b/src/doctest.c
new file mode 100644
index 0000000..34646c1
--- /dev/null
+++ b/src/doctest.c
@@ -0,0 +1,9 @@
+/*
+ * Doctest generation. See doctest.h for more information.
+ */
+#include "doctest.h"
+
+/* This is unusual, but it works. */
+#ifdef DOCTEST
+#include "doc.c"
+#endif
diff --git a/src/doctest.h b/src/doctest.h
new file mode 100644
index 0000000..7c5403b
--- /dev/null
+++ b/src/doctest.h
@@ -0,0 +1,66 @@
+/**
+ * Doc/testing Utilities
+ * Help I can't document my documentation tool with my documentation tool.
+ *
+ * Basics: All to-be-documented functions must be defined with DOCF/DOCF_END.
+ * Additionally, one needs to put #ifdef DOCS/else/endif around their code and docs:
+ *
+ * DOCF(void, foo, void) {
+ * #ifdef DOCS
+ * docs go here
+ * #else
+ * code goes here
+ * #endif
+ * DOCF_END;
+ * }
+ *
+ * D("...") is used for doc lines, DT("...") for doctest lines.
+ *
+ * Internal (static) functions cannot currently be documented, but support for them is planned.
+ *
+ * You must also put your main within #ifndef DOCS/#endif, if you don't wish to document it:
+ *
+ * #ifndef DOCS
+ * int main(int argc, char *argv[]) {
+ * }
+ * #endif
+ *
+ * // or (preferred)
+ *
+ * DOCF(int, main, int argc, char *argv[]) {
+ * #ifdef DOCS
+ * docs go here
+ * #else
+ * code goes here
+ * #endif
+ * DOCF_END;
+ * }
+ */
+
+#ifdef DOCTEST
+#define DOCS
+#endif
+
+#ifdef DOCS
+
+/* docs enabled */
+struct docs;
+
+extern void docs_for( struct docs *doc, char *sig, char *name, char *params );
+extern void docs_line( struct docs *doc, char *s );
+extern void docs_testline( struct docs *doc, int lineno, char *file, char *s);
+
+#define DOCF(sig, name, ...) extern void name##_mkdocs ( struct docs *doc ) { docs_for( doc , #sig , #name , #__VA_ARGS__ ); do
+#define DOCF_END }while(0)
+#define D(s) docs_line(doc, s)
+/* enabled unconditionally as doctests are part of and embedded into docs */
+#define DT(s) docs_testline(doc, __LINE__, __FILE__, s)
+
+#else
+
+/* docs not enabled */
+#define DOCF(sig, name, ...) sig name ( __VA_ARGS__ )
+/* for the sake of semicolon */
+#define DOCF_END do{}while(0)
+
+#endif