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, "<"); 178 else if (*c == '>') 179 fprintf(htmlf, ">"); 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 }