aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-08-06 16:43:57 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-08-09 00:32:13 +0200
commit4ee88984fcca86c5b0c9c4bbb7e9148c7d2fe9db (patch)
treeaa4ab670afd116e419a9661bd266e7c3d0b56dc4
parent83b8b8c2b3622ff7dfc46adf25b6723f1abfb0b5 (diff)
Add hello world example
-rw-r--r--CMakeLists.txt5
-rw-r--r--Makefile6
-rw-r--r--README.md19
-rw-r--r--examples/CMakeLists.txt2
-rw-r--r--examples/Makefile11
-rw-r--r--examples/hello/CMakeLists.txt4
-rw-r--r--examples/hello/Makefile26
-rw-r--r--examples/hello/README.md17
-rw-r--r--examples/hello/main.c101
9 files changed, 191 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 82d6667..9127b07 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.13.5)
+option(BUILD_EXAMPLES ON)
project(slweb C)
add_library(${PROJECT_NAME}
handler.c
@@ -9,3 +10,7 @@ add_library(${PROJECT_NAME}
add_subdirectory(dynstr)
target_include_directories(${PROJECT_NAME} PUBLIC include)
target_link_libraries(${PROJECT_NAME} PUBLIC dynstr)
+
+if(BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif()
diff --git a/Makefile b/Makefile
index e9fada4..c9a29e8 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,12 @@ all: $(PROJECT)
clean:
rm -f $(OBJECTS) $(DEPS)
+ +cd examples && $(MAKE) clean
+
+FORCE:
+
+examples: FORCE
+ +cd examples && $(MAKE)
$(PROJECT): $(OBJECTS)
$(AR) $(ARFLAGS) $@ $(OBJECTS)
diff --git a/README.md b/README.md
index ddc1a01..b800eba 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,25 @@ add_subdirectory(slweb)
target_link_libraries(${PROJECT_NAME} PRIVATE slweb)
```
+### Examples
+
+[A directory](examples) with examples shows how `slweb` can be used by
+applications. These can be built from the top-level directory with:
+
+```sh
+$ make examples
+```
+
+In the case of CMake builds, examples are built by default. This can be turned
+off by assigning `BUILD_EXAMPLES` to `OFF` or `0`:
+
+```sh
+$ mkdir build/
+$ cd build/
+$ cmake .. -DBUILD_EXAMPLES=OFF
+$ cmake --build .
+```
+
## Why this project?
Originally, `slweb` was part of the
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 0000000..1c51e14
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.13)
+add_subdirectory(hello)
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..4fdbb46
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,11 @@
+.POSIX:
+
+all: hello
+
+clean:
+ +cd hello && $(MAKE) clean
+
+FORCE:
+
+hello: FORCE
+ +cd hello && $(MAKE)
diff --git a/examples/hello/CMakeLists.txt b/examples/hello/CMakeLists.txt
new file mode 100644
index 0000000..c22ab33
--- /dev/null
+++ b/examples/hello/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.13)
+project(hello C)
+add_executable(hello main.c)
+target_link_libraries(${PROJECT_NAME} PRIVATE slweb dynstr)
diff --git a/examples/hello/Makefile b/examples/hello/Makefile
new file mode 100644
index 0000000..217bccb
--- /dev/null
+++ b/examples/hello/Makefile
@@ -0,0 +1,26 @@
+.POSIX:
+
+PROJECT = hello
+DEPS = \
+ main.o
+SLWEB = ../../libslweb.a
+DYNSTR = ../../dynstr/libdynstr.a
+CFLAGS = -I ../../include -I ../../dynstr/include
+SLWEB_FLAGS = -L ../../ -l slweb
+DYNSTR_FLAGS = -L ../../dynstr -l dynstr
+
+all: $(PROJECT)
+
+clean:
+ rm -f $(DEPS)
+
+FORCE:
+
+$(PROJECT): $(DEPS) $(SLWEB) $(DYNSTR)
+ $(CC) $(LDFLAGS) $(DEPS) $(SLWEB_FLAGS) $(DYNSTR_FLAGS) -o $@
+
+$(SLWEB): FORCE
+ +cd ../../ && $(MAKE)
+
+$(DYNSTR): FORCE
+ +cd ../../dynstr && $(MAKE)
diff --git a/examples/hello/README.md b/examples/hello/README.md
new file mode 100644
index 0000000..7c7cf74
--- /dev/null
+++ b/examples/hello/README.md
@@ -0,0 +1,17 @@
+# "Hello world" example
+
+This example shows a minimal setup for an application using `slweb`. When
+executed, it starts a HTTP/1.1 server on port `8080` and returns an example
+website reading "Hello from slweb!" when either `/` or `/index.html` are
+accessed by clients.
+
+## How to build
+
+If using `make(1)`, just run `make` from this directory.
+
+If using CMake, examples are built by default when configuring the project
+from [the top-level `CMakeLists.txt`](../../CMakeLists.txt).
+
+## How to run
+
+Run the executable without any command line arguments.
diff --git a/examples/hello/main.c b/examples/hello/main.c
new file mode 100644
index 0000000..f44ff0c
--- /dev/null
+++ b/examples/hello/main.c
@@ -0,0 +1,101 @@
+#include <dynstr.h>
+#include <slweb/handler.h>
+#include <slweb/html.h>
+#include <slweb/http.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int hello(const struct http_payload *const pl,
+ struct http_response *const r, void *const user)
+{
+ int ret = -1;
+ struct html_node *html = html_node_alloc("html"), *body, *p;
+ struct dynstr d;
+
+ dynstr_init(&d);
+
+ if (!html)
+ {
+ fprintf(stderr, "%s: html_node_alloc failed\n", __func__);
+ goto end;
+ }
+ else if (!(body = html_node_add_child(html, "body")))
+ {
+ fprintf(stderr, "%s: html_node_add_child body failed\n", __func__);
+ goto end;
+ }
+ else if (!(p = html_node_add_child(html, "p")))
+ {
+ fprintf(stderr, "%s: html_node_add_child p failed\n", __func__);
+ goto end;
+ }
+ else if (html_node_set_value(p, "Hello from slweb!"))
+ {
+ fprintf(stderr, "%s: html_node_set_value p failed\n", __func__);
+ goto end;
+ }
+ else if (html_serialize(html, &d))
+ {
+ fprintf(stderr, "%s: html_serialize failed\n", __func__);
+ goto end;
+ }
+
+ *r = (const struct http_response)
+ {
+ .status = HTTP_STATUS_OK,
+ .buf.rw = d.str,
+ .n = d.len,
+ .free = free
+ };
+
+ if (http_response_add_header(r, "Content-Type", "text/html"))
+ {
+ fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ html_node_free(html);
+
+ if (ret)
+ dynstr_free(&d);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ const short port = 8080;
+ const struct handler_cfg cfg = {0};
+ struct handler *const h = handler_alloc(&cfg);
+ static const char *const urls[] = {"/", "/index.html"};
+
+ if (!h)
+ {
+ fprintf(stderr, "%s: handler_alloc failed\n", __func__);
+ goto end;
+ }
+
+ for (size_t i = 0; i < sizeof urls / sizeof *urls; i++)
+ if (handler_add(h, urls[i], HTTP_OP_GET, hello, NULL))
+ {
+ fprintf(stderr, "%s: handler_add failed\n", __func__);
+ goto end;
+ }
+
+ if (handler_listen(h, port))
+ {
+ fprintf(stderr, "%s: handler_listen failed\n", __func__);
+ goto end;
+ }
+
+ ret = EXIT_SUCCESS;
+
+end:
+ handler_free(h);
+ return ret;
+}