/* $Xorg: imLcPrs.c,v 1.3 2000/08/17 19:45:14 cpqbld Exp $ */ /****************************************************************** Copyright 1992 by Oki Technosystems Laboratory, Inc. Copyright 1992 by Fuji Xerox Co., Ltd. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Oki Technosystems Laboratory and Fuji Xerox not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Oki Technosystems Laboratory and Fuji Xerox make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Author: Yasuhiro Kawai Oki Technosystems Laboratory Author: Kazunori Nishihara Fuji Xerox ******************************************************************/ /* $XFree86: xc/lib/X11/imLcPrs.c,v 1.9 2003/04/13 19:22:21 dawes Exp $ */ #include #include #include #include "Xlibint.h" #include "Xlcint.h" #include "Ximint.h" #include #include extern int _Xmbstowcs( wchar_t *wstr, char *str, int len ); extern int _Xmbstoutf8( char *ustr, const char *str, int len ); /* * Parsing File Format: * * FILE ::= { [PRODUCTION] [COMMENT] "\n"} * PRODUCTION ::= LHS ":" RHS [ COMMENT ] * COMMENT ::= "#" {} * LHS ::= EVENT { EVENT } * EVENT ::= [MODIFIER_LIST] "<" keysym ">" * MODIFIER_LIST ::= ("!" {MODIFIER} ) | "None" * MODIFIER ::= ["~"] modifier_name * RHS ::= ( STRING | keysym | STRING keysym ) * STRING ::= '"' { CHAR } '"' * CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR * GRAPHIC_CHAR ::= locale (codeset) dependent code * ESCAPED_CHAR ::= ('\\' | '\"' | OCTAL | HEX ) * OCTAL ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]] * OCTAL_CHAR ::= (0|1|2|3|4|5|6|7) * HEX ::= '\' (x|X) HEX_CHAR [HEX_CHAR]] * HEX_CHAR ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f) * */ static int nextch( FILE *fp, int *lastch) { int c; if (*lastch != 0) { c = *lastch; *lastch = 0; } else { c = getc(fp); if (c == '\\') { c = getc(fp); if (c == '\n') { c = getc(fp); } else { ungetc(c, fp); c = '\\'; } } } return(c); } static void putbackch( int c, int *lastch) { *lastch = c; } #define ENDOFFILE 0 #define ENDOFLINE 1 #define COLON 2 #define LESS 3 #define GREATER 4 #define EXCLAM 5 #define TILDE 6 #define STRING 7 #define KEY 8 #define ERROR 9 #ifndef isalnum #define isalnum(c) \ (('0' <= (c) && (c) <= '9') || \ ('A' <= (c) && (c) <= 'Z') || \ ('a' <= (c) && (c) <= 'z')) #endif static int nexttoken( FILE *fp, char *tokenbuf, int *lastch) { int c; int token; char *p; int i, j; while ((c = nextch(fp, lastch)) == ' ' || c == '\t') { } switch (c) { case EOF: token = ENDOFFILE; break; case '\n': token = ENDOFLINE; break; case '<': token = LESS; break; case '>': token = GREATER; break; case ':': token = COLON; break; case '!': token = EXCLAM; break; case '~': token = TILDE; break; case '"': p = tokenbuf; while ((c = nextch(fp, lastch)) != '"') { if (c == '\n' || c == EOF) { putbackch(c, lastch); token = ERROR; goto string_error; } else if (c == '\\') { c = nextch(fp, lastch); switch (c) { case '\\': case '"': *p++ = c; break; case 'n': *p++ = '\n'; break; case 'r': *p++ = '\r'; break; case 't': *p++ = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': i = c - '0'; c = nextch(fp, lastch); for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) { i <<= 3; i += c - '0'; c = nextch(fp, lastch); } putbackch(c, lastch); *p++ = (char)i; break; case 'X': case 'x': i = 0; for (j = 0; j < 2; j++) { c = nextch(fp, lastch); i <<= 4; if (c >= '0' && c <= '9') { i += c - '0'; } else if (c >= 'A' && c <= 'F') { i += c - 'A' + 10; } else if (c >= 'a' && c <= 'f') { i += c - 'a' + 10; } else { putbackch(c, lastch); i >>= 4; break; } } if (j == 0) { token = ERROR; goto string_error; } *p++ = (char)i; break; case EOF: putbackch(c, lastch); token = ERROR; goto string_error; default: *p++ = c; break; } } else { *p++ = c; } } *p = '\0'; token = STRING; break; case '#': while ((c = nextch(fp, lastch)) != '\n' && c != EOF) { } if (c == '\n') { token = ENDOFLINE; } else { token = ENDOFFILE; } break; default: if (isalnum(c) || c == '_' || c == '-') { p = tokenbuf; *p++ = c; c = nextch(fp, lastch); while (isalnum(c) || c == '_' || c == '-') { *p++ = c; c = nextch(fp, lastch); } *p = '\0'; putbackch(c, lastch); token = KEY; } else { token = ERROR; } break; } string_error: return(token); } static long modmask( char *name) { long mask; struct _modtbl { char *name; long mask; }; struct _modtbl *p; static struct _modtbl tbl[] = { { "Ctrl", ControlMask }, { "Lock", LockMask }, { "Caps", LockMask }, { "Shift", ShiftMask }, { "Alt", Mod1Mask }, { "Meta", Mod1Mask }, { NULL, 0 }}; p = tbl; mask = 0; for (p = tbl; p->name != NULL; p++) { if (strcmp(name, p->name) == 0) { mask = p->mask; break; } } return(mask); } static char* TransFileName(Xim im, char *name) { char *home = NULL, *lcCompose = NULL; char *i = name, *ret, *j; int l = 0; while (*i) { if (*i == '%') { i++; switch (*i) { case '%': l++; break; case 'H': home = getenv("HOME"); if (home) l += strlen(home); break; case 'L': lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE); if (lcCompose) l += strlen(lcCompose); break; } } else { l++; } i++; } j = ret = Xmalloc(l+1); if (ret == NULL) return ret; i = name; while (*i) { if (*i == '%') { i++; switch (*i) { case '%': *j++ = '%'; break; case 'H': if (home) { strcpy(j, home); j += strlen(home); } break; case 'L': if (lcCompose) { strcpy(j, lcCompose); j += strlen(lcCompose); Xfree(lcCompose); } break; } i++; } else { *j++ = *i++; } } *j = '\0'; return ret; } #ifndef MB_LEN_MAX #define MB_LEN_MAX 6 #endif static int get_mb_string (Xim im, char *buf, KeySym ks) { XPointer from, to; int from_len, to_len, len; XPointer args[1]; XlcCharSet charset; char local_buf[MB_LEN_MAX]; unsigned int ucs; ucs = KeySymToUcs4(ks); from = (XPointer) &ucs; to = (XPointer) local_buf; from_len = 1; to_len = MB_LEN_MAX; args[0] = (XPointer) &charset; if (_XlcConvert(im->private.local.ucstoc_conv, &from, &from_len, &to, &to_len, args, 1 ) != 0) { return 0; } from = (XPointer) local_buf; to = (XPointer) buf; from_len = MB_LEN_MAX - to_len; to_len = MB_LEN_MAX + 1; args[0] = (XPointer) charset; if (_XlcConvert(im->private.local.cstomb_conv, &from, &from_len, &to, &to_len, args, 1 ) != 0) { return 0; } len = MB_LEN_MAX + 1 - to_len; buf[len] = '\0'; return len; } #define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask) #define LOCAL_WC_BUFSIZE 128 #define LOCAL_UTF8_BUFSIZE 256 #define SEQUENCE_MAX 10 static int parseline( FILE *fp, Xim im, char* tokenbuf) { int token; unsigned modifier_mask; unsigned modifier; unsigned tmp; KeySym keysym = NoSymbol; DefTree **top = &im->private.local.top; DefTree *p = NULL; Bool exclam, tilde; KeySym rhs_keysym = 0; char *rhs_string_mb; int l; int lastch = 0; char local_mb_buf[MB_LEN_MAX+1]; wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc; char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8; struct DefBuffer { unsigned modifier_mask; unsigned modifier; KeySym keysym; }; struct DefBuffer buf[SEQUENCE_MAX]; int i, n; do { token = nexttoken(fp, tokenbuf, &lastch); } while (token == ENDOFLINE); if (token == ENDOFFILE) { return(-1); } n = 0; do { if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) { char *filename; FILE *infp; token = nexttoken(fp, tokenbuf, &lastch); if (token != KEY && token != STRING) goto error; if ((filename = TransFileName(im, tokenbuf)) == NULL) goto error; infp = _XFopenFile(filename, "r"); Xfree(filename); if (infp == NULL) goto error; _XimParseStringFile(infp, im); return (0); } else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) { modifier = 0; modifier_mask = AllMask; token = nexttoken(fp, tokenbuf, &lastch); } else { modifier_mask = modifier = 0; exclam = False; if (token == EXCLAM) { exclam = True; token = nexttoken(fp, tokenbuf, &lastch); } while (token == TILDE || token == KEY) { tilde = False; if (token == TILDE) { tilde = True; token = nexttoken(fp, tokenbuf, &lastch); if (token != KEY) goto error; } tmp = modmask(tokenbuf); if (!tmp) { goto error; } modifier_mask |= tmp; if (tilde) { modifier &= ~tmp; } else { modifier |= tmp; } token = nexttoken(fp, tokenbuf, &lastch); } if (exclam) { modifier_mask = AllMask; } } if (token != LESS) { goto error; } token = nexttoken(fp, tokenbuf, &lastch); if (token != KEY) { goto error; } token = nexttoken(fp, tokenbuf, &lastch); if (token != GREATER) { goto error; } keysym = XStringToKeysym(tokenbuf); if (keysym == NoSymbol) { goto error; } buf[n].keysym = keysym; buf[n].modifier = modifier; buf[n].modifier_mask = modifier_mask; n++; if( n >= SEQUENCE_MAX ) goto error; token = nexttoken(fp, tokenbuf, &lastch); } while (token != COLON); token = nexttoken(fp, tokenbuf, &lastch); if (token == STRING) { if( (rhs_string_mb = Xmalloc(strlen(tokenbuf) + 1)) == NULL ) goto error; strcpy(rhs_string_mb, tokenbuf); token = nexttoken(fp, tokenbuf, &lastch); if (token == KEY) { rhs_keysym = XStringToKeysym(tokenbuf); if (rhs_keysym == NoSymbol) { Xfree(rhs_string_mb); goto error; } token = nexttoken(fp, tokenbuf, &lastch); } if (token != ENDOFLINE && token != ENDOFFILE) { Xfree(rhs_string_mb); goto error; } } else if (token == KEY) { rhs_keysym = XStringToKeysym(tokenbuf); if (rhs_keysym == NoSymbol) { goto error; } token = nexttoken(fp, tokenbuf, &lastch); if (token != ENDOFLINE && token != ENDOFFILE) { goto error; } l = get_mb_string(im, local_mb_buf, rhs_keysym); if (l == 0) { rhs_string_mb = Xmalloc(1); } else { rhs_string_mb = Xmalloc(l + 1); } if( rhs_string_mb == NULL ) { goto error; } memcpy(rhs_string_mb, local_mb_buf, l); rhs_string_mb[l] = '\0'; } else { goto error; } l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1); if (l == LOCAL_WC_BUFSIZE - 1) { local_wc_buf[l] = (wchar_t)'\0'; } if( (rhs_string_wc = (wchar_t *)Xmalloc((l + 1) * sizeof(wchar_t))) == NULL ) { Xfree( rhs_string_mb ); return( 0 ); } memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) ); l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1); if (l == LOCAL_UTF8_BUFSIZE - 1) { local_wc_buf[l] = '\0'; } if( (rhs_string_utf8 = (char *)Xmalloc(l + 1)) == NULL ) { Xfree( rhs_string_wc ); Xfree( rhs_string_mb ); return( 0 ); } memcpy(rhs_string_utf8, local_utf8_buf, l + 1); for (i = 0; i < n; i++) { for (p = *top; p; p = p->next) { if (buf[i].keysym == p->keysym && buf[i].modifier == p->modifier && buf[i].modifier_mask == p->modifier_mask) { break; } } if (p) { top = &p->succession; } else { if( (p = (DefTree*)Xmalloc(sizeof(DefTree))) == NULL ) { Xfree( rhs_string_mb ); goto error; } p->keysym = buf[i].keysym; p->modifier = buf[i].modifier; p->modifier_mask = buf[i].modifier_mask; p->succession = NULL; p->next = *top; p->mb = NULL; p->wc = NULL; p->utf8 = NULL; p->ks = NoSymbol; *top = p; top = &p->succession; } } if( p->mb != NULL ) Xfree( p->mb ); p->mb = rhs_string_mb; if( p->wc != NULL ) Xfree( p->wc ); p->wc = rhs_string_wc; if( p->utf8 != NULL ) Xfree( p->utf8 ); p->utf8 = rhs_string_utf8; p->ks = rhs_keysym; return(n); error: while (token != ENDOFLINE && token != ENDOFFILE) { token = nexttoken(fp, tokenbuf, &lastch); } return(0); } void _XimParseStringFile( FILE *fp, Xim im) { char tb[8192]; char* tbp; struct stat st; if (fstat (fileno (fp), &st) != -1) { unsigned long size = (unsigned long) st.st_size; if (size <= sizeof tb) tbp = tb; else tbp = malloc (size); if (tbp != NULL) { while (parseline(fp, im, tbp) >= 0) {} if (tbp != tb) free (tbp); } } }