Home | History | Annotate | Line # | Download | only in ximcp
      1 /******************************************************************
      2 
      3               Copyright 1992 by Oki Technosystems Laboratory, Inc.
      4               Copyright 1992 by Fuji Xerox Co., Ltd.
      5 
      6 Permission to use, copy, modify, distribute, and sell this software
      7 and its documentation for any purpose is hereby granted without fee,
      8 provided that the above copyright notice appear in all copies and
      9 that both that copyright notice and this permission notice appear
     10 in supporting documentation, and that the name of Oki Technosystems
     11 Laboratory and Fuji Xerox not be used in advertising or publicity
     12 pertaining to distribution of the software without specific, written
     13 prior permission.
     14 Oki Technosystems Laboratory and Fuji Xerox make no representations
     15 about the suitability of this software for any purpose.  It is provided
     16 "as is" without express or implied warranty.
     17 
     18 OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
     19 WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
     20 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
     21 LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     22 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
     23 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     24 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
     25 OR PERFORMANCE OF THIS SOFTWARE.
     26 
     27   Author: Yasuhiro Kawai	Oki Technosystems Laboratory
     28   Author: Kazunori Nishihara	Fuji Xerox
     29 
     30 ******************************************************************/
     31 
     32 
     33 #ifdef HAVE_CONFIG_H
     34 #include <config.h>
     35 #endif
     36 #include <X11/Xlib.h>
     37 #include <X11/Xmd.h>
     38 #include <X11/Xos.h>
     39 #include "Xlibint.h"
     40 #include "Xlcint.h"
     41 #include "Ximint.h"
     42 #include <sys/stat.h>
     43 #include <stdio.h>
     44 #include <limits.h>
     45 #include "pathmax.h"
     46 
     47 #define XLC_BUFSIZE 256
     48 
     49 extern int _Xmbstowcs(
     50     wchar_t	*wstr,
     51     char	*str,
     52     int		len
     53 );
     54 
     55 extern int _Xmbstoutf8(
     56     char	*ustr,
     57     const char	*str,
     58     int		len
     59 );
     60 
     61 static void parsestringfile(FILE *fp, Xim im, int depth);
     62 
     63 /*
     64  *	Parsing File Format:
     65  *
     66  *	FILE          ::= { [PRODUCTION] [COMMENT] "\n"}
     67  *	PRODUCTION    ::= LHS ":" RHS [ COMMENT ]
     68  *	COMMENT       ::= "#" {<any character except null or newline>}
     69  *	LHS           ::= EVENT { EVENT }
     70  *	EVENT         ::= [MODIFIER_LIST] "<" keysym ">"
     71  *	MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
     72  *	MODIFIER      ::= ["~"] MODIFIER_NAME
     73  *	MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
     74  *	RHS           ::= ( STRING | keysym | STRING keysym )
     75  *	STRING        ::= '"' { CHAR } '"'
     76  *	CHAR          ::= GRAPHIC_CHAR | ESCAPED_CHAR
     77  *	GRAPHIC_CHAR  ::= locale (codeset) dependent code
     78  *	ESCAPED_CHAR  ::= ('\\' | '\"' | OCTAL | HEX )
     79  *	OCTAL         ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]]
     80  *	OCTAL_CHAR    ::= (0|1|2|3|4|5|6|7)
     81  *	HEX           ::= '\' (x|X) HEX_CHAR [HEX_CHAR]]
     82  *	HEX_CHAR      ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f)
     83  *
     84  */
     85 
     86 static int
     87 nextch(
     88     FILE *fp,
     89     int *lastch)
     90 {
     91     int c;
     92 
     93     if (*lastch != 0) {
     94 	c = *lastch;
     95 	*lastch = 0;
     96     } else {
     97 	c = getc(fp);
     98 	if (c == '\\') {
     99 	    c = getc(fp);
    100 	    if (c == '\n') {
    101 		c = getc(fp);
    102 	    } else {
    103 		ungetc(c, fp);
    104 		c = '\\';
    105 	    }
    106 	}
    107     }
    108     return(c);
    109 }
    110 
    111 static void
    112 putbackch(
    113     int c,
    114     int *lastch)
    115 {
    116     *lastch = c;
    117 }
    118 
    119 #define ENDOFFILE 0
    120 #define ENDOFLINE 1
    121 #define COLON 2
    122 #define LESS 3
    123 #define GREATER 4
    124 #define EXCLAM 5
    125 #define TILDE 6
    126 #define STRING 7
    127 #define KEY 8
    128 #define ERROR 9
    129 
    130 #ifndef isalnum
    131 #define isalnum(c)      \
    132     (('0' <= (c) && (c) <= '9')  || \
    133      ('A' <= (c) && (c) <= 'Z')  || \
    134      ('a' <= (c) && (c) <= 'z'))
    135 #endif
    136 
    137 static int
    138 nexttoken(
    139     FILE *fp,
    140     char *tokenbuf,
    141     int *lastch)
    142 {
    143     int c;
    144     int token;
    145     char *p;
    146     int i, j;
    147 
    148     while ((c = nextch(fp, lastch)) == ' ' || c == '\t') {
    149     }
    150     switch (c) {
    151       case EOF:
    152 	token = ENDOFFILE;
    153 	break;
    154       case '\n':
    155 	token = ENDOFLINE;
    156 	break;
    157       case '<':
    158 	token = LESS;
    159 	break;
    160       case '>':
    161 	token = GREATER;
    162 	break;
    163       case ':':
    164 	token = COLON;
    165 	break;
    166       case '!':
    167 	token = EXCLAM;
    168 	break;
    169       case '~':
    170 	token = TILDE;
    171 	break;
    172       case '"':
    173 	p = tokenbuf;
    174 	while ((c = nextch(fp, lastch)) != '"') {
    175 	    if (c == '\n' || c == EOF) {
    176 		putbackch(c, lastch);
    177 		token = ERROR;
    178 		goto string_error;
    179 	    } else if (c == '\\') {
    180 		c = nextch(fp, lastch);
    181 		switch (c) {
    182 		  case '\\':
    183 		  case '"':
    184 		    *p++ = c;
    185 		    break;
    186 		  case 'n':
    187 		    *p++ = '\n';
    188 		    break;
    189 		  case 'r':
    190 		    *p++ = '\r';
    191 		    break;
    192 		  case 't':
    193 		    *p++ = '\t';
    194 		    break;
    195 		  case '0':
    196 		  case '1':
    197 		  case '2':
    198 		  case '3':
    199 		  case '4':
    200 		  case '5':
    201 		  case '6':
    202 		  case '7':
    203 		    i = c - '0';
    204 		    c = nextch(fp, lastch);
    205 		    for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) {
    206 			i <<= 3;
    207 			i += c - '0';
    208 			c = nextch(fp, lastch);
    209 		    }
    210 		    putbackch(c, lastch);
    211 		    *p++ = (char)i;
    212 		    break;
    213 		  case 'X':
    214 		  case 'x':
    215 		    i = 0;
    216 		    for (j = 0; j < 2; j++) {
    217 			c = nextch(fp, lastch);
    218  			i <<= 4;
    219 			if (c >= '0' && c <= '9') {
    220 			    i += c - '0';
    221 			} else if (c >= 'A' && c <= 'F') {
    222 			    i += c - 'A' + 10;
    223 			} else if (c >= 'a' && c <= 'f') {
    224 			    i += c - 'a' + 10;
    225 			} else {
    226 			    putbackch(c, lastch);
    227 			    i >>= 4;
    228 			    break;
    229 		        }
    230 		    }
    231 		    if (j == 0) {
    232 		        token = ERROR;
    233 		        goto string_error;
    234 		    }
    235 		    *p++ = (char)i;
    236 		    break;
    237 		  case EOF:
    238 		    putbackch(c, lastch);
    239 		    token = ERROR;
    240 		    goto string_error;
    241 		  default:
    242 		    *p++ = c;
    243 		    break;
    244 		}
    245 	    } else {
    246 		*p++ = c;
    247 	    }
    248 	}
    249 	*p = '\0';
    250 	token = STRING;
    251 	break;
    252       case '#':
    253 	while ((c = nextch(fp, lastch)) != '\n' && c != EOF) {
    254 	}
    255 	if (c == '\n') {
    256 	    token = ENDOFLINE;
    257 	} else {
    258 	    token = ENDOFFILE;
    259 	}
    260 	break;
    261       default:
    262 	if (isalnum(c) || c == '_' || c == '-') {
    263 	    p = tokenbuf;
    264 	    *p++ = c;
    265 	    c = nextch(fp, lastch);
    266 	    while (isalnum(c) || c == '_' || c == '-') {
    267 		*p++ = c;
    268 		c = nextch(fp, lastch);
    269 	    }
    270 	    *p = '\0';
    271 	    putbackch(c, lastch);
    272 	    token = KEY;
    273 	} else {
    274 	    token = ERROR;
    275 	}
    276 	break;
    277     }
    278 string_error:
    279     return(token);
    280 }
    281 
    282 static long
    283 modmask(
    284     char *name)
    285 {
    286     struct _modtbl {
    287 	const char name[6];
    288 	long mask;
    289     };
    290 
    291     static const struct _modtbl tbl[] = {
    292 	{ "Ctrl",	ControlMask	},
    293         { "Lock",	LockMask	},
    294         { "Caps",	LockMask	},
    295         { "Shift",	ShiftMask	},
    296         { "Alt",	Mod1Mask	},
    297         { "Meta",	Mod1Mask	}};
    298 
    299     int i, num_entries = sizeof (tbl) / sizeof (tbl[0]);
    300 
    301     for (i = 0; i < num_entries; i++)
    302         if (!strcmp (name, tbl[i].name))
    303             return tbl[i].mask;
    304 
    305     return 0;
    306 }
    307 
    308 static char*
    309 TransFileName(Xim im, char *name)
    310 {
    311    char *home = NULL, *lcCompose = NULL;
    312    char dir[XLC_BUFSIZE] = "";
    313    char *i = name, *ret = NULL, *j;
    314    size_t l = 0;
    315 
    316    while (*i) {
    317       if (*i == '%') {
    318    	  i++;
    319    	  switch (*i) {
    320    	      case '%':
    321                  l++;
    322    	         break;
    323    	      case 'H':
    324                  if (home == NULL)
    325                      home = getenv("HOME");
    326                  if (home) {
    327                      size_t Hsize = strlen(home);
    328                      if (Hsize > PATH_MAX)
    329                          /* your home directory length is ridiculous */
    330                          goto end;
    331                      l += Hsize;
    332                  }
    333    	         break;
    334    	      case 'L':
    335                  if (lcCompose == NULL)
    336                      lcCompose = _XlcFileName(im->core.lcd, COMPOSE_FILE);
    337                  if (lcCompose) {
    338                      size_t Lsize = strlen(lcCompose);
    339                      if (Lsize > PATH_MAX)
    340                          /* your compose pathname length is ridiculous */
    341                          goto end;
    342                      l += Lsize;
    343                  }
    344    	         break;
    345    	      case 'S':
    346                  if (dir[0] == '\0')
    347                      xlocaledir(dir, XLC_BUFSIZE);
    348                  if (dir[0]) {
    349                      size_t Ssize = strlen(dir);
    350                      if (Ssize > PATH_MAX)
    351                          /* your locale directory path length is ridiculous */
    352                          goto end;
    353                      l += Ssize;
    354                  }
    355    	         break;
    356    	  }
    357       } else {
    358       	  l++;
    359       }
    360       i++;
    361       if (l > PATH_MAX)
    362           /* your expanded path length is ridiculous */
    363           goto end;
    364    }
    365 
    366    j = ret = Xmalloc(l+1);
    367    if (ret == NULL)
    368       goto end;
    369    i = name;
    370    while (*i) {
    371       if (*i == '%') {
    372    	  i++;
    373    	  switch (*i) {
    374    	      case '%':
    375                  *j++ = '%';
    376    	         break;
    377    	      case 'H':
    378    	         if (home) {
    379    	             strcpy(j, home);
    380    	             j += strlen(home);
    381    	         }
    382    	         break;
    383    	      case 'L':
    384    	         if (lcCompose) {
    385                     strcpy(j, lcCompose);
    386                     j += strlen(lcCompose);
    387                  }
    388    	         break;
    389    	      case 'S':
    390                  strcpy(j, dir);
    391                  j += strlen(dir);
    392    	         break;
    393    	  }
    394           i++;
    395       } else {
    396       	  *j++ = *i++;
    397       }
    398    }
    399    *j = '\0';
    400 end:
    401    Xfree(lcCompose);
    402    return ret;
    403 }
    404 
    405 #ifndef MB_LEN_MAX
    406 #define MB_LEN_MAX 6
    407 #endif
    408 
    409 static int
    410 get_mb_string (Xim im, char *buf, KeySym ks)
    411 {
    412     XPointer from, to;
    413     int from_len, to_len, len;
    414     XPointer args[1];
    415     XlcCharSet charset;
    416     char local_buf[MB_LEN_MAX];
    417     unsigned int ucs;
    418     ucs = KeySymToUcs4(ks);
    419 
    420     from = (XPointer) &ucs;
    421     to =   (XPointer) local_buf;
    422     from_len = 1;
    423     to_len = MB_LEN_MAX;
    424     args[0] = (XPointer) &charset;
    425     if (_XlcConvert(im->private.local.ucstoc_conv,
    426                     &from, &from_len, &to, &to_len, args, 1 ) != 0) {
    427          return 0;
    428     }
    429 
    430     from = (XPointer) local_buf;
    431     to =   (XPointer) buf;
    432     from_len = MB_LEN_MAX - to_len;
    433     to_len = MB_LEN_MAX + 1;
    434     args[0] = (XPointer) charset;
    435     if (_XlcConvert(im->private.local.cstomb_conv,
    436                     &from, &from_len, &to, &to_len, args, 1 ) != 0) {
    437          return 0;
    438     }
    439     len = MB_LEN_MAX + 1 - to_len;
    440     buf[len] = '\0';
    441     return len;
    442 }
    443 
    444 #define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask)
    445 #define LOCAL_WC_BUFSIZE 128
    446 #define LOCAL_UTF8_BUFSIZE 256
    447 #define SEQUENCE_MAX	10
    448 
    449 static int
    450 parseline(
    451     FILE *fp,
    452     Xim   im,
    453     char* tokenbuf,
    454     int   depth)
    455 {
    456     int token;
    457     DTModifier modifier_mask;
    458     DTModifier modifier;
    459     DTModifier tmp;
    460     KeySym keysym = NoSymbol;
    461     DTIndex *top = &im->private.local.top;
    462     DefTreeBase *b   = &im->private.local.base;
    463     DTIndex t;
    464     DefTree *p = NULL;
    465     Bool exclam, tilde;
    466     KeySym rhs_keysym = 0;
    467     char *rhs_string_mb;
    468     int l;
    469     int lastch = 0;
    470     char local_mb_buf[MB_LEN_MAX+1];
    471     wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc;
    472     char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8;
    473 
    474     struct DefBuffer {
    475 	DTModifier modifier_mask;
    476 	DTModifier modifier;
    477 	KeySym keysym;
    478     };
    479 
    480     struct DefBuffer buf[SEQUENCE_MAX];
    481     int i, n;
    482 
    483     do {
    484 	token = nexttoken(fp, tokenbuf, &lastch);
    485     } while (token == ENDOFLINE);
    486 
    487     if (token == ENDOFFILE) {
    488 	return(-1);
    489     }
    490 
    491     n = 0;
    492     do {
    493     	if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) {
    494             char *filename;
    495             FILE *infp;
    496             token = nexttoken(fp, tokenbuf, &lastch);
    497             if (token != KEY && token != STRING)
    498                 goto error;
    499             if (++depth > 100)
    500                 goto error;
    501             if ((filename = TransFileName(im, tokenbuf)) == NULL)
    502                 goto error;
    503             infp = _XFopenFile(filename, "r");
    504             Xfree(filename);
    505             if (infp == NULL)
    506                 goto error;
    507             parsestringfile(infp, im, depth);
    508             fclose(infp);
    509             return (0);
    510 	} else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) {
    511 	    modifier = 0;
    512 	    modifier_mask = AllMask;
    513 	    token = nexttoken(fp, tokenbuf, &lastch);
    514 	} else {
    515 	    modifier_mask = modifier = 0;
    516 	    exclam = False;
    517 	    if (token == EXCLAM) {
    518 		exclam = True;
    519 		token = nexttoken(fp, tokenbuf, &lastch);
    520 	    }
    521 	    while (token == TILDE || token == KEY) {
    522 		tilde = False;
    523 		if (token == TILDE) {
    524 		    tilde = True;
    525 		    token = nexttoken(fp, tokenbuf, &lastch);
    526 		    if (token != KEY)
    527 			goto error;
    528 		}
    529 		tmp = modmask(tokenbuf);
    530 		if (!tmp) {
    531 		    goto error;
    532 		}
    533 		modifier_mask |= tmp;
    534 		if (tilde) {
    535 		    modifier &= ~tmp;
    536 		} else {
    537 		    modifier |= tmp;
    538 		}
    539 		token = nexttoken(fp, tokenbuf, &lastch);
    540 	    }
    541 	    if (exclam) {
    542 		modifier_mask = AllMask;
    543 	    }
    544 	}
    545 
    546 	if (token != LESS) {
    547 	    goto error;
    548 	}
    549 
    550 	token = nexttoken(fp, tokenbuf, &lastch);
    551 	if (token != KEY) {
    552 	    goto error;
    553 	}
    554 
    555 	token = nexttoken(fp, tokenbuf, &lastch);
    556 	if (token != GREATER) {
    557 	    goto error;
    558 	}
    559 
    560 	keysym = XStringToKeysym(tokenbuf);
    561 	if (keysym == NoSymbol) {
    562 	    goto error;
    563 	}
    564 
    565 	buf[n].keysym = keysym;
    566 	buf[n].modifier = modifier;
    567 	buf[n].modifier_mask = modifier_mask;
    568 	n++;
    569 	if( n >= SEQUENCE_MAX )
    570 	    goto error;
    571 	token = nexttoken(fp, tokenbuf, &lastch);
    572     } while (token != COLON);
    573 
    574     token = nexttoken(fp, tokenbuf, &lastch);
    575     if (token == STRING) {
    576 	l = strlen(tokenbuf) + 1;
    577 	while (b->mbused + l > b->mbsize) {
    578 	    DTCharIndex newsize = b->mbsize ? b->mbsize * 1.5 : 1024;
    579 	    char *newmb = Xrealloc (b->mb, newsize);
    580 	    if (newmb == NULL)
    581 		goto error;
    582 	    b->mb = newmb;
    583 	    b->mbsize = newsize;
    584 	}
    585 	rhs_string_mb = &b->mb[b->mbused];
    586 	b->mbused    += l;
    587 	strcpy(rhs_string_mb, tokenbuf);
    588 	token = nexttoken(fp, tokenbuf, &lastch);
    589 	if (token == KEY) {
    590 	    rhs_keysym = XStringToKeysym(tokenbuf);
    591 	    if (rhs_keysym == NoSymbol) {
    592 		goto error;
    593 	    }
    594 	    token = nexttoken(fp, tokenbuf, &lastch);
    595 	}
    596 	if (token != ENDOFLINE && token != ENDOFFILE) {
    597 	    goto error;
    598 	}
    599     } else if (token == KEY) {
    600 	rhs_keysym = XStringToKeysym(tokenbuf);
    601 	if (rhs_keysym == NoSymbol) {
    602 	    goto error;
    603 	}
    604 	token = nexttoken(fp, tokenbuf, &lastch);
    605 	if (token != ENDOFLINE && token != ENDOFFILE) {
    606 	    goto error;
    607 	}
    608 
    609         l = get_mb_string(im, local_mb_buf, rhs_keysym);
    610 	while (b->mbused + l + 1 > b->mbsize) {
    611 	    DTCharIndex newsize = b->mbsize ? b->mbsize * 1.5 : 1024;
    612 	    char *newmb = Xrealloc (b->mb, newsize);
    613 	    if (newmb == NULL)
    614 		goto error;
    615 	    b->mb = newmb;
    616 	    b->mbsize = newsize;
    617 	}
    618 	rhs_string_mb = &b->mb[b->mbused];
    619 	b->mbused    += l + 1;
    620         memcpy(rhs_string_mb, local_mb_buf, l);
    621 	rhs_string_mb[l] = '\0';
    622     } else {
    623 	goto error;
    624     }
    625 
    626     l = _Xmbstowcs(local_wc_buf, rhs_string_mb, LOCAL_WC_BUFSIZE - 1);
    627     if (l == LOCAL_WC_BUFSIZE - 1) {
    628 	local_wc_buf[l] = (wchar_t)'\0';
    629     }
    630     while (b->wcused + l + 1 > b->wcsize) {
    631 	DTCharIndex newsize = b->wcsize ? b->wcsize * 1.5 : 512;
    632 	wchar_t *newwc = Xrealloc (b->wc, sizeof(wchar_t) * newsize);
    633 	if (newwc == NULL)
    634 	    goto error;
    635 	b->wc = newwc;
    636 	b->wcsize = newsize;
    637     }
    638     rhs_string_wc = &b->wc[b->wcused];
    639     b->wcused    += l + 1;
    640     memcpy((char *)rhs_string_wc, (char *)local_wc_buf, (l + 1) * sizeof(wchar_t) );
    641 
    642     l = _Xmbstoutf8(local_utf8_buf, rhs_string_mb, LOCAL_UTF8_BUFSIZE - 1);
    643     if (l == LOCAL_UTF8_BUFSIZE - 1) {
    644 	local_utf8_buf[l] = '\0';
    645     }
    646     while (b->utf8used + l + 1 > b->utf8size) {
    647 	DTCharIndex newsize = b->utf8size ? b->utf8size * 1.5 : 1024;
    648 	char *newutf8 = Xrealloc (b->utf8, newsize);
    649 	if (newutf8 == NULL)
    650 	    goto error;
    651 	b->utf8 = newutf8;
    652 	b->utf8size = newsize;
    653     }
    654     rhs_string_utf8 = &b->utf8[b->utf8used];
    655     b->utf8used    += l + 1;
    656     memcpy(rhs_string_utf8, local_utf8_buf, l + 1);
    657 
    658     for (i = 0; i < n; i++) {
    659 	for (t = *top; t; t = b->tree[t].next) {
    660 	    if (buf[i].keysym        == b->tree[t].keysym &&
    661 		buf[i].modifier      == b->tree[t].modifier &&
    662 		buf[i].modifier_mask == b->tree[t].modifier_mask) {
    663 		break;
    664 	    }
    665 	}
    666 	if (t) {
    667 	    p = &b->tree[t];
    668 	    top = &p->succession;
    669 	} else {
    670 	    while (b->treeused >= b->treesize) {
    671 		DefTree *old     = b->tree;
    672 		int      oldsize = b->treesize;
    673 		int      newsize = b->treesize ? b->treesize * 1.5 : 256;
    674 		DefTree *new     = Xrealloc (b->tree, sizeof(DefTree) * newsize);
    675 		if (new == NULL)
    676 		    goto error;
    677 		b->tree = new;
    678 		b->treesize = newsize;
    679 		/* Re-derive top after realloc() to avoid undefined behaviour
    680 		   (and crashes on architectures that track pointer bounds). */
    681 		if (old && top >= (DTIndex *) old && top < (DTIndex *) &old[oldsize])
    682 		    top = (DTIndex *) (((char *)new) + (((char *)top)-(char *)old));
    683 	    }
    684 	    p = &b->tree[b->treeused];
    685 	    p->keysym        = buf[i].keysym;
    686 	    p->modifier      = buf[i].modifier;
    687 	    p->modifier_mask = buf[i].modifier_mask;
    688 	    p->succession    = 0;
    689 	    p->next          = *top;
    690 	    p->mb            = 0;
    691 	    p->wc            = 0;
    692 	    p->utf8          = 0;
    693 	    p->ks            = NoSymbol;
    694 	    *top = b->treeused;
    695 	    top = &p->succession;
    696 	    b->treeused++;
    697 	}
    698     }
    699 
    700     /* old entries no longer freed... */
    701     p->mb   = rhs_string_mb   - b->mb;
    702     p->wc   = rhs_string_wc   - b->wc;
    703     p->utf8 = rhs_string_utf8 - b->utf8;
    704     p->ks   = rhs_keysym;
    705     return(n);
    706 error:
    707     while (token != ENDOFLINE && token != ENDOFFILE) {
    708 	token = nexttoken(fp, tokenbuf, &lastch);
    709     }
    710     return(0);
    711 }
    712 
    713 void
    714 _XimParseStringFile(
    715     FILE *fp,
    716     Xim   im)
    717 {
    718     parsestringfile(fp, im, 0);
    719 }
    720 
    721 static void
    722 parsestringfile(
    723     FILE *fp,
    724     Xim   im,
    725     int   depth)
    726 {
    727     char tb[8192];
    728     char* tbp;
    729     struct stat st;
    730 
    731     if (fstat (fileno (fp), &st) != -1) {
    732 	unsigned long size = (unsigned long) st.st_size;
    733 	if (st.st_size >= INT_MAX)
    734 	    return;
    735 	if (size <= sizeof tb) tbp = tb;
    736 	else tbp = malloc (size);
    737 
    738 	if (tbp != NULL) {
    739 	    while (parseline(fp, im, tbp, depth) >= 0) {}
    740 	    if (tbp != tb) free (tbp);
    741 	}
    742     }
    743 }
    744