434bc29b795f3ee66a38ee2c5bc43faed14c1158
[platform/upstream/kbd.git] / src / mapscrn.c
1 /*
2  * mapscrn.c
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <memory.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/ioctl.h>
13 #include <sys/kd.h>
14 #include "paths.h"
15 #include "findfile.h"
16 #include "kdmapop.h"
17 #include "utf8.h"
18 #include "nls.h"
19
20 /* the two exported functions */
21 void saveoldmap(int fd, char *omfil);
22 void loadnewmap(int fd, char *mfil);
23
24 static int ctoi (unsigned char *);
25
26 /* search for the map file in these directories (with trailing /) */
27 static char *mapdirpath[] = { "", DATADIR "/" TRANSDIR "/", 0 };
28 static char *mapsuffixes[] = { "", ".trans", "_to_uni.trans", 0 };
29
30 #ifdef MAIN
31 #include "getfd.h"
32 #include "version.h"
33
34 int verbose = 0;
35
36 int
37 main(int argc, char *argv[]) {
38         int fd;
39
40         set_progname(argv[0]);
41
42         setlocale(LC_ALL, "");
43         bindtextdomain(PACKAGE, LOCALEDIR);
44         textdomain(PACKAGE);
45
46         if (argc == 2 && !strcmp(argv[1], "-V"))
47             print_version_and_exit();
48
49         if (argc > 1 && !strcmp(argv[1], "-v")) {
50                 verbose = 1;
51                 argc--;
52                 argv++;
53         }
54
55         fd = getfd();
56
57         if (argc >= 3 && !strcmp(argv[1], "-o")) {
58             saveoldmap(fd, argv[2]);
59             argc -= 2;
60             argv += 2;
61             if (argc == 1)
62               exit(0);
63         }
64                 
65         if (argc != 2) {
66                 fprintf(stderr, _("usage: %s [-v] [-o map.orig] map-file\n"),
67                         progname);
68                 exit(1);
69         }
70         loadnewmap(fd, argv[1]);
71         exit(0);
72 }
73 #endif
74
75 /*
76  * Read two-column file (index, value) with index in 0-255
77  * and value in 0-65535. Acceptable representations:
78  * decimal (nnn), octal (0nnn), hexadecimal (0xnnn), Unicode (U+xxxx),
79  * character ('x').
80  * In the character encoding, x may be a single byte binary value
81  * (but not space, tab, comma, #) or a single Unicode value coded
82  * as a UTF-8 sequence.
83  *
84  * Store values in ubuf[], and small values also in buf[].
85  * Set u to 1 in case a value above 255 or a U+ occurs.
86  * Set lineno to line number of first error.
87  */
88 static int
89 parsemap(FILE *fp, char *buf, unsigned short *ubuf, int *u, int *lineno) {
90         char buffer[256];
91         int in, on, ln, ret = 0;
92         char *p, *q;
93
94         ln = 0;
95         while (fgets(buffer,sizeof(buffer)-1,fp)) {
96                 ln++;
97                 if (!*u && strstr(buffer, "U+"))
98                         *u = 1;
99                 p = strtok(buffer," \t\n");
100                 if (p && *p != '#') {
101                         q = strtok(NULL," \t\n#");
102                         if (q) {
103                                 in = ctoi(p);
104                                 on = ctoi(q);
105                                 if (in >= 0 && in < 256 &&
106                                     on >= 0 && on < 65536) {
107                                         ubuf[in] = on;
108                                         if (on < 256)
109                                                 buf[in] = on;
110                                         else
111                                                 *u = 1;
112                                 } else {
113                                         if (!ret)
114                                                 *lineno = ln;
115                                         ret = -1;
116                                 }
117                         }
118                 }
119         }
120         return ret;
121 }
122
123 static int
124 readnewmapfromfile(int fd, char *mfil, char *buf, unsigned short *ubuf) {
125         FILE *fp;
126         struct stat stbuf;
127         int u = 0;
128         int lineno;
129
130         if ((fp = findfile(mfil, mapdirpath, mapsuffixes)) == NULL) {
131                 fprintf(stderr, _("mapscrn: cannot open map file _%s_\n"),
132                         mfil);
133                 exit(1);
134         }
135         if (stat(pathname, &stbuf)) {
136                 perror(pathname);
137                 fprintf(stderr, _("Cannot stat map file"));
138                 exit(1);
139         }
140         if (stbuf.st_size == E_TABSZ) {
141                 if (verbose)
142                         printf(_("Loading binary direct-to-font screen map "
143                                  "from file %s\n"),
144                                pathname);
145                 if (fread(buf,E_TABSZ,1,fp) != 1) {
146                         fprintf(stderr,
147                                 _("Error reading map from file `%s'\n"),
148                                 pathname);
149                         exit(1);
150                 }
151         } else if (stbuf.st_size == 2*E_TABSZ) {
152                 if (verbose)
153                         printf(_("Loading binary unicode screen map "
154                                  "from file %s\n"),
155                                pathname);
156                 if (fread(ubuf,2*E_TABSZ,1,fp) != 1) {
157                         fprintf(stderr,
158                                 _("Error reading map from file `%s'\n"),
159                                 pathname);
160                         exit(1);
161                 }
162                 u = 1;
163         } else  {
164                 if (verbose)
165                         printf(_("Loading symbolic screen map from file %s\n"),
166                                pathname);
167                 if (parsemap(fp,buf,ubuf,&u,&lineno)) {
168                         fprintf(stderr,
169                                 _("Error parsing symbolic map "
170                                   "from `%s', line %d\n"),
171                                 pathname, lineno);
172                         exit(1);
173                 }
174         }
175         fpclose(fp);
176         return u;
177 }
178
179 void
180 loadnewmap(int fd, char *mfil) {
181         unsigned short ubuf[E_TABSZ];
182         char buf[E_TABSZ];
183         int i, u;
184
185         /* default: trivial straight-to-font */
186         for (i=0; i<E_TABSZ; i++) {
187                 buf[i] = i;
188                 ubuf[i] = (0xf000 + i);
189         }
190
191         u = 0;
192         if (mfil)
193                 u = readnewmapfromfile(fd, mfil, buf, ubuf);
194
195         /* do we need to use loaduniscrnmap() ? */
196         if (u) {
197                 /* yes */
198                 if (loaduniscrnmap(fd, ubuf))
199                         exit(1);
200         } else {
201                 /* no */
202                 if (loadscrnmap(fd,buf))
203                         exit(1);
204         }
205 }
206
207 /*
208  * Read decimal, octal, hexadecimal, Unicode (U+xxxx) or character
209  * ('x', x a single byte or a utf8 sequence).
210  */
211 int
212 ctoi(unsigned char *s) {
213         int i;
214
215         if ((strncmp(s,"0x",2) == 0) && 
216             (strspn(s+2,"0123456789abcdefABCDEF") == strlen(s+2)))
217                 sscanf(s+2,"%x",&i);
218
219         else if ((*s == '0') &&
220                  (strspn(s,"01234567") == strlen(s)))
221                 sscanf(s,"%o",&i);
222
223         else if (strspn(s,"0123456789") == strlen(s)) 
224                 sscanf(s,"%d",&i);
225
226         else if ((strncmp(s,"U+",2) == 0) && strlen(s) == 6 &&
227                  (strspn(s+2,"0123456789abcdefABCDEF") == 4))
228                 sscanf(s+2,"%x",&i);
229
230         else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\''))
231                 i=s[1];
232
233         else if (s[0] == '\'') {
234                 int err;
235                 char *s1 = s+1;
236
237                 i = from_utf8(&s1, 0, &err);
238                 if (err || s1[0] != '\'' || s1[1] != 0)
239                         return -1;
240         }
241
242         else return -1;
243
244         return i;
245 }
246
247 void
248 saveoldmap(int fd, char *omfil) {
249         FILE *fp;
250         char buf[E_TABSZ];
251         unsigned short ubuf[E_TABSZ];
252         int i, havemap, haveumap;
253
254         if ((fp = fopen(omfil, "w")) == NULL) {
255                 perror(omfil);
256                 exit(1);
257         }
258         havemap = haveumap = 1;
259         if (getscrnmap(fd,buf))
260                 havemap = 0;
261         if (getuniscrnmap(fd,ubuf))
262                 haveumap = 0;
263         if (havemap && haveumap) {
264                 for (i = 0; i < E_TABSZ; i++) {
265                         if ((ubuf[i] & ~0xff) != 0xf000) {
266                                 havemap = 0;
267                                 break;
268                         }
269                 }
270         }
271         if (havemap) {
272                 if (fwrite(buf,sizeof(buf),1,fp) != 1) {
273                         fprintf(stderr, _("Error writing map to file\n"));
274                         exit(1);
275                 }
276         } else if (haveumap) {
277                 if (fwrite(ubuf,sizeof(ubuf),1,fp) != 1) {
278                         fprintf(stderr, _("Error writing map to file\n"));
279                         exit(1);
280                 }
281         } else {
282                 fprintf(stderr, _("Cannot read console map\n"));
283                 exit(1);
284         }
285         fclose(fp);
286
287         if (verbose)
288                 printf(_("Saved screen map in `%s'\n"), omfil);
289 }