From: Andy Spencer Date: Mon, 24 Dec 2012 03:02:08 +0000 (+0000) Subject: Initial site X-Git-Url: http://pileus.org/git/?p=site;a=commitdiff_plain;h=c9eac6b3caf31152edf4e643a1f8286261acf160 Initial site --- c9eac6b3caf31152edf4e643a1f8286261acf160 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86169d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*~ +*.cgi +*.o +*.swp +pages +aweather +src/html.c +tags diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..602ae5c --- /dev/null +++ b/.htaccess @@ -0,0 +1,12 @@ +Options +ExecCGI +AddHandler cgi-script .cgi +RewriteEngine on + +# Indexes +RewriteRule ^$ '/home' +#RewriteRule ^$ '/home/about' +#RewriteRule ^home$ '/home/about' + +# Pileus rewrites +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule .* 'pileus.cgi/$0' diff --git a/makefile b/makefile new file mode 100644 index 0000000..1d13b63 --- /dev/null +++ b/makefile @@ -0,0 +1,31 @@ +# Settings +PATH := $(PATH):../ct +PROG = pileus.cgi +CC = gcc +CT = ct +CFLAGS = -Wall -Werror -Wno-unused-result -g --std=c99 +CPPFLAGS = $(shell pkg-config --cflags glib-2.0) -I../markdown +LDFLAGS = $(shell pkg-config --libs glib-2.0) -L../markdown -lmarkdown + +# Targets +default: test + +all: $(PROG) + +test: $(PROG) + ./$(PROG) + +clean: + rm -f src/*.o src/html.c $(PROG) + +# Rules +$(PROG): src/main.o src/html.o + $(CC) $(CFLAGS) -o $@ $+ $(LDFLAGS) + +%.o: %.c makefile src/html.h + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +src/%.c: theme/%.ct makefile + $(CT) -o $@ $< + +.SECONDARY: diff --git a/src/html.h b/src/html.h new file mode 100644 index 0000000..b3a5d72 --- /dev/null +++ b/src/html.h @@ -0,0 +1,48 @@ +/* Links */ +#define PILEUS "http://pileus.org/" + +#define DEV_LIST "http://pileus.org/mailman/listinfo/dev" +#define DEV_ARCH "http://pileus.org/pipermail/dev/" + +/* Constants */ +#define BASE "pages" + +/* Forward declarations */ +typedef struct page_t page_t; +typedef struct menu_t menu_t; + +/* Menu display display types */ +typedef enum { + SHOW_NORMAL, + SHOW_ACTIVE, + SHOW_HIDDEN, +} show_t; + +/* Page information */ +struct page_t { + char *title; // title tag + char *keys; // meta keywords tag, or NULL + char *desc; // meta description tag, or NULL + char *text; // unfiltered text + char *html; // generated html +}; + +/* Navigation menu entry */ +struct menu_t { + char *path; // path to the page + char *name; // name of the page + char *base; // base file name of the page + menu_t *next; // next menu item + menu_t *kids; // child menu items for directories + show_t show; // is this part of the current path? +}; + +/* Helper functions */ +void href(const char *url); + +void print_link(char *path, char *name, int cur); +void print_menu(menu_t *menu, int first, int last); + +/* Global functions */ +void print_header(void); +void print_page(page_t *page, menu_t *menu); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..8cfc49c --- /dev/null +++ b/src/main.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include + +#include "html.h" + +/* HTML helper functions */ +void href(const char *url) +{ + const char *path = getenv("REQUEST_URI"); + const char *script = getenv("SCRIPT_NAME"); + if (path && script) { + for (; *path; path++, script++) + if (*path != *script) + break; + for (; *path; path++) + if (*path == '/') + printf("../"); + } + printf("%s", url[0] ? url : "."); +} + +int str_sort(gconstpointer _a, gconstpointer _b) +{ + const char **a = (const char**)_a; + const char **b = (const char**)_b; + return strcmp(*a, *b); +} + +gchar **lsdir(gchar *path) +{ + GPtrArray *ents = g_ptr_array_new(); + GDir *dir = g_dir_open(path, 0, NULL); + if (dir) { + const char *name; + while ((name = g_dir_read_name(dir))) { + if (name[0] == '.') + continue; + if (name[strlen(name)-1] == '~') + continue; + g_ptr_array_add(ents, g_strdup(name)); + } + g_dir_close(dir); + } + g_ptr_array_sort(ents, str_sort); + g_ptr_array_add(ents, NULL); + return (gchar**)g_ptr_array_free(ents, FALSE); +} + +page_t *get_page(const char *path) +{ + char *dir = g_path_get_dirname(path); + char *base = g_path_get_basename(path); + char *ini = g_build_filename(BASE, dir, "menu.ini", NULL); + GKeyFile *conf = g_key_file_new(); + + g_key_file_load_from_file(conf, ini, 0, NULL); + //printf("load: %s -> %s\n", path, ini); + + page_t *page = g_new0(page_t, 1); + + page->title = g_key_file_get_string(conf, base, "title", NULL); + page->keys = g_key_file_get_string(conf, base, "keys", NULL); + page->desc = g_key_file_get_string(conf, base, "desc", NULL); + + g_key_file_free(conf); + g_free(ini); + g_free(base); + g_free(dir); + + return page; +} + +menu_t *get_menu_entry(const char *prefix, const char *entry) +{ + static GRegex *regex = NULL; + if (regex == NULL) + regex = g_regex_new("^([a-zA-Z0-9_-]+)\\.md$", 0, 0, NULL); + + GMatchInfo *matches = NULL; + menu_t *menu = NULL; + char *path = g_build_filename(BASE, prefix, entry, NULL); + + /* Test for directory */ + if (g_file_test(path, G_FILE_TEST_IS_DIR)) { + menu = g_new0(menu_t, 1); + menu->path = g_build_filename(prefix, entry, "/", NULL); + menu->name = g_strdup(entry); + menu->base = g_strdup(entry); + //printf("\tchild=[%s]\n", path); + } + + /* Test for markdown */ + else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) && + g_regex_match(regex, entry, 0, &matches)) { + char *name = g_match_info_fetch(matches, 1); + menu = g_new0(menu_t, 1); + menu->path = g_build_filename(prefix, name, NULL); + menu->name = g_strdup(name); + menu->base = g_strdup(name); + for (char *c = menu->name; *c; c++) + if (*c == '_') + *c = ' '; + //menu->name[0] = toupper(menu->name[0]); + g_match_info_free(matches); + //printf("\tname=[%s]\n", name); + } + + g_free(path); + return menu; +} + +menu_t *get_menu_rec(char *prefix, char **parts) +{ + menu_t head = {}; + menu_t *cur = &head; + menu_t *next = NULL; + char **entries = NULL; + + char *path = g_build_filename(BASE, prefix, NULL); + if (!g_file_test(path, G_FILE_TEST_IS_DIR)) + goto error; + + /* Load menu from key file */ + char *ini = g_build_filename(path, "menu.ini", NULL); + GKeyFile *conf = g_key_file_new(); + g_key_file_load_from_file(conf, ini, 0, NULL); + entries = g_key_file_get_groups(conf, NULL); + for (int i = 0; entries[i]; i++) { + next = get_menu_entry(prefix, entries[i]); + if (!next) { + next = g_new0(menu_t, 1); + next->base = g_strdup(entries[i]); + } + char *pathval = g_key_file_get_string(conf, entries[i], "path", NULL); + char *nameval = g_key_file_get_string(conf, entries[i], "name", NULL); + if (pathval) next->path = pathval; + if (nameval) next->name = nameval; + if (!next->path) next->path = g_strdup(entries[i]); + if (!next->name) next->name = g_strdup(entries[i]); + cur = cur->next = next; + } + g_strfreev(entries); + g_free(ini); + + /* Load menu from directory entries */ + entries = lsdir(path); + for (int i = 0; entries[i]; i++) { + //printf("test: path=%s entry=%s\n", path, entries[i]); + if (g_key_file_has_group(conf, entries[i])) + continue; + if ((next = get_menu_entry(prefix, entries[i]))) + cur = cur->next = next; + } + g_strfreev(entries); + g_key_file_free(conf); + + /* Add child nodes */ + for (cur = head.next; cur; cur = cur->next) { + if (parts && parts[0] && cur->base && !strcmp(cur->base, parts[0])) { + //printf("test: [%s, %s == %s]\n", + // cur->path, cur->base, parts[0]); + cur->kids = get_menu_rec(cur->path, parts+1); + cur->show = SHOW_ACTIVE; + } + if (!strcmp(cur->base, "index")) + cur->show = SHOW_HIDDEN; + } + +error: + g_free(path); + return head.next; +} + +menu_t *get_menu(char *path) +{ +#if 0 + static menu_t dev = { "dev", "Develop", NULL, NULL }; + static menu_t news = { "news", "News", &dev, NULL }; + static menu_t about = { "about", "About", &news, NULL }; + + static menu_t lackey = { "lackey", "lackey", NULL, NULL }; + static menu_t wmpus = { "wmpus", "wmpus", &lackey, NULL }; + static menu_t grits = { "grits", "Grits", &wmpus, &about }; + static menu_t aweather = { "aweather", "AWeather", &grits, NULL }; + static menu_t home = { "", "Home", &aweather, NULL }; + + return &home; +#else + char **parts = g_strsplit(path, "/", -1); + menu_t *menu = get_menu_rec("", parts); + g_strfreev(parts); + return menu; +#endif +} + +void print_menu(menu_t *menu, int first, int last) +{ + for (menu_t *cur = menu; cur; cur = cur->next) { + if (cur->show == SHOW_HIDDEN) + continue; + if (first <= 0) + print_link(cur->path, cur->name, + cur->show == SHOW_ACTIVE); + if (cur->kids && last != 0) + print_menu(cur->kids, first-1, last-1); + } +} + +void debug_menu(page_t *page, menu_t *menu, int depth) +{ + if (page) { + printf("title: '%s'\n", page->title); + printf("keys: '%s'\n", page->keys); + printf("desc: '%s'\n", page->desc); + } + for (menu_t *cur = menu; cur; cur = cur->next) { + for (int i = 0; i < depth; i++) + printf(" "); + printf("menu: %d %s %s '%s'\n", + cur->show, cur->base, cur->path, cur->name); + if (cur->kids) + debug_menu(NULL, cur->kids, depth+1); + } +} + +void free_menu(menu_t *menu) +{ +} + +/* Page display methods */ +static void do_lsdir(page_t *page, const char *dir) +{ + page->html = "Lsdir"; +} + +static void do_regular(page_t *page, const char *file) +{ + const char *query = getenv("QUERY_STRING") ?: ""; + if (g_file_get_contents(file, &page->text, NULL, NULL)) { + if (!strcmp(query, "src")) + page->html = "source"; + else if (!strcmp(query, "hist")) + page->html = "history"; + else + page->html = markdown_to_string(page->text, 0, 0); + } else { + page->html = g_strdup("Page not found"); + } +} + +static void do_notfound(page_t *page, const char *path) +{ + page->html = "Page not found"; +} + +static char *clean(const char *src) +{ + int len = strlen(src); + char *dst = malloc(len+1); + int si=0, ei=len-1, di=0; + while (src[si] == '/') + si++; + while (src[ei] == '/') + ei--; + while (si <= ei) { + dst[di++] = src[si++]; + while (src[si] == '/' && src[si+1] == '/') + si++; + } + dst[di] = '\0'; + return dst; +} + +/* Main */ +int main(int argc, char **argv) +{ + char *path = clean(getenv("PATH_INFO") ?: "/aweather/"); + + print_header(); + + page_t *page = get_page(path); + menu_t *menu = get_menu(path); + //debug_menu(page, menu, 0); + //return 0; + + char *dir = g_strdup_printf("pages/%s", path); + char *index = g_strdup_printf("pages/%s/index.md", path); + char *file = g_strdup_printf("pages/%s.md", path); + + if (g_file_test(index, G_FILE_TEST_IS_REGULAR)) + do_regular(page, index); + else if (g_file_test(file, G_FILE_TEST_IS_REGULAR)) + do_regular(page, file); + else if (g_file_test(dir, G_FILE_TEST_IS_DIR)) + do_lsdir(page, dir); + else + do_notfound(page, path); + + g_free(dir); + g_free(index); + g_free(file); + + print_page(page, menu); + + return 0; +} diff --git a/theme/html.ct b/theme/html.ct new file mode 100644 index 0000000..a882093 --- /dev/null +++ b/theme/html.ct @@ -0,0 +1,57 @@ +<% #include "string.h" %> +<% #include "html.h" %> + +<% void print_header(void) { %> +Content-Type: text/html;charset=UTF-8 + +<% } %> + +<% void print_link(char *path, char *name, int cur) { %> + class="cur"<% } %>><%= name %> +<% } %> + +<% void print_page(page_t *page, menu_t *menu) { %> + + + + + <% if (page->title) printf("%s - ", page->title); %>pileus.org + " rel="stylesheet" type="text/css" /> + + + <% if (page->keys) { %> + + <% } %> + <% if (page->desc) { %> + + <% } %> + + +
+ ">pileus.org + <% if (page->title) printf("%s", page->title); %> +
+

