summaryrefslogtreecommitdiff
path: root/gph.c
diff options
context:
space:
mode:
Diffstat (limited to 'gph.c')
-rw-r--r--gph.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/gph.c b/gph.c
new file mode 100644
index 0000000..6d29be0
--- /dev/null
+++ b/gph.c
@@ -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;
+}