sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

build-page.c (6189B)


      1 #define _POSIX_C_SOURCE 200809L
      2 
      3 #include <sys/stat.h>
      4 #include <sys/types.h>
      5 #include <sys/wait.h>
      6 
      7 #include <dirent.h>
      8 #include <limits.h>
      9 #include <stdarg.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <unistd.h>
     14 
     15 #define CONVERTER "smu","-n"
     16 #define LEN(x) (sizeof(x) / sizeof(x[0]))
     17 #define TITLE_MAX 1024
     18 #define TITLE_DEFAULT "suckless.org"
     19 #define DIR_MAX 1024
     20 
     21 char *html_header =
     22 	"<!doctype html>\n"
     23 	"<html>\n"
     24 	"<head>\n"
     25 	"\t<meta charset=\"utf-8\"/>\n"
     26 	"\t<title>%1$s | suckless.org software that sucks less</title>\n"
     27 	"\t<link rel=\"stylesheet\" type=\"text/css\" href=\"//suckless.org/pub/style.css\"/>\n"
     28 	"</head>\n"
     29 	"\n"
     30 	"<div id=\"header\">\n"
     31 	"\t<a href=\"//suckless.org/\"><img src=\"//suckless.org/logo.svg\" alt=\"\"/></a>&nbsp;\n"
     32 	"\t<a id=\"headerLink\" href=\"//suckless.org/\">suckless.org</a>\n"
     33 	"\t<span class=\"hidden\"> - </span>\n"
     34 	"\t<span id=\"headerSubtitle\">%1$s</span>\n"
     35 	"</div>\n"
     36 	"<hr class=\"hidden\"/>\n";
     37 
     38 char *html_nav_bar =
     39 	"\t<span class=\"right\">\n"
     40 	"\t\t<a href=\"//dl.suckless.org\">download</a>\n"
     41 	"\t\t<a href=\"//git.suckless.org\">source</a>\n"
     42 	"\t</span>\n";
     43 
     44 char *html_footer = "</html>\n";
     45 
     46 struct domain {
     47 	char *label;
     48 	char *dir;
     49 } domain_list[] = {
     50 	{ "home",  "suckless.org" },
     51 	{ "dwm",   "dwm.suckless.org", },
     52 	{ "st",    "st.suckless.org", },
     53 	{ "core",  "core.suckless.org", },
     54 	{ "surf",  "surf.suckless.org", },
     55 	{ "tools", "tools.suckless.org", },
     56 	{ "libs",  "libs.suckless.org", },
     57 	{ "e.V.",  "ev.suckless.org" },
     58 	{ NULL, NULL }
     59 };
     60 
     61 void
     62 die_perror(char *fmt, ...)
     63 {
     64 	va_list ap;
     65 
     66 	va_start(ap, fmt);
     67 	vfprintf(stderr, fmt, ap);
     68 	va_end(ap);
     69 	fputs(": ", stderr);
     70 	perror(NULL);
     71 	exit(1);
     72 }
     73 
     74 void
     75 die(char *fmt, ...)
     76 {
     77 	va_list ap;
     78 
     79 	va_start(ap, fmt);
     80 	vfprintf(stderr, fmt, ap);
     81 	va_end(ap);
     82 	fputc('\n', stderr);
     83 	exit(1);
     84 }
     85 
     86 char *
     87 xstrdup(const char *s)
     88 {
     89 	char *p = strdup(s);
     90 
     91 	if (!p)
     92 		die_perror("strdup");
     93 
     94 	return p;
     95 }
     96 
     97 int
     98 stat_isdir(const char *f)
     99 {
    100 	struct stat s;
    101 
    102 	if (stat(f, &s) == -1) {
    103 		perror(f);
    104 		return 0;
    105 	}
    106 	return S_ISDIR(s.st_mode);
    107 }
    108 
    109 int
    110 stat_isfile(const char *f)
    111 {
    112 	struct stat s;
    113 
    114 	if (stat(f, &s) == -1) {
    115 		perror(f);
    116 		return 0;
    117 	}
    118 	return S_ISREG(s.st_mode);
    119 }
    120 
    121 int
    122 spawn_wait(char **argv)
    123 {
    124         int status;
    125 
    126         switch (fork()) {
    127 	case 0:
    128 		execvp(argv[0], argv);
    129 		exit(126);
    130 	case -1:
    131 		return -1;
    132         }
    133 	if (wait(&status) == -1)
    134 		return -1;
    135 
    136         return WIFEXITED(status) ? 0 : -1;
    137 }
    138 
    139 int
    140 oneline(char *buf, size_t bufsiz, char const *path)
    141 {
    142 	char *r;
    143 	FILE *fp;
    144 
    145 	if (!buf || bufsiz == 0)
    146 		return 0;
    147 	if (!(fp = fopen(path, "r"))) {
    148 		perror(path);
    149 		return 0;
    150 	}
    151 
    152 	fgets(buf, bufsiz, fp);
    153 	if (ferror(fp))
    154 		die_perror("fgets: %s", path);
    155 
    156 	fclose(fp);
    157 
    158 	for (r = buf; *r && *r != '\n'; ++r)
    159 		;
    160 	*r = '\0';
    161 
    162 	return 1;
    163 }
    164 
    165 void
    166 print_name(const char *name)
    167 {
    168 	char c;
    169 	for (; c = *name; ++name)
    170 		putchar((c == '_' || c == '-') ? ' ' : c);
    171 }
    172 
    173 void
    174 print_header(void)
    175 {
    176 	char title[TITLE_MAX];
    177 
    178 	printf(html_header, oneline(title, sizeof(title), ".title") ?
    179 	       title : TITLE_DEFAULT);
    180 }
    181 
    182 void
    183 print_nav_bar(char *domain)
    184 {
    185 	struct domain *d;
    186 
    187 	puts("<div id=\"menu\">");
    188 	for (d = domain_list; d->dir; ++d) {
    189 		if (strcmp(domain, d->dir) == 0)
    190 			printf("\t<a href=\"//%s/\"><b>%s</b></a>\n",
    191 			       d->dir, d->label);
    192 		else
    193 			printf("\t<a href=\"//%s/\">%s</a>\n",
    194 			       d->dir, d->label);
    195 
    196 	}
    197 	fputs(html_nav_bar, stdout);
    198 	puts("</div>");
    199 	puts("<hr class=\"hidden\"/>");
    200 }
    201 
    202 int
    203 qsort_strcmp(const void *a, const void *b)
    204 {
    205 	return strcmp(*(const char **)a, *(const char **)b);
    206 }
    207 
    208 void
    209 menu_panel(char *domain, char *page, char *this, int depth)
    210 {
    211 	DIR *dp;
    212 	struct dirent *de;
    213 	char newdir[PATH_MAX];
    214 	char *d_list[DIR_MAX], *d;
    215 	size_t d_len, l;
    216 	int i;
    217 
    218 	if ((dp = opendir(this ? this : ".")) == NULL)
    219 		die_perror("opendir: %s", this ? this : ".");
    220 
    221 	d_len = 0;
    222 	while(d_len < LEN(d_list) && (de = readdir(dp)))
    223 	     d_list[d_len++] = xstrdup(de->d_name);
    224 	closedir(dp);
    225 
    226 	qsort(d_list, d_len, sizeof *d_list, qsort_strcmp);
    227 
    228 	for (l = 0; l < d_len; free(d_list[l++])) {
    229 		d = d_list[l];
    230 		if (*d == '.')
    231 			continue;
    232 		snprintf(newdir, sizeof(newdir), this ? "%2$s/%1$s" : "%s",
    233 		         d, this);
    234 		if (!stat_isdir(newdir))
    235 			continue;
    236 
    237 		for (i = 0; i < depth + 1; ++i)
    238 			putchar('\t');
    239 		fputs("<li>", stdout);
    240 		if (page && !strncmp(newdir, page, strlen(newdir))) {
    241 			printf("<a href=\"//%s/%s/\"><b>", domain, newdir);
    242 			print_name(d);
    243 			fputs("/</b></a>", stdout);
    244 		} else {
    245 			printf("<a href=\"//%s/%s/\">", domain, newdir);
    246 			print_name(d);
    247 			fputs("/</a>", stdout);
    248 		}
    249 
    250 		if (page && !strncmp(newdir, page, strlen(newdir))) {
    251 			putchar('\n');
    252 			for (i = 0; i < depth + 2; ++i)
    253 				putchar('\t');
    254 			/* TODO: empty <ul></ul> is printed for subitems */
    255 			puts("<ul>");
    256 			menu_panel(domain, page, newdir, depth + 1);
    257 			for (i = 0; i < depth + 2; ++i)
    258 				putchar('\t');
    259 			puts("</ul>");
    260 			for (i = 0; i < depth + 1; ++i)
    261 				putchar('\t');
    262 		}
    263 		puts("</li>");
    264 	}
    265 }
    266 
    267 void
    268 print_menu_panel(char *domain, char *page)
    269 {
    270 	fputs("<div id=\"nav\">\n\t<ul>\n\t<li>", stdout);
    271 	if (!page)
    272 		puts("<a href=\"/\"><b>about</b></a></li>");
    273 	else
    274 		puts("<a href=\"/\">about</a></li>");
    275 	menu_panel(domain, page, NULL, 0);
    276 	puts("\t</ul>");
    277 	puts("</div>");
    278 	puts("<hr class=\"hidden\"/>");
    279 }
    280 
    281 void
    282 print_content(char *domain, char *page)
    283 {
    284 	char index[PATH_MAX];
    285 	char *argv[] = { CONVERTER, index, NULL };
    286 
    287 	snprintf(index, sizeof(index), page ? "%2$s/%1$s" : "%s",
    288 	         "index.md", page);
    289 
    290 	puts("<div id=\"main\">\n");
    291 
    292 	if (stat_isfile(index)) {
    293 		fflush(stdout);
    294 		if (spawn_wait(argv) == -1)
    295 			die_perror("spawn: %s/%s/%s", domain, page, index);
    296 	}
    297 	puts("</div>\n");
    298 }
    299 
    300 void
    301 print_footer(void)
    302 {
    303 	fputs(html_footer, stdout);
    304 }
    305 
    306 int
    307 main(int argc, char *argv[])
    308 {
    309 	char *domain, *page;
    310 
    311 	if (argc != 2)
    312 		die("usage: %s directory", argv[0]);
    313 	if ((page = strchr(argv[1], '/')))
    314 		*page++ = '\0';
    315 	domain = argv[1];
    316 	if (chdir(domain) == -1)
    317 		die_perror("chdir: %s", domain);
    318 
    319 	print_header();
    320 	print_nav_bar(domain);
    321 	puts("<div id=\"content\">");
    322 	print_menu_panel(domain, page);
    323 	print_content(domain, page);
    324 	puts("</div>\n");
    325 	print_footer();
    326 
    327 	return 0;
    328 }