Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

901 lines
18 KiB
C

/* @(#)61 1.9 src/bos/usr/bin/keycomp/keycomp.c, cmdimkc, bos411, 9428A410j 3/24/94 05:37:55 */
/*
* COMPONENT_NAME : (cmdimkc) AIX Input Method Keymap Compiler
*
* FUNCTIONS : keycomp
*
* ORIGINS : 27
*
* (C) COPYRIGHT International Business Machines Corp. 1989-1993
* All Rights Reserved
* Licensed Materials - Property of IBM
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#define _ILS_MACROS
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <X11/keysym.h>
#include "im.h"
#include "imP.h"
#include "dim.h"
/*
* Message Catalog stuffs.
*/
#include <nl_types.h>
#include "keycomp_msg.h"
nl_catd catd;
#define MSGSTR(Num,Str) catgets(catd, MS_KEYCOMP, Num, Str)
#define E_MEM "keycomp : cannot allocate memory\n"
#define E_LINE "keycomp : error at line %d\n"
#define E_ITEM "keycomp : error at line %1$d item %2$d\n"
#define E_MIX "keycomp : %%M and #M/#S cannot be mixed\n"
#define E_USG "Usage: keycomp {-c}\n"
/*
* CLine is a control line which start with #S, #M or %M.
*/
#define CL_ALLOC_UNIT 32
typedef struct _CLine {
int len;
int siz;
short *stat;
} CLine;
/*
* sline is a line starting with #S
*/
static CLine sline = {0, 0, NULL};
/*
* MLines is an array of mlines.
*/
#define MLS_ALLOC_UNIT 32
typedef struct _MLines {
int len;
int siz;
CLine *mline;
} MLines;
static MLines mlines = {0, 0, NULL};
/*
* PLine is a line containing keyboard mapping data.
*/
#define PL_ALLOC_UNIT 32
typedef struct _PLine {
unsigned int keysym;
int len;
int siz;
KeyMapElement *kme;
} PLine;
static int maxplen = 0;
/*
* PLines is an array of Pline.
*/
#define PLS_ALLOC_UNIT 128
typedef struct _PLines {
int len;
int siz;
PLine *pline;
} PLines;
static PLines plines = {0, 0, NULL};
/*
* mflag
* MFLAG_NONE : initial state
* MFLAG_NEW : new format (%M)
* MFLAG_OLD : old format (#S and #M)
*/
#define MFLAG_NONE 0
#define MFLAG_NEW 1
#define MFLAG_OLD 2
static int mflag = MFLAG_NONE;
/*
* current line number and current item number.
* used when issueing error message.
*/
static int line = 0;
static int item = 0;
/*
* Key String
*/
static char *kstr = NULL;
static int kstrsiz = 0;
static int kstrlen = 0;
/*
* Other Keysyms
*/
static unsigned int *oksym = NULL;
static int oksymsiz = 0; /* size in bytes */
static int oksymlen = 0; /* number of keysyms */
/*
* My memory allocator.
* exit on allocation error.
*/
static void *myrealloc(void *base, size_t size)
{
if (base) base = realloc(base, size);
else base = malloc(size);
if (!base) {
fprintf(stderr, MSGSTR(MN_MEM, E_MEM));
exit(2);
}
return base;
}
/*
* get a next line from stdin.
* return NULL pointer on EOF.
*/
static char *getline()
{
int i;
int c;
#define LB_ALLOC_UNIT 512
static char *linebuf = 0;
static int linebufsiz = 0;
static int hiteof = False;
if (hiteof) {
if (linebuf) {
free((void *)linebuf);
linebuf = 0;
linebufsiz = 0;
}
return NULL;
}
for (i = 0; (c = getchar()) != '\n' && c != EOF; i++) {
if (i >= linebufsiz) {
linebufsiz += LB_ALLOC_UNIT;
linebuf = myrealloc(linebuf, linebufsiz);
}
linebuf[i] = c;
}
if (c == EOF)
hiteof = True;
if (i >= linebufsiz) {
linebufsiz += LB_ALLOC_UNIT;
linebuf = myrealloc(linebuf, linebufsiz);
}
linebuf[i] = '\n';
line++;
item = 0;
return linebuf;
}
static int addtokstr(char *str, int len)
{
#define KSTR_ALLOC_UNIT 256
int id;
if (kstrlen + len + 1 >= kstrsiz) {
kstrsiz = ((kstrlen + len + 1) / KSTR_ALLOC_UNIT + 1) *
KSTR_ALLOC_UNIT;
kstr = (char *)myrealloc(kstr, kstrsiz);
}
kstr[kstrlen] = len;
memcpy(kstr + kstrlen + 1, str, len);
id = kstrlen;
kstrlen += len + 1;
return id;
}
static int addtooksym(unsigned int keysym)
{
#define OKSYM_ALLOC_UNIT 512
if (oksymlen * sizeof (unsigned int) >= oksymsiz) {
oksymsiz += OKSYM_ALLOC_UNIT;
oksym = (unsigned int *)myrealloc((void *)oksym, oksymsiz);
}
oksym[oksymlen++] = keysym;
return oksymlen - 1;
}
static void placekeysym(KeyMapElement *kme, unsigned int keysym)
{
int idx;
if ((keysym & 0xff000000) == AIX_PRIVKEYSYM) {
kme->type = KME_PRIVKEYSYM;
PUT3DIGITS(kme->data, keysym);
}
else if ((keysym & 0xff000000)) {
kme->type = KME_OTHERKEYSYM;
idx = addtooksym(keysym);
PUT3DIGITS(kme->data, idx);
}
else {
kme->type = KME_KEYSYM;
PUT3DIGITS(kme->data, keysym);
}
}
#define isodigit(c) ('0' <= (c) && (c) <= '7')
#define ddigit(c) ((c) - '0')
#define odigit(c) ((c) - '0')
#define xdigit(c) \
((c) <= '9' ? (c) - '0' : (c) <= 'F' ? (c) - 'A' + 10 : (c) - 'a' + 10)
char *escchar(char *ptr, char *c)
{
int val;
int cnt;
/* ptr points to next of back slash */
switch (*ptr) {
case '\\': *c = '\\'; ptr++; break;
case 'n': *c = '\n'; ptr++; break;
case 'r': *c = '\r'; ptr++; break;
case 't': *c = '\t'; ptr++; break;
case 'b': *c = '\b'; ptr++; break;
case 'f': *c = '\f'; ptr++; break;
case 'x':
if (!isxdigit(ptr[1]) || !isxdigit(ptr[2]))
return NULL;
*c = (xdigit(ptr[1]) << 4) + xdigit(ptr[2]);
ptr += 3;
break;
case 'd':
val = 0;
cnt = 3;
ptr++;
while (isdigit(*ptr) && cnt--)
val = val * 10 + ddigit(*ptr++);
*c = val;
break;
default:
if (!isodigit(ptr[0])) {
*c = ptr[0];
ptr++;
break;
}
val = 0;
cnt = 3; /* \XXX : octal */
while (isodigit(*ptr) && cnt--)
val = (val << 3) + odigit(*ptr++);
*c = val;
break;
}
return ptr;
}
static int process_DXX(KeyMapElement *kme, char c, char c2)
{
static unsigned int dead_keysyms[] = {
XK_dead_acute, XK_dead_acute, /* apostrophe */
XK_dead_grave, XK_dead_circumflex,
XK_dead_diaeresis, XK_dead_tilde,
XK_dead_caron, XK_dead_breve,
XK_dead_doubleacute, XK_dead_degree,
XK_dead_abovedot, XK_dead_macron,
XK_dead_cedilla, XK_dead_ogonek,
};
c = 10 * (c - '0') + c2 - '0';
if (c > 15)
return False;
placekeysym(kme, dead_keysyms[c]);
return True;
}
typedef struct _KTable {
char *str;
unsigned int keysym;
} KTable;
static int kcomp(KTable *kt1, KTable *kt2)
{
return strcmp(kt1->str, kt2->str);
}
int lookupkeysym(char *ptr, unsigned int *keysym)
{
int high, mid, low;
int ret;
static int initialized = False;
/*
* X11/ks_names.h contains array of keysym name/value.
* Included it and append some private ones.
* Later we qsort it for binary searching.
*/
static KTable ktable[] = {
#include <X11/ks_names.h>
#include <X11/aix_ks_names.h>
{ "BEEP", XK_BEEP },
{ "UNBOUND", XK_UNBOUND },
{ "IGNORE", XK_IGNORE },
{ "*", XK_ALL },
};
if (!initialized) {
qsort((void *)&ktable[0], sizeof (ktable) / sizeof (ktable[0]),
sizeof (ktable[0]), (int (*)())kcomp);
initialized = True;
}
low = 0;
high = sizeof (ktable) / sizeof (ktable[0]);
while (high >= low) {
mid = (high + low) / 2;
if ((ret = strcmp(ptr, ktable[mid].str)) < 0)
high = mid - 1;
else if (ret > 0)
low = mid + 1;
else {
*keysym = ktable[mid].keysym;
return True;
}
}
return False;
}
static char *process_item(KeyMapElement *kme, char *ptr)
{
char c;
char *bp;
unsigned int keysym;
int i;
int id;
static char buf[256];
++item;
switch (*ptr++) {
case 'U':
kme->type = KME_UNBOUND;
PUT3BYTES(kme->data, '\0', '\0', '\0');
return ptr;
case 'X': /* keysym */
if (*ptr++ != 'K' || *ptr++ != '_')
return NULL;
bp = ptr;
while (isalnum(*ptr) || *ptr == '_')
ptr++;
c = *ptr;
*ptr = '\0';
if (!lookupkeysym(bp, &keysym))
return NULL;
*ptr = c;
placekeysym(kme, keysym);
return ptr;
case '\'': /* single quote */
kme->type = KME_SSTR1;
if (*ptr != '\\') {
PUT3BYTES(kme->data, *ptr++, '\0', '\0');
if (*ptr++ != '\'')
return NULL;
return ptr;
}
if (*++ptr == '\'') {
PUT3BYTES(kme->data, *ptr++, '\0', '\0');
if (*ptr++ != '\'')
return NULL;
return ptr;
}
ptr = escchar(ptr, &kme->data[0]);
kme->data[1] = 0;
kme->data[2] = 0;
if (*ptr++ != '\'')
return NULL;
return ptr;
case '"':
if (*ptr == 'D' && isdigit(ptr[1]) && isdigit(ptr[2]) &&
ptr[3] == '"') {
if (!process_DXX(kme, ptr[1], ptr[2]))
return NULL;
return ptr + 4;
}
/*
* loop until next double quote (")
*/
for (i = 0; i < 255; i++) {
if (*ptr == '"')
break;
if (*ptr == '\\') {
if (*++ptr == '"')
kme->data[0] = *ptr++;
else
ptr = escchar(ptr, &buf[i]);
}
else
buf[i] = *ptr++;
}
ptr++;
switch (i) { /* switch by length */
case 0:
kme->type = KME_UNBOUND;
PUT3BYTES(kme->data, '\0', '\0', '\0');
return ptr;
case 1:
kme->type = KME_SSTR1;
PUT3BYTES(kme->data, buf[0], '\0', '\0');
return ptr;
case 2:
if (buf[0] == 0x1b) {
kme->type = KME_ESEQ1;
PUT3BYTES(kme->data, buf[1], '\0', '\0');
}
else {
kme->type = KME_SSTR2;
PUT3BYTES(kme->data, buf[0], buf[1], '\0');
}
return ptr;
case 3:
if (buf[0] == 0x1b) {
kme->type = KME_ESEQ2;
PUT3BYTES(kme->data, buf[1], buf[2], '\0');
}
else {
kme->type = KME_SSTR3;
PUT3BYTES(kme->data, buf[0], buf[1], buf[2]);
}
return ptr;
case 4:
if (buf[0] == 0x1b) {
kme->type = KME_ESEQ3;
PUT3BYTES(kme->data, buf[1], buf[2], buf[3]);
return ptr;
}
break;
case 6:
if (buf[0] == 0x1b) {
if (buf[1] == '[' && isdigit(buf[2]) &&
isdigit(buf[3]) && isdigit(buf[4])) {
if (buf[5] == 'q') {
kme->type = KME_QPFK;
PUT3BYTES(kme->data,
buf[2], buf[3], buf[4]);
return ptr;
}
else if (buf[5] == 'z') {
kme->type = KME_ZPFK;
PUT3BYTES(kme->data,
buf[2], buf[3], buf[4]);
return ptr;
}
}
}
}
kme->type = KME_LSTR;
id = addtokstr(&buf[0], i);
PUT3DIGITS(kme->data, id);
return ptr;
case 'D':
if (isdigit(ptr[0]) && isdigit(ptr[1]) && ptr[2] == '"') {
if (!process_DXX(kme, ptr[0], ptr[1]))
return NULL;
return ptr + 3;
}
case '0':
if (*ptr == 'X' || *ptr == 'x') {
keysym = 0;
ptr++;
while (isxdigit(*ptr)) {
keysym = keysym * 16 + xdigit(*ptr);
ptr++;
}
placekeysym(kme, keysym);
return ptr;
}
c = 0;
i = 3; /* octal */
while (isodigit(*ptr) && i--)
c = (c << 3) + odigit(*ptr++);
kme->type = KME_SSTR1;
PUT3BYTES(kme->data, c, '\0', '\0');
return ptr;
}
return NULL;
}
static int process_line(char *ptr)
{
unsigned int keysym;
int c;
char *bp;
PLine *pline;
if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
/*
* keysym : hexdicimal value
*/
ptr += 2;
keysym = 0;
while (isxdigit(*ptr)) {
keysym = keysym * 16 + xdigit(*ptr);
ptr++;
}
}
else if (ptr[0] == 'X' && ptr[1] == 'K' && ptr[2] == '_') {
/*
* keysym : symbolic
*/
ptr += 3;
bp = ptr;
while (isalnum(*ptr) || *ptr == '_')
ptr++;
c = *ptr;
*ptr = '\0';
if (!lookupkeysym(bp, &keysym)) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
*ptr = c;
}
else {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
if (plines.len >= plines.siz) {
plines.siz += PLS_ALLOC_UNIT;
plines.pline = (PLine *)myrealloc((void *)plines.pline,
plines.siz * sizeof (PLine));
}
pline = &plines.pline[plines.len++];
pline->len = pline->siz = 0;
pline->kme = NULL;
pline->keysym = keysym;
while (1) {
while (1) {
if (*ptr == ' ' || *ptr == '\t' || *ptr == ',') {
ptr++;
continue;
}
if (ptr[0] == '/' && ptr[1] == '*') {
ptr += 2;
while (1) {
if (*ptr != '*' && *ptr != '\n') {
ptr++;
continue;
}
if (*ptr == '\n') {
if (maxplen < pline->len)
maxplen = pline->len;
return True;
}
if (*ptr++ == '/')
break;;
}
}
else
break;
}
if (*ptr == '\n') {
if (maxplen < pline->len)
maxplen = pline->len;
return True;
}
if (*ptr == '\\') {
if (ptr[1] != '\n')
return False;
item = 0;
if (!(ptr = getline())) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
continue;
}
if (pline->len >= pline->siz) {
pline->siz += PL_ALLOC_UNIT;
pline->kme =
(KeyMapElement *)myrealloc((void *)pline->kme,
pline->siz * sizeof (KeyMapElement));
}
if (!(ptr = process_item(&pline->kme[pline->len++], ptr)))
return False;
}
}
static int process_cntl(char *ptr, CLine *cline, int shift)
{
short stat;
cline->len = cline->siz = 0;
cline->stat = NULL;
while (1) {
while (*ptr == ' ' || *ptr == '\t') ptr++;
if (*ptr == '\n')
return True;
if (*ptr == '\\') {
if (ptr[1] != '\n')
return False;
if (!(ptr = getline())) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
continue;
}
if (!isdigit(*ptr))
return False;
stat = 0;
do {
stat = stat * 10 + *ptr++ - '0';
} while (isdigit(*ptr));
if (cline->len >= cline->siz) {
cline->siz += CL_ALLOC_UNIT;
cline->stat = (short *)myrealloc((void *)cline->stat,
cline->siz * sizeof (short));
}
cline->stat[cline->len++] = stat - shift;
}
}
static int comp(PLine *pl1, PLine *pl2)
{
if (pl1->keysym > pl2->keysym)
return 1;
else if (pl2->keysym > pl1->keysym)
return -1;
return 0;
}
static void outputkeymap()
{
int maxstat;
int i, j;
CLine *mline;
short *stat;
short idx;
KeyMapElement *pkme;
IMKeymapFile imfile;
int nstat;
static KeyMapElement unboundkme = {KME_UNBOUND, '\0', '\0', '\0'};
/*
* If there was no #S, #M or %M, default to the old format.
* (#S and #M)
*/
if (mflag == MFLAG_NONE)
mflag = MFLAG_OLD;
/*
* If it's the new format or there was no #S line with the old
* format, create a default sline.
*/
if (mflag == MFLAG_NEW || sline.len == 0) {
sline.siz = maxplen > 32 ? maxplen : 32;
sline.stat = (short *)malloc(sline.siz * sizeof (short));
if (!sline.stat) {
fprintf(stderr, MSGSTR(MN_MEM, E_MEM));
exit(2);
}
for (i = 0; i < sline.siz; i++)
sline.stat[i] = i;
sline.len = sline.siz;
}
/*
* invalidate states (sline) whose value exceed the number of
* elements listed and count the number of valid states.
*/
for (nstat = i = 0; i < sline.len; i++)
if (sline.stat[i] >= maxplen)
sline.stat[i] = -1;
else
nstat++;
/*
* get maximum state number and allocate the state mapping table.
*/
maxstat = 0;
for (i = 0; i < sline.len; i++)
if (maxstat < sline.stat[i])
maxstat = sline.stat[i];
for (i = 0; i < mlines.len; i++) {
mline = &mlines.mline[i];
for (j = 0; j < mline->len; j++)
if (maxstat < mline->stat[j])
maxstat = mline->stat[j];
}
maxstat += ++maxstat % 2;
stat = malloc(maxstat * sizeof (short));
/*
* fill the state mapping table.
*/
for (i = 0; i < maxstat; i++)
stat[i] = -1;
for (i = 0; i < sline.len; i++)
if (sline.stat[i] >= 0)
stat[sline.stat[i]] = i;
for (i = 0; i < mlines.len; i++) {
mline = &mlines.mline[i];
for (j = 1; j < mline->len; j++)
stat[mline->stat[j]] = mflag == MFLAG_NEW
? mline->stat[0]
: stat[mline->stat[0]];
}
/*
* imkeymap file header stuffs.
*/
/* round up to next int boundary */
kstrlen = ((kstrlen + sizeof (int) - 1) / sizeof (int)) * sizeof (int);
imfile.magic = ILS_KEYMAP_MAGIC;
imfile.dummy[0] = imfile.dummy[1] = imfile.dummy[2] = '\0';
imfile.statsiz = maxstat * sizeof (short);
imfile.ksymsiz = plines.len * sizeof (unsigned int);
imfile.elmtsiz = nstat * plines.len * sizeof (KeyMapElement);
imfile.kstrsiz = kstrlen;
imfile.oksymsiz = oksymlen * sizeof (unsigned int);
imfile.stat = sizeof (IMKeymapFile);
imfile.ksym = imfile.stat + imfile.statsiz;
imfile.elmt = imfile.ksym + imfile.ksymsiz;
imfile.kstr = imfile.elmt + imfile.elmtsiz;
imfile.oksym = imfile.kstr + imfile.kstrsiz;
/*
* write the header
*/
fwrite((char *)&imfile, sizeof (IMKeymapFile), 1, stdout);
/*
* write the state mapping table.
*/
fwrite((char *)stat, sizeof (short), maxstat, stdout);
/*
* sort lines by keysym value order.
*/
qsort((void *)plines.pline, plines.len, sizeof (PLine),
(int (*)())comp);
/*
* write the keysym table.
*/
for (i = 0; i < plines.len; i++)
fwrite((char *)&plines.pline[i].keysym,
sizeof (unsigned int), 1, stdout);
/*
* write the elements.
*/
for (i = 0; i < sline.len; i++) {
if ((idx = sline.stat[i]) < 0)
continue;
for (j = 0; j < plines.len; j++) {
if (idx >= plines.pline[j].len)
pkme = &unboundkme;
else
pkme = &plines.pline[j].kme[idx];
fwrite((char *)pkme, sizeof (KeyMapElement), 1, stdout);
}
}
/*
* write the strings if exist.
*/
if (kstrlen > 0)
fwrite((char *)kstr, sizeof (char), kstrlen, stdout);
/*
* write the other keysyms if exist.
*/
if (oksymlen > 0)
fwrite((char *)oksym, sizeof (unsigned int), oksymlen, stdout);
}
/*ARGSUSED*/
main(int argc, char **argv)
{
char *ptr;
setlocale(LC_MESSAGES, "");
#ifndef NL_CAT_LOCALE
catd = catopen(MF_KEYCOMP, 0);
#else
catd = catopen(MF_KEYCOMP, NL_CAT_LOCALE);
#endif /* NL_CAT_LOCALE */
if(argc > 2){
fprintf(stderr, MSGSTR(MN_USG, E_USG));
exit(1);
}else if(argc == 2){
if(strcmp(argv[1], "-c") != 0){
fprintf(stderr, MSGSTR(MN_USG, E_USG));
exit(1);
}
if(CompileCompose() == 0){
return(0);
}else{
return(1);
}
}
line = 0;
while (ptr = getline()) {
if (*ptr == '%') {
if (ptr[1] != 'M') {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
if (mflag == MFLAG_OLD) {
fprintf(stderr, MSGSTR(MN_MIX, E_MIX));
exit(1);
}
if (mlines.len >= mlines.siz) {
mlines.siz += MLS_ALLOC_UNIT;
mlines.mline =
(CLine *)myrealloc((void *)mlines.mline,
mlines.siz * sizeof (CLine));
}
if (!process_cntl(ptr + 2,
&mlines.mline[mlines.len++], 0)) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE), line);
exit(1);
}
mflag = MFLAG_NEW;
continue;
}
if (*ptr == '#') {
if (ptr[1] == 'M') {
if (mflag == MFLAG_NEW) {
fprintf(stderr, MSGSTR(MN_MIX, E_MIX));
exit(1);
}
if (mlines.len >= mlines.siz) {
mlines.siz += MLS_ALLOC_UNIT;
mlines.mline =
(CLine *)myrealloc(
(void *)mlines.mline,
mlines.siz * sizeof (CLine));
}
if (!process_cntl(ptr + 2,
&mlines.mline[mlines.len++], 1)) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE),
line);
exit(1);
}
mflag = MFLAG_OLD;
}
else if (ptr[1] == 'S') {
if (mflag == MFLAG_NEW) {
fprintf(stderr, MSGSTR(MN_MIX, E_MIX));
exit(1);
}
if (!process_cntl(ptr + 2, &sline, 1)) {
fprintf(stderr, MSGSTR(MN_LINE, E_LINE),
line);
exit(1);
}
mflag = MFLAG_OLD;
}
continue;
}
while (*ptr == ' ' || *ptr == '\t') ptr++;
if (*ptr == '\n')
continue;
if (!process_line(ptr)) {
fprintf(stderr, MSGSTR(MN_ITEM, E_ITEM), line, item);
exit(1);
}
}
outputkeymap();
return 0;
}