ab0d6608640f53de360468c04efb688f8faedfa2
[platform/upstream/kbd.git] / src / setfont.c
1 /*
2  * setfont.c - Eugene Crosser & Andries Brouwer
3  *
4  * Version 1.05
5  *
6  * Loads the console font, and possibly the corresponding screen map(s).
7  * We accept two kind of screen maps, one [-m] giving the correspondence
8  * between some arbitrary 8-bit character set currently in use and the
9  * font positions, and the second [-u] giving the correspondence between
10  * font positions and Unicode values.
11  */
12
13 #include <stdio.h>
14 #include <memory.h>
15 #include <fcntl.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/ioctl.h>
22 #include <sys/kd.h>
23 #include <endian.h>
24 #include <sysexits.h>
25 #include "paths.h"
26 #include "getfd.h"
27 #include "findfile.h"
28 #include "loadunimap.h"
29 #include "psf.h"
30 #include "psffontop.h"
31 #include "kdfontop.h"
32 #include "kdmapop.h"
33 #include "xmalloc.h"
34 #include "nls.h"
35 #include "version.h"
36
37 static int position_codepage(int iunit);
38 static void saveoldfont(int fd, char *ofil);
39 static void saveoldfontplusunicodemap(int fd, char *Ofil);
40 static void loadnewfont(int fd, char *ifil,
41                         int iunit, int hwunit, int no_m, int no_u);
42 static void loadnewfonts(int fd, char **ifiles, int ifilct,
43                         int iunit, int hwunit, int no_m, int no_u);
44 extern void saveoldmap(int fd, char *omfil);
45 extern void loadnewmap(int fd, char *mfil);
46 extern void activatemap(void);
47 extern void disactivatemap(void);
48
49 int verbose = 0;
50 int force = 0;
51
52 /* search for the font in these directories (with trailing /) */
53 char *fontdirpath[] = { "", DATADIR "/" FONTDIR "/", 0 };
54 char *fontsuffixes[] = { "", ".psfu", ".psf", ".cp", ".fnt", 0 };
55 /* hide partial fonts a bit - loading a single one is a bad idea */
56 char *partfontdirpath[] = { "", DATADIR "/" FONTDIR "/" PARTIALDIR "/", 0 };
57 char *partfontsuffixes[] = { "", 0 };
58
59 static inline FILE*
60 findfont(char *fnam) {
61     return findfile(fnam, fontdirpath, fontsuffixes);
62 }
63
64 static inline FILE*
65 findpartialfont(char *fnam) {
66     return findfile(fnam, partfontdirpath, partfontsuffixes);
67 }
68
69 static void
70 usage(void)
71 {
72         fprintf(stderr, _(
73 "Usage: setfont [write-options] [-<N>] [newfont..] [-m consolemap] [-u unicodemap]\n"
74 "  write-options (take place before file loading):\n"
75 "    -o  <filename>     Write current font to <filename>\n"
76 "    -O  <filename>     Write current font and unicode map to <filename>\n"
77 "    -om <filename>     Write current consolemap to <filename>\n"
78 "    -ou <filename>     Write current unicodemap to <filename>\n"
79 "If no newfont and no -[o|O|om|ou|m|u] option is given,\n"
80 "a default font is loaded:\n"
81 "    setfont             Load font \"default[.gz]\"\n"
82 "    setfont -<N>        Load font \"default8x<N>[.gz]\"\n"
83 "The -<N> option selects a font from a codepage that contains three fonts:\n"
84 "    setfont -{8|14|16} codepage.cp[.gz]   Load 8x<N> font from codepage.cp\n"
85 "Explicitly (with -m or -u) or implicitly (in the fontfile) given mappings\n"
86 "will be loaded and, in the case of consolemaps, activated.\n"
87 "    -h<N>      (no space) Override font height.\n"
88 "    -m <fn>    Load console screen map.\n"
89 "    -u <fn>    Load font unicode map.\n"
90 "    -m none    Suppress loading and activation of a screen map.\n"
91 "    -u none    Suppress loading of a unicode map.\n"
92 "    -v         Be verbose.\n"
93 "    -V         Print version and exit.\n"
94 "Files are loaded from the current directory or /usr/lib/kbd/*/.\n"
95 ));
96         exit(EX_USAGE);
97 }
98
99 #define MAXIFILES 256
100
101 int
102 main(int argc, char *argv[]) {
103         char *ifiles[MAXIFILES];
104         char *mfil, *ufil, *Ofil, *ofil, *omfil, *oufil;
105         int ifilct = 0, fd, i, iunit, hwunit, no_m, no_u;
106         int restore = 0;
107
108         set_progname(argv[0]);
109
110         setlocale(LC_ALL, "");
111         bindtextdomain(PACKAGE, LOCALEDIR);
112         textdomain(PACKAGE);
113
114         fd = getfd();
115
116         ifiles[0] = mfil = ufil = Ofil = ofil = omfil = oufil = 0;
117         iunit = hwunit = 0;
118         no_m = no_u = 0;
119
120         for (i = 1; i < argc; i++) {
121             if (!strcmp(argv[i], "-V")) {
122                 print_version_and_exit();
123             } else if (!strcmp(argv[i], "-v")) {
124                 verbose++;
125             } else if (!strcmp(argv[i], "-R")) {
126                 restore = 1;
127             } else if (!strcmp(argv[i], "-O")) {
128                 if (++i == argc || Ofil)
129                   usage();
130                 Ofil = argv[i];
131             } else if (!strcmp(argv[i], "-o")) {
132                 if (++i == argc || ofil)
133                   usage();
134                 ofil = argv[i];
135             } else if (!strcmp(argv[i], "-om")) {
136                 if (++i == argc || omfil)
137                   usage();
138                 omfil = argv[i];
139             } else if (!strcmp(argv[i], "-ou")) {
140                 if (++i == argc || oufil)
141                   usage();
142                 oufil = argv[i];
143             } else if (!strcmp(argv[i], "-m")) {
144                 if (++i == argc || mfil)
145                   usage();
146                 if (!strcmp(argv[i], "none"))
147                   no_m = 1;
148                 else
149                   mfil = argv[i];
150             } else if (!strcmp(argv[i], "-u")) {
151                 if (++i == argc || ufil)
152                   usage();
153                 if (!strcmp(argv[i], "none"))
154                   no_u = 1;
155                 else
156                   ufil = argv[i];
157             } else if (!strcmp(argv[i], "-f")) {
158                 force = 1;
159             } else if (!strncmp(argv[i], "-h", 2)) {
160                 hwunit = atoi(argv[i]+2);
161                 if (hwunit <= 0 || hwunit > 32)
162                   usage();
163             } else if (argv[i][0] == '-') {
164                 iunit = atoi(argv[i]+1);
165                 if(iunit <= 0 || iunit > 32)
166                   usage();
167             } else {
168                 if (ifilct == MAXIFILES) {
169                     fprintf(stderr, _("setfont: too many input files\n"));
170                     exit(EX_USAGE);
171                 }
172                 ifiles[ifilct++] = argv[i];
173             }
174         }
175
176         if (ifilct && restore) {
177             fprintf(stderr, _("setfont: cannot both restore from character ROM"
178                               " and from file. Font unchanged.\n"));
179             exit(EX_USAGE);
180         }
181
182         if (!ifilct && !mfil && !ufil &&
183             !Ofil && !ofil && !omfil && !oufil && !restore)
184           /* reset to some default */
185           ifiles[ifilct++] = "";
186
187         if (Ofil)
188           saveoldfontplusunicodemap(fd, Ofil);
189
190         if (ofil)
191           saveoldfont(fd, ofil);
192
193         if (omfil)
194           saveoldmap(fd, omfil);
195
196         if (oufil)
197           saveunicodemap(fd, oufil);
198
199         if (mfil) {
200             loadnewmap(fd, mfil);
201             activatemap();
202             no_m = 1;
203         }
204
205         if (ufil)
206           no_u = 1;
207
208         if (restore)
209           restorefont(fd);
210
211         if (ifilct)
212           loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u);
213
214         if (ufil)
215           loadunicodemap(fd, ufil);
216
217         return 0;
218 }
219
220 /*
221  * 0 - do not test, 1 - test and warn, 2 - test and wipe, 3 - refuse
222  */
223 static int erase_mode = 1;
224
225 static void
226 do_loadfont(int fd, char *inbuf, int width, int height, int hwunit,
227             int fontsize, char *pathname) {
228         char *buf;
229         int i, buflen;
230         int bytewidth = (width+7)/8;
231         int charsize = height * bytewidth;
232         int kcharsize = 32 * bytewidth;
233         int bad_video_erase_char = 0;
234
235         if (height < 1 || height > 32) {
236                 fprintf(stderr, _("Bad character height %d\n"), height);
237                 exit(EX_DATAERR);
238         }
239         if (width < 1 || width > 32) {
240                 fprintf(stderr, _("Bad character width %d\n"), width);
241                 exit(EX_DATAERR);
242         }
243
244         if (!hwunit)
245                 hwunit = height;
246
247         buflen = kcharsize * ((fontsize < 128) ? 128 : fontsize);
248         buf = xmalloc(buflen);
249         memset(buf,0,buflen);
250
251         for (i = 0; i < fontsize; i++)
252                 memcpy(buf+(i*kcharsize), inbuf+(i*charsize), charsize);
253
254         /*
255          * Due to a kernel bug, font position 32 is used
256          * to erase the screen, regardless of maps loaded.
257          * So, usually this font position should be blank.
258          */
259         if (erase_mode) {
260                 for (i = 0; i < kcharsize; i++)
261                         if (buf[32*kcharsize+i])
262                                 bad_video_erase_char = 1;
263                 if (bad_video_erase_char) {
264                         fprintf(stderr,
265                                 _("%s: font position 32 is nonblank\n"),
266                                 progname);
267                         switch(erase_mode) {
268                         case 3:
269                                 exit(EX_DATAERR);
270                         case 2:
271                                 for (i = 0; i < kcharsize; i++)
272                                         buf[32*kcharsize+i] = 0;
273                                 fprintf(stderr, _("%s: wiped it\n"), progname);
274                                 break;
275                         case 1:
276                                 fprintf(stderr,
277                                         _("%s: background will look funny\n"),
278                                         progname);
279                         }
280                         fflush(stderr);
281                         sleep(2);
282                 }
283         }
284
285         if (verbose) {
286                 if (height == hwunit && pathname)
287                         printf(_("Loading %d-char %dx%d font from file %s\n"),
288                                fontsize, width, height, pathname);
289                 else if (height == hwunit)
290                         printf(_("Loading %d-char %dx%d font\n"),
291                                fontsize, width, height);
292                 else if (pathname)
293                         printf(_("Loading %d-char %dx%d (%d) font from file %s\n"),
294                                fontsize, width, height, hwunit, pathname);
295                 else
296                         printf(_("Loading %d-char %dx%d (%d) font\n"),
297                                fontsize, width, height, hwunit);
298         }
299
300         if (putfont(fd, buf, fontsize, width, hwunit))
301                 exit(EX_OSERR);
302 }
303
304 static void
305 do_loadtable(int fd, struct unicode_list *uclistheads, int fontsize) {
306         struct unimapdesc ud;
307         struct unipair *up;
308         int i, ct = 0, maxct;
309         struct unicode_list *ul;
310         struct unicode_seq *us;
311
312         maxct = 0;
313         for (i = 0; i < fontsize; i++) {
314                 ul = uclistheads[i].next;
315                 while(ul) {
316                         us = ul->seq;
317                         if (us && ! us->next)
318                                 maxct++;
319                         ul = ul->next;
320                 }
321         }
322         up = xmalloc(maxct * sizeof(struct unipair));
323         for (i = 0; i < fontsize; i++) {
324                 ul = uclistheads[i].next;
325                 while(ul) {
326                         us = ul->seq;
327                         if (us && ! us->next) {
328                                 up[ct].unicode = us->uc;
329                                 up[ct].fontpos = i;
330                                 ct++;
331                         }
332                         ul = ul->next;
333                 }
334         }
335         if (ct != maxct) {
336                 char *u = _("%s: bug in do_loadtable\n");
337                 fprintf(stderr, u, progname);
338                 exit(EX_SOFTWARE);
339         }
340
341         if (verbose)
342           printf(_("Loading Unicode mapping table...\n"));
343
344         ud.entry_ct = ct;
345         ud.entries = up;
346         if (loadunimap(fd, NULL, &ud))
347                 exit(EX_OSERR);
348 }
349
350 static void
351 loadnewfonts(int fd, char **ifiles, int ifilct,
352              int iunit, int hwunit, int no_m, int no_u) {
353         FILE *fpi;
354         char *ifil, *inbuf, *fontbuf, *bigfontbuf;
355         int inputlth, fontbuflth, fontsize, height, width, bytewidth;
356         int bigfontbuflth, bigfontsize, bigheight, bigwidth;
357         struct unicode_list *uclistheads;
358         int i;
359
360         if (ifilct == 1) {
361                 loadnewfont(fd, ifiles[0], iunit, hwunit, no_m, no_u);
362                 return;
363         }
364
365         /* several fonts that must be merged */
366         /* We just concatenate the bitmaps - only allow psf fonts */
367         bigfontbuf = NULL;
368         bigfontbuflth = 0;
369         bigfontsize = 0;
370         uclistheads = NULL;
371         bigheight = 0;
372         bigwidth = 0;
373
374         for (i=0; i<ifilct; i++) {
375                 ifil = ifiles[i];
376                 if ((fpi = findfont(ifil)) == NULL &&
377                     (fpi = findpartialfont(ifil)) == NULL) {
378                         fprintf(stderr, _("Cannot open font file %s\n"), ifil);
379                         exit(EX_NOINPUT);
380                 }
381
382                 inbuf = fontbuf = NULL;
383                 inputlth = fontbuflth = 0;
384                 fontsize = 0;
385
386                 if(readpsffont(fpi, &inbuf, &inputlth, &fontbuf, &fontbuflth,
387                                &width, &fontsize, bigfontsize,
388                                no_u ? NULL : &uclistheads)) {
389                         fprintf(stderr, _("When loading several fonts, all "
390                                           "must be psf fonts - %s isn't\n"),
391                                 pathname);
392                         exit(EX_DATAERR);
393                 }
394                 bytewidth = (width+7) / 8;
395                 height = fontbuflth / (bytewidth * fontsize);
396                 if (verbose)
397                         printf(_("Read %d-char %dx%d font from file %s\n"),
398                                fontsize, width, height, pathname);
399
400                 if (bigheight == 0)
401                         bigheight = height;
402                 else if (bigheight != height) {
403                         fprintf(stderr, _("When loading several fonts, all "
404                                           "must have the same height\n"));
405                         exit(EX_DATAERR);
406                 }
407                 if (bigwidth == 0)
408                         bigwidth = width;
409                 else if (bigwidth != width) {
410                         fprintf(stderr, _("When loading several fonts, all "
411                                           "must have the same width\n"));
412                         exit(EX_DATAERR);
413                 }
414
415                 bigfontsize += fontsize;
416                 bigfontbuflth += fontbuflth;
417                 bigfontbuf = xrealloc(bigfontbuf, bigfontbuflth);
418                 memcpy(bigfontbuf+bigfontbuflth-fontbuflth,
419                        fontbuf, fontbuflth);
420         }
421         do_loadfont(fd, bigfontbuf, bigwidth, bigheight, hwunit,
422                     bigfontsize, NULL);
423
424         if (uclistheads && !no_u)
425                 do_loadtable(fd, uclistheads, bigfontsize);
426 }
427
428 static void
429 loadnewfont(int fd, char *ifil, int iunit, int hwunit, int no_m, int no_u) {
430         FILE *fpi;
431         char defname[20];
432         int height, width, bytewidth, def = 0;
433         char *inbuf, *fontbuf;
434         int inputlth, fontbuflth, fontsize, offset;
435         struct unicode_list *uclistheads;
436
437         if (!*ifil) {
438                 /* try to find some default file */
439
440                 def = 1;                /* maybe also load default unimap */
441
442                 if (iunit < 0 || iunit > 32)
443                         iunit = 0;
444                 if (iunit == 0) {
445                         if ((fpi = findfont(ifil = "default")) == NULL &&
446                             (fpi = findfont(ifil = "default8x16")) == NULL &&
447                             (fpi = findfont(ifil = "default8x14")) == NULL &&
448                             (fpi = findfont(ifil = "default8x8")) == NULL) {
449                                 fprintf(stderr, _("Cannot find default font\n"));
450                                 exit(EX_NOINPUT);
451                         }
452                 } else {
453                         sprintf(defname, "default8x%d", iunit);
454                         if ((fpi = findfont(ifil = defname)) == NULL &&
455                             (fpi = findfont(ifil = "default")) == NULL) {
456                                 fprintf(stderr, _("Cannot find %s font\n"), ifil);
457                                 exit(EX_NOINPUT);
458                         }
459                 }
460         } else {
461                 if ((fpi = findfont(ifil)) == NULL) {
462                         fprintf(stderr, _("Cannot open font file %s\n"), ifil);
463                         exit(EX_NOINPUT);
464                 }
465         }
466
467         if (verbose > 1)
468                 printf(_("Reading font file %s\n"), ifil);
469
470         inbuf = fontbuf = NULL;
471         inputlth = fontbuflth = fontsize = 0;
472         width = 8;
473         uclistheads = NULL;
474         if(readpsffont(fpi, &inbuf, &inputlth, &fontbuf, &fontbuflth,
475                        &width, &fontsize, 0,
476                        no_u ? NULL : &uclistheads) == 0) {
477                 /* we've got a psf font */
478                 bytewidth = (width+7) / 8;
479                 height = fontbuflth / (bytewidth * fontsize);
480
481                 do_loadfont(fd, fontbuf, width, height, hwunit,
482                             fontsize, pathname);
483                 if (uclistheads && !no_u)
484                         do_loadtable(fd, uclistheads, fontsize);
485 #if 1
486                 if (!uclistheads && !no_u && def)
487                         loadunicodemap(fd, "def.uni");
488 #endif
489                 return;
490         }
491
492         /* instructions to combine fonts? */
493         { char *combineheader = "# combine partial fonts\n";
494           int chlth = strlen(combineheader);
495           char *p, *q;
496           if (inputlth >= chlth && !strncmp(inbuf, combineheader, chlth)) {
497                   char *ifiles[MAXIFILES];
498                   int ifilct = 0;
499                   q = inbuf + chlth;
500                   while(q < inbuf + inputlth) {
501                           p = q;
502                           while (q < inbuf+inputlth && *q != '\n')
503                                   q++;
504                           if (q == inbuf+inputlth) {
505                                   fprintf(stderr,
506                                           _("No final newline in combine file\n"));
507                                   exit(EX_DATAERR);
508                           }
509                           *q++ = 0;
510                           if (ifilct == MAXIFILES) {
511                                   fprintf(stderr,
512                                           _("Too many files to combine\n"));
513                                   exit(EX_DATAERR);
514                           }
515                           ifiles[ifilct++] = p;
516                   }
517                   /* recursive call */
518                   loadnewfonts(fd, ifiles, ifilct, iunit, hwunit, no_m, no_u);
519                   return;
520           }
521         }
522
523         /* file with three code pages? */
524         if (inputlth == 9780) {
525                 offset = position_codepage(iunit);
526                 height = iunit;
527                 fontsize = 256;
528                 width = 8;
529         } else if (inputlth == 32768) {
530                 /* restorefont -w writes a SVGA font to file
531                    restorefont -r restores it
532                    These fonts have size 32768, for two 512-char fonts.
533                    In fact, when BROKEN_GRAPHICS_PROGRAMS is defined,
534                    and it always is, there is no default font that is saved,
535                    so probably the second half is always garbage. */
536                 fprintf(stderr, _("Hmm - a font from restorefont? "
537                                   "Using the first half.\n"));
538                 inputlth = 16384;       /* ignore rest */
539                 fontsize = 512;
540                 offset = 0;
541                 width = 8;
542                 height = 32;
543                 if (!hwunit)
544                         hwunit = 16;
545         } else {
546                 int rem = (inputlth % 256);
547                 if (rem == 0 || rem == 40) {
548                         /* 0: bare code page bitmap */
549                         /* 40: preceded by .cp header */
550                         /* we might check some header details */
551                         offset = rem;
552                 } else {
553                         fprintf(stderr, _("Bad input file size\n"));
554                         exit(EX_DATAERR);
555                 }
556                 fontsize = 256;
557                 width = 8;
558                 height = inputlth/256;
559         }
560         do_loadfont(fd, inbuf+offset, width, height, hwunit, fontsize,
561                     pathname);
562 }
563
564 static int
565 position_codepage(int iunit) {
566         int offset;
567
568         /* code page: first 40 bytes, then 8x16 font,
569            then 6 bytes, then 8x14 font,
570            then 6 bytes, then 8x8 font */
571
572         if (!iunit) {
573             fprintf(stderr,
574                     _("This file contains 3 fonts: 8x8, 8x14 and 8x16."
575                       " Please indicate\n"
576                       "using an option -8 or -14 or -16 "
577                       "which one you want loaded.\n"));
578             exit(EX_USAGE);
579         }
580         switch (iunit) {
581           case 8:
582             offset = 7732; break;
583           case 14:
584             offset = 4142; break;
585           case 16:
586             offset = 40; break;
587           default:
588             fprintf(stderr, _("You asked for font size %d, "
589                               "but only 8, 14, 16 are possible here.\n"),
590                     iunit);
591             exit(EX_USAGE);
592         }
593         return offset;
594 }
595
596 static void
597 do_saveoldfont(int fd, char *ofil, FILE *fpo, int unimap_follows,
598                int *count, int *utf8) {
599
600 /* this is the max font size the kernel is willing to handle */
601 #define MAXFONTSIZE     65536
602         char buf[MAXFONTSIZE];
603
604         int i, ct, width, height, bytewidth, charsize, kcharsize;
605
606         ct = sizeof(buf)/(32*32/8);     /* max size 32x32, 8 bits/byte */
607         if (getfont(fd, buf, &ct, &width, &height))
608                 exit(EX_OSERR);
609
610         /* save as efficiently as possible */
611         bytewidth = (width + 7) / 8;
612         height = font_charheight(buf, ct, width);
613         charsize = height * bytewidth;
614         kcharsize = 32 * bytewidth;
615
616         /* Do we need a psf header? */
617         /* Yes if ct==512 - otherwise we cannot distinguish
618            a 512-char 8x8 and a 256-char 8x16 font. */
619 #define ALWAYS_PSF_HEADER       1
620
621         if (ct != 256 || width != 8 || unimap_follows || ALWAYS_PSF_HEADER) {
622                 int psftype = 1;
623                 int flags = 0;
624
625                 if (unimap_follows)
626                         flags |= WPSFH_HASTAB;
627                 writepsffontheader (fpo, width, height, ct, &psftype, flags);
628                 if (utf8)
629                         *utf8 = (psftype == 2);
630         }
631
632         if (height == 0) {
633                 fprintf(stderr, _("Found nothing to save\n"));
634         } else {
635                 for (i = 0; i < ct; i++) {
636                         if (fwrite(buf+(i*kcharsize), charsize, 1, fpo) != 1) {
637                                 fprintf(stderr, _("Cannot write font file"));
638                                 exit(EX_IOERR);
639                         }
640                 }
641                 if (verbose) {
642                         printf(_("Saved %d-char %dx%d font file on %s\n"),
643                                ct, width, height, ofil);
644                 }
645         }
646
647         if (count)
648                 *count = ct;
649 }
650
651 static void
652 saveoldfont(int fd, char *ofil) {
653     FILE *fpo;
654
655     if((fpo = fopen(ofil, "w")) == NULL) {
656         perror(ofil);
657         exit(EX_CANTCREAT);
658     }
659     do_saveoldfont(fd, ofil, fpo, 0, NULL, NULL);
660     fclose(fpo);
661 }
662
663 static void
664 saveoldfontplusunicodemap(int fd, char *Ofil) {
665     FILE *fpo;
666     int ct;
667     int utf8 = 0;
668
669     if((fpo = fopen(Ofil, "w")) == NULL) {
670         perror(Ofil);
671         exit(EX_CANTCREAT);
672     }
673     ct = 0;
674     do_saveoldfont(fd, Ofil, fpo, 1, &ct, &utf8);
675     appendunicodemap(fd, fpo, ct, utf8);
676     fclose(fpo);
677 }
678
679 /* Only on the current console? On all allocated consoles? */
680 /* A newly allocated console has NORM_MAP by default -
681    probably it should copy the default from the current console?
682    But what if we want a new one because the current one is messed up? */
683 /* For the moment: only the current console, only the G0 set */
684 void
685 activatemap(void) {
686     printf("\033(K");
687 }
688
689 void
690 disactivatemap(void) {
691     printf("\033(B");
692 }