]> Pileus Git - site/blob - src/main.c
8cfc49ca52378a3a48afd6c357dc166e8ada3d0f
[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                 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;
144         }
145         g_strfreev(entries);
146         g_free(ini);
147
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]))
153                         continue;
154                 if ((next = get_menu_entry(prefix, entries[i])))
155                         cur = cur->next = next;
156         }
157         g_strfreev(entries);
158         g_key_file_free(conf);
159
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;
167                 }
168                 if (!strcmp(cur->base, "index"))
169                         cur->show = SHOW_HIDDEN;
170         }
171
172 error:
173         g_free(path);
174         return head.next;
175 }
176
177 menu_t *get_menu(char *path)
178 {
179 #if 0
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   };
183
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   };
189
190         return &home;
191 #else
192         char  **parts = g_strsplit(path, "/", -1);
193         menu_t *menu = get_menu_rec("", parts);
194         g_strfreev(parts);
195         return menu;
196 #endif
197 }
198
199 void print_menu(menu_t *menu, int first, int last)
200 {
201         for (menu_t *cur = menu; cur; cur = cur->next) {
202                 if (cur->show == SHOW_HIDDEN)
203                         continue;
204                 if (first <= 0)
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);
209         }
210 }
211
212 void debug_menu(page_t *page, menu_t *menu, int depth)
213 {
214         if (page) {
215                 printf("title: '%s'\n", page->title);
216                 printf("keys:  '%s'\n", page->keys);
217                 printf("desc:  '%s'\n", page->desc);
218         }
219         for (menu_t *cur = menu; cur; cur = cur->next) {
220                 for (int i = 0; i < depth; i++)
221                         printf("  ");
222                 printf("menu: %d %s %s '%s'\n",
223                         cur->show, cur->base, cur->path, cur->name);
224                 if (cur->kids)
225                         debug_menu(NULL, cur->kids, depth+1);
226         }
227 }
228
229 void free_menu(menu_t *menu)
230 {
231 }
232
233 /* Page display methods */
234 static void do_lsdir(page_t *page, const char *dir)
235 {
236         page->html = "Lsdir";
237 }
238
239 static void do_regular(page_t *page, const char *file)
240 {
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";
247                 else
248                         page->html = markdown_to_string(page->text, 0, 0);
249         } else {
250                 page->html = g_strdup("Page not found");
251         }
252 }
253
254 static void do_notfound(page_t *page, const char *path)
255 {
256         page->html = "Page not found";
257 }
258
259 static char *clean(const char *src)
260 {
261         int   len = strlen(src);
262         char *dst = malloc(len+1);
263         int si=0, ei=len-1, di=0;
264         while (src[si] == '/')
265                 si++;
266         while (src[ei] == '/')
267                 ei--;
268         while (si <= ei) {
269                 dst[di++] = src[si++];
270                 while (src[si] == '/' && src[si+1] == '/')
271                         si++;
272         }
273         dst[di] = '\0';
274         return dst;
275 }
276
277 /* Main */
278 int main(int argc, char **argv)
279 {
280         char *path = clean(getenv("PATH_INFO") ?: "/aweather/");
281
282         print_header();
283
284         page_t *page = get_page(path);
285         menu_t *menu = get_menu(path);
286         //debug_menu(page, menu, 0);
287         //return 0;
288
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);
292
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))
298                 do_lsdir(page, dir);
299         else
300                 do_notfound(page, path);
301
302         g_free(dir);
303         g_free(index);
304         g_free(file);
305
306         print_page(page, menu);
307
308         return 0;
309 }