Skip to content

shrimple 🇵🇱 🏳️‍⚧️

shrimple mind. shrimple problems. complex solutions. she/her

Links 2, a graphical browser I wanna build upon. And a quick look at how ELinks is doing.

Posted on February[²⁰26], Sunday 15.February[²⁰26], Monday 16. By Shrimple 8 Comments on Links 2, a graphical browser I wanna build upon. And a quick look at how ELinks is doing.

We all know the three: Lynx, Links 2, ELinks. And w3m, the thing that pioneered inline images. Of these, Links is also among Dillo and NetSurf as a graphical browser —

Unlike its Links pre-1 fork, ELinks, which never chose to follow the upstream on that one;

Nowadays, elinks.cz web site is defunct for a month now — but exclusively on GitHub, the community remains active. Once a fork, rkd77’s ELinks, once (until 2020) having to call itself felinks, is now the continuation. The INSTALL mentions Alternatively, instead of Meson: ./configure &&… …There is no ./configure.

After I got all the deps one by one, the meson compile then told me my openssl/ssl.h expects a non-const CRYPTO_EX_DATA pointer as from parameter to socket_SSL_ex_data_dup, not constthe meson compile fails due to const SSL method parameter (which seems to be possibly a too lax type signature for today’s standards)  — and by the way, clangd then told me, with my LibreSSL setup with preprocessor having no defs for the file in my editor:elinks' ssl.c, starting with comment "SSL support - wrappers for SSL routines", and below the clangd in my Helix editor displays me inline the "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And the you want exactly *what* from me?" from later ifdefs, where it occurs in an else block in case of neither CONFIG_OPENSSL nor defined(CONFIG_GNUTLS).In 2022, @drizzlebactin has inquired in a GitHub issue, if there’s any plan for adding support for libressl. She received a No.
(Although this issue is probably not related to the compile error. And pretty sure not related to what I saw in my editor.)

This ELinks nowadays has «tabs, local cgi, mailcap, gopher», «is highly customizable and can be extended via scripts». The Gemini protocol support didn’t TOFU… so they SSL_VERIFY_NONE “for the short-term”. «FSP, gopher, bittorrent; browser scripting (lua, python, perl , etc.) […]»

@IngaLovinde once, last day of November 2024, thoroughly reported on findings including lack of display:none and visibility:hidden handling, which ELinks did in neither of its two (built-in, and LibCSS) CSS engines;
; within 25 minutes, ae got a community reply suggesting to try
document.css.ignore_display_none = 0 (as = 1 means “show” for that setting), which helped some of the cases
— and the next morning some of aer findings were already receiving fixes from rkd77.

see “elinks is missing some key features (including HTML4 features) needed for graceful degradation of modern websites” #341

A bit oddly, I’m going to be interested in the graphical Links 2.

If we rank the three graphical browsers by how faithful they are to how illegible (small, etc.) the text seems to be mandated to be,

  1. NetSurf will show overlapping pieces of text when your CSS is funky enough, and will make the text small if told to
  2. Dillo will usually not enact the styling that chances it to overlap things, and the small thing to trouble you will usually be its own UI on a HiDPI display
  3. Links2 will apply just one kind of CSS styling: display:none. You still have tables, you have the frames in your framesets, but the styling is dismissed. For the non-essential presentation aspects, that’s less than ELinks while being a graphical browser (in the graphical mode).

(Funnily enough, the logic for display:none in Links skips the hidden input tags, in order to not accidentally make them visible.)

Screenshot of graphical mode of Links, showing menus extended into "Network options" and "HTTP options"Links graphical mode screenshot of a website advertising some old FrameKeeper product. We can see content being aligned to the middle and in various other ways, an IFrame being indicated on top, some images embedded, and varying alignment of the contentLinks graphical mode displaying an entry about I Love Free Software Day on Free Software Foundation Europe blog. For some reason, the heart (I presume) is replaced by two… "blast" characters, it seems. The image renders, the font is very neat for reading

When I’m already at HiDPI, I will mention that the changelog for release 2.19 mentions on a Windows case:

Sun Mar 31 15:59:40 CEST 2019 mikulas

Disable high-DPI scaling on Windows

Links makes it possible to specify scaling of text and images in the
dialog windows, so this should preferably be used instead of
system-level scaling

