summaryrefslogtreecommitdiffstats
path: root/src/UCAuto.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/UCAuto.c816
1 files changed, 816 insertions, 0 deletions
diff --git a/src/UCAuto.c b/src/UCAuto.c
new file mode 100644
index 0000000..2b17591
--- /dev/null
+++ b/src/UCAuto.c
@@ -0,0 +1,816 @@
+/*
+ * $LynxId: UCAuto.c,v 1.56 2021/06/09 22:29:43 tom Exp $
+ *
+ * This file contains code for changing the Linux console mode.
+ * Currently some names for font files are hardwired in here.
+ * You have to change this code if it needs accommodation for your
+ * system (or get the required files...).
+ *
+ * Depending on the Display Character Set switched to, and the previous
+ * one as far as it is known, system("setfont ...") and/or output of
+ * escape sequences to switch console mode are done. Curses will be
+ * temporarily suspended while that happens.
+ *
+ * NOTE that the setfont calls will also affect all other virtual consoles.
+ *
+ * Any ideas how to do this for other systems?
+ */
+
+#include <HTUtils.h>
+#include <LYUtils.h>
+
+#include <UCMap.h>
+#include <UCDefs.h>
+#include <UCAuto.h>
+#include <LYGlobalDefs.h>
+#include <LYStrings.h>
+#include <LYClean.h>
+#include <LYLeaks.h>
+#include <LYCharSets.h>
+
+#ifdef EXP_CHARTRANS_AUTOSWITCH
+
+#include <HTFile.h>
+#include <www_wait.h>
+
+#ifdef LINUX
+#include <sysexits.h> /* EX_DATAERR, etc. */
+#endif
+
+# ifdef CAN_SWITCH_DISPLAY_CHARSET
+char *charset_switch_rules;
+char *charsets_directory;
+int auto_other_display_charset = -1;
+int codepages[2];
+int real_charsets[2] =
+{-1, -1}; /* Non "auto-" charsets for the cps */
+int switch_display_charsets;
+
+# endif
+
+#ifdef HAVE_USE_LEGACY_CODING
+static int original_coding = 0;
+#endif
+
+# ifdef __EMX__
+/* If we "just include" <os2.h>, BOOLEAN conflicts. */
+# define BOOLEAN OS2_BOOLEAN /* This file doesn't use it, conflicts */
+# define INCL_VIO /* I want some Vio functions.. */
+# define INCL_DOSPROCESS /* TIB PIB. */
+# define INCL_DOSNLS /* DosQueryCp. */
+# include <os2.h> /* Misc stuff.. */
+# include <os2thunk.h> /* 32 bit to 16 bit pointer conv */
+# endif
+
+#ifdef LINUX
+typedef enum {
+ Is_Unset,
+ Is_Set,
+ Dunno,
+ Dont_Care
+} TGen_state_t;
+
+/*
+ * List the states the console has been set to via SCS (select character-set).
+ */
+typedef enum {
+ GN_Blat1, /* Latin-1 */
+ GN_Ucp437, /* PC -> PC */
+ GN_Kuser, /* user-defined */
+ GN_dunno,
+ GN_dontCare
+} TTransT_t;
+
+static char *T_font_fn = NULL; /* font filename */
+static char *T_umap_fn = NULL; /* unicode-map filename */
+
+#define NOOUTPUT "2>/dev/null >/dev/null"
+
+/*
+ * Return the configured path of the setfont/consolechars program.
+ */
+static const char *GetSetfontPath(void)
+{
+ return HTGetProgramPath(ppSETFONT);
+}
+
+/*
+ * setfont and consolechars have different options and available data.
+ */
+static BOOL isSetFont(void)
+{
+ const char *program = GetSetfontPath();
+ const char *slash = strrchr(program, '/');
+ const char *leaf = (slash ? slash + 1 : program);
+
+ return (BOOL) !strcmp(leaf, "setfont");
+}
+
+/*
+ * Here are the differences in options which affect lynx:
+ */
+#define setfont_u() (isSetFont() ? "-u " : "--sfm ")
+#define setfont_o() (isSetFont() ? "-o " : "--old-font-raw ")
+#define setfont_ou() (isSetFont() ? "-ou " : "--old-sfm ")
+#define console_font() (isSetFont() ? "" : "--font ")
+
+/*
+ * call_setfont - execute "setfont" command via system()
+ * returns: 0 ok (as far as we know)
+ * -1 error (assume font and umap are not loaded)
+ * 1 error with umap (assume font loaded but umap empty)
+ */
+static int call_setfont(const char *font,
+ const char *fnsuffix,
+ const char *umap)
+{
+ const char *program = GetSetfontPath();
+ char *T_setfont_cmd = NULL;
+ int rv;
+
+ /*
+ * console-data package has only a few unicode maps.
+ */
+ if (!isSetFont())
+ umap = 0;
+
+ if ((font && T_font_fn && !strcmp(font, T_font_fn))
+ && (umap && T_umap_fn && !strcmp(umap, T_umap_fn))) {
+ /*
+ * No need to repeat.
+ */
+ return 0;
+ }
+ if (font)
+ StrAllocCopy(T_font_fn, font);
+ if (umap)
+ StrAllocCopy(T_umap_fn, umap);
+
+ if (!*fnsuffix)
+ fnsuffix = "";
+
+ if (non_empty(umap) && non_empty(font)) {
+ HTSprintf0(&T_setfont_cmd, "%s %s%s%s %s%s %s",
+ program,
+ console_font(), font, fnsuffix,
+ setfont_u(), umap,
+ NOOUTPUT);
+ } else if (non_empty(font)) {
+ HTSprintf0(&T_setfont_cmd, "%s %s%s%s %s",
+ program,
+ console_font(), font, fnsuffix,
+ NOOUTPUT);
+ } else if (non_empty(umap)) {
+ HTSprintf0(&T_setfont_cmd, "%s %s%s %s",
+ program,
+ setfont_u(), umap,
+ NOOUTPUT);
+ }
+
+ if (T_setfont_cmd) {
+ CTRACE((tfp, "Changing font: '%s'\n", T_setfont_cmd));
+ rv = LYSystem(T_setfont_cmd);
+ FREE(T_setfont_cmd);
+ if (rv) {
+ CTRACE((tfp, "call_setfont: system returned %d (0x%x)!\n",
+ rv, (unsigned) rv));
+ if (rv == -1 || WIFSIGNALED(rv) || !WIFEXITED(rv)) {
+ return -1;
+ } else if ((WEXITSTATUS(rv) == EX_DATAERR ||
+ WEXITSTATUS(rv) == EX_NOINPUT) &&
+ non_empty(umap)) {
+ /*
+ * Check if the font was loaded ok but something was wrong with
+ * the umap file.
+ */
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void write_esc(const char *p)
+{
+ int fd = open("/dev/tty", O_WRONLY);
+
+ if (fd >= 0) {
+ IGNORE_RC(write(fd, p, strlen(p)));
+ close(fd);
+ }
+}
+
+static int nonempty_file(const char *p)
+{
+ struct stat sb;
+
+ return (stat(p, &sb) == 0 &&
+ S_ISREG(sb.st_mode) &&
+ (sb.st_size != 0));
+}
+
+static BOOL on_console(void)
+{
+ if ((non_empty(x_display)) ||
+ LYgetXDisplay() != NULL) {
+ /*
+ * We won't do anything in an xterm. Better that way...
+ */
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * This is the thing that actually gets called from display_page().
+ */
+void UCChangeTerminalCodepage(int newcs,
+ LYUCcharset *p)
+{
+ const char *program = GetSetfontPath();
+ static int lastcs = -1;
+ static const char *lastname = NULL;
+ static TTransT_t lastTransT = GN_dunno;
+ static TGen_state_t lastUtf = Dunno;
+ static TGen_state_t lastHasUmap = Dunno;
+
+ static char *old_font = NULL;
+ static char *old_umap = NULL;
+
+ const char *name;
+ TTransT_t TransT = GN_dunno;
+ TGen_state_t Utf = Dunno;
+ TGen_state_t HasUmap = Dunno;
+
+ char *tmpbuf1 = NULL;
+ char *tmpbuf2 = NULL;
+ int status = 0;
+
+ if (!on_console())
+ return;
+
+#ifdef HAVE_USE_LEGACY_CODING
+ if (newcs < 0) {
+ use_legacy_coding(original_coding);
+ } else {
+ original_coding = use_legacy_coding(2);
+ }
+#endif
+
+ /*
+ * Restore the original character set.
+ */
+ if (newcs < 0 || p == 0) {
+ if (non_empty(old_font) &&
+ non_empty(old_umap)) {
+
+ if (nonempty_file(old_font)) {
+ if (nonempty_file(old_umap)) {
+ HTSprintf0(&tmpbuf1, "%s %s%s %s%s %s",
+ program,
+ console_font(), old_font,
+ setfont_u(), old_umap,
+ NOOUTPUT);
+ } else {
+ HTSprintf0(&tmpbuf1, "%s %s%s %s",
+ program,
+ console_font(), old_font,
+ NOOUTPUT);
+ }
+ CTRACE((tfp, "Restoring font: '%s'\n", tmpbuf1));
+ status = LYSystem(tmpbuf1);
+ if (status != 0) {
+ CTRACE((tfp, "...system returned %d (0x%x)\n", status,
+ (unsigned) status));
+ }
+ FREE(tmpbuf1);
+ }
+ }
+ if (newcs < 0 && p == 0) {
+ if (old_font) {
+ (void) LYRemoveTemp(old_font);
+ FREE(old_font);
+ }
+ if (old_umap) {
+ (void) LYRemoveTemp(old_umap);
+ FREE(old_umap);
+ }
+ if (status == 0) {
+ FREE(T_font_fn);
+ FREE(T_umap_fn);
+ }
+ }
+ return;
+ } else if (lastcs < 0 && old_umap == 0 && old_font == 0) {
+ FILE *fp1;
+ FILE *fp2 = NULL;
+
+ if ((old_font = typecallocn(char, LY_MAXPATH)) != 0)
+ old_umap = typecallocn(char, LY_MAXPATH);
+
+ if (old_font == NULL)
+ outofmem(__FILE__, "UCChangeTerminalCodepage");
+
+ if ((fp1 = LYOpenTemp(old_font, ".fnt", BIN_W)) != 0)
+ fp2 = LYOpenTemp(old_umap, ".uni", BIN_W);
+
+ if (fp1 && fp2) {
+ size_t nlen;
+ int rv;
+
+ HTSprintf0(&tmpbuf1, "%s %s%s %s%s %s",
+ program,
+ setfont_o(), old_font,
+ setfont_ou(), old_umap,
+ NOOUTPUT);
+
+ CTRACE((tfp, "Saving font: '%s'\n", tmpbuf1));
+ rv = LYSystem(tmpbuf1);
+ if (rv != 0) {
+ CTRACE((tfp, "...system returned %d (0x%x)\n", rv, (unsigned) rv));
+ }
+ FREE(tmpbuf1);
+ LYCloseTempFP(fp1);
+ LYCloseTempFP(fp2);
+
+ /* free up a few bytes */
+ if ((nlen = strlen(old_font) + 1) < LY_MAXPATH)
+ old_font = typeRealloc(char, old_font, nlen);
+
+ if ((nlen = strlen(old_umap) + 1) < LY_MAXPATH)
+ old_umap = typeRealloc(char, old_umap, nlen);
+ } else {
+ if (fp1)
+ (void) LYRemoveTemp(old_font);
+ FREE(old_font);
+ FREE(old_umap);
+ }
+ }
+
+ name = p->MIMEname;
+
+ /*
+ * Font sizes are currently hardwired here.
+ */
+#define SUFF1 ".f16"
+#define SUFF2 "-16.psf"
+#define SUFF3 "-8x16"
+#define SUFF4 "8x16"
+#define SUFF5 ".cp -16"
+#define SUFF6 "_8x16"
+
+ /* NOTE: `!!umap not in kbd!!' comments below means that the *.uni file
+ * is not found in kbd package. Reference Debian Package: kbd-data,
+ * Version: 0.96a-14. They should be located elsewhere or generated.
+ * Also some cpNNN fonts used below are not in the kbd-data. - kw
+ */
+
+ if (!StrNCmp(name, "iso-8859-1", 10) &&
+ (!name[10] || !isdigit(UCH(name[10])))) {
+ if ((lastHasUmap == Is_Set) && !strcmp(lastname, "cp850")) {
+ /*
+ * cp850 already contains all latin1 characters.
+ */
+ if (lastTransT != GN_Blat1) {
+ TransT = GN_Blat1;
+ }
+ } else {
+ /*
+ * "setfont lat1u-16.psf -u lat1u.uni"
+ */
+ status = call_setfont("lat1u", SUFF2, "lat1u.uni");
+ HasUmap = Is_Set;
+ if (lastTransT != GN_Blat1) {
+ TransT = GN_Blat1;
+ }
+ }
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "iso-8859-2")) {
+ /*
+ * "setfont iso02.f16 -u iso02.uni"
+ */
+ status = call_setfont("iso02", SUFF1, "iso02.uni");
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "iso-8859-15")) {
+ /*
+ * "setfont lat0-16.psf"
+ */
+ status = call_setfont("lat0", SUFF2, NULL);
+ TransT = GN_Blat1; /* bogus! */
+ HasUmap = Dunno; /* distributed lat0 files have bogus map data! */
+ Utf = Is_Unset;
+ } else if (!StrNCmp(name, "iso-8859-", 9)) {
+ if (strlen(name) <= 10 || !isdigit(UCH(name[10])))
+ HTSprintf0(&tmpbuf1, "iso0%s", &name[9]);
+ else
+ HTSprintf0(&tmpbuf1, "iso%s", &name[9]);
+ HTSprintf0(&tmpbuf2, "%s.uni", tmpbuf1);
+ /*
+ * "setfont iso0N.f16 -u iso0N.uni"
+ */
+ status = call_setfont(tmpbuf1, SUFF1, tmpbuf2);
+ FREE(tmpbuf1);
+ FREE(tmpbuf2);
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "koi8-r")) {
+ /*
+ * "setfont koi8-8x16"
+ * !!umap not in kbd!!
+ */
+ status = call_setfont("koi8", SUFF3, "koi8r.uni");
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "koi8-u")) {
+ /*
+ * "setfont koi8u_8x16"
+ * !!umap not in kbd!!
+ */
+ status = call_setfont("koi8u", SUFF6, "koi8u.uni");
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "cp437")) {
+ /*
+ * "setfont default8x16 -u cp437.uni"
+ */
+ status = call_setfont("default", SUFF4, "cp437.uni");
+ if (lastTransT == GN_Kuser || lastTransT == GN_Ucp437)
+ TransT = GN_dontCare;
+ else
+ TransT = GN_Ucp437;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "cp850")) {
+ /*
+ * "setfont cp850-8x16 -u cp850.uni"
+ * !!umap not in kbd!!
+ */
+ status = call_setfont("cp850", SUFF3, "cp850.uni");
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "cp866") ||
+ !strcmp(name, "cp852") ||
+ !strcmp(name, "cp862")) { /* MS-Kermit has these files */
+ HTSprintf0(&tmpbuf2, "%s.uni", name);
+ /*
+ * "setfont cpNNN.f16"
+ * !!umap not in kbd!!
+ */
+ status = call_setfont(name, SUFF1, tmpbuf2);
+ FREE(tmpbuf2);
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "cp737")) {
+ /*
+ * "setfont cp737.cp"
+ * !!umap not in kbd!!
+ */
+ if (isSetFont()) {
+ status = call_setfont("737", SUFF5, "cp737.uni");
+ } else {
+ status = call_setfont("greek", "", "cp737.uni");
+ }
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "cp857")) {
+ status = call_setfont("cp857", SUFF3, "cp857.uni");
+ TransT = GN_Kuser;
+ HasUmap = Is_Set;
+ Utf = Is_Unset;
+ } else if (!strcmp(name, "x-transparent")) {
+ Utf = Dont_Care;
+ } else if (!strcmp(name, "us-ascii")) {
+ Utf = Dont_Care;
+ } else if (!StrNCmp(name, "mnem", 4)) {
+ Utf = Dont_Care;
+ }
+
+ if (status == 1)
+ HasUmap = Is_Unset;
+ else if (status < 0) {
+ if (HasUmap == Is_Set)
+ HasUmap = Dunno;
+ name = "unknown-8bit";
+ }
+
+ if (TransT != lastTransT) {
+ if (TransT == GN_Blat1) {
+ /*
+ * Switch Linux console to lat1 table.
+ */
+ write_esc("\033(B");
+ } else if (TransT == GN_Ucp437) {
+ /*
+ * Switch Linux console to 437 table?
+ */
+ write_esc("\033(U");
+ } else if (TransT == GN_Kuser) {
+ /*
+ * Switch Linux console to user table.
+ */
+ write_esc("\033(K");
+ }
+ if (TransT != GN_dunno && TransT != GN_dontCare) {
+ lastTransT = TransT;
+ }
+ }
+
+ if (HasUmap != Dont_Care && HasUmap != Dunno)
+ lastHasUmap = HasUmap;
+
+ if (p->enc == UCT_ENC_UTF8) {
+ if (lastUtf != Is_Set) {
+ Utf = Is_Set;
+ /*
+ * Turn Linux console UTF8 mode ON.
+ */
+ write_esc("\033%G");
+ lastUtf = Utf;
+ }
+ return;
+ } else if (lastUtf == Is_Set && Utf != Dont_Care) {
+ Utf = Is_Unset;
+ /*
+ * Turn Linux console UTF8 mode OFF.
+ */
+ write_esc("\033%@");
+ lastUtf = Utf;
+ }
+
+ if (Utf != Dont_Care && Utf != Dunno)
+ lastUtf = Utf;
+
+ lastcs = newcs;
+ lastname = name;
+}
+
+#else /* Not LINUX: */
+/*
+ * This is the thing that actually gets called from display_page().
+ */
+void UCChangeTerminalCodepage(int newcs,
+ LYUCcharset *p)
+{
+#ifdef __EMX__
+ int res = 0;
+
+#ifdef HAVE_USE_LEGACY_CODING
+ if (newcs < 0) {
+ use_legacy_coding(original_coding);
+ } else {
+ original_coding = use_legacy_coding(2);
+ }
+#endif
+
+ if (newcs < 0)
+ newcs = auto_display_charset;
+ res = Switch_Display_Charset(newcs, SWITCH_DISPLAY_CHARSET_REALLY);
+ CTRACE((tfp,
+ "UCChangeTerminalCodepage: Switch_Display_Charset(%d) returned %d\n",
+ newcs, res));
+#else
+ CTRACE((tfp, "UCChangeTerminalCodepage: Called, but not implemented!"));
+#endif
+}
+#endif /* LINUX */
+
+#ifdef CAN_SWITCH_DISPLAY_CHARSET
+
+int Find_Best_Display_Charset(int ord)
+{
+ const char *name = LYCharSet_UC[ord].MIMEname;
+ char *s = charset_switch_rules, *r;
+ char buf[160];
+ static int lowercase;
+ int n = strlen(name), source = 1;
+
+ if (!s || !n)
+ return ord;
+ if (!lowercase++)
+ LYLowerCase(charset_switch_rules);
+ while (1) {
+ while (*s && StrChr(" \t,", *s))
+ s++; /* Go to start of a name or ':' */
+ if (!*s && source)
+ return ord; /* OK to find nothing */
+ if (!*s) {
+ sprintf(buf,
+ gettext("No destination for '%.80s' in CHARSET_SWITCH_RULES"),
+ name);
+ HTInfoMsg(buf);
+ return ord;
+ }
+ if (*s == ':') {
+ /* Before the replacement name */
+ while (*s && StrChr(" \t:", *s))
+ s++; /* Go to the replacement */
+ /* At start of the replacement name */
+ r = s;
+ while (*s && !StrChr(" \t,:", *s))
+ s++; /* Skip the replacement */
+ if (source)
+ continue;
+ break;
+ }
+ /* At start of the source name */
+ if (source && !strncasecomp(name, s, n) && StrChr(" \t,", s[n])) { /* Found! */
+ source = 0;
+ s += n;
+ continue; /* Look for the replacement */
+ }
+ while (*s && !StrChr(" \t,:", *s))
+ s++; /* Skip the other source names */
+ }
+ /* Here r point to the replacement, s to the end of the replacement. */
+ if (s >= r + sizeof(buf)) {
+ HTInfoMsg(gettext("Charset name in CHARSET_SWITCH_RULES too long"));
+ return ord;
+ }
+ LYStrNCpy(buf, r, s - r);
+ n = UCGetLYhndl_byMIME(buf);
+ if (n < 0) {
+ sprintf(buf,
+ gettext("Unknown charset name '%.*s' in CHARSET_SWITCH_RULES"),
+ s - r, r);
+ HTInfoMsg(buf);
+ return ord;
+ }
+ return n;
+}
+
+# ifdef __EMX__
+/* Switch display for the best fit for LYCharSet_UC[ord].
+ If really is MAYBE, the switch is tentative only, another switch may happen
+ before the actual display.
+
+ Returns the charset we switched to. */
+static int _Switch_Display_Charset(int ord, enum switch_display_charset_t really)
+{
+ const char *name;
+ unsigned short cp;
+ static int font_loaded_for = -1, old_h, old_w;
+ int rc, ord1;
+ UCHAR msgbuf[MAXPATHLEN + 80];
+
+ CTRACE((tfp, "_Switch_Display_Charset(cp=%d, really=%d).\n", ord, really));
+ /* Do not trust current_char_set unless REALLY, we fake it if MAYBE! */
+ if (ord == current_char_set && really == SWITCH_DISPLAY_CHARSET_MAYBE)
+ return ord;
+ if (ord == auto_other_display_charset
+ || ord == auto_display_charset || ord == font_loaded_for) {
+ if (really == SWITCH_DISPLAY_CHARSET_MAYBE)
+ return ord; /* Report success, to avoid flicker, switch later */
+ } else /* Currently supports only koi8-r to cp866 translation */
+ ord = Find_Best_Display_Charset(ord);
+
+ /* Ignore sizechange unless the font is loaded */
+ if (ord != font_loaded_for && really == SWITCH_DISPLAY_CHARSET_RESIZE)
+ return ord;
+
+ if (ord == real_charsets[0] || ord == real_charsets[1]) {
+ ord1 = (ord == real_charsets[1]
+ ? auto_other_display_charset : auto_display_charset);
+ if (really == SWITCH_DISPLAY_CHARSET_MAYBE)
+ return ord; /* Can switch later, report success to avoid flicker */
+ } else
+ ord1 = ord;
+ if (ord == current_char_set && really == SWITCH_DISPLAY_CHARSET_MAYBE)
+ return ord;
+
+ name = LYCharSet_UC[ord1].MIMEname;
+ if (ord1 == auto_other_display_charset || ord1 == auto_display_charset) {
+ retry:
+ rc = VioSetCp(0, codepages[ord1 == auto_other_display_charset], 0);
+ if (rc == 0)
+ goto report;
+ err:
+ sprintf(msgbuf, gettext("Can't change to '%s': err=%#x=%d"), name, rc, rc);
+ HTInfoMsg(msgbuf);
+ return -1;
+ }
+
+ /* Not a "prepared" codepage. Need to load the user font. */
+ if (charsets_directory) {
+ TIB *tib; /* Can't load font in a windowed-VIO */
+ PIB *pib;
+ VIOFONTINFO f[2];
+ VIOFONTINFO *font;
+ UCHAR b[1 << 17];
+ UCHAR *buf = b;
+ UCHAR fnamebuf[MAXPATHLEN];
+ FILE *file;
+ APIRET rc;
+ long i, j;
+
+ /* 0 means a FS protected-mode session */
+ if (font_loaded_for == -1 /* Did not try it yet */
+ && (DosGetInfoBlocks(&tib, &pib) || pib->pib_ultype != 0)) {
+ ord = ord1 = auto_display_charset;
+ goto retry;
+ }
+ /* Should not cross 64K boundaries: */
+ font = f;
+ if (((((ULONG) (char *) f) + sizeof(*font)) & 0xFFFF) < sizeof(*font))
+ font++;
+ if (((ULONG) buf) & 0xFFFF)
+ buf += 0x10000 - (((ULONG) buf) & 0xFFFF);
+ font->cb = sizeof(*font); /* How large is this structure */
+ font->type = 0; /* Not the BIOS, the loaded font. */
+ font->cbData = 65535; /* How large is my buffer? */
+ font->pbData = _emx_32to16(buf); /* Wants an 16:16 pointer */
+
+ rc = VioGetFont(font, 0); /* Retrieve data for current font */
+ if (rc) {
+ sprintf(msgbuf,
+ gettext("Can't fetch current font info: err=%#x=%d"), rc, rc);
+ HTInfoMsg(msgbuf);
+ ord = ord1 = auto_display_charset;
+ goto retry;
+ }
+ if (ord1 == font_loaded_for
+ && old_h == font->cyCell && old_w == font->cxCell) {
+ /* The same as the previous font */
+ if ((rc = VioSetCp(0, -1, 0))) /* -1: User font */
+ goto err;
+ goto report;
+ }
+ sprintf(fnamebuf, "%s/%dx%d/%s.fnt",
+ charsets_directory, font->cyCell, font->cxCell, name);
+ file = fopen(fnamebuf, BIN_R);
+ if (!file) {
+ sprintf(msgbuf, gettext("Can't open font file '%s'"), fnamebuf);
+ HTInfoMsg(msgbuf);
+ ord = ord1 = auto_display_charset;
+ goto retry;
+ }
+ i = ftell(file);
+ fseek(file, 0, SEEK_END);
+ if (ftell(file) - i != font->cbData) {
+ fclose(file);
+ sprintf(msgbuf, gettext("Mismatch of size of font file '%s'"), fnamebuf);
+ HTAlert(msgbuf);
+ ord = ord1 = auto_display_charset;
+ goto retry;
+ }
+ fseek(file, i, SEEK_SET);
+ fread(buf, 1, font->cbData, file);
+ fclose(file);
+ rc = VioSetFont(font, 0); /* Put it all back.. */
+ if (rc) {
+ sprintf(msgbuf, gettext("Can't set font: err=%#x=%d"), rc, rc);
+ HTInfoMsg(msgbuf);
+ ord = ord1 = auto_display_charset;
+ font_loaded_for = -1;
+ goto retry;
+ }
+ font_loaded_for = ord1;
+ old_h = font->cyCell;
+ old_w = font->cxCell;
+ } else {
+ ord = ord1 = auto_display_charset;
+ goto retry;
+ }
+ report:
+ CTRACE((tfp, "Display font set to '%s'.\n", name));
+ return ord;
+}
+# endif /* __EMX__ */
+
+int Switch_Display_Charset(const int ord, const enum switch_display_charset_t really)
+{
+ int prev = current_char_set;
+ int res;
+ static int repeated;
+
+ if (!switch_display_charsets)
+ return 0;
+ res = _Switch_Display_Charset(ord, really);
+ if (res < 0 || prev == res) /* No change */
+ return 0;
+ /* Register the change */
+ current_char_set = res;
+ HTMLUseCharacterSet(current_char_set);
+ return 1;
+}
+#endif /* CAN_SWITCH_DISPLAY_CHARSET */
+
+#else /* EXP_CHARTRANS_AUTOSWITCH not defined: */
+/*
+ * This is the thing that actually gets called from display_page().
+ */
+void UCChangeTerminalCodepage(int newcs GCC_UNUSED,
+ LYUCcharset *p GCC_UNUSED)
+{
+ CTRACE((tfp, "UCChangeTerminalCodepage: Called, but not implemented!"));
+}
+#endif /* EXP_CHARTRANS_AUTOSWITCH */