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