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 if (!parts[0] && !strcmp(next->base, "index"))
144 next->show = SHOW_ACTIVE;
145 cur = cur->next = next;
150 /* Load menu from directory entries */
151 entries = lsdir(path);
152 for (int i = 0; entries[i]; i++) {
153 //printf("test: path=%s entry=%s\n", path, entries[i]);
154 if (g_key_file_has_group(conf, entries[i]))
156 if ((next = get_menu_entry(prefix, entries[i])))
157 cur = cur->next = next;
158 if (!strcmp(cur->base, "index"))
159 cur->show = SHOW_HIDDEN;
162 g_key_file_free(conf);
164 /* Add child nodes */
165 for (cur = head.next; cur; cur = cur->next) {
166 if (parts && parts[0] && cur->base && !strcmp(cur->base, parts[0])) {
167 //printf("test: [%s, %s == %s]\n",
168 // cur->path, cur->base, parts[0]);
169 cur->kids = get_menu_rec(cur->path, parts+1);
170 cur->show = SHOW_ACTIVE;
179 menu_t *get_menu(char *path)
182 static menu_t dev = { "dev", "Develop", NULL, NULL };
183 static menu_t news = { "news", "News", &dev, NULL };
184 static menu_t about = { "about", "About", &news, NULL };
186 static menu_t lackey = { "lackey", "lackey", NULL, NULL };
187 static menu_t wmpus = { "wmpus", "wmpus", &lackey, NULL };
188 static menu_t grits = { "grits", "Grits", &wmpus, &about };
189 static menu_t aweather = { "aweather", "AWeather", &grits, NULL };
190 static menu_t home = { "", "Home", &aweather, NULL };
194 char **parts = g_strsplit(path, "/", -1);
195 menu_t *menu = get_menu_rec("", parts);
201 void print_menu(menu_t *menu, int first, int last)
203 for (menu_t *cur = menu; cur; cur = cur->next) {
204 if (cur->show == SHOW_HIDDEN)
207 print_link(cur->path, cur->name,
208 cur->show == SHOW_ACTIVE);
209 if (cur->kids && last != 0)
210 print_menu(cur->kids, first-1, last-1);
214 void debug_menu(page_t *page, menu_t *menu, int depth)
217 printf("title: '%s'\n", page->title);
218 printf("keys: '%s'\n", page->keys);
219 printf("desc: '%s'\n", page->desc);
221 for (menu_t *cur = menu; cur; cur = cur->next) {
222 for (int i = 0; i < depth; i++)
224 printf("menu: %d %s %s '%s'\n",
225 cur->show, cur->base, cur->path, cur->name);
227 debug_menu(NULL, cur->kids, depth+1);
231 void free_menu(menu_t *menu)
235 /* Page display methods */
236 static void do_lsdir(page_t *page, const char *dir)
238 page->html = "Lsdir";
241 static void do_regular(page_t *page, const char *file)
243 const char *query = getenv("QUERY_STRING") ?: "";
244 if (g_file_get_contents(file, &page->text, NULL, NULL)) {
245 if (!strcmp(query, "src"))
246 page->html = "source";
247 else if (!strcmp(query, "hist"))
248 page->html = "history";
250 page->html = markdown_to_string(page->text, 0, 0);
252 page->error = g_strdup("403 Forbidden");
253 page->html = g_strdup("Page not accessable\n");
257 static void do_notfound(page_t *page, const char *path)
259 page->error = g_strdup("404 Not Found");
260 page->html = g_strdup("Page not found\n");
263 static char *clean(const char *src)
265 int len = strlen(src);
266 char *dst = malloc(len+1);
267 int si=0, ei=len-1, di=0;
268 while (src[si] == '/')
270 while (src[ei] == '/')
273 dst[di++] = src[si++];
274 while (src[si] == '/' && src[si+1] == '/')
282 int main(int argc, char **argv)
284 char *path = clean(getenv("PATH_INFO") ?: "/");
286 page_t *page = get_page(path);
287 menu_t *menu = get_menu(path);
288 //debug_menu(page, menu, 0);
291 char *dir = g_strdup_printf("pages/%s", path);
292 char *index = g_strdup_printf("pages/%s/index.md", path);
293 char *file = g_strdup_printf("pages/%s.md", path);
295 if (g_file_test(index, G_FILE_TEST_IS_REGULAR))
296 do_regular(page, index);
297 else if (g_file_test(file, G_FILE_TEST_IS_REGULAR))
298 do_regular(page, file);
299 else if (g_file_test(dir, G_FILE_TEST_IS_DIR))
302 do_notfound(page, path);
309 print_page(page, menu);