- fix warnings in tools/cptoqe.c - fix signed char issue in tools/kmaptoqe.c - fix optional argument parsing in tools/unicode_gen.c - generate qe_bidir_get_type() and qe_bidir_get_type_test() functions for bidir_tables target
665 lines
18 KiB
C
665 lines
18 KiB
C
/*
|
|
* Convert Yudit kmap files to QEmacs binary internal format
|
|
*
|
|
* Copyright (c) 2002 Fabrice Bellard.
|
|
* Copyright (c) 2007-2020 Charlie Gordon.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <assert.h>
|
|
|
|
#include "cutils.h"
|
|
|
|
#ifndef countof
|
|
#define countof(a) ((int)(sizeof(a) / sizeof((a)[0])))
|
|
#endif
|
|
|
|
//#define TEST
|
|
|
|
#define NB_MAX 15000
|
|
|
|
typedef struct InputEntry {
|
|
unsigned char input[20];
|
|
int len;
|
|
unsigned short output[20];
|
|
int olen;
|
|
int order;
|
|
} InputEntry;
|
|
|
|
static InputEntry inputs[NB_MAX];
|
|
static int nb_inputs;
|
|
static char kmap_names[300][128];
|
|
static int kmap_offsets[300];
|
|
static int nb_kmaps;
|
|
static char name[128];
|
|
static int table_start[NB_MAX], nb_starts;
|
|
static int table_val[NB_MAX];
|
|
static int is_chinese_cj, gen_table;
|
|
static int freq[32];
|
|
static FILE *outfile;
|
|
static unsigned char outbuf[100000], *outbuf_ptr;
|
|
|
|
/* sort function implements strict order, making qsort stable */
|
|
static int sort_func(const void *a1, const void *b1)
|
|
{
|
|
const InputEntry *a = a1;
|
|
const InputEntry *b = b1;
|
|
int val;
|
|
|
|
if (gen_table) {
|
|
val = a->input[0] - b->input[0];
|
|
if (val != 0)
|
|
return val;
|
|
}
|
|
val = a->output[0] - b->output[0];
|
|
if (val != 0)
|
|
return val;
|
|
return a->order - b->order;
|
|
}
|
|
|
|
|
|
static int offset, write_data;
|
|
|
|
static void put_byte(int b)
|
|
{
|
|
if (write_data)
|
|
*outbuf_ptr++ = b;
|
|
offset++;
|
|
}
|
|
|
|
static void gen_map(void)
|
|
{
|
|
int len, c, d, last, delta, i, k, j;
|
|
int last_input0;
|
|
InputEntry *ip;
|
|
|
|
last = 0;
|
|
nb_starts = 0;
|
|
last_input0 = 0;
|
|
offset = 0;
|
|
for (k = 0, ip = inputs; k < nb_inputs; k++, ip++) {
|
|
unsigned char *input = ip->input;
|
|
int first, output;
|
|
|
|
if (gen_table) {
|
|
if (last_input0 != ip->input[0]) {
|
|
if (last_input0 != 0)
|
|
put_byte(0);
|
|
last_input0 = ip->input[0];
|
|
table_val[nb_starts] = last_input0;
|
|
table_start[nb_starts++] = offset;
|
|
last = 0;
|
|
}
|
|
}
|
|
|
|
len = ip->len;
|
|
output = ip->output[0];
|
|
delta = output - last;
|
|
last = output;
|
|
|
|
#ifdef TEST
|
|
/* frequencies */
|
|
if (delta > 30)
|
|
delta = 30;
|
|
else if (delta < -1)
|
|
delta = -1;
|
|
freq[delta + 1]++;
|
|
#endif
|
|
|
|
if (is_chinese_cj) {
|
|
assert(input[len-1] == ' ');
|
|
len--;
|
|
}
|
|
|
|
first = 0;
|
|
if (gen_table)
|
|
first = 1;
|
|
|
|
/* c = 0x00 end of table
|
|
* c = 0x01..0x1d delta unicode
|
|
* c = 0x1e unicode output mapping follows
|
|
* c = 0x1f unicode input char follows.
|
|
* c = 0x20..0x7f input character
|
|
* c = 0x80 unused
|
|
* c = 0x81 unused
|
|
* c = 0x82..0x9d extra unicode outputs follow
|
|
* c = 0x9e first unicode output mapping follows
|
|
* c = 0x9f last unicode input char follows and delta==1.
|
|
* c = 0xa0..0xff last input character and delta==1
|
|
*/
|
|
for (j = first; j < len; j++) {
|
|
c = input[j];
|
|
d = 0;
|
|
if (j == (len - 1) && delta == 1 && ip->olen == 1)
|
|
d = 0x80;
|
|
if (c >= 0x20 && c <= 0x7f) {
|
|
put_byte(c | d);
|
|
} else {
|
|
put_byte(d | 0x1f);
|
|
put_byte((c >> 8) & 0xff);
|
|
put_byte(c & 0xff);
|
|
}
|
|
}
|
|
if (ip->olen > 1) {
|
|
if (delta != 0) {
|
|
put_byte(0x80 | 0x1e);
|
|
put_byte((output >> 8) & 0xff);
|
|
put_byte(output & 0xff);
|
|
}
|
|
put_byte(0x80 | ip->olen);
|
|
for (i = 1; i < ip->olen; i++) {
|
|
put_byte((ip->output[i] >> 8) & 0xff);
|
|
put_byte(ip->output[i] & 0xff);
|
|
}
|
|
} else {
|
|
/* XXX: potential problem if first == len. We avoid it
|
|
by forcing an emission of a unicode char */
|
|
if (first == len)
|
|
delta = 0;
|
|
if (delta != 1) {
|
|
if (delta >= 1 && delta <= 0x1d) {
|
|
put_byte(delta);
|
|
} else {
|
|
put_byte(0x1e);
|
|
put_byte((output >> 8) & 0xff);
|
|
put_byte(output & 0xff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
put_byte(0);
|
|
}
|
|
|
|
static void putcp(int c, int *sp)
|
|
{
|
|
switch (c) {
|
|
case '=':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
goto x2;
|
|
case '\\':
|
|
case '"':
|
|
case '-':
|
|
case '+':
|
|
printf("\\%c", c);
|
|
*sp = 0;
|
|
break;
|
|
default:
|
|
if (c >= 256) {
|
|
if (!*sp)
|
|
printf(" ");
|
|
printf("0x%04X ", c);
|
|
*sp = 1;
|
|
break;
|
|
} else
|
|
if (c <= 0x20 || c >= 0x7F) {
|
|
x2:
|
|
if (!*sp)
|
|
printf(" ");
|
|
printf("0x%02X ", c);
|
|
*sp = 1;
|
|
break;
|
|
} else {
|
|
printf("%c", c);
|
|
*sp = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int dump_kmap(const char *filename)
|
|
{
|
|
FILE *f;
|
|
char buf[1024];
|
|
int i, n, c, off, pos, x;
|
|
|
|
f = fopen(filename, "rb");
|
|
if (!f) {
|
|
fprintf(stderr, "kmaptoqe: cannot open %s\n", filename);
|
|
return 1;
|
|
}
|
|
if (fread(buf, 4, 1, f) != 1 || memcmp(buf, "kmap", 4)) {
|
|
fprintf(stderr, "kmaptoqe: invalid signature %s\n", filename);
|
|
fclose(f);
|
|
return 1;
|
|
}
|
|
printf("// Dump of QEmacs kmap file %s\n"
|
|
"kmap {\n", filename);
|
|
printf(" {\n");
|
|
for (nb_kmaps = 0;; nb_kmaps++) {
|
|
off = getc(f) << 24;
|
|
off |= getc(f) << 16;
|
|
off |= getc(f) << 8;
|
|
off |= getc(f) << 0;
|
|
if (off == 0)
|
|
break;
|
|
kmap_offsets[nb_kmaps] = off;
|
|
for (i = 0;; i++) {
|
|
c = getc(f);
|
|
if (c == EOF || i >= countof(kmap_names[nb_kmaps])) {
|
|
fprintf(stderr, "%s: invalid map name\n", filename);
|
|
fclose(f);
|
|
return 1;
|
|
}
|
|
kmap_names[nb_kmaps][i] = c;
|
|
if (c == 0)
|
|
break;
|
|
}
|
|
printf(" 0x%04x: %s\n", off, kmap_names[nb_kmaps]);
|
|
}
|
|
printf(" }\n");
|
|
|
|
pos = ftell(f);
|
|
|
|
for (n = x = 0;;) {
|
|
|
|
if (pos == kmap_offsets[n]) {
|
|
|
|
if (x > 0) {
|
|
printf("\n");
|
|
x = 0;
|
|
}
|
|
if (n > 0) {
|
|
printf(" }\n");
|
|
printf(" }\n");
|
|
}
|
|
printf("\n { // %s\n", kmap_names[n]);
|
|
c = getc(f);
|
|
pos++;
|
|
nb_starts = c & 0x7F;
|
|
is_chinese_cj = c >> 7;
|
|
gen_table = (nb_starts > 0);
|
|
|
|
printf(" nb_starts=%d, is_chinese_cj=%d\n",
|
|
nb_starts, is_chinese_cj);
|
|
|
|
if (gen_table) {
|
|
printf(" {\n");
|
|
for (i = 0; i < nb_starts; i++) {
|
|
c = getc(f);
|
|
off = getc(f) << 16;
|
|
off |= getc(f) << 8;
|
|
off |= getc(f) << 0;
|
|
pos += 4;
|
|
table_val[i] = c;
|
|
table_start[i] = off;
|
|
printf(" table_val[%d]=0x%02x ('%c'), table_start[%d]=0x%04x\n",
|
|
i, c, c, i, off);
|
|
}
|
|
printf(" }\n");
|
|
}
|
|
n++;
|
|
printf(" {\n");
|
|
x = 0;
|
|
|
|
if (1) {
|
|
int len, olen, flag, k, s, last = 0, sp;
|
|
|
|
s = 0;
|
|
for (k = 0;; k++) {
|
|
unsigned char *input;
|
|
|
|
input = inputs[k].input;
|
|
olen = 1;
|
|
len = 0;
|
|
sp = 1;
|
|
|
|
nextc:
|
|
c = getc(f);
|
|
pos++;
|
|
if (c == EOF)
|
|
break;
|
|
|
|
/* c = 0x00 end of table
|
|
* c = 0x01..0x1d delta unicode
|
|
* c = 0x1e unicode output mapping follows
|
|
* c = 0x1f unicode input char follows.
|
|
* c = 0x20..0x7f input character
|
|
* c = 0x80 unused
|
|
* c = 0x81 unused
|
|
* c = 0x82..0x9d extra unicode outputs follow
|
|
* c = 0x9e first unicode output mapping follows
|
|
* c = 0x9f last unicode input char follows and delta==1.
|
|
* c = 0xa0..0xff last input character and delta==1
|
|
*/
|
|
if (c == 0) {
|
|
if (!gen_table || ++s >= nb_starts)
|
|
break;
|
|
last = 0;
|
|
goto nextc;
|
|
}
|
|
|
|
if (len == 0) {
|
|
printf(" \"");
|
|
if (gen_table) {
|
|
putcp(table_val[s], &sp);
|
|
}
|
|
}
|
|
|
|
flag = c >> 7;
|
|
c &= 0x7f;
|
|
|
|
if (c < 0x1e) {
|
|
if (flag) {
|
|
olen = c;
|
|
} else {
|
|
last += c;
|
|
}
|
|
goto nextk;
|
|
}
|
|
if (c == 0x1e) {
|
|
last = getc(f) << 8;
|
|
last |= getc(f) << 0;
|
|
pos += 2;
|
|
if (flag)
|
|
goto nextc;
|
|
else
|
|
goto nextk;
|
|
}
|
|
if (c == 0x1f) {
|
|
c = getc(f) << 8;
|
|
c |= getc(f) << 0;
|
|
pos += 2;
|
|
input[len++] = c;
|
|
putcp(c, &sp);
|
|
if (flag) {
|
|
last += 1;
|
|
goto nextk;
|
|
}
|
|
goto nextc;
|
|
}
|
|
if (c >= 0x20) {
|
|
input[len++] = c;
|
|
putcp(c, &sp);
|
|
if (flag) {
|
|
last += 1;
|
|
goto nextk;
|
|
}
|
|
goto nextc;
|
|
}
|
|
nextk:
|
|
if (is_chinese_cj) {
|
|
putcp(' ', &sp);
|
|
}
|
|
if (!sp)
|
|
printf(" ");
|
|
printf("= 0x%04X", last);
|
|
/* multiple unicode chars */
|
|
for (i = 1; i < olen; i++) {
|
|
c = getc(f) << 8;
|
|
c |= getc(f) << 0;
|
|
pos += 2;
|
|
printf(" 0x%04X", c);
|
|
}
|
|
printf("\",\n");
|
|
}
|
|
}
|
|
if (pos == kmap_offsets[n])
|
|
continue;
|
|
}
|
|
|
|
if ((c = getc(f)) == EOF)
|
|
break;
|
|
pos++;
|
|
|
|
if (x == 0)
|
|
printf(" ");
|
|
printf("0x%02x, ", c);
|
|
if (++x == 8) {
|
|
printf("\n");
|
|
x = 0;
|
|
}
|
|
}
|
|
|
|
if (x > 0)
|
|
printf("\n");
|
|
|
|
if (n > 0) {
|
|
printf(" }\n");
|
|
printf(" }\n");
|
|
}
|
|
|
|
printf("}\n");
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
static inline char *skipspaces(char *p) {
|
|
while (isspace((unsigned char)*p))
|
|
p++;
|
|
return p;
|
|
}
|
|
|
|
static int getcp(char *p, char **pp) {
|
|
if (*p == '\0') {
|
|
return -1;
|
|
} else
|
|
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
|
|
return strtoul(p, pp, 0);
|
|
} else
|
|
if (*p == '\\') {
|
|
p++;
|
|
if (*p == 't') {
|
|
*pp = p + 1;
|
|
return '\t';
|
|
} else
|
|
if (p[0] >= '0' && p[0] <= '3'
|
|
&& p[1] >= '0' && p[1] <= '7'
|
|
&& p[2] >= '0' && p[2] <= '7') {
|
|
*pp = p + 3;
|
|
return ((p[0] - '0') << 6) | ((p[1] - '0') << 3) |
|
|
((p[2] - '0') << 0);
|
|
} else {
|
|
*pp = p + 1;
|
|
return (unsigned char)*p;
|
|
}
|
|
} else
|
|
if ((*p & 0xe0) == 0xc0 && (p[1] & 0xc0) == 0x80) {
|
|
/* 2 byte UTF-8 encoded glyph */
|
|
*pp = p + 2;
|
|
return ((*p & 0x1f) << 6) | ((p[1] & 0x3f) << 0);
|
|
} else {
|
|
/* single byte */
|
|
*pp = p + 1;
|
|
return (unsigned char)*p;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *filename;
|
|
int i, j, k, line_num, len;
|
|
FILE *f;
|
|
char line[1024], *p;
|
|
unsigned char *q;
|
|
int c, size;
|
|
InputEntry *ip;
|
|
|
|
if (argc < 3) {
|
|
printf("kmaptoqe -- Convert yudit keyboard maps to qemacs compressed format\n"
|
|
"usage: kmaptoqe outfile kmaps...\n"
|
|
" kmaptoqe --dump outfile\n");
|
|
exit(1);
|
|
}
|
|
if (!strcmp(argv[1], "--dump")) {
|
|
return dump_kmap(argv[2]);
|
|
}
|
|
|
|
outfile = fopen(argv[1], "wb");
|
|
if (!outfile) {
|
|
perror(argv[1]);
|
|
exit(1);
|
|
}
|
|
outbuf_ptr = outbuf;
|
|
|
|
memset(freq, 0, sizeof(freq));
|
|
|
|
nb_kmaps = 0;
|
|
for (i = 2; i < argc; i++) {
|
|
filename = argv[i];
|
|
f = fopen(filename, "r");
|
|
if (!f) {
|
|
perror(filename);
|
|
exit(1);
|
|
}
|
|
p = strrchr(filename, '/');
|
|
if (!p)
|
|
p = filename;
|
|
else
|
|
p++;
|
|
|
|
pstrcpy(name, sizeof(name), p);
|
|
for (p = name; *p != '\0' && *p != '.'; p++) {
|
|
if (*p == '-')
|
|
*p = '_';
|
|
}
|
|
*p = '\0';
|
|
pstrcpy(kmap_names[nb_kmaps], sizeof(kmap_names[nb_kmaps]), name);
|
|
kmap_offsets[nb_kmaps] = outbuf_ptr - outbuf;
|
|
nb_kmaps++;
|
|
/* special compression for CJ */
|
|
is_chinese_cj = !strcmp(name, "Chinese_CJ");
|
|
gen_table = !strcmp(name, "Chinese_CJ") ||
|
|
!strcmp(name, "TeX") ||
|
|
!strcmp(name, "Troff") ||
|
|
!strcmp(name, "SGML");
|
|
|
|
nb_inputs = 0;
|
|
ip = inputs;
|
|
line_num = 0;
|
|
for (;;) {
|
|
if (fgets(line, sizeof(line), f) == NULL)
|
|
break;
|
|
line_num++;
|
|
p = skipspaces(line);
|
|
if (*p == '\0' || *p == '/' || *p == '#')
|
|
continue;
|
|
if (*p != '\"')
|
|
goto invalid;
|
|
p++;
|
|
len = 0;
|
|
q = ip->input;
|
|
for (;;) {
|
|
p = skipspaces(p);
|
|
if (*p == '=' && p[1] != '=')
|
|
break;
|
|
c = getcp(p, &p);
|
|
if (c < 0)
|
|
goto invalid;
|
|
if (c >= 256) {
|
|
fprintf(stderr, "%s:%d: Invalid char 0x%x\n",
|
|
filename, line_num, c);
|
|
goto skip;
|
|
}
|
|
if (len >= countof(ip->input))
|
|
goto invalid;
|
|
q[len++] = c;
|
|
}
|
|
ip->len = len;
|
|
p = skipspaces(p + 1);
|
|
for (ip->olen = 0;;) {
|
|
c = getcp(p, &p);
|
|
if (c < 0)
|
|
goto invalid;
|
|
if (ip->olen >= countof(ip->output))
|
|
goto invalid;
|
|
ip->output[ip->olen++] = c;
|
|
p = skipspaces(p);
|
|
if (*p == '"')
|
|
break;
|
|
}
|
|
ip->order = ip - inputs;
|
|
ip++;
|
|
nb_inputs++;
|
|
continue;
|
|
invalid:
|
|
fprintf(stderr, "%s:%d: Invalid mapping: %s\n",
|
|
filename, line_num, line);
|
|
skip:;
|
|
}
|
|
|
|
qsort(inputs, nb_inputs, sizeof(InputEntry), sort_func);
|
|
|
|
/* first pass to compute offsets */
|
|
write_data = 0;
|
|
gen_map();
|
|
|
|
write_data = 1;
|
|
|
|
/* write start map */
|
|
put_byte(nb_starts | (is_chinese_cj ? 0x80 : 0));
|
|
if (gen_table) {
|
|
for (k = 0; k < nb_starts; k++) {
|
|
j = table_start[k];
|
|
put_byte(table_val[k]);
|
|
put_byte((j >> 16) & 0xff);
|
|
put_byte((j >> 8) & 0xff);
|
|
put_byte(j & 0xff);
|
|
}
|
|
}
|
|
|
|
gen_map();
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
#ifdef TEST
|
|
for (k = 0; k < 32; k++) {
|
|
fprintf(stderr, "freq[%d] = %d\n", k, freq[k]);
|
|
}
|
|
#endif
|
|
|
|
/* write header */
|
|
size = 4;
|
|
for (i = 0; i < nb_kmaps; i++) {
|
|
size += strlen(kmap_names[i]) + 1 + 4;
|
|
}
|
|
size += 4; /* last offset at zero */
|
|
|
|
fwrite("kmap", 1, 4, outfile);
|
|
|
|
for (i = 0; i < nb_kmaps; i++) {
|
|
int off;
|
|
off = kmap_offsets[i] + size;
|
|
fputc((off >> 24) & 0xff, outfile);
|
|
fputc((off >> 16) & 0xff, outfile);
|
|
fputc((off >> 8) & 0xff, outfile);
|
|
fputc((off >> 0) & 0xff, outfile);
|
|
fwrite(kmap_names[i], 1, strlen(kmap_names[i]) + 1, outfile);
|
|
}
|
|
fputc(0, outfile);
|
|
fputc(0, outfile);
|
|
fputc(0, outfile);
|
|
fputc(0, outfile);
|
|
|
|
fwrite(outbuf, 1, outbuf_ptr - outbuf, outfile);
|
|
|
|
fclose(outfile);
|
|
|
|
return 0;
|
|
}
|