I know I've been high-density-posting.
I'm like a shark. I can't get enough gopher.

I wrote a great gopher browser, that you don't even need to have to use.
This tutorial is openbsd based. Your unix-like OS is probably similar.
If you can adapt it to your OS I will link to you.

Dependency: Embeddable common lisp "ecl". The heir to Austin-Kyoto lisp.
'''ksh
pkg_add ecl
'''
On obscure operating systems you might need to install openbsd-netcat.
Let me know if it gives you trouble.

Let's look at sdf.org using netcat. This is all that ever needs to happen.
'''ksh
printf "\n" | nc sdf.org 70
'''
But let's use ECL to make this a little easier.
First, let's get granfalloon.lisp with our gopher browser.
'''ksh
printf "/users/screwtape/common-lisp/granfalloon.lisp\n"  | nc sdf.org 70 > granfalloon.lisp
'''
For security's sake, let's check the sha256.
'''ksh
sha256 granfalloon.lisp
'''
I got
>SHA256 (granfalloon.lisp) = 29ed96185066718932fc9b44b36d1239bfa642581f3eaf5f48f91c32931ef5e7

At this juncture you should peruse the 85 lines of code to your content.

Let's fire her up.
'''ksh
ecl --load granfalloon.lisp
'''
GETTING OUT OF ECL GRACEFULLY:
If something has gone wrong, at the prompt normally you can :r1<enter> (or whatever number 'restart toplevel' is.
If you want to get out to restart whereever do Ctrl+c, and instead of restarting type (si:quit)<enter>.
(which is quit generally in ECL). Lisp is designed not for randomly quitting and restarting though.

Now the default in lisp is to send lines of input to your running program.
This is called a REPL. Something like this will be waiting for you:
'''"ksh" but actually ecl.
>
'''
Let's enter the granfalloon package so we don't have to specify it all the time.
'''ecl
>(in-package gfln)
'''
I bet I'm going to regret leaving the r out of that nickname.
You can type granfalloon there if you want to.
Now lets browse sdf.org again, and then look at the tools we have for it.
'''ecl
granfalloon>(bind-nl)
'''
I got #<bytecompiled-closure #<bytecompiled-function READLINE-STAT 0x1eb5f2b050>>
GRANFALLOON>.
The bind-nl function has bound a closure that returns the next line of the
gopher item, or nil if none is available.
Let's get all the lines available with granfalloon's function, nconc-nls
'''ecl
granfalloon> (nconc-nls)
'''
That's a bit more like it!

Let's store it in a lisp variable, and use a macro that hides it from being
printed. (-q &body) is gfln's macro that just hides output.
(setq *lines* (form)) is lisp's way of making *lines* refer to the result of
(forms). It will work whether you feel a deep understanding or not.
We have to make a new connection, since we consumed all the lines before.
That's okay.
'''ecl
granfalloon> (bind-nl)
granfalloon> (-q (setq *lines* (nconc-nls)))
granfalloon> *lines*
'''
Yep, they're all there... In lisp we like to put *earmuffs* on global variables.
Now we have the *lines* stored so we don't need to download them again.
Let's print them plainly like a shell would using gfln:plain
'''ecl
granfalloon> (plain *lines*)
'''
It's about time we started beating the competition, right? (Sez me.).
Let's use common lisp's subseq to plainly display a subseq of those lines.
'''ecl
granfalloon> (plain (subseq *lines* 0 5))
'''
This gophermap is structured a little funny, but we are seeing what's really there.
'''output
Welcome to the SDF Public Access UNIX System .. est. 1987              null.host       1
i               null.host       1
iOfficial Site of the Internet Gopher Club Underground Syndicate                null.host       1
i               null.host       1
iWe offer FREE and inexpensive memberships for people interested                null.host       1
'''
Wandering around subseqs of the gophermap like this is the intended browsing.
Let's be a little tricky and use common lisp to number the lines we print.
'''ecl
granfalloon> (plain (loop for x from 1 for line in *lines* collecting (cons x line)))
'''
Using common lisp is an advantage of common lisp. Don't worry about the fact that that line works though.
Line 14 looks good. We can print it in particular like this
'''ecl
granfalloon> (nth (- 14 1) *lines*)
'''
nth indexes from 0 :-(. Lisps use prefix notation.
Annoyingly, plain needs non-lists to be templated into lists, using backtick here. Don't worry about it.
'''ecl
granfalloon> (plain `(,(nth 13 *lines*)))
'''
Let's go somewhere new. First, let's save sdf.org for later in *sdf.org* (quietly again).
'''ecl
(-q (setq *sdf.org* *lines*))
'''
Now *sdf.org* can be used anywhere and anyhow we used *lines*. Let's go to that /phlogs/ item specifier in 13.
We're just going to type, since the point of granfalloon isn't directly to become lisp wizards.
Quietly, since (length */phlogs/*) yields 371.
'''ecl
granfalloon> (bind-nl :spec "/phlogs/")
granfalloon> (-q (setq */phlogs/* (nconc-nls)))
granfalloon> (plain (subseq */phlogs/* 0 11))
'''
That's a fancy gopher.club banner. Last active phlog listings begin at line 12 (the 13th line)
'''ecl
granfalloon> (plain (subseq */phlogs/* 12 16))
'''
Let's talk about copying and pasting into an xterm using a mouse, since lots of people do that.
First, let's start typing our command up until after the first double-quote.
'''ecl
granfalloon> (bind-nl :spec "
'''
We could keep typing, but if you use a mouse it can be convenient to "sweep out" long item specifiers.
To do that, you press down left click on the first letter you want, and drag it right along the line
to the last letter you want. I went for /users/screwtape/.
While it's highlighted in xterm, middle clicking the mouse will drop it at the cursor in the terminal/ecl.
<one middle click later>
'''ecl
granfalloon> (bind-nl :spec "/users/screwtape/
'''

Same old...
'''ecl
granfalloon> (bind-nl :spec "/users/screwtape/")
granfalloon> (-q (setq *screwtape* (nconc-nls)))
granfalloon> (plain (subseq *screwtape* 0 20))
'''

Let's look at an item-type 0 text file (we've been looking at item-type 1, directories). They are both text files.
>0Wed Feb 16 ;sam ple ed iting   /users/screwtape/tmp.upObQMkxa1 sdf.org 70
'''ecl
granfalloon> (bind-nl :spec "/users/screwtape/tmp.upObQMkxa1")
granfalloon> (-q (setq *sam-d.txt* (nconc-nls)))
granfalloon> (plain (subseq *sam-d.txt* 0 5))
'''
Let's wrap this up by visiting somewhere outside of sdf.org. I didn't look at jns's homegopher yet.
He links it in his gophermap.
We could look manually via (plain */phlogs/*) or creeping through using subseq, but I *am* a lisp wizard.
'''ecl
granfalloon> (find "jns" */phlogs/* :test 'search)
granfalloon> (bind-nl :spec "/users/jns/")
granfalloon> (-q (setq *jns* (nconc-nls)))
granfalloon> (remove-if (lambda (x) (search "sdf.org" x)) *jns*)
granfalloon> (bind-nl :address "gopher.linkerror.com" :spec "/phlog/2021")
'''
Neat. You know, I sent him an email in which I had a deep misimpression of what termcap(3) was talking about.

Well, that was a bit of a journey! Maybe we'll do binary file formats like sound and images next time after I post
my rich media with C lisp.

screwtape

Postscript
The pun I'm making is that gopher doesn't need a browser. So a gopher browser would be an absent browser.
Say what you will, no 20+ hour builds.
Further our (absent) gopher browser is the only browser featured in the books of bokonon.

>If you want want to inspect a granfalloon, remove the skin from a toy balloon.

#[!got log#]
-----------------------------------------------
commit 560a6a0c7efa092c509466304db9d10a058144d9
from: <[email protected]>
date: Fri Feb 18 05:06:07 2022 UTC

When bokonon was asked about his social media, he listed his sdf.org phlog.
The people of san lorenzo panicked about needing to build a new browser.
Bokonon explained that the browser they needed didn't need to exist
but also wouldn't support gemini protocol.