bpaul-webgen

html generator for bpaul.xyz
Log | Files | Refs | README

main.c (4783B)


      1 #include <dirent.h>
      2 #include <errno.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/stat.h>
      7 #include <unistd.h>
      8 
      9 const char start_html[] = "<html>"
     10 "<head>"
     11 "<meta charset=\"UTF-8\">"
     12 "<meta name=\"viewport\" content=\"initial-scale=1,maximum-scale=1\">"
     13 "<link rel=\"authorization_endpoint\" href=\"https://indieauth.com/auth\">"
     14 "<link href=\"https://github.com/b-paul\" rel=\"me\">"
     15 "<style>"
     16 "a{"
     17 "color:inherit;"
     18 "outline:0;"
     19 "text-decoration:inherit;"
     20 "}"
     21 ""
     22 "body{"
     23 "font-family:monospace;"
     24 "color:white;"
     25 "background-color:black;"
     26 "}"
     27 ""
     28 "pre{"
     29 "font-family:monospace;"
     30 "}"
     31 "</style>"
     32 "</head>"
     33 "<body>"
     34 "<pre>\n";
     35 
     36 const char end_html[] = "</pre>"
     37 						"</body>"
     38 						"</html>\n";
     39 
     40 struct links_entry {
     41 	char *href;
     42 	int minx, miny;
     43 	int maxx, maxy;
     44 };
     45 
     46 size_t
     47 line_count(const char *buf) {
     48 	const char *ptr = buf;
     49 	size_t cnt      = 0;
     50 	while (*ptr != '\0') {
     51 		if (*ptr == '\n')
     52 			cnt++;
     53 		ptr++;
     54 	}
     55 	return cnt;
     56 }
     57 
     58 size_t
     59 fsize(FILE *f) {
     60 	size_t len;
     61 	fseek(f, 0, SEEK_END);
     62 	len = ftell(f);
     63 	fseek(f, 0, SEEK_SET);
     64 	return len;
     65 }
     66 
     67 char *
     68 add_path(const char *dir, const char *name) {
     69 	size_t len = strlen(dir) + strlen(name) + 2;
     70 	char *buf  = malloc(len);
     71 	memcpy(buf, dir, len);
     72 
     73 	strcat(buf, name);
     74 
     75 	return buf;
     76 }
     77 
     78 void
     79 iterate(DIR *d, const char *curdir) {
     80 	struct dirent *entry;
     81 
     82 	/* If the end of the stream is reached, exit.
     83 	 * Errno is reset to determine whether the NULL value means end of stream
     84 	 * of error */
     85 	errno = 0;
     86 	if ((entry = readdir(d)) == NULL) {
     87 		if (errno) {
     88 			perror("readdir");
     89 		}
     90 		return;
     91 	}
     92 
     93 	/* Skip dotfiles */
     94 	if (entry->d_name[0] == '.') {
     95 		goto skip;
     96 	}
     97 
     98 	if (entry->d_type == DT_REG) {
     99 		/* Only want files without file extensions */
    100 		if (strrchr(entry->d_name, '.') != NULL) {
    101 			goto skip;
    102 		}
    103 
    104 		char *buf  = add_path(curdir, entry->d_name);
    105 		char *link = add_path(buf, ".links");
    106 		char *html = add_path(buf, ".html");
    107 
    108 		/* Only want files which have a .links file */
    109 		if (access(link, F_OK) != 0) {
    110 			goto skip;
    111 		}
    112 
    113 		/* Read the .links file */
    114 		char *links_buf;
    115 		size_t len;
    116 		FILE *linkf = fopen(link, "r");
    117 		len         = fsize(linkf);
    118 		links_buf   = malloc(len);
    119 		fread(links_buf, 1, len, linkf);
    120 
    121 		fclose(linkf);
    122 
    123 		size_t entry_cnt;
    124 		entry_cnt = line_count(links_buf);
    125 
    126 		/* Store each entry in the .links file into this struct array */
    127 		struct links_entry *entries = malloc(sizeof(struct links_entry) * entry_cnt);
    128 
    129 		for (size_t i = 0; i < entry_cnt; i++, links_buf = NULL) {
    130 			entries[i].href = strtok(links_buf, " \n");
    131 			entries[i].miny = atoi(strtok(NULL, " \n"));
    132 			entries[i].minx = atoi(strtok(NULL, " \n"));
    133 			entries[i].maxy = atoi(strtok(NULL, " \n"));
    134 			entries[i].maxx = atoi(strtok(NULL, " \n"));
    135 		}
    136 
    137 		/* Read ascii file and add links when needed */
    138 		FILE *f     = fopen(buf, "r");
    139 		FILE *htmlf = fopen(html, "w");
    140 		char *c     = malloc(1);
    141 		len         = fsize(f);
    142 		int x = 1, y = 1;
    143 		int opened = 0;
    144 
    145 		/* Print html */
    146 		fprintf(htmlf, start_html);
    147 		for (size_t j = 0; j < len; j++) {
    148 			fread(c, 1, 1, f);
    149 			for (size_t i = 0; i < entry_cnt; i++) {
    150 				/* If there is either a start or end of a link, print it */
    151 				if (y >= entries[i].miny && y <= entries[i].maxy
    152 				    && x == entries[i].minx) {
    153 					fprintf(htmlf, "<a href=\"%s\">", entries[i].href);
    154 					opened = i;
    155 				} else if (y >= entries[i].miny && y <= entries[i].maxy
    156 				           && x == entries[i].maxx + 1) {
    157 					fprintf(htmlf, "</a>");
    158 					opened = 0;
    159 				}
    160 			}
    161 			x++;
    162 			if (*c == '\n') {
    163 				/* If a link was opened but not closed, there was not enough
    164 				 * space to put the close part.
    165 				 * Add more space so that it can be closed properly */
    166 				if (opened) {
    167 					while (x <= entries[opened].maxx + 1) {
    168 						fputc(' ', htmlf);
    169 						x++;
    170 					}
    171 					fprintf(htmlf, "</a>");
    172 				}
    173 				x = 1;
    174 				y++;
    175 			}
    176 			if (*c == '<')
    177 				fprintf(htmlf, "&lt;");
    178 			else if (*c == '>')
    179 				fprintf(htmlf, "&gt;");
    180 			else
    181 				fputc(*c, htmlf);
    182 		}
    183 		fprintf(htmlf, end_html);
    184 
    185 		fclose(f);
    186 		fclose(htmlf);
    187 
    188 		free(buf);
    189 		free(link);
    190 		free(links_buf);
    191 	} else if (entry->d_type == DT_DIR) {
    192 		/* For directories, reiterate */
    193 
    194 		/* Create a string that appends the directory name to the current
    195 		 * directory name */
    196 		char *buf = add_path(curdir, entry->d_name);
    197 		strcat(buf, "/");
    198 
    199 		DIR *newd;
    200 		if ((newd = opendir((buf))) == NULL) {
    201 			perror("opendir");
    202 			return;
    203 		}
    204 
    205 		/* Iterate */
    206 		iterate(newd, buf);
    207 
    208 		free(buf);
    209 	}
    210 skip:
    211 	seekdir(d, entry->d_off);
    212 	iterate(d, curdir);
    213 }
    214 
    215 int
    216 main(int argc, char **argv) {
    217 	if (argc < 2) {
    218 		puts("Please specify a directory");
    219 		exit(0);
    220 	}
    221 
    222 	DIR *d;
    223 
    224 	if ((d = opendir(argv[1])) == NULL) {
    225 		puts("That is not a valid directory");
    226 		exit(0);
    227 	}
    228 	strcat(argv[1], "/");
    229 	iterate(d, argv[1]);
    230 
    231 	return 0;
    232 }