/* ** 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 #include #include #include #include #include #include #include #ifdef EXP_CHARTRANS_AUTOSWITCH #ifdef LINUX typedef enum { Is_Unset, Is_Set, Dunno, Dont_Care } TGen_state_t; typedef enum { G0, G1 } TGNstate_t; typedef enum { GN_Blat1, GN_0decgraf, GN_Ucp437, GN_Kuser, GN_dunno, GN_dontCare } TTransT_t; static char *T_font_fn = NULL; static char *T_umap_fn = NULL; #define SETFONT "setfont" #define NOOUTPUT "2>/dev/null >/dev/null" /* * 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) */ PRIVATE int call_setfont ARGS3( CONST char *, font, CONST char *, fnsuffix, CONST char *, umap) { char *T_setfont_cmd = NULL; int rv; 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 (umap &&*umap && font && *font) { HTSprintf0(&T_setfont_cmd, "%s %s%s -u %s %s", SETFONT, font, fnsuffix, umap, NOOUTPUT); } else if (font && *font) { HTSprintf0(&T_setfont_cmd, "%s %s%s %s", SETFONT, font, fnsuffix, NOOUTPUT); } else if (umap && *umap) { HTSprintf0(&T_setfont_cmd, "%s -u %s %s", SETFONT, umap, NOOUTPUT); } if (T_setfont_cmd) { CTRACE((tfp, "Executing setfont: '%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, rv)); if ((rv == 0x4200 || rv == 0x4100) && umap && *umap) /* * It seems setfont returns 65 or 66 to the shell if * the font was loaded ok but something was wrong with * the umap file. - kw */ return 1; else return -1; } } return 0; } PRIVATE void write_esc ARGS1( CONST char *, p) { int fd = open("/dev/tty", O_WRONLY); if (fd >= 0) { write(fd, p, strlen(p)); close(fd); } } PRIVATE int nonempty_file ARGS1( CONST char *, p) { struct stat sb; return (stat(p, &sb) == 0 && S_ISREG(sb.st_mode) && (sb.st_size != 0)); } /* * This is the thing that actually gets called from display_page(). */ PUBLIC void UCChangeTerminalCodepage ARGS2( int, newcs, LYUCcharset *, p) { 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; /* * Restore the original character set. */ if (newcs < 0 || p == 0) { if (old_font && *old_font && old_umap && *old_umap) { int have_font = nonempty_file(old_font); int have_umap = nonempty_file(old_umap); if (have_font) { if (have_umap) { HTSprintf0(&tmpbuf1, "%s %s -u %s %s", SETFONT, old_font, old_umap, NOOUTPUT); } else { HTSprintf0(&tmpbuf1, "%s %s %s", SETFONT, old_font, NOOUTPUT); } CTRACE((tfp, "Executing setfont to restore: '%s'\n", tmpbuf1)); status = LYSystem(tmpbuf1); FREE(tmpbuf1); } } if (newcs < 0 && p == 0) { if (old_font) { LYRemoveTemp(old_font); FREE(old_font); } if (old_umap) { 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 = calloc(1, LY_MAXPATH))) old_umap = calloc(1, LY_MAXPATH); if ((fp1 = LYOpenTemp(old_font, ".fnt", "wb"))) fp2 = LYOpenTemp(old_umap, ".uni", "wb"); if (fp1 && fp2) { size_t nlen; char *rp; HTSprintf0(&tmpbuf1, "%s -o %s -ou %s %s", SETFONT, old_font, old_umap, NOOUTPUT); CTRACE((tfp, "Executing setfont to save: '%s'\n", tmpbuf1)); LYSystem(tmpbuf1); FREE(tmpbuf1); LYCloseTempFP(fp1); LYCloseTempFP(fp2); if ((nlen = strlen(old_font)) + 1 < LY_MAXPATH && (rp = realloc(old_font, nlen + 1))) old_font = rp; if ((nlen = strlen(old_umap)) + 1 < LY_MAXPATH && (rp = realloc(old_umap, nlen + 1))) old_umap = rp; } else { if (fp1) LYRemoveTemp(old_font); if (fp2) LYRemoveTemp(old_umap); 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" /* * Use this for output of escape sequences. */ if ((x_display != NULL) || LYgetXDisplay() != NULL) { /* * We won't do anything in an xterm. Better that way... */ return; } /* 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((unsigned char)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")) { #ifdef NOTDEFINED /* * "setfont lat2-16.psf -u lat2.uni" */ status = call_setfont("lat2", SUFF2, "lat2.uni"); #endif /* NOTDEFINED */ /* * "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((unsigned char)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" */ status = call_setfont("koi8", SUFF3, "koi8r.uni"); /* !!umap not in kbd!! */ 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" */ status = call_setfont("cp850", SUFF3, "cp850.uni"); /* !!umap not in kbd!! */ TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; } else if (!strcmp(name, "cp866") || !strcmp(name, "cp852") || #if 0 !strcmp(name, "cp861") || !strcmp(name, "cp850") || !strcmp(name, "cp437") || #endif !strcmp(name, "cp862")) { /* MS-Kermit has these files */ HTSprintf0(&tmpbuf2, "%s.uni", name); /* * "setfont cpNNN.f16" */ status = call_setfont(name, SUFF1, tmpbuf2); /* !!umap not in kbd!! */ FREE(tmpbuf2); TransT = GN_Kuser; HasUmap = Is_Set; Utf = Is_Unset; } else if (!strcmp(name, "cp737")) { /* * "setfont cp737.cp" */ status = call_setfont("737", SUFF5, "cp737.uni"); /* !!umap not in kbd!! */ 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_0decgraf) { write_esc("\033(0"); } 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; } else { TransT = lastTransT; } } 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(). */ PUBLIC void UCChangeTerminalCodepage ARGS2( int, newcs, LYUCcharset *, p) { #ifdef __EMX__ int res = 0; if (p->codepage > 0) { res = VioSetCp(0, p->codepage, 0); CTRACE((tfp, "UCChangeTerminalCodepage: VioSetCp(%d) returned %d\n", p->codepage, res)); } #else CTRACE((tfp, "UCChangeTerminalCodepage: Called, but not implemented!")); #endif } #endif /* LINUX */ #else /* EXP_CHARTRANS_AUTOSWITCH not defined: */ /* * This is the thing that actually gets called from display_page(). */ PUBLIC void UCChangeTerminalCodepage ARGS2( int, newcs GCC_UNUSED, LYUCcharset *, p GCC_UNUSED) { CTRACE((tfp, "UCChangeTerminalCodepage: Called, but not implemented!")); } #endif /* EXP_CHARTRANS_AUTOSWITCH */