Imported Upstream version 2.0.90
[platform/upstream/kbd.git] / src / mapscrn.c
index 323daf0..11739e4 100644 (file)
 /*
  * mapscrn.c
  */
+#include "config.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <memory.h>
 #include <string.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
-#include <sys/kd.h>
+#include <linux/kd.h>
+
+#include <kbdfile.h>
+
+#include "libcommon.h"
+
 #include "paths.h"
-#include "findfile.h"
-#include "nls.h"
+#include "kdmapop.h"
+#include "utf8.h"
 
 /* the two exported functions */
 void saveoldmap(int fd, char *omfil);
 void loadnewmap(int fd, char *mfil);
 
-static int parsemap (FILE *, char*);
-static int ctoi (unsigned char *);
+static int ctoi(char *);
 
 /* search for the map file in these directories (with trailing /) */
-static char *mapdirpath[] = { "", DATADIR "/" TRANSDIR "/", 0 };
-static char *mapsuffixes[] = { "", 0 };
+static const char *const mapdirpath[]  = { "", DATADIR "/" TRANSDIR "/", 0 };
+static const char *const mapsuffixes[] = { "", ".trans", "_to_uni.trans", ".acm", 0 };
 
 #ifdef MAIN
-#include "getfd.h"
-#include "version.h"
-
 int verbose = 0;
+int debug   = 0;
 
