Initial site
authorAndy Spencer <andy753421@gmail.com>
Mon, 24 Dec 2012 03:02:08 +0000 (03:02 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 24 Dec 2012 05:42:15 +0000 (05:42 +0000)
.gitignore [new file with mode: 0644]
.htaccess [new file with mode: 0644]
makefile [new file with mode: 0644]
src/html.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
theme/html.ct [new file with mode: 0644]
theme/script.js [new file with mode: 0644]
theme/style.css [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..86169d9
--- /dev/null
@@ -0,0 +1,8 @@
+*~
+*.cgi
+*.o
+*.swp
+pages
+aweather
+src/html.c
+tags
diff --git a/.htaccess b/.htaccess
new file mode 100644 (file)
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 (file)
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 (file)
index 0000000..b3a5d72
--- /dev/null
@@ -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 (file)
index 0000000..8cfc49c
--- /dev/null
@@ -0,0 +1,309 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <markdown_lib.h>
+
+#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 (file)
index 0000000..a882093
--- /dev/null
@@ -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) { %>
+       <a href="<% href(path); %>"<% if (cur) { %> class="cur"<% } %>><%= name %></a>
+<% } %>
+
+<% void print_page(page_t *page, menu_t *menu) { %>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+       <head>
+               <title><% if (page->title) printf("%s - ", page->title); %>pileus.org</title>
+               <link href="<% href("theme/style.css"); %>" rel="stylesheet" type="text/css" />
+               <meta http-equiv="X-UA-Compatible" content="IE=9" />
+               <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+               <% if (page->keys) { %>
+               <meta name="keywords" content="<%= page->keys %>" />
+               <% } %>
+               <% if (page->desc) { %>
+               <meta name="description" content="<%= page->desc %>" />
+               <% } %>
+       </head>
+       <body>
+               <div class="title">
+                       <a href="<% href(""); %>">pileus.org</a>
+                       <span><% if (page->title) printf("%s", page->title); %></span>
+               </div>
+               <h1 class="nav">
+                       <% print_menu(menu, 0, 0); %>
+                       <span style="float:right;">
+                       <!--
+                       <a href="?">View</a>
+                       <a href="?src">Source</a>
+                       <a href="?hist">History</a>
+                       -->
+                       </span>
+               </h1>
+               <h2 class="nav">
+                       <% print_menu(menu, 1, -1); %>
+               </h2>
+               <div class="content">
+                       <%= page->html %>
+                       <div class="bottom"></div>
+               </div>
+               <div class="footer">
+                       Copyright © 2012 pileus.org
+               </div>
+       </body>
+</html>
+<% } %>
diff --git a/theme/script.js b/theme/script.js
new file mode 100644 (file)
index 0000000..f9c17ea
--- /dev/null
@@ -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 (file)
index 0000000..cb11975
--- /dev/null
@@ -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;
+}