#include #include #include #include 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; }