That is true and only slightly cumbersome, as the fonts for UI and for HTML are in two different whole menus. And you need to remember to “Save Settings” in the “Settings” menu. And “Save HTML Settings” in the “View” menu.

What really contributes to the aesthetic of graphical mode of Links to me is that while it can support FreeType fonts (at least can be compiled with such), by default it uses fonts that it pre-renders from PostScript font to bitmaps for the given size. And, optionally, subpixel optimization (which I keep disabled, staying on “CRT” optimization).

Where exactly is Links 2

It’s an amazing piece of software that is still getting compiled for OpenVMS, DOS, and OS/2 with EMX. It has a special mode for Braille readers where all menus are displayed full-screen. It is considered extremely stable, and very safe to use on the hostile web.

Links 2 upstream comes from https://links.twibright.com/. There doesn’t seem to be a Git/SVN/CVS repo accessible anywhere. You just download a source tarball.

But then there is one place where I found more, and it was a once-mirror of no-longer-online self-hosted “Polish Linux Distribution”s links2 package spec github.com/pld-linux/links2 containing a bunch of patches applied by the rpm spec therein, currently building the 2.30 version with the following patches:

This section contains, in spec order, a bunch patches patches by PLD Linux contributors

Note: copyright (earlier than 2012-2023) belongs to rkd77, megabajt, qboosh, grzegol, et al (PLD Linux contributors). May be presumed GPLv2

Patch for “glinks” executable symlink/alias to start in graphical mode

--- links-2.2/main.c	2007-12-11 17:45:38.000000000 +0100
+++ links-2.2/main.c.new	2010-01-21 22:00:22.020403979 +0100
@@ -4,6 +4,9 @@
  * This file is a part of the Links program, released under GPL.
  */
 
+#define _GNU_SOURCE
+#include <string.h>
+
 #include "links.h"
 
 int retval = RET_OK;
@@ -290,6 +290,7 @@
 
 static void fixup_g(void)
 {
+	if (strncmp(basename(path_to_exe), "glinks", 6) == 0) ggr = 1;
 	if (ggr_drv[0] || ggr_mode[0] || force_g) ggr = 1;
 	if (dmp) ggr = 0;
 }
Patch for to enable pkg-config in autoconf for things like library dependencies

--- links-2.28/configure.in.orig	2022-10-07 20:47:33.616006730 +0200
+++ links-2.28/configure.in	2022-10-07 22:59:34.119764346 +0200
@@ -536,6 +536,8 @@ fi
 
 AC_CHECK_LIB(bsd, strmode)
 
+PKG_PROG_PKG_CONFIG
+
 dnl User option
 
 AC_MSG_CHECKING([for requested debug level])
Patch for showing part of src attribute for images when there is no better fallback than [IMG]

--- links-2.7/html.c.orig	2013-06-23 18:17:51.248954518 +0200
+++ links-2.7/html.c	2013-06-23 18:30:42.988922132 +0200
@@ -1062,7 +1062,54 @@
 				add_to_strn(&al, cast_uchar "]");
 			} else if (usemap) al = stracpy(cast_uchar "[USEMAP]");
 			else if (ismap) al = stracpy(cast_uchar "[ISMAP]");