+ <% print_menu(menu, 0, 0); %> + + + +

+ +
+ <%= page->html %> +
+
+ + + +<% } %> diff --git a/theme/script.js b/theme/script.js new file mode 100644 index 0000000..f9c17ea --- /dev/null +++ b/theme/script.js @@ -0,0 +1,8 @@ +function show() { + var hidden = document.getElementsByClassName('hidden'); + var shown = document.getElementsByClassName('shown'); + for (i = 0; i < hidden.length; i ++) + hidden[i].style.display = "block"; + for (i = 0; i < shown.length; i ++) + shown[i].style.display = "none"; +} diff --git a/theme/style.css b/theme/style.css new file mode 100644 index 0000000..cb11975 --- /dev/null +++ b/theme/style.css @@ -0,0 +1,125 @@ +/* Global styles */ +body { + margin: 0; + padding: 0; + background: #eeeeee; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0; + padding: 0; + font-weight: normal; +} + +a { + text-decoration: none; +} + +a img { + border: none; +} + +blockquote { + display: block; + font-style: italic; + font-family: serif; + border-left: solid 0.1em black; + padding-left: 4px +} + +/* Title */ +.title { + padding: 10px 20px; + text-shadow: 1px 1px #fff; +} + +.title span { + color: #666666; + font-size: 16pt; + font-style: italic; + padding-left: 40px; +} + +.title a { + color: #444444; + font-size: 20pt; + font-style: normal; +} + +/* Top nav */ +h1.nav { + background: #444488; + font-size: 12pt; + border-style: solid none solid none; + border-width: 1px; + border-color: #222244; + padding: 5px 10px; +} + +h1.nav a { + color: #ffffff; + padding: 5px 10px; +} + +h1.nav a:hover { + background: #6666aa; +} + +h1.nav .cur { + font-style: italic; + font-weight: bold; +} + +/* Side nav */ +h2.nav { + float: left; + font-size: 12pt; + width: 200px; + padding: 20px 0; + border-right: solid 1px #ccc; +} + +h2.nav a { + color: #000000; + display: block; + padding: 5px 0 5px 20px; +} + +h2.nav a:hover { + background: #eeeeee; +} + +h2.nav .cur { + font-style: italic; + font-weight: bold; +} + +/* Content */ +.content { + padding: 20px 20px 20px 220px; + background: #ffffff; +} + +.content .bottom { + clear: both; +} + +.content h1 { + margin: 25px 0px 7px 0px; +} + +.content h2 { + margin: 20px 0px 7px 0px; +} + +.content h3 { + margin: 15px 0px 7px 0px; +} + +/* Footer */ +.footer { + padding: 10px; + clear: both; + text-align: right; + border-top: solid 1px #444444; +}