bpaul-webgen

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

main.c (5071B)


      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 	/* +2 because i wanted to add a '/' to the end of something apparently... */
     70 	size_t len = strlen(dir) + strlen(name) + 2;
     71 	char *buf  = malloc(len);
     72 	memcpy(buf, dir, strlen(dir) + 1);
     73 
     74 	strcat(buf, name);
     75 
     76 	return buf;
     77 }
     78 
     79 void
     80 iterate(DIR *d, const char *curdir) {
     81 	struct dirent *entry;
     82 
     83 	/* If the end of the stream is reached, exit.
     84 	 * Errno is reset to determine whether the NULL value means end of stream
     85 	 * of error */
     86 	errno = 0;
     87 	if ((entry = readdir(d)) == NULL) {
     88 		if (errno) {
     89 			perror("readdir");
     90 		}
     91 		return;
     92 	}
     93 
     94 	/* Skip dotfiles */
     95 	if (entry->d_name[0] == '.') {
     96 		goto skip;
     97 	}
     98 
     99 	if (entry->d_type == DT_REG) {
    100 		/* Only want files without file extensions */
    101 		if (strrchr(entry->d_name, '.') != NULL) {
    102 			goto skip;
    103 		}
    104 
    105 		char *buf  = add_path(curdir, entry->d_name);
    106 		char *link = add_path(buf, ".links");
    107 		char *html = add_path(buf, ".html");
    108 
    109 		/* Only want files which have a .links file */
    110 		if (access(link, F_OK) != 0) {
    111 			free(buf);
    112 			free(link);
    113 			free(html);
    114 			goto skip;
    115 		}
    116 
    117 		/* Read the .links file */
    118 		char *links_buf;
    119 		size_t len;
    120 		FILE *linkf = fopen(link, "r");
    121 		len         = fsize(linkf);
    122 		links_buf   = malloc(len);
    123 		fread(links_buf, 1, len, linkf);
    124 
    125 		fclose(linkf);
    126 
    127 		size_t entry_cnt;
    128 		entry_cnt = line_count(links_buf);
    129 
    130 		/* Store each entry in the .links file into this struct array */
    131 		struct links_entry *entries = malloc(sizeof(struct links_entry) * entry_cnt);
    132 
    133 		for (size_t i = 0; i < entry_cnt; i++, links_buf = NULL) {
    134 			entries[i].href = strtok(links_buf, " \n");
    135 			entries[i].miny = atoi(strtok(NULL, " \n"));
    136 			entries[i].minx = atoi(strtok(NULL, " \n"));
    137 			entries[i].maxy = atoi(strtok(NULL, " \n"));
    138 			entries[i].maxx = atoi(strtok(NULL, " \n"));
    139 		}
    140 
    141 		/* Read ascii file and add links when needed */
    142 		FILE *f     = fopen(buf, "r");
    143 		FILE *htmlf = fopen(html, "w");
    144 		/* WHAT AM I LOOKING AT??? */
    145 		char *c     = malloc(1);
    146 		len         = fsize(f);
    147 		int x = 1, y = 1;
    148 		int opened = 0;
    149 
    150 		/* Print html */
    151 		fprintf(htmlf, start_html);
    152 		for (size_t j = 0; j < len; j++) {
    153 			fread(c, 1, 1, f);
    154 			for (size_t i = 0; i < entry_cnt; i++) {
    155 				/* If there is either a start or end of a link, print it */
    156 				if (y >= entries[i].miny && y <= entries[i].maxy
    157 				    && x == entries[i].minx) {
    158 					fprintf(htmlf, "<a href=\"%s\">", entries[i].href);
    159 					opened = i;
    160 				} else if (y >= entries[i].miny && y <= entries[i].maxy
    161 				           && x == entries[i].maxx + 1) {
    162 					fprintf(htmlf, "</a>");
    163 					opened = 0;
    164 				}
    165 			}
    166 			x++;
    167 			if (*c == '\n') {
    168 				/* If a link was opened but not closed, there was not enough
    169 				 * space to put the close part.
    170 				 * Add more space so that it can be closed properly */
    171 				if (opened) {
    172 					while (x <= entries[opened].maxx + 1) {
    173 						fputc(' ', htmlf);
    174 						x++;
    175 					}
    176 					fprintf(htmlf, "</a>");
    177 				}
    178 				x = 1;
    179 				y++;
    180 			}
    181 			if (*c == '<')
    182 				fprintf(htmlf, "&lt;");
    183 			else if (*c == '>')
    184 				fprintf(htmlf, "&gt;");
    185 			else
    186 				fputc(*c, htmlf);
    187 		}
    188 		fprintf(htmlf, end_html);
    189 
    190 		fclose(f);
    191 		fclose(htmlf);
    192 
    193 		free(buf);
    194 		free(link);
    195 		free(html);
    196 		free(links_buf);
    197 		free(entries);
    198 		free(c);
    199 	} else if (entry->d_type == DT_DIR) {
    200 		/* For directories, reiterate */
    201 
    202 		/* Create a string that appends the directory name to the current
    203 		 * directory name */
    204 		char *buf = add_path(curdir, entry->d_name);
    205 		strcat(buf, "/");
    206 
    207 		DIR *newd;
    208 		if ((newd = opendir((buf))) == NULL) {
    209 			perror("opendir");
    210 			free(buf);
    211 			return;
    212 		}
    213 
    214 		/* Iterate */
    215 		iterate(newd, buf);
    216 
    217 		free(buf);
    218 	}
    219 skip:
    220 	seekdir(d, entry->d_off);
    221 	iterate(d, curdir);
    222 }
    223 
    224 int
    225 main(int argc, char **argv) {
    226 	if (argc < 2) {
    227 		puts("Please specify a directory");
    228 		exit(0);
    229 	}
    230 
    231 	DIR *d;
    232 
    233 	if ((d = opendir(argv[1])) == NULL) {
    234 		puts("That is not a valid directory");
    235 		exit(0);
    236 	}
    237 	/* IS THIS SAFE???? atp i don't want to know... */
    238 	strcat(argv[1], "/");
    239 	iterate(d, argv[1]);
    240 	closedir(d);
    241 
    242 	return 0;
    243 }