fontxlfd.c revision c7b4381a
1/*
2
3Copyright 1990, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * Author:  Keith Packard, MIT X Consortium
31 */
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36#include "libxfontint.h"
37#include	<X11/fonts/fontmisc.h>
38#include	<X11/fonts/fontstruct.h>
39#include	<X11/fonts/fontxlfd.h>
40#include	<X11/fonts/fontutil.h>
41#include	<X11/fonts/fntfilst.h> /* for MAXFONTNAMELEN */
42#include	<X11/Xos.h>
43#include	<math.h>
44#include	<stdlib.h>
45#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
46#define NO_LOCALE
47#endif
48#ifndef NO_LOCALE
49#include	<locale.h>
50#endif
51#include	<ctype.h>
52#include	<stdio.h>	/* for sprintf() */
53#include	"src/util/replace.h"
54
55static char *
56GetInt(char *ptr, int *val)
57{
58    if (*ptr == '*') {
59	*val = -1;
60	ptr++;
61    } else
62	for (*val = 0; *ptr >= '0' && *ptr <= '9';)
63	    *val = *val * 10 + *ptr++ - '0';
64    if (*ptr == '-')
65	return ptr;
66    return (char *) 0;
67}
68
69#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
70#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
71
72
73#ifndef NO_LOCALE
74static struct lconv *locale = 0;
75#endif
76static const char *radix = ".", *plus = "+", *minus = "-";
77
78static char *
79readreal(char *ptr, double *result)
80{
81    char buffer[80], *p1, *p2;
82
83#ifndef NO_LOCALE
84    /* Figure out what symbols apply in this locale */
85
86    if (!locale)
87    {
88	locale = localeconv();
89	if (locale->decimal_point && *locale->decimal_point)
90	    radix = locale->decimal_point;
91	if (locale->positive_sign && *locale->positive_sign)
92	    plus = locale->positive_sign;
93	if (locale->negative_sign && *locale->negative_sign)
94	    minus = locale->negative_sign;
95    }
96#endif
97    /* Copy the first 80 chars of ptr into our local buffer, changing
98       symbols as needed. */
99    for (p1 = ptr, p2 = buffer;
100	 *p1 && (p2 - buffer) < sizeof(buffer) - 1;
101	 p1++, p2++)
102    {
103	switch(*p1)
104	{
105	    case '~': *p2 = *minus; break;
106	    case '+': *p2 = *plus; break;
107	    case '.': *p2 = *radix; break;
108	    default: *p2 = *p1;
109	}
110    }
111    *p2 = 0;
112
113    /* Now we have something that strtod() can interpret... do it. */
114    *result = strtod(buffer, &p1);
115    /* Return NULL if failure, pointer past number if success */
116    return (p1 == buffer) ? (char *)0 : (ptr + (p1 - buffer));
117}
118
119#define XLFD_DOUBLE_TO_TEXT_BUF_SIZE 80
120
121static char *
122xlfd_double_to_text(double value, char *buffer, int space_required)
123{
124    register char *p1;
125    int ndigits, exponent;
126    const size_t buflen = XLFD_DOUBLE_TO_TEXT_BUF_SIZE;
127
128#ifndef NO_LOCALE
129    if (!locale)
130    {
131	locale = localeconv();
132	if (locale->decimal_point && *locale->decimal_point)
133	    radix = locale->decimal_point;
134	if (locale->positive_sign && *locale->positive_sign)
135	    plus = locale->positive_sign;
136	if (locale->negative_sign && *locale->negative_sign)
137	    minus = locale->negative_sign;
138    }
139#endif
140
141    if (space_required)
142	*buffer++ = ' ';
143
144    /* Render the number using printf's idea of formatting */
145    snprintf(buffer, buflen, "%.*le", XLFD_NDIGITS, value);
146
147    /* Find and read the exponent value */
148    for (p1 = buffer + strlen(buffer);
149	*p1-- != 'e' && p1[1] != 'E';);
150    exponent = atoi(p1 + 2);
151    if (value == 0.0) exponent = 0;
152
153    /* Figure out how many digits are significant */
154    while (p1 >= buffer && (!isdigit((unsigned char)*p1) || *p1 == '0')) p1--;
155    ndigits = 0;
156    while (p1 >= buffer) if (isdigit((unsigned char)*p1--)) ndigits++;
157
158    /* Figure out notation to use */
159    if (exponent >= XLFD_NDIGITS || ndigits - exponent > XLFD_NDIGITS + 1)
160    {
161	/* Scientific */
162	snprintf(buffer, buflen, "%.*le", ndigits - 1, value);
163    }
164    else
165    {
166	/* Fixed */
167	ndigits -= exponent + 1;
168	if (ndigits < 0) ndigits = 0;
169	snprintf(buffer, buflen, "%.*lf", ndigits, value);
170	if (exponent < 0)
171	{
172	    p1 = buffer;
173	    while (*p1 && *p1 != '0') p1++;
174	    while (*p1++) p1[-1] = *p1;
175	}
176    }
177
178    /* Last step, convert the locale-specific sign and radix characters
179       to our own. */
180    for (p1 = buffer; *p1; p1++)
181    {
182	if (*p1 == *minus) *p1 = '~';
183	else if (*p1 == *plus) *p1 = '+';
184	else if (*p1 == *radix) *p1 = '.';
185    }
186
187    return buffer - space_required;
188}
189
190double
191xlfd_round_double(double x)
192{
193   /* Utility for XLFD users to round numbers to XLFD_NDIGITS
194      significant digits.  How do you round to n significant digits on
195      a binary machine?  */
196
197#if defined(i386) || defined(__i386__) || \
198    defined(ia64) || defined(__ia64__) || \
199    defined(__alpha__) || defined(__alpha) || \
200    defined(__hppa__) || \
201    defined(__amd64__) || defined(__amd64) || \
202    defined(sgi)
203#include <float.h>
204
205/* if we have IEEE 754 fp, we can round to binary digits... */
206
207#if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53)
208
209#ifndef M_LN2
210#define M_LN2       0.69314718055994530942
211#endif
212#ifndef M_LN10
213#define M_LN10      2.30258509299404568402
214#endif
215
216/* convert # of decimal digits to # of binary digits */
217#define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5))
218
219   union conv_d {
220      double d;
221      unsigned char b[8];
222   } d;
223   int i,j,k,d_exp;
224
225   if (x == 0)
226      return x;
227
228   /* do minor sanity check for IEEE 754 fp and correct byte order */
229   d.d = 1.0;
230   if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) {
231
232      /*
233       * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits
234       */
235
236      d.d = x;
237      d_exp = (d.b[7] << 4) | (d.b[6] >> 4);
238
239      i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
240      j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
241      for (; i<7; i++) {
242	 k = d.b[i] + j;
243	 d.b[i] = k;
244	 if (k & 0x100) j = 1;
245	 else break;
246      }
247      if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) {
248	 /* mantissa overflow: increment exponent */
249	 d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1);
250	 d.b[7] = d_exp >> 4;
251	 d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4);
252      }
253
254      i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
255      j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
256      d.b[i] &= ~(j-1);
257      for (;--i>=0;) d.b[i] = 0;
258
259      return d.d;
260   }
261   else
262#endif
263#endif /* i386 || __i386__ */
264    {
265	/*
266	 * If not IEEE 754:  Let printf() do it for you.
267	 */
268
269	char buffer[40];
270
271	snprintf(buffer, sizeof(buffer), "%.*lg", XLFD_NDIGITS, x);
272	return atof(buffer);
273    }
274}
275
276static char *
277GetMatrix(char *ptr, FontScalablePtr vals, int which)
278{
279    double *matrix;
280
281    if (which == PIXELSIZE_MASK)
282	matrix = vals->pixel_matrix;
283    else if (which == POINTSIZE_MASK)
284	matrix = vals->point_matrix;
285    else return (char *)0;
286
287    while (isspace((unsigned char)*ptr)) ptr++;
288    if (*ptr == '[')
289    {
290	/* This is a matrix containing real numbers.  It would be nice
291	   to use strtod() or sscanf() to read the numbers, but those
292	   don't handle '~' for minus and we cannot force them to use a
293	   "."  for the radix.  We'll have to do the hard work ourselves
294	   (in readreal()).  */
295
296	if ((ptr = readreal(++ptr, matrix + 0)) &&
297	    (ptr = readreal(ptr, matrix + 1)) &&
298	    (ptr = readreal(ptr, matrix + 2)) &&
299	    (ptr = readreal(ptr, matrix + 3)))
300	{
301	    while (isspace((unsigned char)*ptr)) ptr++;
302	    if (*ptr != ']')
303		ptr = (char *)0;
304	    else
305	    {
306		ptr++;
307		while (isspace((unsigned char)*ptr)) ptr++;
308		if (*ptr == '-')
309		{
310		    if (which == POINTSIZE_MASK)
311			vals->values_supplied |= POINTSIZE_ARRAY;
312		    else
313			vals->values_supplied |= PIXELSIZE_ARRAY;
314		}
315		else ptr = (char *)0;
316	    }
317	}
318    }
319    else
320    {
321	int value;
322	if ((ptr = GetInt(ptr, &value)))
323	{
324	    vals->values_supplied &= ~which;
325	    if (value > 0)
326	    {
327		matrix[3] = (double)value;
328		if (which == POINTSIZE_MASK)
329		{
330		    matrix[3] /= 10.0;
331		    vals->values_supplied |= POINTSIZE_SCALAR;
332		}
333		else
334		    vals->values_supplied |= PIXELSIZE_SCALAR;
335		/* If we're concocting the pixelsize array from a scalar,
336		   we will need to normalize element 0 for the pixel shape.
337		   This is done in FontFileCompleteXLFD(). */
338		matrix[0] = matrix[3];
339		matrix[1] = matrix[2] = 0.0;
340	    }
341	    else if (value < 0)
342	    {
343		if (which == POINTSIZE_MASK)
344		    vals->values_supplied |= POINTSIZE_WILDCARD;
345		else
346		    vals->values_supplied |= PIXELSIZE_WILDCARD;
347	    }
348	}
349    }
350    return ptr;
351}
352
353
354static void
355append_ranges(char *fname, size_t fnamelen, int nranges, fsRange *ranges)
356{
357    if (nranges)
358    {
359        int i;
360
361        strlcat(fname, "[", fnamelen);
362        for (i = 0; i < nranges && strlen(fname) < 1010; i++)
363        {
364	    size_t curlen;
365	    if (i) strlcat(fname, " ", fnamelen);
366	    curlen = strlen(fname);
367	    snprintf(fname + curlen, fnamelen - curlen, "%d",
368		     minchar(ranges[i]));
369	    if (ranges[i].min_char_low ==
370		ranges[i].max_char_low &&
371		ranges[i].min_char_high ==
372		ranges[i].max_char_high) continue;
373	    snprintf(fname + curlen, fnamelen - curlen, "_%d",
374		     maxchar(ranges[i]));
375        }
376        strlcat(fname, "]", fnamelen);
377    }
378}
379
380Bool
381FontParseXLFDName(char *fname, FontScalablePtr vals, int subst)
382{
383    register char *ptr;
384    register char *ptr1,
385               *ptr2,
386               *ptr3,
387               *ptr4;
388    register char *ptr5;
389    FontScalableRec tmpvals;
390    char        replaceChar = '0';
391    char        tmpBuf[1024];
392    size_t      tlen;
393    size_t      fnamelen = MAXFONTNAMELEN; /* assumed for now */
394    int         spacingLen;
395    int		l;
396    char	*p;
397
398    bzero(&tmpvals, sizeof(tmpvals));
399    if (subst != FONT_XLFD_REPLACE_VALUE)
400	*vals = tmpvals;
401
402    if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) ||  /* fndry */
403	    !(ptr = strchr(ptr + 1, '-')) ||	/* family_name */
404	    !(ptr1 = ptr = strchr(ptr + 1, '-')) ||	/* weight_name */
405	    !(ptr = strchr(ptr + 1, '-')) ||	/* slant */
406	    !(ptr = strchr(ptr + 1, '-')) ||	/* setwidth_name */
407	    !(ptr = strchr(ptr + 1, '-')) ||	/* add_style_name */
408	    !(ptr = strchr(ptr + 1, '-')) ||	/* pixel_size */
409	    !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) ||
410	    !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) ||
411	    !(ptr = GetInt(ptr + 1, &tmpvals.x)) ||	/* resolution_x */
412	    !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) ||  /* resolution_y */
413	    !(ptr4 = ptr = strchr(ptr + 1, '-')) ||	/* spacing */
414	    !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */
415	    !(ptr = strchr(ptr + 1, '-')) ||	/* charset_registry */
416	    strchr(ptr + 1, '-'))/* charset_encoding */
417	return FALSE;
418
419    /* Lop off HP charset subsetting enhancement.  Interpreting this
420       field requires allocating some space in which to return the
421       results.  So, to prevent memory leaks, this procedure will simply
422       lop off and ignore charset subsetting, and initialize the
423       relevant vals fields to zero.  It's up to the caller to make its
424       own call to FontParseRanges() if it's interested in the charset
425       subsetting.  */
426
427    if (subst != FONT_XLFD_REPLACE_NONE &&
428	(p = strchr(strrchr(fname, '-'), '[')))
429    {
430	tmpvals.values_supplied |= CHARSUBSET_SPECIFIED;
431	*p = '\0';
432    }
433
434    /* Fill in deprecated fields for the benefit of rasterizers that care
435       about them. */
436    tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ?
437		    (int)(tmpvals.pixel_matrix[3] + .5) :
438		    (int)(tmpvals.pixel_matrix[3] - .5);
439    tmpvals.point = (tmpvals.point_matrix[3] >= 0) ?
440                    (int)(tmpvals.point_matrix[3] * 10 + .5) :
441                    (int)(tmpvals.point_matrix[3] * 10 - .5);
442
443    spacingLen = ptr4 - ptr3 + 1;
444
445    switch (subst) {
446    case FONT_XLFD_REPLACE_NONE:
447	*vals = tmpvals;
448	break;
449    case FONT_XLFD_REPLACE_STAR:
450	replaceChar = '*';
451	/* FALLTHROUGH */
452    case FONT_XLFD_REPLACE_ZERO:
453	strlcpy(tmpBuf, ptr2, sizeof(tmpBuf));
454	ptr5 = tmpBuf + (ptr5 - ptr2);
455	ptr3 = tmpBuf + (ptr3 - ptr2);
456	ptr2 = tmpBuf;
457	ptr = ptr1 + 1;
458
459	ptr = strchr(ptr, '-') + 1;		/* skip weight */
460	ptr = strchr(ptr, '-') + 1;		/* skip slant */
461	ptr = strchr(ptr, '-') + 1;		/* skip setwidth_name */
462	ptr = strchr(ptr, '-') + 1;		/* skip add_style_name */
463
464	if ((ptr - fname) + spacingLen + strlen(ptr5) + 10 >= (unsigned)1024)
465	    return FALSE;
466	*ptr++ = replaceChar;
467	*ptr++ = '-';
468	*ptr++ = replaceChar;
469	*ptr++ = '-';
470	*ptr++ = '*';
471	*ptr++ = '-';
472	*ptr++ = '*';
473	if (spacingLen > 2)
474	{
475	    memmove(ptr, ptr3, spacingLen);
476	    ptr += spacingLen;
477	}
478	else
479	{
480	    *ptr++ = '-';
481	    *ptr++ = '*';
482	    *ptr++ = '-';
483	}
484	*ptr++ = replaceChar;
485	strlcpy(ptr, ptr5, fnamelen - (ptr - fname));
486	*vals = tmpvals;
487	break;
488    case FONT_XLFD_REPLACE_VALUE:
489	if (vals->values_supplied & PIXELSIZE_MASK)
490	{
491	    tmpvals.values_supplied =
492		(tmpvals.values_supplied & ~PIXELSIZE_MASK) |
493		(vals->values_supplied & PIXELSIZE_MASK);
494	    tmpvals.pixel_matrix[0] = vals->pixel_matrix[0];
495	    tmpvals.pixel_matrix[1] = vals->pixel_matrix[1];
496	    tmpvals.pixel_matrix[2] = vals->pixel_matrix[2];
497	    tmpvals.pixel_matrix[3] = vals->pixel_matrix[3];
498	}
499	if (vals->values_supplied & POINTSIZE_MASK)
500	{
501	    tmpvals.values_supplied =
502		(tmpvals.values_supplied & ~POINTSIZE_MASK) |
503		(vals->values_supplied & POINTSIZE_MASK);
504	    tmpvals.point_matrix[0] = vals->point_matrix[0];
505	    tmpvals.point_matrix[1] = vals->point_matrix[1];
506	    tmpvals.point_matrix[2] = vals->point_matrix[2];
507	    tmpvals.point_matrix[3] = vals->point_matrix[3];
508	}
509	if (vals->x >= 0)
510	    tmpvals.x = vals->x;
511	if (vals->y >= 0)
512	    tmpvals.y = vals->y;
513	if (vals->width >= 0)
514	    tmpvals.width = vals->width;
515	else if (vals->width < -1)	/* overload: -1 means wildcard */
516	    tmpvals.width = -vals->width;
517
518
519	p = ptr1 + 1;				/* weight field */
520	l = strchr(p, '-') - p;
521	snprintf(tmpBuf, sizeof(tmpBuf), "%*.*s", l, l, p);
522
523	p += l + 1;				/* slant field */
524	l = strchr(p, '-') - p;
525	tlen = strlen(tmpBuf);
526	snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "-%*.*s", l, l, p);
527
528	p += l + 1;				/* setwidth_name */
529	l = strchr(p, '-') - p;
530	tlen = strlen(tmpBuf);
531	snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "-%*.*s", l, l, p);
532
533	p += l + 1;				/* add_style_name field */
534	l = strchr(p, '-') - p;
535	tlen = strlen(tmpBuf);
536	snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "-%*.*s", l, l, p);
537
538	strlcat(tmpBuf, "-", sizeof(tmpBuf));
539	if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY)
540	{
541	    char buffer[XLFD_DOUBLE_TO_TEXT_BUF_SIZE];
542	    strlcat(tmpBuf, "[", sizeof(tmpBuf));
543	    strlcat(tmpBuf,
544		    xlfd_double_to_text(tmpvals.pixel_matrix[0], buffer, 0),
545		    sizeof(tmpBuf));
546	    strlcat(tmpBuf,
547		    xlfd_double_to_text(tmpvals.pixel_matrix[1], buffer, 1),
548		    sizeof(tmpBuf));
549	    strlcat(tmpBuf,
550		    xlfd_double_to_text(tmpvals.pixel_matrix[2], buffer, 1),
551		    sizeof(tmpBuf));
552	    strlcat(tmpBuf,
553		    xlfd_double_to_text(tmpvals.pixel_matrix[3], buffer, 1),
554		    sizeof(tmpBuf));
555	    strlcat(tmpBuf, "]", sizeof(tmpBuf));
556	}
557	else
558	{
559	    tlen = strlen(tmpBuf);
560	    snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "%d",
561		     (int)(tmpvals.pixel_matrix[3] + .5));
562	}
563	strlcat(tmpBuf, "-", sizeof(tmpBuf));
564	if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
565	{
566	    char buffer[XLFD_DOUBLE_TO_TEXT_BUF_SIZE];
567	    strlcat(tmpBuf, "[", sizeof(tmpBuf));
568	    strlcat(tmpBuf,
569		    xlfd_double_to_text(tmpvals.point_matrix[0], buffer, 0),
570		    sizeof(tmpBuf));
571	    strlcat(tmpBuf,
572		    xlfd_double_to_text(tmpvals.point_matrix[1], buffer, 1),
573		    sizeof(tmpBuf));
574	    strlcat(tmpBuf,
575		    xlfd_double_to_text(tmpvals.point_matrix[2], buffer, 1),
576		    sizeof(tmpBuf));
577	    strlcat(tmpBuf,
578		    xlfd_double_to_text(tmpvals.point_matrix[3], buffer, 1),
579		    sizeof(tmpBuf));
580	    strlcat(tmpBuf, "]", sizeof(tmpBuf));
581	}
582	else
583	{
584	    tlen = strlen(tmpBuf);
585	    snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "%d",
586		     (int)(tmpvals.point_matrix[3] * 10.0 + .5));
587	}
588	tlen = strlen(tmpBuf);
589	snprintf(tmpBuf + tlen, sizeof(tmpBuf) - tlen, "-%d-%d%*.*s%d%s",
590		 tmpvals.x, tmpvals.y,
591		 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5);
592	strlcpy(ptr1 + 1, tmpBuf, fnamelen - (ptr1 - fname));
593	if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges)
594	    strlcat(fname, "[]", fnamelen);
595	else
596	    append_ranges(fname, fnamelen, vals->nranges, vals->ranges);
597	break;
598    }
599    return TRUE;
600}
601
602fsRange *FontParseRanges(char *name, int *nranges)
603{
604    int n;
605    unsigned long l;
606    char *p1, *p2;
607    fsRange *result = (fsRange *)0;
608
609    name = strchr(name, '-');
610    for (n = 1; name && n < 14; n++)
611	name = strchr(name + 1, '-');
612
613    *nranges = 0;
614    if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0;
615    p1++;
616
617    while (*p1 && *p1 != ']')
618    {
619	fsRange thisrange;
620
621	l = strtol(p1, &p2, 0);
622	if (p2 == p1 || l > 0xffff) break;
623	thisrange.max_char_low = thisrange.min_char_low = l & 0xff;
624	thisrange.max_char_high = thisrange.min_char_high = l >> 8;
625
626	p1 = p2;
627	if (*p1 == ']' || *p1 == ' ')
628	{
629	    while (*p1 == ' ') p1++;
630	    if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
631		break;
632	}
633	else if (*p1 == '_')
634	{
635	    l = strtol(++p1, &p2, 0);
636	    if (p2 == p1 || l > 0xffff) break;
637	    thisrange.max_char_low = l & 0xff;
638	    thisrange.max_char_high = l >> 8;
639	    p1 = p2;
640	    if (*p1 == ']' || *p1 == ' ')
641	    {
642		while (*p1 == ' ') p1++;
643		if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
644		    break;
645	    }
646	}
647	else break;
648    }
649
650    return result;
651}
652