Introduction
Introduction Statistics Contact Development Disclaimer Help
split libgcgi.h into a .c and .h file - libgcgi - REST library for Gopher
git clone git://bitreich.org/libgcgi git://hg6vgqziawt5s4dj.onion/libgcgi
Log
Files
Refs
Tags
README
LICENSE
---
commit 052f666afd7390d53ec4b3ad91882e7e76b7a49f
parent 5bc5afc6bfca4948fee87a59a87aede28f2de765
Author: Josuah Demangeon <[email protected]>
Date: Sat, 30 Jul 2022 13:38:07 +0200
split libgcgi.h into a .c and .h file
Diffstat:
M Makefile | 6 +++---
M index.c | 11 ++---------
A libgcgi.c | 283 +++++++++++++++++++++++++++++…
M libgcgi.h | 328 ++---------------------------…
4 files changed, 303 insertions(+), 325 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -1,10 +1,10 @@
LDFLAGS = -static
-CFLAGS = -g -pedantic -std=c99 -Wall -Wextra -Wno-unused-function
+CFLAGS = -g -pedantic -std=c99 -Wall -Wextra
all: index.cgi
clean:
rm -f *.o index.cgi
-index.cgi: index.c libgcgi.h
- ${CC} ${LDFLAGS} ${CFLAGS} -o $@ index.c
+index.cgi: index.c libgcgi.c libgcgi.h
+ ${CC} ${LDFLAGS} ${CFLAGS} -o $@ index.c libgcgi.c
diff --git a/index.c b/index.c
@@ -1,13 +1,6 @@
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stddef.h>
#include <unistd.h>
-#include <sys/stat.h>
+#include <stdio.h>
#include "libgcgi.h"
diff --git a/libgcgi.c b/libgcgi.c
@@ -0,0 +1,283 @@
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "libgcgi.h"
+
+#define GCGI_MATCH_NUM 5
+
+char *gcgi_gopher_search;
+char *gcgi_gopher_path;
+char *gcgi_gopher_host;
+char *gcgi_gopher_port;
+struct gcgi_var_list gcgi_gopher_query;
+
+void
+gcgi_fatal(char *fmt, ...)
+{
+ va_list va;
+ char msg[1024];
+
+ va_start(va, fmt);
+ vsnprintf(msg, sizeof msg, fmt, va);
+ printf("error: %s\n", msg);
+ exit(1);
+}
+
+static char *
+gcgi_fopenread(char *path)
+{
+ FILE *fp;
+ char *buf;
+ ssize_t ssz;
+ size_t sz;
+
+ if ((fp = fopen(path, "r")) == NULL)
+ return NULL;
+ if (fseek(fp, 0, SEEK_END) == -1)
+ return NULL;
+ if ((ssz = ftell(fp)) == -1)
+ return NULL;
+ sz = ssz;
+ if (fseek(fp, 0, SEEK_SET) == -1)
+ return NULL;
+ if ((buf = malloc(sz + 1)) == NULL)
+ return NULL;
+ if (fread(buf, sz, 1, fp) == sz) {
+ errno = EFBIG;
+ goto error_free;
+ }
+ if (ferror(fp))
+ goto error_free;
+ fclose(fp);
+ buf[sz] = '\0';
+ return buf;
+error_free:
+ free(buf);
+ return NULL;
+}
+
+static int
+gcgi_cmp_var(const void *v1, const void *v2)
+{
+ return strcasecmp(((struct gcgi_var *)v1)->key, ((struct gcgi_var *)v2…
+}
+
+void
+gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val)
+{
+ void *mem;
+
+ vars->len++;
+ if ((mem = realloc(vars->list, vars->len * sizeof *vars->list)) == NUL…
+ gcgi_fatal("realloc");
+ vars->list = mem;
+ vars->list[vars->len-1].key = key;
+ vars->list[vars->len-1].val = val;
+}
+
+void
+gcgi_sort_var_list(struct gcgi_var_list *vars)
+{
+ qsort(vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var);
+}
+
+char *
+gcgi_get_var(struct gcgi_var_list *vars, char *key)
+{
+ struct gcgi_var *v, q = { .key = key };
+
+ v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_va…
+ return (v == NULL) ? NULL : v->val;
+}
+
+void
+gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val)
+{
+ struct gcgi_var *v, q;
+
+ q.key = key;
+ v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_va…
+ if (v != NULL) {
+ v->val = val;
+ return;
+ }
+ gcgi_add_var(vars, key, val);
+ gcgi_sort_var_list(vars);
+}
+
+void
+gcgi_read_var_list(struct gcgi_var_list *vars, char *path)
+{
+ char *line, *tail, *key, *s;
+
+ line = NULL;
+
+ if ((tail = vars->buf = gcgi_fopenread(path)) == NULL)
+ gcgi_fatal("opening %s: %s", path, strerror(errno));
+ while ((line = strsep(&tail, "\n")) != NULL) {
+ if (line[0] == '\0')
+ break;
+ key = strsep(&line, ":");
+ if (line == NULL || *line++ != ' ')
+ gcgi_fatal("%s: missing ': ' separator", path);
+ gcgi_add_var(vars, key, line);
+ }
+ gcgi_set_var(vars, "text", tail ? tail : "");
+ gcgi_set_var(vars, "file", (s = strrchr(path, '/')) ? s + 1 : path);
+ gcgi_sort_var_list(vars);
+}
+
+void
+gcgi_free_var_list(struct gcgi_var_list *vars)
+{
+ if (vars->buf != NULL)
+ free(vars->buf);
+ free(vars->list);
+}
+
+int
+gcgi_write_var_list(struct gcgi_var_list *vars, char *dst)
+{
+ FILE *fp;
+ struct gcgi_var *v;
+ size_t n;
+ char path[1024];
+ char *text;
+
+ text = NULL;
+
+ snprintf(path, sizeof path, "%s.tmp", dst);
+ if ((fp = fopen(path, "w")) == NULL)
+ gcgi_fatal("opening '%s' for writing", path);
+
+ for (v = vars->list, n = vars->len; n > 0; v++, n--) {
+ if (strcasecmp(v->key, "Text") == 0) {
+ text = text ? text : v->val;
+ continue;
+ }
+ assert(strchr(v->key, '\n') == NULL);
+ assert(strchr(v->val, '\n') == NULL);
+ fprintf(fp, "%s: %s\n", v->key, v->val);
+ }
+ fprintf(fp, "\n%s", text ? text : "");
+
+ fclose(fp);
+ if (rename(path, dst) == -1)
+ gcgi_fatal( "renaming '%s' to '%s'", path, dst);
+ return 0;
+}
+
+static int
+gcgi_match(char const *glob, char *path, char **matches, size_t m)
+{
+ if (m >= GCGI_MATCH_NUM)
+ gcgi_fatal("too many wildcards in glob");
+ matches[m] = NULL;
+ while (*glob != '*' && *path != '\0' && *glob == *path)
+ glob++, path++;
+ if (glob[0] == '*') {
+ if (*glob != '\0' && gcgi_match(glob + 1, path, matches, m + 1…
+ if (matches[m] == NULL)
+ matches[m] = path;
+ *path = '\0';
+ return 1;
+ } else if (*path != '\0' && gcgi_match(glob, path + 1, matches…
+ matches[m] = (char *)path;
+ return 1;
+ }
+ }
+ return *glob == '\0' && *path == '\0';
+}
+
+static void
+gcgi_decode_url(struct gcgi_var_list *vars, char *s)
+{
+ char *tok, *eq;
+
+ while ((tok = strsep(&s, "&"))) {
+ //gcgi_decode_hex(tok);
+ if ((eq = strchr(tok, '=')) == NULL)
+ continue;
+ *eq = '\0';
+ gcgi_add_var(vars, tok, eq + 1);
+ }
+ gcgi_sort_var_list(vars);
+}
+
+void
+gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc)
+{
+ char *query_string;
+
+ if (argc != 5)
+ gcgi_fatal("wrong number of arguments: %c", argc);
+ assert(argv[0] && argv[1] && argv[2] && argv[3]);
+
+ /* executable.[d]cgi $search $arguments $host $port */
+ gcgi_gopher_search = argv[1];
+ gcgi_gopher_path = argv[2];
+ gcgi_gopher_host = argv[3];
+ gcgi_gopher_port = argv[4];
+ query_string = strchr(gcgi_gopher_path, '?');
+ if (query_string != NULL) {
+ *query_string++ = '\0';
+ gcgi_decode_url(&gcgi_gopher_query, query_string);
+ }
+
+ for (; h->glob != NULL; h++) {
+ char *matches[GCGI_MATCH_NUM + 1];
+ if (!gcgi_match(h->glob, gcgi_gopher_path, matches, 0))
+ continue;
+ h->fn(matches);
+ return;
+ }
+ gcgi_fatal("no handler for '%s'", gcgi_gopher_path);
+}
+
+static char*
+gcgi_next_var(char *head, char **tail)
+{
+ char *beg, *end;
+
+ if ((beg = strstr(head, "{{")) == NULL
+ || (end = strstr(beg, "}}")) == NULL)
+ return NULL;
+ *beg = *end = '\0';
+ *tail = end + strlen("}}");
+ return beg + strlen("{{");
+}
+
+void
+gcgi_template(char const *path, struct gcgi_var_list *vars)
+{
+ FILE *fp;
+ size_t sz;
+ char *line, *head, *tail, *key, *val;
+
+ if ((fp = fopen(path, "r")) == NULL)
+ gcgi_fatal("opening template %s", path);
+ sz = 0;
+ line = NULL;
+ while (getline(&line, &sz, fp) > 0) {
+ head = tail = line;
+ for (; (key = gcgi_next_var(head, &tail)); head = tail) {
+ fputs(head, stdout);
+ if ((val = gcgi_get_var(vars, key)))
+ fputs(val, stdout);
+ else
+ fprintf(stdout, "{{error:%s}}", key);
+ }
+ fputs(tail, stdout);
+ }
+ if (ferror(fp))
+ gcgi_fatal("reading from template: %s", strerror(errno));
+ fclose(fp);
+}
diff --git a/libgcgi.h b/libgcgi.h
@@ -19,328 +19,30 @@ struct gcgi_var_list {
};
/* main loop executing h->fn() if h->glob is matching */
-static void gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc…
+void gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc);
/* abort the program with an error message sent to the client */
-static void gcgi_fatal(char *fmt, ...);
+void gcgi_fatal(char *fmt, ...);
/* print a template with every "{{name}}" looked up in `vars` */
-static void gcgi_template(char const *path, struct gcgi_var_list *vars);
-
-/* print `s` with all gophermap special characters escaped */
-static void gcgi_print_gophermap(char const *s);
+void gcgi_template(char const *path, struct gcgi_var_list *vars);
/* manage a `key`-`val` pair storage `vars`, as used with gcgi_template */
-static void gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val);
-static void gcgi_sort_var_list(struct gcgi_var_list *vars);
-static void gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val);
-static char *gcgi_get_var(struct gcgi_var_list *vars, char *key);
-static void gcgi_free_var_list(struct gcgi_var_list *vars);
+void gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val);
+void gcgi_sort_var_list(struct gcgi_var_list *vars);
+void gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val);
+char *gcgi_get_var(struct gcgi_var_list *vars, char *key);
+void gcgi_free_var_list(struct gcgi_var_list *vars);
/* store and read a list of variables onto a simple RFC822-like format */
-static void gcgi_read_var_list(struct gcgi_var_list *vars, char *path);
-static int gcgi_write_var_list(struct gcgi_var_list *vars, char *path);
+void gcgi_read_var_list(struct gcgi_var_list *vars, char *path);
+int gcgi_write_var_list(struct gcgi_var_list *vars, char *path);
/* components of the gopher request */
-char *gcgi_gopher_search;
-char *gcgi_gopher_path;
-char *gcgi_gopher_host;
-char *gcgi_gopher_port;
-static struct gcgi_var_list gcgi_gopher_query;
-
-
-/// POLICE LINE /// DO NOT CROSS ///
-
-
-#define GCGI_MATCH_NUM 5
-
-static void
-gcgi_fatal(char *fmt, ...)
-{
- va_list va;
- char msg[1024];
-
- va_start(va, fmt);
- vsnprintf(msg, sizeof msg, fmt, va);
- printf("error: %s\n", msg);
- exit(1);
-}
-
-static inline char *
-gcgi_fopenread(char *path)
-{
- FILE *fp;
- char *buf;
- ssize_t ssz;
- size_t sz;
-
- if ((fp = fopen(path, "r")) == NULL)
- return NULL;
- if (fseek(fp, 0, SEEK_END) == -1)
- return NULL;
- if ((ssz = ftell(fp)) == -1)
- return NULL;
- sz = ssz;
- if (fseek(fp, 0, SEEK_SET) == -1)
- return NULL;
- if ((buf = malloc(sz + 1)) == NULL)
- return NULL;
- if (fread(buf, sz, 1, fp) == sz) {
- errno = EFBIG;
- goto error_free;
- }
- if (ferror(fp))
- goto error_free;
- fclose(fp);
- buf[sz] = '\0';
- return buf;
-error_free:
- free(buf);
- return NULL;
-}
-
-static int
-gcgi_cmp_var(const void *v1, const void *v2)
-{
- return strcasecmp(((struct gcgi_var *)v1)->key, ((struct gcgi_var *)v2…
-}
-
-static void
-gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val)
-{
- void *mem;
-
- vars->len++;
- if ((mem = realloc(vars->list, vars->len * sizeof *vars->list)) == NUL…
- gcgi_fatal("realloc");
- vars->list = mem;
- vars->list[vars->len-1].key = key;
- vars->list[vars->len-1].val = val;
-}
-
-static void
-gcgi_sort_var_list(struct gcgi_var_list *vars)
-{
- qsort(vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var);
-}
-
-static char *
-gcgi_get_var(struct gcgi_var_list *vars, char *key)
-{
- struct gcgi_var *v, q = { .key = key };
-
- v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_va…
- return (v == NULL) ? NULL : v->val;
-}
-
-static void
-gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val)
-{
- struct gcgi_var *v, q;
-
- q.key = key;
- v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_va…
- if (v != NULL) {
- v->val = val;
- return;
- }
- gcgi_add_var(vars, key, val);
- gcgi_sort_var_list(vars);
-}
-
-static void
-gcgi_read_var_list(struct gcgi_var_list *vars, char *path)
-{
- char *line, *tail, *key, *s;
-
- line = NULL;
-
- if ((tail = vars->buf = gcgi_fopenread(path)) == NULL)
- gcgi_fatal("opening %s: %s", path, strerror(errno));
- while ((line = strsep(&tail, "\n")) != NULL) {
- if (line[0] == '\0')
- break;
- key = strsep(&line, ":");
- if (line == NULL || *line++ != ' ')
- gcgi_fatal("%s: missing ': ' separator", path);
- gcgi_add_var(vars, key, line);
- }
- gcgi_set_var(vars, "text", tail ? tail : "");
- gcgi_set_var(vars, "file", (s = strrchr(path, '/')) ? s + 1 : path);
- gcgi_sort_var_list(vars);
-}
-
-static void
-gcgi_free_var_list(struct gcgi_var_list *vars)
-{
- if (vars->buf != NULL)
- free(vars->buf);
- free(vars->list);
-}
-
-static int
-gcgi_write_var_list(struct gcgi_var_list *vars, char *dst)
-{
- FILE *fp;
- struct gcgi_var *v;
- size_t n;
- char path[1024];
- char *text;
-
- text = NULL;
-
- snprintf(path, sizeof path, "%s.tmp", dst);
- if ((fp = fopen(path, "w")) == NULL)
- gcgi_fatal("opening '%s' for writing", path);
-
- for (v = vars->list, n = vars->len; n > 0; v++, n--) {
- if (strcasecmp(v->key, "Text") == 0) {
- text = text ? text : v->val;
- continue;
- }
- assert(strchr(v->key, '\n') == NULL);
- assert(strchr(v->val, '\n') == NULL);
- fprintf(fp, "%s: %s\n", v->key, v->val);
- }
- fprintf(fp, "\n%s", text ? text : "");
-
- fclose(fp);
- if (rename(path, dst) == -1)
- gcgi_fatal( "renaming '%s' to '%s'", path, dst);
- return 0;
-}
-
-static inline int
-gcgi_match(char const *glob, char *path, char **matches, size_t m)
-{
- if (m >= GCGI_MATCH_NUM)
- gcgi_fatal("too many wildcards in glob");
- matches[m] = NULL;
- while (*glob != '*' && *path != '\0' && *glob == *path)
- glob++, path++;
- if (glob[0] == '*') {
- if (*glob != '\0' && gcgi_match(glob + 1, path, matches, m + 1…
- if (matches[m] == NULL)
- matches[m] = path;
- *path = '\0';
- return 1;
- } else if (*path != '\0' && gcgi_match(glob, path + 1, matches…
- matches[m] = (char *)path;
- return 1;
- }
- }
- return *glob == '\0' && *path == '\0';
-}
-
-static inline void
-gcgi_decode_url(struct gcgi_var_list *vars, char *s)
-{
- char *tok, *eq;
-
- while ((tok = strsep(&s, "&"))) {
- //gcgi_decode_hex(tok);
- if ((eq = strchr(tok, '=')) == NULL)
- continue;
- *eq = '\0';
- gcgi_add_var(vars, tok, eq + 1);
- }
- gcgi_sort_var_list(vars);
-}
-
-static void
-gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc)
-{
- char *query_string;
-
- if (argc != 5)
- gcgi_fatal("wrong number of arguments: %c", argc);
- assert(argv[0] && argv[1] && argv[2] && argv[3]);
-
- /* executable.[d]cgi $search $arguments $host $port */
- gcgi_gopher_search = argv[1];
- gcgi_gopher_path = argv[2];
- gcgi_gopher_host = argv[3];
- gcgi_gopher_port = argv[4];
- query_string = strchr(gcgi_gopher_path, '?');
- if (query_string != NULL) {
- *query_string++ = '\0';
- gcgi_decode_url(&gcgi_gopher_query, query_string);
- }
-
- for (; h->glob != NULL; h++) {
- char *matches[GCGI_MATCH_NUM + 1];
- if (!gcgi_match(h->glob, gcgi_gopher_path, matches, 0))
- continue;
- h->fn(matches);
- return;
- }
- gcgi_fatal("no handler for '%s'", gcgi_gopher_path);
-}
-
-static void
-gcgi_print_gophermap(char const *s)
-{
- for (; *s != '\0'; s++) {
- switch(*s) {
- case '<':
- fputs("&lt;", stdout);
- break;
- case '>':
- fputs("&gt;", stdout);
- break;
- case '"':
- fputs("&quot;", stdout);
- break;
- case '\'':
- fputs("&#39;", stdout);
- break;
- case '&':
- fputs("&amp;", stdout);
- break;
- default:
- fputc(*s, stdout);
- }
- }
-}
-
-static inline char*
-gcgi_next_var(char *head, char **tail)
-{
- char *beg, *end;
-
- if ((beg = strstr(head, "{{")) == NULL
- || (end = strstr(beg, "}}")) == NULL)
- return NULL;
- *beg = *end = '\0';
- *tail = end + strlen("}}");
- return beg + strlen("{{");
-}
-
-static void
-gcgi_template(char const *path, struct gcgi_var_list *vars)
-{
- FILE *fp;
- size_t sz;
- char *line, *head, *tail, *key, *val;
-
- if ((fp = fopen(path, "r")) == NULL)
- gcgi_fatal("opening template %s", path);
- sz = 0;
- line = NULL;
- while (getline(&line, &sz, fp) > 0) {
- head = tail = line;
- for (; (key = gcgi_next_var(head, &tail)); head = tail) {
- fputs(head, stdout);
- if ((val = gcgi_get_var(vars, key)))
- gcgi_print_gophermap(val);
- else
- fprintf(stdout, "{{error:%s}}", key);
- }
- fputs(tail, stdout);
- }
- if (ferror(fp))
- gcgi_fatal("reading from template: %s", strerror(errno));
- fclose(fp);
-}
+extern char *gcgi_gopher_search;
+extern char *gcgi_gopher_path;
+extern char *gcgi_gopher_host;
+extern char *gcgi_gopher_port;
+extern struct gcgi_var_list gcgi_gopher_query;
#endif
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.