digest-gopher | Converts gopher to plaintext-with-links. |
| download: http://git.y1.nz/archives/digest-gopher.tar.gz | |
| README | Files | Log | Refs |
commit 0b5a175c2790c338bf79dfa3b1e5ef7baa840995 Author: Emma Weaver <emma@y1.nz> Date: Wed, 15 Jul 2026 12:18:38 -0500 Initial functionality Diffstat:
| A | .gitignore | 1 | + |
| A | Makefile | 14 | ++++++++++++++ |
| A | README | 16 | ++++++++++++++++ |
| A | config.mk | 5 | +++++ |
| A | digest-gopher.1 | 33 | +++++++++++++++++++++++++++++++++ |
| A | main.c | 157 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | test/1 | 162 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | test/2 | 32 | ++++++++++++++++++++++++++++++++ |
| A | test/3 | 7 | +++++++ |
9 files changed, 427 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +digest-gopher diff --git a/Makefile b/Makefile @@ -0,0 +1,14 @@ +include config.mk + +all: digest-gopher + +digest-gopher: main.c + $(CC) main.c -o digest-gopher + +install: digest-gopher + cp -f digest-gopher $(PREFIX)/bin + mkdir -p $(MANPREFIX)/man1 + cp -f digest-gopher.1 $(MANPREFIX)/man1 + +clean: + rm -f digest-gopher diff --git a/README b/README @@ -0,0 +1,16 @@ +............... +.DIGEST-gopher. +............... + + summary + +Converts gopher (.gph) documents into plaintext-with-links. + +Intended to be used as part of the [bro](http://git.y1.nz/) browser project, +a browser that Uses your OS instead of replacing it. + + build + +Edit config.mk to reflect your system's configuration, then use `make` to +compile the digest-gopher binary, then if you want use `make install` to +install it onto your system. diff --git a/config.mk b/config.mk @@ -0,0 +1,5 @@ +# Edit this file to suit your system + +CC = cc -Wextra -Wpedantic -std=c99 +PREFIX = /usr/local +MANPREFIX = /usr/local/share/man diff --git a/digest-gopher.1 b/digest-gopher.1 @@ -0,0 +1,33 @@ +.Dd July 12, 2026 +.Dt DIGEST-GOPHER 1 +.Os +.Sh NAME +.Nm digest-gopher +.Nd Gopher to plaintext-with-links converter +.Sh SYNOPSIS +.Nm +.Op Fl o Ar OUTFILE +INFILE +.Sh DESCRIPTION +.Nm +reads in gopher-formatted text (as described in [RFC1436]) and writes +plaintext with markdown-style links with absolute URIs. The URIs produced by +this program are formatted according to the gopher URI scheme as described in +[RFC4266]. Lines are labelled with a short, human-readable prefix to communicate +their type. Their original gopher type character is used as the divider between +the prefix and the body of each line. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl o Ar OUTFILE +Specify a file to write output into. Default behavior is to write output to stdout. +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr well 1 +.Xr digest-html 1 +.Xr hurl 1 +.Xr bro 1 +.Xr +.Sh AUTHORS +.An Emma Weaver Aq Mt emma@y1.nz diff --git a/main.c b/main.c @@ -0,0 +1,157 @@ +#include <stdio.h> /* printf etc etc */ +#include <unistd.h> /* getopt */ + +#define MAX_LINE_LENGTH 255 +#define PRINT_USAGE { \ + printf( \ + "Convert gopher to plaintext-with-links." "\n" \ + "Usage: %s [-o OUTFILE] GPHFILE" "\n", \ + argv[0] \ + ); \ + return 1; \ +} +#define IS_UNASCII(c) (c != '\t' && c != '\n' && c != '\r') +#define SAFE_FREE(name) if (name != NULL) free(name); + +/* globals */ +FILE *out; +char line[MAX_LINE_LENGTH]; +int line_index = 0; + +/** + * Finds the first '\t' in the string, if one is found, replace it with + * '\0' and return a pointer to the next char. If the string null-terminates + * before any '\t' are found, return the pointer to its '\0'. + */ +char * +delimit(char *str) +{ + int i = 0; + for (;;) { + if (str[i] == '\t') { + str[i] = '\0'; + return str + (i+1); + } + if (str[i] == '\0') return str + i; + i++; + } +} + +/** Return a null-terminated string, to indicate what type a line is. */ +const char * +get_prefix(char type) +{ + switch (type) { + case '0': return "txt"; + case '1': return ""; + case '2': return "CSO"; + case '3': return "err"; + case '4': return "mac"; + case '5': return "dos"; + case '6': return "uue"; + case '7': return "srch"; // TODO handle like HTML forms + case '8': return "teln"; + case '9': return "bin"; + case '+': return "mir"; + case 'T': return "ibm"; + case 'g': return "gif"; + case 'I': return "img"; + case 'h': return "html"; + case 'i': return ""; + default: return "(?)"; + } +} + +void +print_escaped(const char *display) +{ + char ch; + int i = 0; + for (;;) { + ch = display[i++]; + if (ch == '\0') return; + switch (ch) { + case '[': fprintf(out, "\\["); break; + case ']': fprintf(out, "\\]"); break; + default: fputc(ch, out); + } + } +} + +/** Using a null-terminated line written to line, print the line to out. */ +int +parse_line() +{ + char type = line[0]; + if (type == '.') return 1; + const char *prefix = get_prefix(type); + char *start = line+1; + char *user_display = start; + start = delimit(start); char *selector = start; + start = delimit(start); char *host = start; + start = delimit(start); char *port = start; + start = delimit(start); + + // TODO are there any other non-link-typed lines? + if (type == 'i') { + fprintf(out, " "); + print_escaped(user_display); + fprintf(out, "\n"); + return 0; + } + + fprintf(out, "[%c ", type); + print_escaped(user_display); + fprintf(out, "]("); + if ( + selector[0] == 'U' && + selector[1] == 'R' && + selector[2] == 'L' && + selector[3] == ':' + ) fprintf(out, "%s", selector + 4); + else fprintf(out, "gopher://%s:%s/%c%s", host, port, type, selector); + fprintf(out, ")" "\n"); + return 0; +} + +/** + * Read a file line-by-line and parse one line at a time using the line buffer. + */ +int +main(int argc, char *argv[]) +{ + const char *infile = NULL, *outfile = NULL; + FILE *in; + + int opt; + for (;;) { + opt = getopt(argc, argv, "f:o:"); + if (opt == -1) break; + switch (opt) { + case 'o': outfile = optarg; break; + default: PRINT_USAGE; + } + } + if (optind != argc-1) PRINT_USAGE; + + in = fopen(argv[optind], "r"); + out = outfile == NULL ? stdout : fopen(outfile, "w"); + + char ch; + for (;;) { + ch = fgetc(in); + if (ch == '\r') continue; + line[line_index++] = ch == '\n' ? '\0' : ch; + line[line_index] = '\0'; + if ( + line_index == MAX_LINE_LENGTH-1 || + ch == '\0' || ch == EOF + ) return 0; + if (ch == '\n') { + parse_line(); + line_index = 0; + } + } + + fclose(in); fclose(out); +} diff --git a/test/1 b/test/1 @@ -0,0 +1,162 @@ +i Welcome to tilde.pink! Err tilde.pink 70 +i Err tilde.pink 70 +i ___________________ Err tilde.pink 70 +i /o.-==-. .-. .-==-.o\ Err tilde.pink 70 +i || )) (( || Err tilde.pink 70 +i \\____// \\____// Err tilde.pink 70 +i `-==-' `-==-' Err tilde.pink 70 +i Err tilde.pink 70 +iA tilde server of a different shade. tilde.pink is an open tilde Err tilde.pink 70 +iserver, providing shell, email, and gopher/gemini accounts. We are Err tilde.pink 70 +ia web free tilde using geomyidae to serve gopher, and gmid to Err tilde.pink 70 +iserve gemini. tilde.pink runs on NetBSD. NetBSD is a unix-like Err tilde.pink 70 +ioperating system, similar to Linux, but different in many ways. If Err tilde.pink 70 +iyou're up to the challenge and want to learn new things, sign up Err tilde.pink 70 +ittoday. Err tilde.pink 70 +i Err tilde.pink 70 +1Sign Up /signup.gph tilde.pink 70 +1Documentation /documentation.gph tilde.pink 70 +iContact: contact@tilde.pink Err tilde.pink 70 +i Err tilde.pink 70 +i -=News=- Err tilde.pink 70 +i Err tilde.pink 70 +i26 May 26 - Gee, I haven't updated this in a while. Is this Err tilde.pink 70 +ithing still on? Err tilde.pink 70 +i Err tilde.pink 70 +i09 Jun 25 - It's a newish year, time for a new gemini server. Err tilde.pink 70 +iThere were some issues with vger, so we're switching it up and Err tilde.pink 70 +irunning gmid. I hope nothing breaks. I've also changed the contact Err tilde.pink 70 +iemail from register@ to contact@, because it just makes more sense. Err tilde.pink 70 +i Err tilde.pink 70 +i21 Jul 24 - The script sucked. We're back to alphabetical order Err tilde.pink 70 +iuntil further notice. Also, the server was reloacted to a Err tilde.pink 70 +iHetzner dedi in Finland. Who needs money anyway? Err tilde.pink 70 +i Err tilde.pink 70 +i29 Apr 24 - Wow, the first major change to the tilde.pink home Err tilde.pink 70 +ipage! User capsule and gopher hole links are now listed by most Err tilde.pink 70 +irecently updated. A script checks the all files in public_gemini Err tilde.pink 70 +iindex.gmi, and public_gopher, not just the index. Err tilde.pink 70 +i Err tilde.pink 70 +i23 Apr 24 - Hey, you know, I always forget to update this thing Err tilde.pink 70 +iwhen I make changes. The server is now running on NetBSD 10! It Err tilde.pink 70 +itook forever for the release to come out. Err tilde.pink 70 +i Err tilde.pink 70 +i01 Jan 24 - Well now, after skipping all of 2023, we're finally Err tilde.pink 70 +iupdating the the news section! After forever, IPV6 is now Err tilde.pink 70 +ifunctioning on Pink. Somewhere in all that, the server was Err tilde.pink 70 +iupgraded to NetBSD 9.3. When do you think 10 will be released? Err tilde.pink 70 +i Err tilde.pink 70 +1Project Gemini / geminiprotocol.net 70 +i Err tilde.pink 70 +1Old News /oldnews.gph tilde.pink 70 +i Err tilde.pink 70 +iUsers: Err tilde.pink 70 +i Err tilde.pink 70 +1~adamdh /~adamdh/ tilde.pink 70 +1~ahmed /~ahmed/ tilde.pink 70 +1~allure /~allure/ tilde.pink 70 +1~aniruddh /~aniruddh/ tilde.pink 70 +1~antyda /~antyda/ tilde.pink 70 +1~aru /~aru/ tilde.pink 70 +1~astersystem /~astersystem/ tilde.pink 70 +1~bart /~bart/ tilde.pink 70 +1~bencollver /~bencollver/ tilde.pink 70 +1~betabube /~betabube/ tilde.pink 70 +1~brennan /~brennan/ tilde.pink 70 +1~charo /~charo/ tilde.pink 70 +1~chizra /~chizra/ tilde.pink 70 +1~den /~den/ tilde.pink 70 +1~diehauch /~diehauch/ tilde.pink 70 +1~doriancodes /~doriancodes/ tilde.pink 70 +1~dothide /~dothide/ tilde.pink 70 +1~drot /~drot/ tilde.pink 70 +1~edim /~edim/ tilde.pink 70 +1~emily /~emily/ tilde.pink 70 +1~ervras /~ervras/ tilde.pink 70 +1~exologist /~exologist/ tilde.pink 70 +1~fc03cf /~fc03cf/ tilde.pink 70 +1~ff3366 /~ff3366/ tilde.pink 70 +1~ffuentes /~ffuentes/ tilde.pink 70 +1~fl3a /~fl3a/ tilde.pink 70 +1~foxygel /~foxygel/ tilde.pink 70 +1~funtoomen /~funtoomen/ tilde.pink 70 +1~fzzyyti /~fzzyyti/ tilde.pink 70 +1~g1n /~g1n/ tilde.pink 70 +1~g4slv /~g4slv/ tilde.pink 70 +1~gamliel /~gamliel/ tilde.pink 70 +1~ghoti /~ghoti/ tilde.pink 70 +1~gliggy /~gliggy/ tilde.pink 70 +1~gristlehex /~gristlehex/ tilde.pink 70 +1~hedy /~hedy/ tilde.pink 70 +1~hydraz /~hydraz/ tilde.pink 70 +1~id2 /~id2/ tilde.pink 70 +1~inquibrator /~inquibrator/ tilde.pink 70 +1~irek /~irek/ tilde.pink 70 +1~jamesisadog /~jamesisadog/ tilde.pink 70 +1~jan6 /~jan6/ tilde.pink 70 +1~jay /~jay/ tilde.pink 70 +1~jbehnke747 /~jbehnke747/ tilde.pink 70 +1~jsv /~jsv/ tilde.pink 70 +1~k /~k/ tilde.pink 70 +1~kaa /~kaa/ tilde.pink 70 +1~kati256 /~kati256/ tilde.pink 70 +1~katsuragi /~katsuragi/ tilde.pink 70 +1~kiiwii /~kiiwii/ tilde.pink 70 +1~krst /~krst/ tilde.pink 70 +1~ksv /~ksv/ tilde.pink 70 +1~kubikpixel /~kubikpixel/ tilde.pink 70 +1~l4nn-1312 /~l4nn-1312/ tilde.pink 70 +1~lano /~lano/ tilde.pink 70 +1~lel /~lel/ tilde.pink 70 +1~luke /~luke/ tilde.pink 70 +1~mao /~mao/ tilde.pink 70 +1~matt6 /~matt6/ tilde.pink 70 +1~mosi /~mosi/ tilde.pink 70 +1~n3tshift /~n3tshift/ tilde.pink 70 +1~nagi /~nagi/ tilde.pink 70 +1~nifty /~nifty/ tilde.pink 70 +1~okennzy /~okennzy/ tilde.pink 70 +1~one2seven /~one2seven/ tilde.pink 70 +1~opfez /~opfez/ tilde.pink 70 +1~performa /~performa/ tilde.pink 70 +1~pfr /~pfr/ tilde.pink 70 +1~piwiggly /~piwiggly/ tilde.pink 70 +1~plim /~plim/ tilde.pink 70 +1~priyal /~priyal/ tilde.pink 70 +1~racoon /~racoon/ tilde.pink 70 +1~rosie52 /~rosie52/ tilde.pink 70 +1~rveeblefetzer /~rveeblefetzer/ tilde.pink 70 +1~salmon /~salmon/ tilde.pink 70 +1~seafork /~seafork/ tilde.pink 70 +1~sebkply /~sebkply/ tilde.pink 70 +1~shrew /~shrew/ tilde.pink 70 +1~smlckz /~smlckz/ tilde.pink 70 +1~snowcrash /~snowcrash/ tilde.pink 70 +1~soweli-iki /~soweli-iki/ tilde.pink 70 +1~spaghettifiedcat /~spaghettifiedcat/ tilde.pink 70 +1~sparkingcircuit /~sparkingcircuit/ tilde.pink 70 +1~stern /~stern/ tilde.pink 70 +1~sys860 /~sys860/ tilde.pink 70 +1~tarial /~tarial/ tilde.pink 70 +1~teasel /~teasel/ tilde.pink 70 +1~thaweazl /~thaweazl/ tilde.pink 70 +1~trent /~trent/ tilde.pink 70 +1~tuesday /~tuesday/ tilde.pink 70 +1~unixplumber /~unixplumber/ tilde.pink 70 +1~v11e /~v11e/ tilde.pink 70 +1~vaibhav /~vaibhav/ tilde.pink 70 +1~warbler /~warbler/ tilde.pink 70 +1~yakumo_izuru /~yakumo_izuru/ tilde.pink 70 +1~yuno /~yuno/ tilde.pink 70 +1~zer0pink /~zer0pink/ tilde.pink 70 +i Err tilde.pink 70 +i Err tilde.pink 70 +iECDSA fingerprint: SHA256:nQ5tp9xU7Pm+qdnhPnW+6QOb1TYCU41JWbvpW6Z7Gyo Err tilde.pink 70 +i Err tilde.pink 70 +iThis tilde server kills fascists! Err tilde.pink 70 +i Err tilde.pink 70 +ijan6 ate my turtle Err tilde.pink 70 +i Err tilde.pink 70 +iToday is Sweetmorn, the 50th day of Confusion in the YOLD 3192 Err tilde.pink 70 +iCelebrate Confuflux Err tilde.pink 70 +. diff --git a/test/2 b/test/2 @@ -0,0 +1,32 @@ +iWelcome to gopher at quux.org! fake (NULL) 0 +i fake (NULL) 0 +iThis server has a lot of information of historic interest, fake (NULL) 0 +ifunny, or just plain entertaining -- all presented in Gopher. fake (NULL) 0 +iThere are many mirrors here of rare or valuable files with the fake (NULL) 0 +iaim to preserve them in case their host disappears. PLEASE READ fake (NULL) 0 +i"About This Server" FOR IMPORTANT NOTES AND LEGAL INFORMATION. fake (NULL) 0 +i fake (NULL) 0 +0About This Server /About This Server.txt gopher.quux.org 70 + +1Archives /Archives gopher.quux.org 70 + +1Books /Books gopher.quux.org 70 + +1Communication /Communication gopher.quux.org 70 + +iThis directory contains the entire text of the book fake (NULL) 0 +i"We the Media: Grassroots Journalism by the People, for the People" fake (NULL) 0 +iby Dan Gillmor in various formats. fake (NULL) 0 +i fake (NULL) 0 +iFeel free to download and enjoy. fake (NULL) 0 +1Computers /Computers gopher.quux.org 70 + +1Current Issues and Events (Updated Apr. 23, 2002) /Current gopher.quux.org 70 + +1Development Projects /devel gopher.quux.org 70 + +0Gopher's 10th Anniversary /3.0.0.txt gopher.quux.org 70 + +1Government, Politics, Law, and Conflict /Government gopher.quux.org 70 + +0How To Help /How To Help.txt gopher.quux.org 70 + +1Humor and Fun /Humor and Fun gopher.quux.org 70 + +1Index to Quux.Org /Archives/index gopher.quux.org 70 +1Internet /Internet gopher.quux.org 70 + +1Other Gopher Servers /Software/Gopher/servers gopher.quux.org 70 +1People /People gopher.quux.org 70 + +1Reference /Reference gopher.quux.org 70 + +1Software and Downloads /Software gopher.quux.org 70 + +1The Gopher Project /Software/Gopher gopher.quux.org 70 +0What's New /whatsnew.txt gopher.quux.org 70 + diff --git a/test/3 b/test/3 @@ -0,0 +1,7 @@ +1Fortune Databases /Humor and Fun/Fortune Databases gopher.quux.org 70 + +1Microsoft_KSH.txt /Humor and Fun/Microsoft_KSH.txt gopher.quux.org 70 +1Nerd Humor /Archives/mirrors/OBI/Nerd.Humor gopher.quux.org 70 +1Politics /Humor and Fun/Politics gopher.quux.org 70 + +1Pranks & Practical Jokes /Humor and Fun/Pranks gopher.quux.org 70 + +1Textfiles Humor Section /Archives/mirrors/textfiles.com/humor gopher.quux.org 70 +1Usenet Oracle Archives /Archives/mirrors/ftp.cs.indiana.edu/pub/oracle gopher.quux.org 70
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.