5 #include <markdown_lib.h>
9 /* HTML helper functions */
10 void href(const char *url)
12 const char *path = getenv("REQUEST_URI");
13 const char *script = getenv("SCRIPT_NAME");
15 for (; *path; path++, script++)
22 printf("%s", url[0] ? url : ".");
25 int str_sort(gconstpointer _a, gconstpointer _b)
27 const char **a = (const char**)_a;
28 const char **b = (const char**)_b;
29 return strcmp(*a, *b);
32 gchar **lsdir(gchar *path)
34 GPtrArray *ents = g_ptr_array_new();
35 GDir *dir = g_dir_open(path, 0, NULL);
38 while ((name = g_dir_read_name(dir))) {
41 if (name[strlen(name)-1] == '~')
43 g_ptr_array_add(ents, g_strdup(name));
47 g_ptr_array_sort(ents, str_sort);
48 g_ptr_array_add(ents, NULL);
49 return (gchar**)g_ptr_array_free(ents, FALSE);
52 page_t *get_page(const char *path)
54 char *dir = g_path_get_dirname(path);
55 char *base = g_path_get_basename(path);
56 char *ini = g_build_filename(BASE, dir, "menu.ini", NULL);
57 GKeyFile *conf = g_key_file_new();
59 g_key_file_load_from_file(conf, ini, 0, NULL);
60 //printf("load: %s -> %s\n", path, ini);
62 page_t *page = g_new0(page_t, 1);
64 page->title = g_key_file_get_string(conf, base, "title", NULL);
65 page->keys = g_key_file_get_string(conf, base, "keys", NULL);
66 page->desc = g_key_file_get_string(conf, base, "desc", NULL);
68 g_key_file_free(conf);
76 menu_t *get_menu_entry(const char *prefix, const char *entry)
78 static GRegex *regex = NULL;
80 regex = g_regex_new("^([a-zA-Z0-9_-]+)\\.md$", 0, 0, NULL);
82 GMatchInfo *matches = NULL;
84 char *path = g_build_filename(BASE, prefix, entry, NULL);
86 /* Test for directory */
87 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
88 menu = g_new0(menu_t, 1);
89 menu->path = g_build_filename(prefix, entry, "/", NULL);
90 menu->name = g_strdup(entry);
91 menu->base = g_strdup(entry);
92 //printf("\tchild=[%s]\n", path);
95 /* Test for markdown */
96 else if (g_file_test(path, G_FILE_TEST_IS_REGULAR) &&
97 g_regex_match(regex, entry, 0, &matches)) {
98 char *name = g_match_info_fetch(matches, 1);
99 menu = g_new0(menu_t, 1);
100 menu->path = g_build_filename(prefix, name, NULL);
101 menu->name = g_strdup(name);
102 menu->base = g_strdup(name);
103 for (char *c = menu->name; *c; c++)
106 //menu->name[0] = toupper(menu->name[0]);
107 g_match_info_free(matches);
108 //printf("\tname=[%s]\n", name);
115 menu_t *get_menu_rec(char *prefix, char **parts)
120 char **entries = NULL;
122 char *path = g_build_filename(BASE, prefix, NULL);
123 if (!g_file_test(path, G_FILE_TEST_IS_DIR))
126 /* Load menu from key file */
127 char *ini = g_build_filename(path, "menu.ini", NULL);
128 GKeyFile *conf = g_key_file_new();
129 g_key_file_load_from_file(conf, ini, 0, NULL);
130 entries = g_key_file_get_groups(conf, NULL);
131 for (int i = 0; entries[i]; i++) {
132 next = get_menu_entry(prefix, entries[i]);
134 next = g_new0(menu_t, 1);
135 next->base = g_strdup(entries[i]);
137 char *pathval = g_key_file_get_string(conf, entries[i], "path", NULL);
138 char *nameval = g_key_file_get_string(conf, entries[i], "name", NULL);
139 if (pathval) next->path = pathval;
140 if (nameval) next->name = nameval;
141 if (!next->path) next->path = g_strdup(entries[i]);
142 if (!next->name) next->name = g_strdup(entries[i]);
143 cur = cur->next = next;
148 /* Load menu from directory entries */
149 entries = lsdir(path);
150 for (int i = 0; entries[i]; i++) {
151 //printf("test: path=%s entry=%s\n", path, entries[i]);
152 if (g_key_file_has_group(conf, entries[i]))
154 if ((next = get_menu_entry(prefix, entries[i])))
155 cur = cur->next = next;
158 g_key_file_free(conf);
160 /* Add child nodes */
161 for (cur = head.next; cur; cur = cur->next) {
162 if (parts && parts[0] && cur->base && !strcmp(cur->base, parts[0])) {
163 //printf("test: [%s, %s == %s]\n",
164 // cur->path, cur->base, parts[0]);
165 cur->kids = get_menu_rec(cur->path, parts+1);
166 cur->show = SHOW_ACTIVE;
168 if (!strcmp(cur->base, "index"))
169 cur->show = SHOW_HIDDEN;
177 menu_t *get_menu(char *path)
180 static menu_t dev = { "dev", "Develop", NULL, NULL };
181 static menu_t news = { "news", "News", &dev, NULL };
182 static menu_t about = { "about", "About", &news, NULL };
184 static menu_t lackey = { "lackey", "lackey", NULL, NULL };
185 static menu_t wmpus = { "wmpus", "wmpus", &lackey, NULL };
186 static menu_t grits = { "grits", "Grits", &wmpus, &about };
187 static menu_t aweather = { "aweather", "AWeather", &grits, NULL };
188 static menu_t home = { "", "Home", &aweather, NULL };
192 char **parts = g_strsplit(path, "/", -1);
193 menu_t *menu = get_menu_rec("", parts);
199 void print_menu(menu_t *menu, int first, int last)
201 for (menu_t *cur = menu; cur; cur = cur->next) {
202 if (cur->show == SHOW_HIDDEN)
205 print_link(cur->path, cur->name,
206 cur->show == SHOW_ACTIVE);
207 if (cur->kids && last != 0)
208 print_menu(cur->kids, first-1, last-1);
212 void debug_menu(page_t *page, menu_t *menu, int depth)
215 printf("title: '%s'\n", page->title);
216 printf("keys: '%s'\n", page->keys);
217 printf("desc: '%s'\n", page->desc);
219 for (menu_t *cur = menu; cur; cur = cur->next) {
220 for (int i = 0; i < depth; i++)
222 printf("menu: %d %s %s '%s'\n",
223 cur->show, cur->base, cur->path, cur->name);
225 debug_menu(NULL, cur->kids, depth+1);
229 void free_menu(menu_t *menu)
233 /* Page display methods */
234 static void do_lsdir(page_t *page, const char *dir)
236 page->html = "Lsdir";
239 static void do_regular(page_t *page, const char *file)
241 const char *query = getenv("QUERY_STRING") ?: "";
242 if (g_file_get_contents(file, &page->text, NULL, NULL)) {
243 if (!strcmp(query, "src"))
244 page->html = "source";
245 else if (!strcmp(query, "hist"))
246 page->html = "history";
248 page->html = markdown_to_string(page->text, 0, 0);
250 page->error = g_strdup("403 Forbidden");
251 page->html = g_strdup("Page not accessable\n");
255 static void do_notfound(page_t *page, const char *path)
257 page->error = g_strdup("404 Not Found");
258 page->html = g_strdup("Page not found\n");
261 static char *clean(const char *src)
263 int len = strlen(src);
264 char *dst = malloc(len+1);
265 int si=0, ei=len-1, di=0;
266 while (src[si] == '/')
268 while (src[ei] == '/')
271 dst[di++] = src[si++];
272 while (src[si] == '/' && src[si+1] == '/')
280 int main(int argc, char **argv)
282 char *path = clean(getenv("PATH_INFO") ?: "/");
284 page_t *page = get_page(path);
285 menu_t *menu = get_menu(path);
286 //debug_menu(page, menu, 0);
289 char *dir = g_strdup_printf("pages/%s", path);
290 char *index = g_strdup_printf("pages/%s/index.md", path);
291 char *file = g_strdup_printf("pages/%s.md", path);
293 if (g_file_test(index, G_FILE_TEST_IS_REGULAR))
294 do_regular(page, index);
295 else if (g_file_test(file, G_FILE_TEST_IS_REGULAR))
296 do_regular(page, file);
297 else if (g_file_test(dir, G_FILE_TEST_IS_DIR))
300 do_notfound(page, path);
307 print_page(page, menu);