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 int hideval = g_key_file_get_boolean(conf, entries[i], "hide", NULL);
140 if (pathval) next->path = pathval;
141 if (nameval) next->name = nameval;
142 if (!next->path) next->path = g_strdup(entries[i]);
143 if (!next->name) next->name = g_strdup(entries[i]);
145 next->show = SHOW_HIDDEN;
146 if (!parts[0] && !strcmp(next->base, "index"))
147 next->show = SHOW_ACTIVE;
148 cur = cur->next = next;
153 /* Load menu from directory entries */
154 entries = lsdir(path);
155 for (int i = 0; entries[i]; i++) {
156 //printf("test: path=%s entry=%s\n", path, entries[i]);
157 if (g_key_file_has_group(conf, entries[i]))
159 if ((next = get_menu_entry(prefix, entries[i])))
160 cur = cur->next = next;
161 if (!strcmp(cur->base, "index"))
162 cur->show = SHOW_HIDDEN;
165 g_key_file_free(conf);
167 /* Add child nodes */
168 for (cur = head.next; cur; cur = cur->next) {
169 if (parts && parts[0] && cur->base && !strcmp(cur->base, parts[0])) {
170 //printf("test: [%s, %s == %s]\n",
171 // cur->path, cur->base, parts[0]);
172 cur->kids = get_menu_rec(cur->path, parts+1);
173 cur->show = SHOW_ACTIVE;
182 menu_t *get_menu(char *path)
185 static menu_t dev = { "dev", "Develop", NULL, NULL };
186 static menu_t news = { "news", "News", &dev, NULL };
187 static menu_t about = { "about", "About", &news, NULL };
189 static menu_t lackey = { "lackey", "lackey", NULL, NULL };
190 static menu_t wmpus = { "wmpus", "wmpus", &lackey, NULL };
191 static menu_t grits = { "grits", "Grits", &wmpus, &about };
192 static menu_t aweather = { "aweather", "AWeather", &grits, NULL };
193 static menu_t home = { "", "Home", &aweather, NULL };
197 char **parts = g_strsplit(path, "/", -1);
198 menu_t *menu = get_menu_rec("", parts);
204 int get_slashes(char *path)
207 for (int i = 0; path[i]; i++) {
210 if (path[i] != '/' && !path[i+1])
216 void print_menu(menu_t *menu, int first, int last)
218 for (menu_t *cur = menu; cur; cur = cur->next) {
219 if (first <= 0 && cur->show != SHOW_HIDDEN)
220 print_link(cur->path, cur->name,
221 cur->show == SHOW_ACTIVE,
222 get_slashes(cur->path));
223 if (cur->kids && last != 0) {
226 print_menu(cur->kids, first-1, last-1);
233 void debug_menu(page_t *page, menu_t *menu, int depth)
236 printf("title: '%s'\n", page->title);
237 printf("keys: '%s'\n", page->keys);
238 printf("desc: '%s'\n", page->desc);
240 for (menu_t *cur = menu; cur; cur = cur->next) {
241 for (int i = 0; i < depth; i++)
243 printf("menu: %d %s %s '%s'\n",
244 cur->show, cur->base, cur->path, cur->name);
246 debug_menu(NULL, cur->kids, depth+1);
250 void free_menu(menu_t *menu)
254 /* Page display methods */
255 static void do_lsdir(page_t *page, const char *dir)
257 page->html = "Lsdir";
260 static void do_regular(page_t *page, const char *file)
262 const char *query = getenv("QUERY_STRING") ?: "";
263 if (g_file_get_contents(file, &page->text, NULL, NULL)) {
264 if (!strcmp(query, "src"))
265 page->html = "source";
266 else if (!strcmp(query, "hist"))
267 page->html = "history";
269 page->html = markdown_to_string(page->text, 0, 0);
271 page->error = g_strdup("403 Forbidden");
272 page->html = g_strdup("Page not accessable\n");
276 static void do_notfound(page_t *page, const char *path)
278 page->error = g_strdup("404 Not Found");
279 page->html = g_strdup("Page not found\n");
282 static char *clean(const char *src)
284 int len = strlen(src);
285 char *dst = malloc(len+1);
286 int si=0, ei=len-1, di=0;
287 while (src[si] == '/')
289 while (src[ei] == '/')
292 dst[di++] = src[si++];
293 while (src[si] == '/' && src[si+1] == '/')
301 int main(int argc, char **argv)
303 char *path = clean(getenv("PATH_INFO") ?: "/");
305 page_t *page = get_page(path);
306 menu_t *menu = get_menu(path);
307 //debug_menu(page, menu, 0);
310 char *dir = g_strdup_printf("pages/%s", path);
311 char *index = g_strdup_printf("pages/%s/index.md", path);
312 char *file = g_strdup_printf("pages/%s.md", path);
314 if (g_file_test(index, G_FILE_TEST_IS_REGULAR))
315 do_regular(page, index);
316 else if (g_file_test(file, G_FILE_TEST_IS_REGULAR))
317 do_regular(page, file);
318 else if (g_file_test(dir, G_FILE_TEST_IS_DIR))
321 do_notfound(page, path);
328 print_page(page, menu);