diff options
Diffstat (limited to 'gph.c')
-rw-r--r-- | gph.c | 288 |
1 files changed, 288 insertions, 0 deletions
@@ -0,0 +1,288 @@ +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct Elems Elems; +struct Elems { + char **e; + int num; +}; + +typedef struct Indexs Indexs; +struct Indexs { + Elems **n; + int num; +}; + + +void * +xcalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) { + perror("calloc"); + exit(1); + } + + return p; +} + +void * +xmalloc(size_t size) +{ + void *p; + + if (!(p = malloc(size))) { + perror("malloc"); + exit(1); + } + + return p; +} + +void * +xrealloc(void *ptr, size_t size) +{ + if (!(ptr = realloc(ptr, size))) { + perror("realloc"); + exit(1); + } + + return ptr; +} + +char * +xstrdup(const char *str) +{ + char *ret; + + if (!(ret = strdup(str))) { + perror("strdup"); + exit(1); + } + + return ret; +} + +void +freeelem(Elems *e) +{ + if (e != NULL) { + if (e->e != NULL) { + for (;e->num > 0; e->num--) + if (e->e[e->num - 1] != NULL) + free(e->e[e->num - 1]); + free(e->e); + } + free(e); + } + return; +} + +void +freeindex(Indexs *i) +{ + if (i != NULL) { + if (i->n != NULL) { + for (;i->num > 0; i->num--) + freeelem(i->n[i->num - 1]); + free(i->n); + } + free(i); + } + + return; +} + +void +addelem(Elems *e, char *s) +{ + e->num++; + e->e = xrealloc(e->e, sizeof(char *) * e->num); + e->e[e->num - 1] = xstrdup(s); + + return; +} + +Elems * +getadv(char *str) +{ + char *b, *e, *o, *bo; + Elems *ret; + + ret = xcalloc(1, sizeof(Elems)); + + if (strchr(str, '\t')) { + addelem(ret, "i"); + addelem(ret, "Happy helping ☃ here: You tried to " + "output a spurious tab character. This will " + "break gopher. Please review your scripts. " + "Have a nice day!"); + addelem(ret, "Err"); + addelem(ret, "server"); + addelem(ret, "port"); + + return ret; + } + + if (str[0] == '[') { + o = xstrdup(str); + b = o + 1; + bo = b; + while ((e = strchr(bo, '|')) != NULL) { + if (e != bo && e[-1] == '\\') { + memmove(&e[-1], e, strlen(e)); + bo = e; + continue; + } + *e = '\0'; + e++; + addelem(ret, b); + b = e; + bo = b; + } + + e = strchr(b, ']'); + if (e != NULL) { + *e = '\0'; + addelem(ret, b); + } + free(o); + + if (ret->e != NULL && ret->e[0] != NULL && ret->e[0][0] == '\0') { + freeelem(ret); + ret = xcalloc(1, sizeof(Elems)); + + addelem(ret, "i"); + addelem(ret, "Happy helping ☃ here: You did not " + "specify an item type on this line. Please " + "review your scripts. " + "Have a nice day!"); + addelem(ret, "Err"); + addelem(ret, "server"); + addelem(ret, "port"); + + return ret; + } + + if (ret->e != NULL && ret->num == 5) + return ret; + + /* Invalid entry: Give back the whole line. */ + freeelem(ret); + ret = xcalloc(1, sizeof(Elems)); + } + + b = str; + if (*str == 't') + b++; + addelem(ret, "i"); + addelem(ret, b); + addelem(ret, "Err"); + addelem(ret, "server"); + addelem(ret, "port"); + + return ret; +} + +void +addindexs(Indexs *idx, Elems *el) +{ + idx->num++; + idx->n = xrealloc(idx->n, sizeof(Elems) * idx->num); + idx->n[idx->num - 1] = el; + + return; +} + +Indexs * +scanfile(char *fname) +{ + char *ln = NULL; + size_t linesiz = 0; + ssize_t n; + FILE *fp; + Indexs *ret; + Elems *el; + + if (!(fp = fopen(fname, "r"))) + return NULL; + + ret = xcalloc(1, sizeof(Indexs)); + + while ((n = getline(&ln, &linesiz, fp)) > 0) { + if (ln[n - 1] == '\n') + ln[--n] = '\0'; + el = getadv(ln); + if(el == NULL) + continue; + + addindexs(ret, el); + } + if (ferror(fp)) + perror("getline"); + free(ln); + fclose(fp); + + if (ret->n == NULL) { + free(ret); + return NULL; + } + + return ret; +} + +int +printelem(int fd, Elems *el, char *file, char *base, char *addr, char *port) +{ + char *path, *p, buf[PATH_MAX+1]; + int len; + + if (!strcmp(el->e[3], "server")) { + free(el->e[3]); + el->e[3] = xstrdup(addr); + } + if (!strcmp(el->e[4], "port")) { + free(el->e[4]); + el->e[4] = xstrdup(port); + } + + /* + * Ignore if the path is from base, if it might be some h type with + * some URL and ignore various types that have different semantics but + * to point to some file or directory. + */ + if ((el->e[2][0] != '\0' + && el->e[2][0] != '/' + && el->e[0][0] != 'i' + && el->e[0][0] != '2' + && el->e[0][0] != '3' + && el->e[0][0] != '8' + && el->e[0][0] != 'w' + && el->e[0][0] != 'T') && + !(el->e[0][0] == 'h' && !strncmp(el->e[2], "URL:", 4))) { + path = file + strlen(base); + if ((p = strrchr(path, '/'))) + len = p - path; + else + len = strlen(path); + snprintf(buf, sizeof(buf), "%s%.*s/%s", base, len, path, el->e[2]); + + if ((path = realpath(buf, NULL)) && + !strncmp(base, path, strlen(base))) { + p = path + strlen(base); + free(el->e[2]); + el->e[2] = xstrdup(p[0]? p : "/"); + } + free(path); + } + + if (dprintf(fd, "%.1s%s\t%s\t%s\t%s\r\n", el->e[0], el->e[1], el->e[2], + el->e[3], el->e[4]) < 0) { + perror("printelem: dprintf"); + return -1; + } + return 0; +} |