3 Copyright 1990, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
30 * Author: Keith Packard, MIT X Consortium
36 #include <X11/fonts/fontmisc.h>
37 #include <X11/fonts/fontstruct.h>
38 #include <X11/fonts/fontxlfd.h>
39 #include <X11/fonts/fontutil.h>
43 #if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
50 #include <stdio.h> /* for sprintf() */
53 GetInt(char *ptr, int *val)
59 for (*val = 0; *ptr >= '0' && *ptr <= '9';)
60 *val = *val * 10 + *ptr++ - '0';
66 #define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))
67 #define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8))
71 static struct lconv *locale = 0;
73 static char *radix = ".", *plus = "+", *minus = "-";
76 readreal(char *ptr, double *result)
78 char buffer[80], *p1, *p2;
81 /* Figure out what symbols apply in this locale */
85 locale = localeconv();
86 if (locale->decimal_point && *locale->decimal_point)
87 radix = locale->decimal_point;
88 if (locale->positive_sign && *locale->positive_sign)
89 plus = locale->positive_sign;
90 if (locale->negative_sign && *locale->negative_sign)
91 minus = locale->negative_sign;
94 /* Copy the first 80 chars of ptr into our local buffer, changing
96 for (p1 = ptr, p2 = buffer;
97 *p1 && (p2 - buffer) < sizeof(buffer) - 1;
102 case '~': *p2 = *minus; break;
103 case '+': *p2 = *plus; break;
104 case '.': *p2 = *radix; break;
110 /* Now we have something that strtod() can interpret... do it. */
111 *result = strtod(buffer, &p1);
112 /* Return NULL if failure, pointer past number if success */
113 return (p1 == buffer) ? (char *)0 : (ptr + (p1 - buffer));
117 xlfd_double_to_text(double value, char *buffer, int space_required)
121 int ndigits, exponent;
126 locale = localeconv();
127 if (locale->decimal_point && *locale->decimal_point)
128 radix = locale->decimal_point;
129 if (locale->positive_sign && *locale->positive_sign)
130 plus = locale->positive_sign;
131 if (locale->negative_sign && *locale->negative_sign)
132 minus = locale->negative_sign;
135 /* Compute a format to use to render the number */
136 sprintf(formatbuf, "%%.%dle", XLFD_NDIGITS);
141 /* Render the number using printf's idea of formatting */
142 sprintf(buffer, formatbuf, value);
144 /* Find and read the exponent value */
145 for (p1 = buffer + strlen(buffer);
146 *p1-- != 'e' && p1[1] != 'E';);
147 exponent = atoi(p1 + 2);
148 if (value == 0.0) exponent = 0;
150 /* Figure out how many digits are significant */
151 while (p1 >= buffer && (!isdigit(*p1) || *p1 == '0')) p1--;
153 while (p1 >= buffer) if (isdigit(*p1--)) ndigits++;
155 /* Figure out notation to use */
156 if (exponent >= XLFD_NDIGITS || ndigits - exponent > XLFD_NDIGITS + 1)
159 sprintf(formatbuf, "%%.%dle", ndigits - 1);
160 sprintf(buffer, formatbuf, value);
165 ndigits -= exponent + 1;
166 if (ndigits < 0) ndigits = 0;
167 sprintf(formatbuf, "%%.%dlf", ndigits);
168 sprintf(buffer, formatbuf, value);
172 while (*p1 && *p1 != '0') p1++;
173 while (*p1++) p1[-1] = *p1;
177 /* Last step, convert the locale-specific sign and radix characters
179 for (p1 = buffer; *p1; p1++)
181 if (*p1 == *minus) *p1 = '~';
182 else if (*p1 == *plus) *p1 = '+';
183 else if (*p1 == *radix) *p1 = '.';
186 return buffer - space_required;
190 xlfd_round_double(double x)
192 /* Utility for XLFD users to round numbers to XLFD_NDIGITS
193 significant digits. How do you round to n significant digits on
196 #if defined(i386) || defined(__i386__) || \
197 defined(ia64) || defined(__ia64__) || \
198 defined(__alpha__) || defined(__alpha) || \
199 defined(__hppa__) || \
200 defined(__amd64__) || defined(__amd64) || \
204 /* if we have IEEE 754 fp, we can round to binary digits... */
206 #if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53)
209 #define M_LN2 0.69314718055994530942
212 #define M_LN10 2.30258509299404568402
215 /* convert # of decimal digits to # of binary digits */
216 #define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5))
227 /* do minor sanity check for IEEE 754 fp and correct byte order */
229 if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) {
232 * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits
236 d_exp = (d.b[7] << 4) | (d.b[6] >> 4);
238 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
239 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
243 if (k & 0x100) j = 1;
246 if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) {
247 /* mantissa overflow: increment exponent */
248 d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1);
250 d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4);
253 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
254 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
256 for (;--i>=0;) d.b[i] = 0;
262 #endif /* i386 || __i386__ */
265 * If not IEEE 754: Let printf() do it for you.
268 char formatbuf[40], buffer[40];
270 sprintf(formatbuf, "%%.%dlg", XLFD_NDIGITS);
271 sprintf(buffer, formatbuf, x);
277 GetMatrix(char *ptr, FontScalablePtr vals, int which)
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;
287 while (isspace(*ptr)) ptr++;
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
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)))
301 while (isspace(*ptr)) ptr++;
307 while (isspace(*ptr)) ptr++;
310 if (which == POINTSIZE_MASK)
311 vals->values_supplied |= POINTSIZE_ARRAY;
313 vals->values_supplied |= PIXELSIZE_ARRAY;
315 else ptr = (char *)0;
322 if ((ptr = GetInt(ptr, &value)))
324 vals->values_supplied &= ~which;
327 matrix[3] = (double)value;
328 if (which == POINTSIZE_MASK)
331 vals->values_supplied |= POINTSIZE_SCALAR;
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;
343 if (which == POINTSIZE_MASK)
344 vals->values_supplied |= POINTSIZE_WILDCARD;
346 vals->values_supplied |= PIXELSIZE_WILDCARD;
355 append_ranges(char *fname, int nranges, fsRange *ranges)
362 for (i = 0; i < nranges && strlen(fname) < 1010; i++)
364 if (i) strcat(fname, " ");
365 sprintf(fname + strlen(fname), "%d",
367 if (ranges[i].min_char_low ==
368 ranges[i].max_char_low &&
369 ranges[i].min_char_high ==
370 ranges[i].max_char_high) continue;
371 sprintf(fname + strlen(fname), "_%d",
379 FontParseXLFDName(char *fname, FontScalablePtr vals, int subst)
387 FontScalableRec tmpvals;
388 char replaceChar = '0';
394 bzero(&tmpvals, sizeof(tmpvals));
395 if (subst != FONT_XLFD_REPLACE_VALUE)
398 if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) || /* fndry */
399 !(ptr = strchr(ptr + 1, '-')) || /* family_name */
400 !(ptr1 = ptr = strchr(ptr + 1, '-')) || /* weight_name */
401 !(ptr = strchr(ptr + 1, '-')) || /* slant */
402 !(ptr = strchr(ptr + 1, '-')) || /* setwidth_name */
403 !(ptr = strchr(ptr + 1, '-')) || /* add_style_name */
404 !(ptr = strchr(ptr + 1, '-')) || /* pixel_size */
405 !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) ||
406 !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) ||
407 !(ptr = GetInt(ptr + 1, &tmpvals.x)) || /* resolution_x */
408 !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) || /* resolution_y */
409 !(ptr4 = ptr = strchr(ptr + 1, '-')) || /* spacing */
410 !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */
411 !(ptr = strchr(ptr + 1, '-')) || /* charset_registry */
412 strchr(ptr + 1, '-'))/* charset_encoding */
415 /* Lop off HP charset subsetting enhancement. Interpreting this
416 field requires allocating some space in which to return the
417 results. So, to prevent memory leaks, this procedure will simply
418 lop off and ignore charset subsetting, and initialize the
419 relevant vals fields to zero. It's up to the caller to make its
420 own call to FontParseRanges() if it's interested in the charset
423 if (subst != FONT_XLFD_REPLACE_NONE &&
424 (p = strchr(strrchr(fname, '-'), '[')))
426 tmpvals.values_supplied |= CHARSUBSET_SPECIFIED;
430 /* Fill in deprecated fields for the benefit of rasterizers that care
432 tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ?
433 (int)(tmpvals.pixel_matrix[3] + .5) :
434 (int)(tmpvals.pixel_matrix[3] - .5);
435 tmpvals.point = (tmpvals.point_matrix[3] >= 0) ?
436 (int)(tmpvals.point_matrix[3] * 10 + .5) :
437 (int)(tmpvals.point_matrix[3] * 10 - .5);
439 spacingLen = ptr4 - ptr3 + 1;
442 case FONT_XLFD_REPLACE_NONE:
445 case FONT_XLFD_REPLACE_STAR:
447 case FONT_XLFD_REPLACE_ZERO:
448 strcpy(tmpBuf, ptr2);
449 ptr5 = tmpBuf + (ptr5 - ptr2);
450 ptr3 = tmpBuf + (ptr3 - ptr2);
454 ptr = strchr(ptr, '-') + 1; /* skip weight */
455 ptr = strchr(ptr, '-') + 1; /* skip slant */
456 ptr = strchr(ptr, '-') + 1; /* skip setwidth_name */
457 ptr = strchr(ptr, '-') + 1; /* skip add_style_name */
459 if ((ptr - fname) + spacingLen + strlen(ptr5) + 10 >= (unsigned)1024)
461 *ptr++ = replaceChar;
463 *ptr++ = replaceChar;
470 memmove(ptr, ptr3, spacingLen);
479 *ptr++ = replaceChar;
483 case FONT_XLFD_REPLACE_VALUE:
484 if (vals->values_supplied & PIXELSIZE_MASK)
486 tmpvals.values_supplied =
487 (tmpvals.values_supplied & ~PIXELSIZE_MASK) |
488 (vals->values_supplied & PIXELSIZE_MASK);
489 tmpvals.pixel_matrix[0] = vals->pixel_matrix[0];
490 tmpvals.pixel_matrix[1] = vals->pixel_matrix[1];
491 tmpvals.pixel_matrix[2] = vals->pixel_matrix[2];
492 tmpvals.pixel_matrix[3] = vals->pixel_matrix[3];
494 if (vals->values_supplied & POINTSIZE_MASK)
496 tmpvals.values_supplied =
497 (tmpvals.values_supplied & ~POINTSIZE_MASK) |
498 (vals->values_supplied & POINTSIZE_MASK);
499 tmpvals.point_matrix[0] = vals->point_matrix[0];
500 tmpvals.point_matrix[1] = vals->point_matrix[1];
501 tmpvals.point_matrix[2] = vals->point_matrix[2];
502 tmpvals.point_matrix[3] = vals->point_matrix[3];
508 if (vals->width >= 0)
509 tmpvals.width = vals->width;
510 else if (vals->width < -1) /* overload: -1 means wildcard */
511 tmpvals.width = -vals->width;
514 p = ptr1 + 1; /* weight field */
515 l = strchr(p, '-') - p;
516 sprintf(tmpBuf, "%*.*s", l, l, p);
518 p += l + 1; /* slant field */
519 l = strchr(p, '-') - p;
520 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
522 p += l + 1; /* setwidth_name */
523 l = strchr(p, '-') - p;
524 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
526 p += l + 1; /* add_style_name field */
527 l = strchr(p, '-') - p;
528 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
531 if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY)
535 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[0],
537 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[1],
539 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[2],
541 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[3],
547 sprintf(tmpBuf + strlen(tmpBuf), "%d",
548 (int)(tmpvals.pixel_matrix[3] + .5));
551 if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
555 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[0],
557 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[1],
559 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[2],
561 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[3],
567 sprintf(tmpBuf + strlen(tmpBuf), "%d",
568 (int)(tmpvals.point_matrix[3] * 10.0 + .5));
570 sprintf(tmpBuf + strlen(tmpBuf), "-%d-%d%*.*s%d%s",
571 tmpvals.x, tmpvals.y,
572 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5);
573 strcpy(ptr1 + 1, tmpBuf);
574 if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges)
577 append_ranges(fname, vals->nranges, vals->ranges);
583 fsRange *FontParseRanges(char *name, int *nranges)
588 fsRange *result = (fsRange *)0;
590 name = strchr(name, '-');
591 for (n = 1; name && n < 14; n++)
592 name = strchr(name + 1, '-');
595 if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0;
598 while (*p1 && *p1 != ']')
602 l = strtol(p1, &p2, 0);
603 if (p2 == p1 || l > 0xffff) break;
604 thisrange.max_char_low = thisrange.min_char_low = l & 0xff;
605 thisrange.max_char_high = thisrange.min_char_high = l >> 8;
608 if (*p1 == ']' || *p1 == ' ')
610 while (*p1 == ' ') p1++;
611 if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
616 l = strtol(++p1, &p2, 0);
617 if (p2 == p1 || l > 0xffff) break;
618 thisrange.max_char_low = l & 0xff;
619 thisrange.max_char_high = l >> 8;
621 if (*p1 == ']' || *p1 == ' ')
623 while (*p1 == ' ') p1++;
624 if (add_range(&thisrange, nranges, &result, TRUE) != Successful)