-			else al = stracpy(cast_uchar "[IMG]");
+			else{
+				unsigned char *str = get_attr_val(a, "src");
+				unsigned char *s;
+				int r, i;
+				/* How images will be displayed:
+				* fake_alt = 0   -- do not truncate long names,
+				* fake_alt = 30  -- truncate long names to 30% of term width,
+				* fake_alt = 100 -- truncate long names to 100% of term width.
+				*/         
+				int fake_alt = 20;
+				int max_len;
+				int name_len;
+				/* substitute string for hidden characters */
+				unsigned char *fake_str = stracpy("*");
+				if(str && fake_alt){
+					/* FIXME: replace following '80' with screen width */
+					max_len = (int)80*((float)fake_alt/100);
+					r = strcspn(str, "?");
+					if (!(s = mem_alloc((r + 1) * sizeof(char)))) return;
+					strncpy(s, str, r);
+					s[r] = '\0';
+					for(r = strlen(s) - 1; r >= 0; --r)
+						if(dir_sep(s[r])) break;
+					r++;
+					if(strlen(s + r) > max_len){
+						for(i = strlen(s) -1; i>=0; --i)
+							if(s[i] == '.') break;
+						if(max_len < strlen(s + i)) al = stracpy("[IMG]");
+						else{
+							if(!(al = mem_alloc((max_len + strlen(fake_str) + 3) * sizeof(char)))) return;
+							name_len = max_len - strlen(s + i);
+							strcpy(al, "[\0");
+							strncat(al, s + r, name_len/2);
+							strcat(al, fake_str);
+							strcat(al, s + r + (strlen(s + r) - max_len + name_len/2));
+							strcat(al, "]");
+						}
+					}
+					else{
+						if(!(al = mem_alloc((strlen(s + r) + 3) * sizeof(char)))) return;
+						sprintf(al, "[%s]", s + r);
+					}
+					mem_free(s);
+					mem_free(str);
+					mem_free(fake_str);
+				}
+				else al = stracpy("[IMG]");
+			}
 		}
 		if (al) {
 			if (ismap) {
Patch for providing a migration path for users with bookmark file from old versions

--- links-2.22/bookmark.c.old	2021-03-20 18:44:34.524720442 +0100
+++ links-2.22/bookmark.c	2021-03-20 18:45:06.331385178 +0100
@@ -785,6 +785,18 @@
 			msg_box(ses->term, getml(f, NULL), TEXT_(T_BOOKMARK_ERROR), AL_CENTER, TEXT_(T_UNABLE_TO_WRITE_TO_BOOKMARK_FILE), cast_uchar " ", f, cast_uchar ": ", get_err_msg(err, ses->term), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
 		}
 	}
+	/* try to create bookmarks.html based on old bookmarks (from links <= 0.97) */
+	if (access(bookmarks_file, R_OK) != 0) {
+		char *prev;
+
+		if ((prev = get_current_dir_name()) && chdir(links_home) == 0) {
+			if (access("bookmarks", R_OK) == 0 && access("/usr/bin/perl", X_OK) == 0) {
+				system("/usr/bin/perl -lne '@l = split(q(\\|)); print qq($l[0])' bookmarks > bookmarks.html");
+			}
+			chdir(prev);
+			free(prev);
+		}
+	}
 
 	EINTRLOOP(rs, stat(cast_const_char bookmarks_file, &bookmarks_st));
 	if (rs)
Patch for using ~/.links2 rather than ~/.links, and analogously

--- links-2.1pre16/links.1.orig 2005-01-22 21:51:55.000000000 +0100
+++ links-2.1pre16/links.1      2005-01-28 20:47:50.217234704 +0100
@@ -303,7 +303,7 @@

 .SH FILES
 .TP
-.IP "~/.links/links.cfg"
+.IP "~/.links2/links.cfg"
 Per-user configfile, automatically created by
 .B links.
 .SH PLATFORMS
--- links-2.22/default.c.old	2021-03-20 19:10:17.237960076 +0100
+++ links-2.22/default.c	2021-03-20 19:10:57.477957622 +0100
@@ -797,7 +797,7 @@
 		while (home_links[0] && dir_sep(home_links[strlen(cast_const_char home_links) - 1])) home_links[strlen(cast_const_char home_links) - 1] = 0;
 		EINTRLOOP(rs, stat(cast_const_char home_links, &st));
 		if (!rs && S_ISDIR(st.st_mode)) {
-			add_to_strn(&home_links, cast_uchar "/links");
+			add_to_strn(&home_links, cast_uchar "/links2");
 		} else {
 			fprintf(stderr, "CONFIG_DIR set to %s. But directory %s doesn't exist.\n\007", config_dir, home_links);
 			portable_sleep(3000);
@@ -810,9 +810,9 @@
 #if defined(DOS)
 		add_to_strn(&home_links, cast_uchar "links.cfg");
 #elif defined(OPENVMS) || defined(HAIKU)
-		add_to_strn(&home_links, cast_uchar "links");
+		add_to_strn(&home_links, cast_uchar "links2");
 #else
-		add_to_strn(&home_links, cast_uchar ".links");
+		add_to_strn(&home_links, cast_uchar ".links2");
 #endif
 	}
 	EINTRLOOP(rs, stat(cast_const_char home_links, &st));
@@ -840,7 +840,7 @@
 #ifdef DOS
 	add_to_strn(&home_links, cast_uchar "links.cfg");
 #else
-	add_to_strn(&home_links, cast_uchar "links");
+	add_to_strn(&home_links, cast_uchar "links2");
 #endif
 	EINTRLOOP(rs, stat(cast_const_char home_links, &st));
 	if (rs) {
Patch for opening non-existent filepaths where a .gz-suffixed gzipped filed exists

--- links-2.10/file.c.gzip	2015-07-15 12:17:21.831370450 +0200
+++ links-2.10/file.c	2015-07-15 12:17:25.037715949 +0200
@@ -224,11 +224,17 @@ void file_func(struct connection *c)
 		abort_connection(c);
 		return;
 	}
+opening:
 	if (!(name = get_filename(c->url))) {
 		setcstate(c, S_OUT_OF_MEM); abort_connection(c); return;
 	}
 	EINTRLOOP(rs, stat(cast_const_char name, &stt));
 	if (rs) {
+		if (strncmp(c->url + strlen(c->url) - 3, ".gz", 3) != 0) {
+			add_to_strn(&c->url, ".gz");
+			mem_free(name);
+			goto opening;
+		}
 		mem_free(name);
 		setcstate(c, get_error_from_errno(errno)); abort_connection(c); return;
 	}
Patch for Polish translations

Introducing strings for menu items like saving clipboard to file, DNS preferences, cookies, fonts, windows, and original authors’ URLs.


--- links-2.29/intl/polish.lng~	2023-03-09 19:13:27.000000000 +0100
+++ links-2.29/intl/polish.lng	2023-03-23 09:55:27.103304736 +0100
@@ -656,8 +656,8 @@
 T_HK_DOCUMENT_INFO, "I",
 T_HK_HEADER_INFO, "F",
 T_HK_FRAME_AT_FULL_SCREEN, "Y",
-T_HK_SAVE_CLIPBOARD_TO_A_FILE, NULL,
-T_HK_LOAD_CLIPBOARD_FROM_A_FILE, NULL,
+T_HK_SAVE_CLIPBOARD_TO_A_FILE, "Zapis schowka do pliku",
+T_HK_LOAD_CLIPBOARD_FROM_A_FILE, "Odczyt schowka z pliku",
 T_HK_HTML_OPTIONS, "U",
 T_HK_COLOR, "K",
 T_HK_SAVE_HTML_OPTIONS, "Z",
@@ -671,14 +671,14 @@
 T_HK_IPV6_OPTIONS, "I",
 T_HK_PROXIES, "P",
 T_HK_SSL_OPTIONS, "L",
-T_HK_DNS_OPTIONS, NULL,
+T_HK_DNS_OPTIONS, "Opcje DNS",
 T_HK_HTTP_OPTIONS, "H",
 T_HK_FTP_OPTIONS, "F",
 T_HK_SMB_OPTIONS, "S",
 T_HK_JAVASCRIPT_OPTIONS, "J",
 T_HK_MISCELANEOUS_OPTIONS, "N",
-T_HK_COOKIES, NULL,
-T_HK_FONTS, NULL,
+T_HK_COOKIES, "Ciasteczka",
+T_HK_FONTS, "Fonty",
 T_HK_CACHE, "P",
 T_HK_MAIL_AND_TELNEL, "C",
 T_HK_ASSOCIATIONS, "S",
@@ -695,7 +695,7 @@
 T_HK_VIEW, "W",
 T_HK_LINK, "L",
 T_HK_DOWNLOADS, "O",
-T_HK_WINDOWS, NULL,
+T_HK_WINDOWS, "Okna",
 T_HK_SETUP, "U",
 T_HK_HELP, "M",
 T_HK_DISPLAY_USEMAP, "M",
@@ -717,6 +717,6 @@
 T_HK_WINDOW, "O",
 T_HK_FULL_SCREEN, "P",
 T_HK_BEOS_TERMINAL, "B",
-T_URL_MANUAL, NULL,
-T_URL_HOMEPAGE, NULL,
-T_URL_CALIBRATION, NULL,
+T_URL_MANUAL, "http://links.twibright.com/user_en.html",
+T_URL_HOMEPAGE, "http://links.twibright.com/",
+T_URL_CALIBRATION, "http://links.twibright.com/calibration.html",
Patch replacing an Automake macro with an Autoconf one

--- links-2.22/configure.in.old	2021-03-20 19:16:29.597937288 +0100
+++ links-2.22/configure.in	2021-03-20 19:16:50.644602655 +0100
@@ -18,7 +18,7 @@
 export LDFLAGS
 export LIBS
 
-AM_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS(config.h)
 
 dnl Checks for programs.
 AC_PROG_CC
Patch enabling Autoconf detection of a C++ compiler

--- links-2.7/configure.in.old	2013-04-06 20:56:02.641704629 +0200
+++ links-2.7/configure.in	2013-04-06 20:56:18.208612038 +0200
@@ -18,7 +18,7 @@ AC_CONFIG_HEADERS(config.h)
 dnl Checks for programs.
 AC_PROG_CC
 
-dnl AC_PROG_CXX
+AC_PROG_CXX
 dnl AC_PROG_AWK
 dnl AM_PROG_LEX
 dnl AC_PROG_YACC

So, I just pasted a bunch of patches from a legacy Linux distribution into my blog post.

This is a first for me in the patch-oriented development practices. I had to learn how to apply those — for that, I learned I need to use the quilt tool for patch management, that let’s me either create a series file, or should be able to just take in the spec file that is present in the repo. I, perhaps needlessly, did the former, by listing the files in order into a file named series and putting it in my clone of github.com/pld-linux/links2 cloned as patches directory name in the directory of extracted links-2.30 tarball. And ran «quilt push -a» to apply them.

My goals

I think I’m gonna like Links as a base — by implementing a bunch of patches of my own — for a browser that can do

  • Gemini protocol
  • adding links to some special bookmark folders rather than opening them, perhaps a tour-like UX but less linear
  • interoperate with a lightweight feed reader that opens links in a browser, or display an Atom/RSS feed on its own
  • Gopher protocol

Basically, yeah, Offpunk browser is cool but I want it more calming to the eye, somewhat featureful for smolweb content presentation, and usable with a mouse.

Since this is another project where I will be doing experimental changes for own ergonomics, some of my patches might end up being exotic — think, mouse chording for some reason.

Wild Software Writing Tags:links2, oss-contributing, smolweb

Post navigation

Previous Post: Simplistic reconciliation of mostly-append text files like Offpunk lists: draft involving Kahn’s algorithm

Related Posts

  • Amending my Offpunk redirection implementation Wild Software Writing
  • Slash-hierarchical list names — my draft implementation for Offpunk Wild Software Writing
  • Subscription into list rather than tour — Offpunk draft feature patch Wild Software Writing
  • Experimentally expanding Offpunk browser Part 1 (nightly) Wild Software Writing
  • Bugfix for list URI for my Offpunk redirections implementation draft Wild Software Writing
  • Distributed file version management in 15 minutes of Bash Wild Software Writing

Comments (8) on “Links 2, a graphical browser I wanna build upon. And a quick look at how ELinks is doing.”

  1. Mizuki says:
    February[²⁰26], Sunday 15. at 2pm

    how the hell did you find me here, I'm pretty sure my mastodon was never linked anywhere…
    it's been quite a while isn't it, that issue was when I tried to compile elinks with msys2 on windows, and kept running into funky openssl errors
    now elinks actually provides a windows binary yay :3
    for me I like to stick with lynx and elinks, if I need GUIs then might as well run full blown firefox, the point of these browsers is usage in consoles (like arch install media)…

    Reply as
    Reply on the Fediverse

    Remote Reply

    Original Comment URL

    Copy and paste the Comment URL into the search field of your favorite fediverse app or server.

    Your Profile

    Or, if you know your own profile, we can start things that way!
    1. Shrimple says:
      February[²⁰26], Sunday 15. at 2pm

      Hi!! yay so cool this is happening, extremely nice to meet you

      The path was: gh account → profile linked github pages webbed site → section “Socials” had a “Mastodon (maybe)” and that’s the handle I linked :3

      Firefox doesn’t even start up in less than 10 seconds on my netbook to begin with :3

      And, just consider the case of Offpunk browser (https://offpunk.net), the motivations behind it aren’t just to keep to the terminal or to have the things fetched offline, it is to work around the addictive nature of opening new tabs and navigating the links like a labyrinth rather than a planned tour

      Reply
      1. Mizuki says:
        February[²⁰26], Sunday 15. at 2pm

        just had to uv tool install offpunk :3
        I did recall looking into these "weird" protocols in my terminal browser using days (especially looking at that gigantic lynx compile instruction file)
        gemini gopher something something
        but never really looked deep into it
        seems like gemini in like the "old pre-JS web" so to speak
        that's really nice meoww
        anyhow, thank you so much for mentioning me! i'm glad that i left my tiny footprint on the web somewhere ^^

        Reply as
        Reply on the Fediverse

        Remote Reply

        Original Comment URL

        Copy and paste the Comment URL into the search field of your favorite fediverse app or server.

        Your Profile

        Or, if you know your own profile, we can start things that way!
        1. Shrimple says:
          February[²⁰26], Sunday 15. at 2pm

          waow so cool you enjoy i did <3

          well gemini is way further back than hypertext web, it’s almost like gopher but made less for file listings; it’s like taking new ideas and simple fetch approach into the textfiles and the kermit, just the http GET and no text reflowing

          Reply
          1. Mizuki 🌺🧬🧪 says:
            February[²⁰26], Sunday 15. at 3pm

            man you know a lot of old tech :3
            am pretty young so the first tech I grew up using was sandy bridge…

          2. Shrimple says:
            February[²⁰26], Sunday 15. at 3pm

            Oh I was not around for any of these, all I did was see modern phlogs when Gemini was already pretty common among folks, and accidentally briefly learn about Kermit while very recently looking into NNCP and Filespooler again on https://complete.org/

  2. Shrimple says:
    February[²⁰26], Sunday 15. at 2pm

    This blog post DoesN’t™ “Show content” on Akkoma. @mkljczk is at it already 😊🥴

    I guess good thing I posted with a content warning, who knows what WouldN’t™ if I had posted without

    Reply
    1. Shrimple says:
      February[²⁰26], Sunday 15. at 3pm

      You may also be stuck unable to navigate in your Akkoma frontend after navigating to my post.

      Reply

Leave a Reply to Shrimple Cancel reply

Your email address will not be published. Required fields are marked *

Atom feed for this page

Atom feed for this blog

against-messy-software bash big.ugly.git.patch. chromium-and-derivatives community fragment golang kde links2 linux microsoft-edge network offpunk offpunk:lists offpunk:redirections oss-contributing perl programming-tips scripting smolweb subscribe superuser window-decorations Wordpress_ActivityPub_plugin

  • February 2026 (4)
  • January 2026 (10)

Categories

  • Influencing Society

    (1)
  • Meta

    (2)
  • Oddities of alternate reality

    (1)
  • Programming Technologies

    (1)
  • Software Imposed On Us

    (1)
  • Wild Software Writing

    (8)
shrimple 🇵🇱  🏳️‍⚧️
shrimple 🇵🇱 🏳️‍⚧️
@shrimple@www.shrimple.pl
Follow

shrimple mind. shrimple problems. complex solutions. she/her

14 posts
5 followers

Follow shrimple 🇵🇱 🏳️‍⚧️

My Profile

Copy and paste my profile into the search field of your favorite fediverse app or server.

Your Profile

Or, if you know your own profile, we can start things that way!
  • Distributed file version management in 15 minutes of Bash Wild Software Writing
  • Slash-hierarchical list names — my draft implementation for Offpunk Wild Software Writing
  • Hello world! Meta
  • Getting TLS1.3 Key Log from Go application with requests by a library, and using it in Wireshark Programming Technologies
  • Experimentally expanding Offpunk browser Part 1 (nightly) Wild Software Writing
  • Amending my Offpunk redirection implementation Wild Software Writing
  • Forcing KWin decorations and MS Edge’s 1cm shadow gradient Software Imposed On Us
  • when DMI info like Serial not in hostnamectl output Oddities of alternate reality

shrimple@shrimple.pl

Copyright © 2026 shrimple 🇵🇱 🏳️‍⚧️.

Powered by PressBook News WordPress theme