finish up translations and setup doc server stuff
This commit is contained in:
39
doc/src/config.c
Normal file
39
doc/src/config.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <ctorm/log.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
|
||||
option_t options[] = {
|
||||
{"host", "0.0.0.0:7003", true }, // host the server should listen on
|
||||
{NULL, NULL, false},
|
||||
};
|
||||
|
||||
int32_t config_load(config_t *conf) {
|
||||
bzero(conf, sizeof(*conf));
|
||||
|
||||
char *value = NULL;
|
||||
conf->options = options;
|
||||
|
||||
for (option_t *opt = conf->options; opt->name != NULL; opt++) {
|
||||
if ((value = getenv(opt->name)) != NULL)
|
||||
opt->value = value;
|
||||
|
||||
if (opt->required && *opt->value == 0) {
|
||||
error("please specify a value for the required config option %s", opt->name);
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
conf->count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *config_get(config_t *conf, const char *name) {
|
||||
for (int32_t i = 0; i < conf->count; i++)
|
||||
if (strcmp(conf->options[i].name, name) == 0)
|
||||
return conf->options[i].value;
|
||||
return NULL;
|
||||
}
|
25
doc/src/main.c
Normal file
25
doc/src/main.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <ctorm/all.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "routes.h"
|
||||
#include "config.h"
|
||||
|
||||
int main() {
|
||||
config_t conf;
|
||||
app_config_t config;
|
||||
|
||||
if (config_load(&conf) < 0)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
app_config_new(&config);
|
||||
config.disable_logging = true;
|
||||
|
||||
app_t *app = app_new(&config);
|
||||
GET(app, "/read", GET_read);
|
||||
|
||||
if (!app_run(app, config_get(&conf, "host")))
|
||||
error("failed to start the app: %s", app_geterror());
|
||||
|
||||
app_free(app);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
118
doc/src/routes/read.c
Normal file
118
doc/src/routes/read.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <linux/limits.h>
|
||||
#include <ctorm/all.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <cmark.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "routes.h"
|
||||
|
||||
void GET_read(req_t *req, res_t *res) {
|
||||
const char *lang = REQ_QUERY("lang");
|
||||
const char *name = REQ_QUERY("name");
|
||||
|
||||
char fp[PATH_MAX + 1], md[NAME_MAX + 1];
|
||||
struct dirent *dirent = NULL;
|
||||
int32_t name_len = 0, ent_len = 0;
|
||||
DIR *dir = NULL;
|
||||
|
||||
bzero(fp, sizeof(fp));
|
||||
bzero(md, sizeof(md));
|
||||
|
||||
if (NULL == name)
|
||||
return RES_REDIRECT("/");
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
if (NULL == lang)
|
||||
lang = "en";
|
||||
|
||||
if (NULL == (dir = opendir("docs"))) {
|
||||
error("failed to open the docs dir: %s", strerror(errno));
|
||||
RES_SENDFILE("html/internal.html");
|
||||
res->code = 500;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
if (strncmp(dirent->d_name, lang, PATH_MAX) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (NULL == dirent) {
|
||||
RES_SENDFILE("html/notfound.html");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(fp, sizeof(fp), "docs/%s", lang);
|
||||
|
||||
if (NULL == (dir = opendir(fp))) {
|
||||
error("failed to open the language dir: %s", strerror(errno));
|
||||
RES_SENDFILE("html/internal.html");
|
||||
res->code = 500;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
if ((ent_len = strlen(dirent->d_name) - 3) != name_len)
|
||||
continue;
|
||||
|
||||
if (strncmp(dirent->d_name, name, name_len) == 0) {
|
||||
memcpy(md, dirent->d_name, ent_len + 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (NULL == dirent) {
|
||||
RES_SENDFILE("html/notfound.html");
|
||||
return;
|
||||
}
|
||||
|
||||
char *md_content = NULL, md_fp[PATH_MAX + 1];
|
||||
struct stat md_st;
|
||||
int md_fd = 0;
|
||||
|
||||
snprintf(md_fp, sizeof(fp), "%s/%s", fp, md);
|
||||
|
||||
if ((md_fd = open(md_fp, O_RDONLY)) < 0) {
|
||||
error("failed to open %s: %s", fp, strerror(errno));
|
||||
goto err_internal_close;
|
||||
}
|
||||
|
||||
if (fstat(md_fd, &md_st) < 0) {
|
||||
error("failed to fstat %s: %s", fp, strerror(errno));
|
||||
goto err_internal_close;
|
||||
}
|
||||
|
||||
if ((md_content = mmap(0, md_st.st_size, PROT_READ, MAP_PRIVATE, md_fd, 0)) == NULL) {
|
||||
error("failed to mmap %s: %s", fp, strerror(errno));
|
||||
goto err_internal_close;
|
||||
}
|
||||
|
||||
char *parsed = cmark_markdown_to_html(md_content, md_st.st_size, CMARK_OPT_DEFAULT);
|
||||
RES_SEND(parsed);
|
||||
|
||||
free(parsed);
|
||||
munmap(md_content, md_st.st_size);
|
||||
close(md_fd);
|
||||
|
||||
return;
|
||||
|
||||
err_internal_close:
|
||||
close(md_fd);
|
||||
|
||||
RES_SENDFILE("html/internal.html");
|
||||
return;
|
||||
}
|
Reference in New Issue
Block a user