iadd a manpage and README, and update the code to reflect the light changes - libgcgi - REST library for Gopher Err bitreich.org 70 hgit clone git://bitreich.org/libgcgi git://hg6vgqziawt5s4dj.onion/libgcgi URL:git://bitreich.org/libgcgi git://hg6vgqziawt5s4dj.onion/libgcgi bitreich.org 70 1Log /scm/libgcgi/log.gph bitreich.org 70 1Files /scm/libgcgi/files.gph bitreich.org 70 1Refs /scm/libgcgi/refs.gph bitreich.org 70 1Tags /scm/libgcgi/tag bitreich.org 70 1README /scm/libgcgi/file/README.gph bitreich.org 70 1LICENSE /scm/libgcgi/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 1commit f1f14c75ca3477d51d1a4e09b917a5e5f869e672 /scm/libgcgi/commit/f1f14c75ca3477d51d1a4e09b917a5e5f869e672.gph bitreich.org 70 1parent 052f666afd7390d53ec4b3ad91882e7e76b7a49f /scm/libgcgi/commit/052f666afd7390d53ec4b3ad91882e7e76b7a49f.gph bitreich.org 70 hAuthor: Josuah Demangeon URL:mailto:me@josuah.net bitreich.org 70 iDate: Tue, 2 Aug 2022 13:20:15 +0200 Err bitreich.org 70 i Err bitreich.org 70 iadd a manpage and README, and update the code to reflect the light changes Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i M Makefile | 3 +++ Err bitreich.org 70 i A README | 199 +++++++++++++++++++++++++++++++ Err bitreich.org 70 i M db/vars | 2 +- Err bitreich.org 70 i D gph/404.gph | 1 - Err bitreich.org 70 i A gph/page_not_found.gph | 1 + Err bitreich.org 70 i M index.c | 8 ++++---- Err bitreich.org 70 i A libgcgi.3 | 339 +++++++++++++++++++++++++++++++ Err bitreich.org 70 i M libgcgi.c | 28 ++++++++++++++++++++++------ Err bitreich.org 70 i M libgcgi.h | 4 +--- Err bitreich.org 70 i Err bitreich.org 70 i9 files changed, 570 insertions(+), 15 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/Makefile b/Makefile /scm/libgcgi/file/Makefile.gph bitreich.org 70 i@@ -6,5 +6,8 @@ all: index.cgi Err bitreich.org 70 i clean: Err bitreich.org 70 i rm -f *.o index.cgi Err bitreich.org 70 i Err bitreich.org 70 i+README: libgcgi.3 Err bitreich.org 70 i+ mandoc -Tutf8 libgcgi.3 | col -b | sed '1h; $$g' >$@ Err bitreich.org 70 i+ Err bitreich.org 70 i index.cgi: index.c libgcgi.c libgcgi.h Err bitreich.org 70 i ${CC} ${LDFLAGS} ${CFLAGS} -o $@ index.c libgcgi.c Err bitreich.org 70 1diff --git a/README b/README /scm/libgcgi/file/README.gph bitreich.org 70 i@@ -0,0 +1,199 @@ Err bitreich.org 70 i+LIBGCGI(3) Library Functions Manual LIBGCGI(3) Err bitreich.org 70 i+ Err bitreich.org 70 i+NAME Err bitreich.org 70 i+ gcgi_handle_request, gcgi_fatal, gcgi_template, gcgi_set_var, Err bitreich.org 70 i+ gcgi_get_var, gcgi_free_var_list, gcgi_read_var_list, Err bitreich.org 70 i+ gcgi_write_var_list, gcgi_gopher_search, gcgi_gopher_path, Err bitreich.org 70 i+ gcgi_gopher_query, gcgi_gopher_host, gcgi_gopher_port, REST library for Err bitreich.org 70 i+ Gopher Err bitreich.org 70 i+ Err bitreich.org 70 i+SYNOPSIS Err bitreich.org 70 i+ #include Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc); Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_fatal(char *fmt, ...); Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_template(char const *path, struct gcgi_var_list *vars); Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val); Err bitreich.org 70 i+ Err bitreich.org 70 i+ char * Err bitreich.org 70 i+ gcgi_get_var(struct gcgi_var_list *vars, char *key); Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_free_var_list(struct gcgi_var_list *vars); Err bitreich.org 70 i+ Err bitreich.org 70 i+ void Err bitreich.org 70 i+ gcgi_read_var_list(struct gcgi_var_list *vars, char *path); Err bitreich.org 70 i+ Err bitreich.org 70 i+ int Err bitreich.org 70 i+ gcgi_write_var_list(struct gcgi_var_list *vars, char *path); Err bitreich.org 70 i+ Err bitreich.org 70 i+ char *gcgi_gopher_search Err bitreich.org 70 i+ char *gcgi_gopher_path Err bitreich.org 70 i+ char *gcgi_gopher_host Err bitreich.org 70 i+ char *gcgi_gopher_port Err bitreich.org 70 i+ struct gcgi_var_list gcgi_gopher_query Err bitreich.org 70 i+ Err bitreich.org 70 i+DESCRIPTION Err bitreich.org 70 i+ Request Handling Err bitreich.org 70 i+ The central element of the library is an array of structures, using Err bitreich.org 70 i+ appropriate handler depending on the query path. Err bitreich.org 70 i+ Err bitreich.org 70 i+ struct gcgi_handler { Err bitreich.org 70 i+ char const *glob; Err bitreich.org 70 i+ void (*fn)(char **matches); Err bitreich.org 70 i+ }; Err bitreich.org 70 i+ Err bitreich.org 70 i+ The glob is a string against which the path (everything in the query Err bitreich.org 70 i+ before the ?) will be matched against. Err bitreich.org 70 i+ Err bitreich.org 70 i+ The fn function pointer will be called, with an array of matches passed Err bitreich.org 70 i+ as argument. There are as many matches populated as there are * in Err bitreich.org 70 i+ glob. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_handle_request(struct gcgi_handler h[], int argc, char **argv) Err bitreich.org 70 i+ Given an array of handlers h, call the first function pointer Err bitreich.org 70 i+ that matches. argc and argv should be set to the program ones to Err bitreich.org 70 i+ extract the arguments given by geomyidae(8). The h struct is an Err bitreich.org 70 i+ array of struct gcgi_handler: Err bitreich.org 70 i+ Err bitreich.org 70 i+ Content Generation Err bitreich.org 70 i+ According to geomyidae(8) behavior, the output format will be: Err bitreich.org 70 i+ a raw gophermap if the binary is index.cgi, Err bitreich.org 70 i+ a geomyidae(8) gph format if the binary is index.dcgi. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_fatal(char *fmt, ...) Err bitreich.org 70 i+ Prints an error message formatted by fmt and exit(3) the program Err bitreich.org 70 i+ with status 1. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_template(char const *path, struct gcgi_var_list *vars) Err bitreich.org 70 i+ Format the template at path replacing every occurence of Err bitreich.org 70 i+ {{key}} by the matching value by searching in vars. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_print_gophermap(char type, char *desc, char *path, char *host, Err bitreich.org 70 i+ char *port) Err bitreich.org 70 i+ Print a gophermap entry line with type, desc, path, host, port to Err bitreich.org 70 i+ be set to the chosen value as described in RFC 1436. Both host Err bitreich.org 70 i+ and port are NULL, default values will be used. Err bitreich.org 70 i+ Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_print_gph(char type, char *desc, char *path, char *host, char Err bitreich.org 70 i+ *port) Err bitreich.org 70 i+ Print a gph entry line with type, desc, path, host, port to be Err bitreich.org 70 i+ set to the chosen value as described in geomyidae(8) manual page. Err bitreich.org 70 i+ If host or port are NULL, default values will be used. Err bitreich.org 70 i+ Err bitreich.org 70 i+ Variable List Handling Err bitreich.org 70 i+ A common data format is used for handling lists of variables: Err bitreich.org 70 i+ For parsing a simple text-based database format and writing it back. Err bitreich.org 70 i+ For storing the parsed query string in gcgi_gopher_query. Err bitreich.org 70 i+ For passing variables to expand in the templates. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val) Err bitreich.org 70 i+ Overwrite with val the value of a variable matching key of vars. Err bitreich.org 70 i+ The key and val buffers are not duplicated, and must remain valid Err bitreich.org 70 i+ at all time they need to be accessible, such as through Err bitreich.org 70 i+ gcgi_get_var(). Err bitreich.org 70 i+ Err bitreich.org 70 i+ char * gcgi_get_var(struct gcgi_var_list *vars, char *key) Err bitreich.org 70 i+ Get the value of the variable of vars matching key or NULL if Err bitreich.org 70 i+ none match. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_free_var_list(struct gcgi_var_list *vars) Err bitreich.org 70 i+ Free memory used by a list of variable. This only frees the Err bitreich.org 70 i+ memory allocated by this library. Err bitreich.org 70 i+ Err bitreich.org 70 i+ void gcgi_read_var_list(struct gcgi_var_list *vars, char *path) Err bitreich.org 70 i+ Store all variables from path onto variables in vars. The file Err bitreich.org 70 i+ format is similar to RFC822 messages or HTTP headers: Err bitreich.org 70 i+ One line per variable, with a key=value format. Err bitreich.org 70 i+ The key is everything at the beginning of the line until the Err bitreich.org 70 i+ occurence of :. Err bitreich.org 70 i+ The value is everything after : . Err bitreich.org 70 i+ After the list of variables, an empty line declares the body Err bitreich.org 70 i+ of the message, which continues until the end and is stored in Err bitreich.org 70 i+ a text key. Err bitreich.org 70 i+ Err bitreich.org 70 i+ int gcgi_write_var_list(struct gcgi_var_list *vars, char *path) Err bitreich.org 70 i+ Encode the variable list vars into a new file at path. A Err bitreich.org 70 i+ temporary file will be created in the meantime, and the Err bitreich.org 70 i+ replacement will be atomic so that no partial write can occur. Err bitreich.org 70 i+ The text special key will be turned into the body of the Err bitreich.org 70 i+ message after an empty line instead of a variable on its own Err bitreich.org 70 i+ line. Err bitreich.org 70 i+ Err bitreich.org 70 i+ Global Variables Err bitreich.org 70 i+ These variables are filled with the components of the query. They will Err bitreich.org 70 i+ only be valid after handle_request() is called. Err bitreich.org 70 i+ Err bitreich.org 70 i+ char *gcgi_gopher_search Err bitreich.org 70 i+ From argv[1], this is the search string, passed after a tab in Err bitreich.org 70 i+ the gopher protocol for item type 7. Err bitreich.org 70 i+ Err bitreich.org 70 i+ char *gcgi_gopher_path Err bitreich.org 70 i+ From argv[2], this is the query path. It is the full query Err bitreich.org 70 i+ without the search string and with the query string removed. Err bitreich.org 70 i+ Err bitreich.org 70 i+ struct gcgi_var_list gcgi_gopher_query Err bitreich.org 70 i+ From argv[2], this is the query string stored as a key-value Err bitreich.org 70 i+ gcgi_var_list. It is extracted from the part of the query after Err bitreich.org 70 i+ the ?, usually formated as Err bitreich.org 70 i+ ?key1=value1&key2=value2&key3=value3 Err bitreich.org 70 i+ Err bitreich.org 70 i+ char *gcgi_gopher_host Err bitreich.org 70 i+ From argv[3], this is the current host name configured in Err bitreich.org 70 i+ geomyidae(8). It is what to use as a host in links printed Err bitreich.org 70 i+ out. Err bitreich.org 70 i+ Err bitreich.org 70 i+ char *gcgi_gopher_port Err bitreich.org 70 i+ From argv[4], this is the current port number configured in Err bitreich.org 70 i+ geomyidae(8). It is what to use as a port in links printed Err bitreich.org 70 i+ out. Err bitreich.org 70 i+ Err bitreich.org 70 i+EXAMPLES Err bitreich.org 70 i+ #include "libgcgi.h" Err bitreich.org 70 i+ Err bitreich.org 70 i+ /* implementation of each handler here */ Err bitreich.org 70 i+ Err bitreich.org 70 i+ static struct gcgi_handler handlers[] = { Err bitreich.org 70 i+ { "/", page_home }, Err bitreich.org 70 i+ { "/song", page_song_list }, Err bitreich.org 70 i+ { "/song/*", page_song_item }, Err bitreich.org 70 i+ { "*", page_not_found }, Err bitreich.org 70 i+ { NULL, NULL }, Err bitreich.org 70 i+ }; Err bitreich.org 70 i+ Err bitreich.org 70 i+ int Err bitreich.org 70 i+ main(int argc, char **argv) Err bitreich.org 70 i+ { Err bitreich.org 70 i+ /* privilege dropping, chroot and/or syscall restriction here */ Err bitreich.org 70 i+ Err bitreich.org 70 i+ gcgi_handle_request(handlers, argv, argc); Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+ } Err bitreich.org 70 i+ Err bitreich.org 70 i+ENVIRONMENT VARIABLES Err bitreich.org 70 i+ libgcgi does not use environment variable, but the application code can Err bitreich.org 70 i+ make use of them. The environment variables applied to geomyidae(8) will Err bitreich.org 70 i+ be inherited and accessible. Err bitreich.org 70 i+ Err bitreich.org 70 i+BUGS Err bitreich.org 70 i+ To debug libgcgi, it is possible to call it on a command line, which will Err bitreich.org 70 i+ show all logging and error messages displayed on stderr: Err bitreich.org 70 i+ Err bitreich.org 70 i+ $ ./index.cgi "" "/song/never-bored-of-adventure?lyrics=1&comments=1" "" "" Err bitreich.org 70 i+ Err bitreich.org 70 i+CAVEATS Err bitreich.org 70 i+ The Gopher protocol is not designed for file upload. A dedicated file Err bitreich.org 70 i+ upload protocol such as SFTP or FTP may be used instead. Err bitreich.org 70 i+ Err bitreich.org 70 i+ The Gopher protocol is not designed for dynamic scripting. A dedicated Err bitreich.org 70 i+ remote interface protocol such as SSH or telnet may be used instead. Err bitreich.org 70 i+ Err bitreich.org 70 i+LIBGCGI(3) Library Functions Manual LIBGCGI(3) Err bitreich.org 70 1diff --git a/db/vars b/db/vars /scm/libgcgi/file/db/vars.gph bitreich.org 70 i@@ -1 +1 @@ Err bitreich.org 70 i-Variable-From-Db: Lucky 777 Hat Err bitreich.org 70 i+name: world Err bitreich.org 70 1diff --git a/gph/404.gph b/gph/404.gph /scm/libgcgi/file/gph/404.gph.gph bitreich.org 70 i@@ -1 +0,0 @@ Err bitreich.org 70 i-Hello world! Err bitreich.org 70 1diff --git a/gph/page_not_found.gph b/gph/page_not_found.gph /scm/libgcgi/file/gph/page_not_found.gph.gph bitreich.org 70 i@@ -0,0 +1 @@ Err bitreich.org 70 i+Hello {{name}}! Err bitreich.org 70 1diff --git a/index.c b/index.c /scm/libgcgi/file/index.c.gph bitreich.org 70 i@@ -10,7 +10,7 @@ Err bitreich.org 70 i #endif Err bitreich.org 70 i Err bitreich.org 70 i static void Err bitreich.org 70 i-error_404(char **matches) Err bitreich.org 70 i+error_page_not_found(char **matches) Err bitreich.org 70 i { Err bitreich.org 70 i struct gcgi_var_list vars = {0}; Err bitreich.org 70 i char *var; Err bitreich.org 70 i@@ -21,12 +21,12 @@ error_404(char **matches) Err bitreich.org 70 i if ((var = gcgi_get_var(&gcgi_gopher_query, "var")) != NULL) Err bitreich.org 70 i printf("I got the $var though! -> '%s'\n", var); Err bitreich.org 70 i Err bitreich.org 70 i- gcgi_template("gph/404.gph", &vars); Err bitreich.org 70 i+ gcgi_template("gph/error_page_not_found.gph", &vars); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i static struct gcgi_handler handlers[] = { Err bitreich.org 70 i- { "*", error_404 }, Err bitreich.org 70 i- { NULL, NULL }, Err bitreich.org 70 i+ { "*", error_page_not_found }, Err bitreich.org 70 i+ { NULL, NULL }, Err bitreich.org 70 i }; Err bitreich.org 70 i Err bitreich.org 70 i int Err bitreich.org 70 1diff --git a/libgcgi.3 b/libgcgi.3 /scm/libgcgi/file/libgcgi.3.gph bitreich.org 70 i@@ -0,0 +1,339 @@ Err bitreich.org 70 i+.Dd $Mdocdate: August 01 2022 $ Err bitreich.org 70 i+.Dt LIBGCGI 3 Err bitreich.org 70 i+.Os Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh NAME Err bitreich.org 70 i+. Err bitreich.org 70 i+.Nm gcgi_handle_request , Err bitreich.org 70 i+.Nm gcgi_fatal , Err bitreich.org 70 i+.Nm gcgi_template , Err bitreich.org 70 i+.Nm gcgi_set_var , Err bitreich.org 70 i+.Nm gcgi_get_var , Err bitreich.org 70 i+.Nm gcgi_free_var_list , Err bitreich.org 70 i+.Nm gcgi_read_var_list , Err bitreich.org 70 i+.Nm gcgi_write_var_list , Err bitreich.org 70 i+.Nm gcgi_gopher_search , Err bitreich.org 70 i+.Nm gcgi_gopher_path , Err bitreich.org 70 i+.Nm gcgi_gopher_query , Err bitreich.org 70 i+.Nm gcgi_gopher_host , Err bitreich.org 70 i+.Nm gcgi_gopher_port , Err bitreich.org 70 i+.Nd REST library for Gopher Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh SYNOPSIS Err bitreich.org 70 i+. Err bitreich.org 70 i+.In libgcgi.h Err bitreich.org 70 i+. Err bitreich.org 70 i+.Ft "void" Fn gcgi_handle_request "struct gcgi_handler h[]" "char **argv" "int argc" Err bitreich.org 70 i+.Ft "void" Fn gcgi_fatal "char *fmt" "..." Err bitreich.org 70 i+.Ft "void" Fn gcgi_template "char const *path" "struct gcgi_var_list *vars" Err bitreich.org 70 i+.Ft "void" Fn gcgi_set_var "struct gcgi_var_list *vars" "char *key" "char *val" Err bitreich.org 70 i+.Ft "char *" Fn gcgi_get_var "struct gcgi_var_list *vars" "char *key" Err bitreich.org 70 i+.Ft "void" Fn gcgi_free_var_list "struct gcgi_var_list *vars" Err bitreich.org 70 i+.Ft "void" Fn gcgi_read_var_list "struct gcgi_var_list *vars" "char *path" Err bitreich.org 70 i+.Ft "int" Fn gcgi_write_var_list "struct gcgi_var_list *vars" "char *path" Err bitreich.org 70 i+.Vt char *gcgi_gopher_search Err bitreich.org 70 i+.Vt char *gcgi_gopher_path Err bitreich.org 70 i+.Vt char *gcgi_gopher_host Err bitreich.org 70 i+.Vt char *gcgi_gopher_port Err bitreich.org 70 i+.Vt struct gcgi_var_list gcgi_gopher_query Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh DESCRIPTION Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Ss Request Handling Err bitreich.org 70 i+. Err bitreich.org 70 i+The central element of the library is an array of structures, Err bitreich.org 70 i+using appropriate handler depending on the query path. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+.Bd -literal Err bitreich.org 70 i+struct gcgi_handler { Err bitreich.org 70 i+ char const *glob; Err bitreich.org 70 i+ void (*fn)(char **matches); Err bitreich.org 70 i+}; Err bitreich.org 70 i+.Ed Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+The Err bitreich.org 70 i+.Vt glob Err bitreich.org 70 i+is a string against which the path (everything in the query before the Err bitreich.org 70 i+.Dq ? ) Err bitreich.org 70 i+will be matched against. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+The Err bitreich.org 70 i+.Vt fn Err bitreich.org 70 i+function pointer will be called, with an array of matches passed as argument. Err bitreich.org 70 i+There are as many matches populated as there are Err bitreich.org 70 i+.Dq "*" Err bitreich.org 70 i+in Err bitreich.org 70 i+.Vt glob . Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+.Bl -tag Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_handle_request "struct gcgi_handler h[]" "int argc" "char **argv" Err bitreich.org 70 i+Given an array of handlers Err bitreich.org 70 i+.Fa h , Err bitreich.org 70 i+call the first function pointer that matches. Err bitreich.org 70 i+.Fa argc Err bitreich.org 70 i+and Err bitreich.org 70 i+.Fa argv Err bitreich.org 70 i+should be set to the program ones to extract the arguments given by Err bitreich.org 70 i+.Xr geomyidae 8 . Err bitreich.org 70 i+The Err bitreich.org 70 i+.Fa h Err bitreich.org 70 i+struct is an array of Err bitreich.org 70 i+.Vt struct gcgi_handler : Err bitreich.org 70 i+. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Ss Content Generation Err bitreich.org 70 i+. Err bitreich.org 70 i+According to Err bitreich.org 70 i+.Xr geomyidae 8 Err bitreich.org 70 i+behavior, the output format will be: Err bitreich.org 70 i+.Bl -bullet -compact -width x Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Err bitreich.org 70 i+a raw gophermap if the binary is Err bitreich.org 70 i+.Dq index.cgi , Err bitreich.org 70 i+.It Err bitreich.org 70 i+a Err bitreich.org 70 i+.Xr geomyidae 8 Err bitreich.org 70 i+.Sq gph Err bitreich.org 70 i+format if the binary is Err bitreich.org 70 i+.Dq index.dcgi . Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+.Bl -tag Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_fatal "char *fmt" "..." Err bitreich.org 70 i+Prints an error message formatted by Err bitreich.org 70 i+.Fa fmt Err bitreich.org 70 i+and Err bitreich.org 70 i+.Xr exit 3 Err bitreich.org 70 i+the program with status 1. Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_template "char const *path" "struct gcgi_var_list *vars" Err bitreich.org 70 i+Format the template at Err bitreich.org 70 i+.Fa path Err bitreich.org 70 i+replacing every occurence of Err bitreich.org 70 i+.Dq {{key}} Err bitreich.org 70 i+by the matching value by searching in Err bitreich.org 70 i+.Fa vars . Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt void Fn gcgi_print_gophermap "char type" "char *desc" "char *path" "char *host" "char *port" Err bitreich.org 70 i+Print a gophermap entry line with Err bitreich.org 70 i+.Fa type , Err bitreich.org 70 i+.Fa desc , Err bitreich.org 70 i+.Fa path , Err bitreich.org 70 i+.Fa host , Err bitreich.org 70 i+.Fa port Err bitreich.org 70 i+to be set to the chosen value as described in RFC 1436. Err bitreich.org 70 i+Both Err bitreich.org 70 i+.Fa host Err bitreich.org 70 i+and Err bitreich.org 70 i+.Fa port Err bitreich.org 70 i+are NULL, default values will be used. Err bitreich.org 70 i+ Err bitreich.org 70 i+.It Ft void Fn gcgi_print_gph "char type" "char *desc" "char *path" "char *host" "char *port" Err bitreich.org 70 i+Print a gph entry line with Err bitreich.org 70 i+.Fa type , Err bitreich.org 70 i+.Fa desc , Err bitreich.org 70 i+.Fa path , Err bitreich.org 70 i+.Fa host , Err bitreich.org 70 i+.Fa port Err bitreich.org 70 i+to be set to the chosen value as described in Err bitreich.org 70 i+.Xr geomyidae 8 Err bitreich.org 70 i+manual page. Err bitreich.org 70 i+If Err bitreich.org 70 i+.Fa host Err bitreich.org 70 i+or Err bitreich.org 70 i+.Fa port Err bitreich.org 70 i+are NULL, default values will be used. Err bitreich.org 70 i+. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Ss Variable List Handling Err bitreich.org 70 i+. Err bitreich.org 70 i+A common data format is used for handling lists of variables: Err bitreich.org 70 i+.Bl -bullet -compact -width x Err bitreich.org 70 i+.It Err bitreich.org 70 i+For parsing a simple text-based database format and writing it back. Err bitreich.org 70 i+.It Err bitreich.org 70 i+For storing the parsed query string in Err bitreich.org 70 i+.Vt gcgi_gopher_query . Err bitreich.org 70 i+.It Err bitreich.org 70 i+For passing variables to expand in the templates. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+.Bl -tag Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_set_var "struct gcgi_var_list *vars" "char *key" "char *val" Err bitreich.org 70 i+Overwrite with Err bitreich.org 70 i+.Fa val Err bitreich.org 70 i+the value of a variable matching Err bitreich.org 70 i+.Fa key Err bitreich.org 70 i+of Err bitreich.org 70 i+.Fa vars . Err bitreich.org 70 i+The Err bitreich.org 70 i+.Fa key Err bitreich.org 70 i+and Err bitreich.org 70 i+.Fa val Err bitreich.org 70 i+buffers are not duplicated, and must remain valid at all time they need to be Err bitreich.org 70 i+accessible, such as through Err bitreich.org 70 i+.Fn gcgi_get_var . Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "char *" Fn gcgi_get_var "struct gcgi_var_list *vars" "char *key" Err bitreich.org 70 i+Get the value of the variable of Err bitreich.org 70 i+.Fa vars Err bitreich.org 70 i+matching Err bitreich.org 70 i+.Fa key Err bitreich.org 70 i+or NULL if none match. Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_free_var_list "struct gcgi_var_list *vars" Err bitreich.org 70 i+Free memory used by a list of variable. Err bitreich.org 70 i+This only frees the memory allocated by this library. Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "void" Fn gcgi_read_var_list "struct gcgi_var_list *vars" "char *path" Err bitreich.org 70 i+Store all variables from Err bitreich.org 70 i+.Fa path Err bitreich.org 70 i+onto variables in Err bitreich.org 70 i+.Fa vars . Err bitreich.org 70 i+The file format is similar to RFC822 messages or HTTP headers: Err bitreich.org 70 i+.Bl -bullet -compact -width x Err bitreich.org 70 i+.It Err bitreich.org 70 i+One line per variable, with a key=value format. Err bitreich.org 70 i+.It Err bitreich.org 70 i+The key is everything at the beginning of the line until the occurence of Err bitreich.org 70 i+.Dq ":" . Err bitreich.org 70 i+.It Err bitreich.org 70 i+The value is everything after Err bitreich.org 70 i+.Dq ": " . Err bitreich.org 70 i+.It Err bitreich.org 70 i+After the list of variables, an empty line declares the body of the message, Err bitreich.org 70 i+which continues until the end and is stored in a Err bitreich.org 70 i+.Dq text Err bitreich.org 70 i+key. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Ft "int" Fn gcgi_write_var_list "struct gcgi_var_list *vars" "char *path" Err bitreich.org 70 i+Encode the variable list Err bitreich.org 70 i+.Fa vars Err bitreich.org 70 i+into a new file at Err bitreich.org 70 i+.Fa path . Err bitreich.org 70 i+A temporary file will be created in the meantime, Err bitreich.org 70 i+and the replacement will be atomic so that no partial write can occur. Err bitreich.org 70 i+The Err bitreich.org 70 i+.Dq text Err bitreich.org 70 i+special key will be turned into the body of the message after an empty line Err bitreich.org 70 i+instead of a variable on its own line. Err bitreich.org 70 i+. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Ss Global Variables Err bitreich.org 70 i+. Err bitreich.org 70 i+These variables are filled with the components of the query. Err bitreich.org 70 i+They will only be valid after Err bitreich.org 70 i+.Fn handle_request Err bitreich.org 70 i+is called. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+.Bl -tag Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt char *gcgi_gopher_search Err bitreich.org 70 i+From argv[1], this is the search string, passed after a tab in Err bitreich.org 70 i+the gopher protocol for item type Err bitreich.org 70 i+.Dq 7 . Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt char *gcgi_gopher_path Err bitreich.org 70 i+From argv[2], this is the query path. Err bitreich.org 70 i+It is the full query without the search string and with the query string removed. Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt struct gcgi_var_list gcgi_gopher_query Err bitreich.org 70 i+From argv[2], this is the query string stored as a key-value Err bitreich.org 70 i+.Vt gcgi_var_list . Err bitreich.org 70 i+It is extracted from the part of the query after the Err bitreich.org 70 i+.Dq ? , Err bitreich.org 70 i+usually formated as Err bitreich.org 70 i+.Dq ?key1=value1&key2=value2&key3=value3 Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt char *gcgi_gopher_host Err bitreich.org 70 i+From argv[3], this is the current host name configured in Err bitreich.org 70 i+.Xr geomyidae 8 . Err bitreich.org 70 i+It is what to use as a Err bitreich.org 70 i+.Sq host Err bitreich.org 70 i+in links printed out. Err bitreich.org 70 i+. Err bitreich.org 70 i+.It Vt char *gcgi_gopher_port Err bitreich.org 70 i+From argv[4], this is the current port number configured in Err bitreich.org 70 i+.Xr geomyidae 8 . Err bitreich.org 70 i+It is what to use as a Err bitreich.org 70 i+.Sq port Err bitreich.org 70 i+in links printed out. Err bitreich.org 70 i+. Err bitreich.org 70 i+.El Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh EXAMPLES Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Bd -literal Err bitreich.org 70 i+#include "libgcgi.h" Err bitreich.org 70 i+ Err bitreich.org 70 i+/* implementation of each handler here */ Err bitreich.org 70 i+ Err bitreich.org 70 i+static struct gcgi_handler handlers[] = { Err bitreich.org 70 i+ { "/", page_home }, Err bitreich.org 70 i+ { "/song", page_song_list }, Err bitreich.org 70 i+ { "/song/*", page_song_item }, Err bitreich.org 70 i+ { "*", page_not_found }, Err bitreich.org 70 i+ { NULL, NULL }, Err bitreich.org 70 i+}; Err bitreich.org 70 i+ Err bitreich.org 70 i+int Err bitreich.org 70 i+main(int argc, char **argv) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ /* privilege dropping, chroot and/or syscall restriction here */ Err bitreich.org 70 i+ Err bitreich.org 70 i+ gcgi_handle_request(handlers, argv, argc); Err bitreich.org 70 i+ return 0; Err bitreich.org 70 i+} Err bitreich.org 70 i+.Ed Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh ENVIRONMENT VARIABLES Err bitreich.org 70 i+. Err bitreich.org 70 i+.Nm libgcgi Err bitreich.org 70 i+does not use environment variable, but the application code can make use of them. Err bitreich.org 70 i+The environment variables applied to Err bitreich.org 70 i+.Xr geomyidae 8 Err bitreich.org 70 i+will be inherited and accessible. Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh BUGS Err bitreich.org 70 i+. Err bitreich.org 70 i+To debug Err bitreich.org 70 i+.Nm libgcgi , Err bitreich.org 70 i+it is possible to call it on a command line, which will show all logging and error messages displayed on stderr: Err bitreich.org 70 i+. Err bitreich.org 70 i+.Bd -literal Err bitreich.org 70 i+$ ./index.cgi "" "/song/never-bored-of-adventure?lyrics=1&comments=1" "" "" Err bitreich.org 70 i+.Ed Err bitreich.org 70 i+. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Sh CAVEATS Err bitreich.org 70 i+. Err bitreich.org 70 i+The Gopher protocol is not designed for file upload. Err bitreich.org 70 i+A dedicated file upload protocol such as SFTP or FTP may be used instead. Err bitreich.org 70 i+. Err bitreich.org 70 i+.Pp Err bitreich.org 70 i+The Gopher protocol is not designed for dynamic scripting. Err bitreich.org 70 i+A dedicated remote interface protocol such as SSH or telnet may be used instead. Err bitreich.org 70 1diff --git a/libgcgi.c b/libgcgi.c /scm/libgcgi/file/libgcgi.c.gph bitreich.org 70 i@@ -70,7 +70,7 @@ gcgi_cmp_var(const void *v1, const void *v2) Err bitreich.org 70 i return strcasecmp(((struct gcgi_var *)v1)->key, ((struct gcgi_var *)v2)->key); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i-void Err bitreich.org 70 i+static void Err bitreich.org 70 i gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val) Err bitreich.org 70 i { Err bitreich.org 70 i void *mem; Err bitreich.org 70 i@@ -83,7 +83,7 @@ gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val) Err bitreich.org 70 i vars->list[vars->len-1].val = val; Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i-void Err bitreich.org 70 i+static void Err bitreich.org 70 i gcgi_sort_var_list(struct gcgi_var_list *vars) Err bitreich.org 70 i { Err bitreich.org 70 i qsort(vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var); Err bitreich.org 70 i@@ -138,8 +138,7 @@ gcgi_read_var_list(struct gcgi_var_list *vars, char *path) Err bitreich.org 70 i void Err bitreich.org 70 i gcgi_free_var_list(struct gcgi_var_list *vars) Err bitreich.org 70 i { Err bitreich.org 70 i- if (vars->buf != NULL) Err bitreich.org 70 i- free(vars->buf); Err bitreich.org 70 i+ free(vars->buf); Err bitreich.org 70 i free(vars->list); Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i@@ -159,7 +158,7 @@ gcgi_write_var_list(struct gcgi_var_list *vars, char *dst) Err bitreich.org 70 i gcgi_fatal("opening '%s' for writing", path); Err bitreich.org 70 i Err bitreich.org 70 i for (v = vars->list, n = vars->len; n > 0; v++, n--) { Err bitreich.org 70 i- if (strcasecmp(v->key, "Text") == 0) { Err bitreich.org 70 i+ if (strcasecmp(v->key, "text") == 0) { Err bitreich.org 70 i text = text ? text : v->val; Err bitreich.org 70 i continue; Err bitreich.org 70 i } Err bitreich.org 70 i@@ -203,7 +202,6 @@ gcgi_decode_url(struct gcgi_var_list *vars, char *s) Err bitreich.org 70 i char *tok, *eq; Err bitreich.org 70 i Err bitreich.org 70 i while ((tok = strsep(&s, "&"))) { Err bitreich.org 70 i- //gcgi_decode_hex(tok); Err bitreich.org 70 i if ((eq = strchr(tok, '=')) == NULL) Err bitreich.org 70 i continue; Err bitreich.org 70 i *eq = '\0'; Err bitreich.org 70 i@@ -256,6 +254,24 @@ gcgi_next_var(char *head, char **tail) Err bitreich.org 70 i } Err bitreich.org 70 i Err bitreich.org 70 i void Err bitreich.org 70 i+gcgi_print_gophermap(char type, char *desc, char *path, char *host, char *port) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ assert(type >= 0x30); Err bitreich.org 70 i+ printf("%c%s\t%s\t%s\t%s\n", type, desc, path, host, port); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i+gcgi_print_gph(char type, char *desc, char *path, char *host, char *port) Err bitreich.org 70 i+{ Err bitreich.org 70 i+ assert(type >= 0x30); Err bitreich.org 70 i+ if (host == NULL) Err bitreich.org 70 i+ host = "server"; Err bitreich.org 70 i+ if (port == NULL) Err bitreich.org 70 i+ port = "port"; Err bitreich.org 70 i+ printf("[%c|%s|%s|%s|%s]\n", type, desc, path, host, port); Err bitreich.org 70 i+} Err bitreich.org 70 i+ Err bitreich.org 70 i+void Err bitreich.org 70 i gcgi_template(char const *path, struct gcgi_var_list *vars) Err bitreich.org 70 i { Err bitreich.org 70 i FILE *fp; Err bitreich.org 70 1diff --git a/libgcgi.h b/libgcgi.h /scm/libgcgi/file/libgcgi.h.gph bitreich.org 70 i@@ -28,8 +28,6 @@ void gcgi_fatal(char *fmt, ...); Err bitreich.org 70 i void gcgi_template(char const *path, struct gcgi_var_list *vars); Err bitreich.org 70 i Err bitreich.org 70 i /* manage a `key`-`val` pair storage `vars`, as used with gcgi_template */ Err bitreich.org 70 i-void gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val); Err bitreich.org 70 i-void gcgi_sort_var_list(struct gcgi_var_list *vars); Err bitreich.org 70 i void gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val); Err bitreich.org 70 i char *gcgi_get_var(struct gcgi_var_list *vars, char *key); Err bitreich.org 70 i void gcgi_free_var_list(struct gcgi_var_list *vars); Err bitreich.org 70 i@@ -41,8 +39,8 @@ int gcgi_write_var_list(struct gcgi_var_list *vars, char *path); Err bitreich.org 70 i /* components of the gopher request */ Err bitreich.org 70 i extern char *gcgi_gopher_search; Err bitreich.org 70 i extern char *gcgi_gopher_path; Err bitreich.org 70 i+extern struct gcgi_var_list gcgi_gopher_query; Err bitreich.org 70 i extern char *gcgi_gopher_host; Err bitreich.org 70 i extern char *gcgi_gopher_port; Err bitreich.org 70 i-extern struct gcgi_var_list gcgi_gopher_query; Err bitreich.org 70 i Err bitreich.org 70 i #endif Err bitreich.org 70 .