]> Pileus Git - site/blob - src/main.c
d3c7e12dcdae01b3f5162f5d34ea5e979c170a85
[site] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <markdown_lib.h>
6
7 #include "html.h"
8
9 /* HTML helper functions */
10 void href(const char *url)
11 {
12         const char *path   = getenv("REQUEST_URI");
13         const char *script = getenv("SCRIPT_NAME");
14         if (path && script) {
15                 for (; *path; path++, script++)
16                         if (*path != *script)
17                                 break;
18                 for (; *path; path++)
19                         if (*path == '/')
20                                 printf("../");
21         }
22         printf("%s", url[0] ? url : ".");
23 }
24
25 int str_sort(gconstpointer _a, gconstpointer _b)
26 {
27         const char **a = (const char**)_a;
28         const char **b = (const char**)_b;
29         return strcmp(*a, *b);
30 }
31
32 gchar **lsdir(gchar *path)
33 {
34         GPtrArray *ents = g_ptr_array_new();
35         GDir      *dir  = g_dir_open(path, 0, NULL);
36         if (dir) {
37                 const char *name;
38                 while ((name = g_dir_read_name(dir))) {
39                         if (name[0] == '.')
40                                 continue;
41                         if (name[strlen(name)-1] == '~')
42                                 continue;
43                         g_ptr_array_add(ents, g_strdup(name));
44                 }
45                 g_dir_close(dir);
46         }
47         g_ptr_array_sort(ents, str_sort);
48         g_ptr_array_add(ents, NULL);
49         return (gchar**)g_ptr_array_free(ents, FALSE);
50 }
51
52 page_t *get_page(const char *path)
53 {
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();
58
59         g_key_file_load_from_file(conf, ini, 0, NULL);
60         //printf("load: %s -> %s\n", path, ini);
61
62         page_t *page = g_new0(page_t, 1);
63
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);
67
68         g_key_file_free(conf);
69         g_free(ini);
70         g_free(base);
71         g_free(dir);
72
73         return page;
74 }
75
76 menu_t *get_menu_entry(const char *prefix, const char *entry)
77 {
78         static GRegex *regex = NULL;
79         if (regex == NULL)
80                 regex = g_regex_new("^([a-zA-Z0-9_-]+)\\.md$", 0, 0, NULL);
81
82         GMatchInfo *matches = NULL;
83         menu_t *menu = NULL;
84         char *path = g_build_filename(BASE, prefix, entry, NULL);
85
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);
93         }
94
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++)
104                         if (*c == '_')
105                                 *c = ' ';
106                 //menu->name[0] = toupper(menu->name[0]);
107                 g_match_info_free(matches);
108                 //printf("\tname=[%s]\n", name);
109         }
110
111         g_free(path);
112         return menu;
113 }
114
115 menu_t *get_menu_rec(char *prefix, char **parts)
116 {
117         menu_t  head = {};
118         menu_t *cur  = &head;
119         menu_t *next = NULL;
120         char **entries = NULL;
121
122         char *path = g_build_filename(BASE, prefix, NULL);
123         if (!g_file_test(path, G_FILE_TEST_IS_DIR))
124                 goto error;
125
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]);
133                 if (!next) {
134                         next = g_new0(menu_t, 1);
135                         next->base = g_strdup(entries[i]);
136                 }
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]);
144                 if (hideval)
145                         next->show = SHOW_HIDDEN;
146                 if (!parts[0] && !strcmp(next->base, "index"))
147                         next->show = SHOW_ACTIVE;
148                 cur = cur->next = next;
149         }
150         g_strfreev(entries);
151         g_free(ini);
152
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]))
158                         continue;
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;
163         }
164         g_strfreev(entries);
165         g_key_file_free(conf);
166
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;
174                 }
175         }
176
177 error:
178         g_free(path);
179         return head.next;
180 }
181
182 menu_t *get_menu(char *path)
183 {
184 #if 0
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   };
188
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   };
194
195         return &home;
196 #else
197         char  **parts = g_strsplit(path, "/", -1);
198         menu_t *menu = get_menu_rec("", parts);
199         g_strfreev(parts);
200         return menu;
201 #endif
202 }
203
204 void print_menu(menu_t *menu, int first, int last)
205 {
206         for (menu_t *cur = menu; cur; cur = cur->next) {
207                 if (first <= 0 && cur->show != SHOW_HIDDEN)
208                         print_link(cur->path, cur->name,
209                                 cur->show == SHOW_ACTIVE);
210                 if (cur->kids && last != 0)
211                         print_menu(cur->kids, first-1, last-1);
212         }
213 }
214
215 void debug_menu(page_t *page, menu_t *menu, int depth)
216 {
217         if (page) {
218                 printf("title: '%s'\n", page->title);
219                 printf("keys:  '%s'\n", page->keys);
220                 printf("desc:  '%s'\n", page->desc);
221         }
222         for (menu_t *cur = menu; cur; cur = cur->next) {
223                 for (int i = 0; i < depth; i++)
224                         printf("  ");
225                 printf("menu: %d %s %s '%s'\n",
226                         cur->show, cur->base, cur->path, cur->name);
227                 if (cur->kids)
228                         debug_menu(NULL, cur->kids, depth+1);
229         }
230 }
231
232 void free_menu(menu_t *menu)
233 {
234 }
235
236 /* Page display methods */
237 static void do_lsdir(page_t *page, const char *dir)
238 {
239         page->html = "Lsdir";
240 }
241
242 static void do_regular(page_t *page, const char *file)
243 {
244         const char *query = getenv("QUERY_STRING") ?: "";
245         if (g_file_get_contents(file, &page->text, NULL, NULL)) {
246                 if (!strcmp(query, "src"))
247                         page->html = "source";
248                 else if (!strcmp(query, "hist"))
249                         page->html = "history";
250                 else
251                         page->html = markdown_to_string(page->text, 0, 0);
252         } else {
253                 page->error = g_strdup("403 Forbidden");
254                 page->html  = g_strdup("Page not accessable\n");
255         }
256 }
257
258 static void do_notfound(page_t *page, const char *path)
259 {
260         page->error = g_strdup("404 Not Found");
261         page->html  = g_strdup("Page not found\n");
262 }
263
264 static char *clean(const char *src)
265 {
266         int   len = strlen(src);
267         char *dst = malloc(len+1);
268         int si=0, ei=len-1, di=0;
269         while (src[si] == '/')
270                 si++;
271         while (src[ei] == '/')
272                 ei--;
273         while (si <= ei) {
274                 dst[di++] = src[si++];
275                 while (src[si] == '/' && src[si+1] == '/')
276                         si++;
277         }
278         dst[di] = '\0';
279         return dst;
280 }
281
282 /* Main */
283 int main(int argc, char **argv)
284 {
285         char *path = clean(getenv("PATH_INFO") ?: "/");
286
287         page_t *page = get_page(path);
288         menu_t *menu = get_menu(path);
289         //debug_menu(page, menu, 0);
290         //return 0;
291
292         char *dir   = g_strdup_printf("pages/%s",          path);
293         char *index = g_strdup_printf("pages/%s/index.md", path);
294         char *file  = g_strdup_printf("pages/%s.md",       path);
295
296         if (g_file_test(index, G_FILE_TEST_IS_REGULAR))
297                 do_regular(page, index);
298         else if (g_file_test(file, G_FILE_TEST_IS_REGULAR))
299                 do_regular(page, file);
300         else if (g_file_test(dir, G_FILE_TEST_IS_DIR))
301                 do_lsdir(page, dir);
302         else
303                 do_notfound(page, path);
304
305         g_free(dir);
306         g_free(index);
307         g_free(file);
308
309         print_header(page);
310         print_page(page, menu);
311
312         return 0;
313 }