-int
-main(int argc, char *argv[]) {
+int main(int argc, char *argv[])
+{
        int fd;
 
        set_progname(argv[0]);
-
-       setlocale(LC_ALL, "");
-       bindtextdomain(PACKAGE, LOCALEDIR);
-       textdomain(PACKAGE);
+       setuplocale();
 
        if (argc == 2 && !strcmp(argv[1], "-V"))
-           print_version_and_exit();
+               print_version_and_exit();
+
+       if (argc > 1 && !strcmp(argv[1], "-v")) {
+               verbose = 1;
+               argc--;
+               argv++;
+       }
 
-       fd = getfd();
+       if ((fd = getfd(NULL)) < 0)
+               kbd_error(EXIT_FAILURE, 0, _("Couldn't get a file descriptor referring to the console"));
 
        if (argc >= 3 && !strcmp(argv[1], "-o")) {
-           saveoldmap(fd, argv[2]);
-           argc -= 2;
-           argv += 2;
-           if (argc == 1)
-             exit(0);
+               saveoldmap(fd, argv[2]);
+               argc -= 2;
+               argv += 2;
+               if (argc == 1)
+                       exit(EXIT_SUCCESS);
        }
-               
+
        if (argc != 2) {
-               fprintf(stderr, _("usage: %s [-o map.orig] map-file\n"),
-                       progname);
-               exit(1);
+               fprintf(stderr, _("usage: %s [-V] [-v] [-o map.orig] map-file\n"),
+                       get_progname());
+               exit(EXIT_FAILURE);
        }
        loadnewmap(fd, argv[1]);
-       exit(0);
+       exit(EXIT_SUCCESS);
 }
 #endif
 
-void
-loadnewmap(int fd, char *mfil) {
-       FILE *fp;
+/*
+ * Read two-column file (index, value) with index in 0-255
+ * and value in 0-65535. Acceptable representations:
+ * decimal (nnn), octal (0nnn), hexadecimal (0xnnn), Unicode (U+xxxx),
+ * character ('x').
+ * In the character encoding, x may be a single byte binary value
+ * (but not space, tab, comma, #) or a single Unicode value coded
+ * as a UTF-8 sequence.
+ *
+ * Store values in ubuf[], and small values also in buf[].
+ * Set u to 1 in case a value above 255 or a U+ occurs.
+ * Set lineno to line number of first error.
+ */
+static int
+parsemap(FILE *fp, char *buf, unsigned short *ubuf, int *u, int *lineno)
+{
+       char buffer[256];
+       int in, on, ln, ret = 0;
+       char *p, *q;
+
+       ln = 0;
+       while (fgets(buffer, sizeof(buffer) - 1, fp)) {
+               ln++;
+               if (!*u && strstr(buffer, "U+"))
+                       *u = 1;
+               p          = strtok(buffer, " \t\n");
+               if (p && *p != '#') {
+                       q = strtok(NULL, " \t\n#");
+                       if (q) {
+                               in = ctoi(p);
+                               on = ctoi(q);
+                               if (in >= 0 && in < 256 &&
+                                   on >= 0 && on < 65536) {
+                                       ubuf[in] = on;
+                                       if (on < 256)
+                                               buf[in] = on;
+                                       else
+                                               *u = 1;
+                               } else {
+                                       if (!ret)
+                                               *lineno = ln;
+                                       ret             = -1;
+                               }
+                       }
+               }
+       }
+       return ret;
+}
+
+static int
+readnewmapfromfile(char *mfil, char *buf, unsigned short *ubuf)
+{
        struct stat stbuf;
-       char buf[E_TABSZ];
-       int i;
+       int u      = 0;
+       int lineno = 0;
+       struct kbdfile *fp;
+
+       if ((fp = kbdfile_new(NULL)) == NULL)
+               nomem();
 
-       if ((fp = findfile(mfil, mapdirpath, mapsuffixes)) == NULL) {
-               fprintf(stderr, _("mapscrn: cannot open map file _%s_\n"),
-                       mfil);
+       if (kbdfile_find(mfil, mapdirpath, mapsuffixes, fp)) {
+               fprintf(stderr, _("mapscrn: cannot open map file _%s_\n"),
+                       mfil);
                exit(1);
        }
-       if (stat(pathname, &stbuf)) {
-               perror(pathname);
+       if (stat(kbdfile_get_pathname(fp), &stbuf)) {
+               perror(kbdfile_get_pathname(fp));
                fprintf(stderr, _("Cannot stat map file"));
                exit(1);
        }
-       if (stbuf.st_size != E_TABSZ) {
+       if (stbuf.st_size == E_TABSZ) {
                if (verbose)
-                       printf(_("Loading symbolic screen map from file %s\n"),
-                              pathname);
-               if (parsemap(fp,buf)) {
+                       printf(_("Loading binary direct-to-font screen map "
+                                "from file %s\n"),
+                              kbdfile_get_pathname(fp));
+               if (fread(buf, E_TABSZ, 1, kbdfile_get_file(fp)) != 1) {
                        fprintf(stderr,
-                               _("Error parsing symbolic map from `%s'\n"),
-                               pathname);
+                               _("Error reading map from file `%s'\n"),
+                               kbdfile_get_pathname(fp));
                        exit(1);
                }
-       } else  {
+       } else if (stbuf.st_size == 2 * E_TABSZ) {
                if (verbose)
-                       printf(_("Loading binary screen map from file %s\n"),
-                              pathname);
-               if (fread(buf,E_TABSZ,1,fp) != 1) {
+                       printf(_("Loading binary unicode screen map "
+                                "from file %s\n"),
+                              kbdfile_get_pathname(fp));
+               if (fread(ubuf, 2 * E_TABSZ, 1, kbdfile_get_file(fp)) != 1) {
                        fprintf(stderr,
-                               _("Error reading map from file `%s'\n"),
-                               pathname);
+                               _("Error reading map from file `%s'\n"),
+                               kbdfile_get_pathname(fp));
                        exit(1);
                }
+               u = 1;
+       } else {
+               if (verbose)
+                       printf(_("Loading symbolic screen map from file %s\n"),
+                              kbdfile_get_pathname(fp));
+               if (parsemap(kbdfile_get_file(fp), buf, ubuf, &u, &lineno)) {
+                       fprintf(stderr,
+                               _("Error parsing symbolic map "
+                                 "from `%s', line %d\n"),
+                               kbdfile_get_pathname(fp), lineno);
+                       exit(1);
+               }
+       }
+       kbdfile_free(fp);
+       return u;
+}
+
+void loadnewmap(int fd, char *mfil)
+{
+       unsigned short ubuf[E_TABSZ];
+       char buf[E_TABSZ];
+       int i, u;
+
+       /* default: trivial straight-to-font */
+       for (i = 0; i < E_TABSZ; i++) {
+               buf[i]  = i;
+               ubuf[i] = (0xf000 + i);
        }
-       fpclose(fp);
 
-       i = ioctl(fd,PIO_SCRNMAP,buf);
-       if (i) {
-               perror("PIO_SCRNMAP");
-               exit(1);
+       u = 0;
+       if (mfil)
+               u = readnewmapfromfile(mfil, buf, ubuf);
+
+       /* do we need to use loaduniscrnmap() ? */
+       if (u) {
+               /* yes */
+               if (loaduniscrnmap(fd, ubuf))
+                       exit(1);
+       } else {
+               /* no */
+               if (loadscrnmap(fd, buf))
+                       exit(1);
        }
 }
 
-static int
-parsemap(FILE *fp, char buf[]) {
-  char buffer[256];
-  int in, on;
-  char *p, *q;
-
-  for (in=0; in<256; in++) buf[in]=in;
-
-  while (fgets(buffer,sizeof(buffer)-1,fp)) {
-      p = strtok(buffer," \t\n");
-      if (p && *p != '#') {
-         q = strtok(NULL," \t\n#");
-         if (q) {
-             in = ctoi(p);
-             on = ctoi(q);
-             if (in >= 0 && on >= 0) buf[in] = on;
-         }
-      }
-  }
-  return(0);
-}
+/*
+ * Read decimal, octal, hexadecimal, Unicode (U+xxxx) or character
+ * ('x', x a single byte or a utf8 sequence).
+ */
+int ctoi(char *s)
+{
+       int i;
+
+       if ((strncmp(s, "0x", 2) == 0) &&
+           (strspn(s + 2, "0123456789abcdefABCDEF") == strlen(s + 2)))
+               (void)sscanf(s + 2, "%x", &i);
 
-int
-ctoi(unsigned char *s) {
-  int i;
+       else if ((*s == '0') &&
+                (strspn(s, "01234567") == strlen(s)))
+               (void)sscanf(s, "%o", &i);
 
-  if ((strncmp(s,"0x",2) == 0) && 
-      (strspn(s+2,"0123456789abcdefABCDEF") == strlen(s+2)))
-    sscanf(s+2,"%x",&i);
+       else if (strspn(s, "0123456789") == strlen(s))
+               (void)sscanf(s, "%d", &i);
 
-  else if ((*s == '0') &&
-          (strspn(s,"01234567") == strlen(s)))
-    sscanf(s,"%o",&i);
+       else if ((strncmp(s, "U+", 2) == 0) && strlen(s) == 6 &&
+                (strspn(s + 2, "0123456789abcdefABCDEF") == 4))
+               (void)sscanf(s + 2, "%x", &i);
 
-  else if (strspn(s,"0123456789") == strlen(s)) 
-    sscanf(s,"%d",&i);
+       else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
+               i = s[1];
 
-  else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
-    i=s[1];
+       else if (s[0] == '\'') {
+               int err;
+               char *s1 = s + 1;
 
-  else return(-1);
+               i = from_utf8(&s1, 0, &err);
+               if (err || s1[0] != '\'' || s1[1] != 0)
+                       return -1;
+       }
 
-  if (i < 0 || i > 255) {
-      fprintf(stderr, _("mapscrn: format error detected in _%s_\n"), s);
-      exit(1);
-  }
+       else
+               return -1;
 
-  return(i);
+       return i;
 }
 
-void
-saveoldmap(int fd, char *omfil) {
-    FILE *fp;
-    int i;
-    char buf[E_TABSZ];
-
-    if ((fp = fopen(omfil, "w")) == NULL) {
-       perror(omfil);
-       exit(1);
-    }
-    i = ioctl(fd,GIO_SCRNMAP,buf);
-    if (i) {
-       perror("GIO_SCRNMAP");
-       exit(1);
-    }
-    if (fwrite(buf,E_TABSZ,1,fp) != 1) {
-       fprintf(stderr, _("Error writing map to file"));
-       exit(1);
-    }
-    fclose(fp);
-
-    if (verbose)
-      printf(_("Saved screen map in `%s'\n"), omfil);
+void saveoldmap(int fd, char *omfil)
+{
+       FILE *fp;
+       char buf[E_TABSZ];
+       unsigned short ubuf[E_TABSZ];
+       int i, havemap, haveumap;
+
+       if ((fp = fopen(omfil, "w")) == NULL) {
+               perror(omfil);
+               exit(1);
+       }
+       havemap = haveumap = 1;
+       if (getscrnmap(fd, buf))
+               havemap = 0;
+       if (getuniscrnmap(fd, ubuf))
+               haveumap = 0;
+       if (havemap && haveumap) {
+               for (i = 0; i < E_TABSZ; i++) {
+                       if ((ubuf[i] & ~0xff) != 0xf000) {
+                               havemap = 0;
+                               break;
+                       }
+               }
+       }
+       if (havemap) {
+               if (fwrite(buf, sizeof(buf), 1, fp) != 1) {
+                       fprintf(stderr, _("Error writing map to file\n"));
+                       exit(1);
+               }
+       } else if (haveumap) {
+               if (fwrite(ubuf, sizeof(ubuf), 1, fp) != 1) {
+                       fprintf(stderr, _("Error writing map to file\n"));
+                       exit(1);
+               }
+       } else {
+               fprintf(stderr, _("Cannot read console map\n"));
+               exit(1);
+       }
+       fclose(fp);
+
+       if (verbose)
+               printf(_("Saved screen map in `%s'\n"), omfil);
 }