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 const 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)
120 int ndigits, exponent;
125 locale = localeconv();
126 if (locale->decimal_point && *locale->decimal_point)
127 radix = locale->decimal_point;
128 if (locale->positive_sign && *locale->positive_sign)
129 plus = locale->positive_sign;
130 if (locale->negative_sign && *locale->negative_sign)
131 minus = locale->negative_sign;
138 /* Render the number using printf's idea of formatting */
139 sprintf(buffer, "%.*le", XLFD_NDIGITS, value);
141 /* Find and read the exponent value */
142 for (p1 = buffer + strlen(buffer);
143 *p1-- != 'e' && p1[1] != 'E';);
144 exponent = atoi(p1 + 2);
145 if (value == 0.0) exponent = 0;
147 /* Figure out how many digits are significant */
148 while (p1 >= buffer && (!isdigit(*p1) || *p1 == '0')) p1--;
150 while (p1 >= buffer) if (isdigit(*p1--)) ndigits++;
152 /* Figure out notation to use */
153 if (exponent >= XLFD_NDIGITS || ndigits - exponent > XLFD_NDIGITS + 1)
156 sprintf(buffer, "%.*le", ndigits - 1, value);
161 ndigits -= exponent + 1;
162 if (ndigits < 0) ndigits = 0;
163 sprintf(buffer, "%.*lf", ndigits, value);
167 while (*p1 && *p1 != '0') p1++;
168 while (*p1++) p1[-1] = *p1;
172 /* Last step, convert the locale-specific sign and radix characters
174 for (p1 = buffer; *p1; p1++)
176 if (*p1 == *minus) *p1 = '~';
177 else if (*p1 == *plus) *p1 = '+';
178 else if (*p1 == *radix) *p1 = '.';
181 return buffer - space_required;
185 xlfd_round_double(double x)
187 /* Utility for XLFD users to round numbers to XLFD_NDIGITS
188 significant digits. How do you round to n significant digits on
191 #if defined(i386) || defined(__i386__) || \
192 defined(ia64) || defined(__ia64__) || \
193 defined(__alpha__) || defined(__alpha) || \
194 defined(__hppa__) || \
195 defined(__amd64__) || defined(__amd64) || \
199 /* if we have IEEE 754 fp, we can round to binary digits... */
201 #if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53)
204 #define M_LN2 0.69314718055994530942
207 #define M_LN10 2.30258509299404568402
210 /* convert # of decimal digits to # of binary digits */
211 #define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5))
222 /* do minor sanity check for IEEE 754 fp and correct byte order */
224 if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) {
227 * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits
231 d_exp = (d.b[7] << 4) | (d.b[6] >> 4);
233 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
234 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
238 if (k & 0x100) j = 1;
241 if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) {
242 /* mantissa overflow: increment exponent */
243 d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1);
245 d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4);
248 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3;
249 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07);
251 for (;--i>=0;) d.b[i] = 0;
257 #endif /* i386 || __i386__ */
260 * If not IEEE 754: Let printf() do it for you.
265 sprintf(buffer, "%.*lg", XLFD_NDIGITS, x);
271 GetMatrix(char *ptr, FontScalablePtr vals, int which)
275 if (which == PIXELSIZE_MASK)
276 matrix = vals->pixel_matrix;
277 else if (which == POINTSIZE_MASK)
278 matrix = vals->point_matrix;
279 else return (char *)0;
281 while (isspace(*ptr)) ptr++;
284 /* This is a matrix containing real numbers. It would be nice
285 to use strtod() or sscanf() to read the numbers, but those
286 don't handle '~' for minus and we cannot force them to use a
287 "." for the radix. We'll have to do the hard work ourselves
290 if ((ptr = readreal(++ptr, matrix + 0)) &&
291 (ptr = readreal(ptr, matrix + 1)) &&
292 (ptr = readreal(ptr, matrix + 2)) &&
293 (ptr = readreal(ptr, matrix + 3)))
295 while (isspace(*ptr)) ptr++;
301 while (isspace(*ptr)) ptr++;
304 if (which == POINTSIZE_MASK)
305 vals->values_supplied |= POINTSIZE_ARRAY;
307 vals->values_supplied |= PIXELSIZE_ARRAY;
309 else ptr = (char *)0;
316 if ((ptr = GetInt(ptr, &value)))
318 vals->values_supplied &= ~which;
321 matrix[3] = (double)value;
322 if (which == POINTSIZE_MASK)
325 vals->values_supplied |= POINTSIZE_SCALAR;
328 vals->values_supplied |= PIXELSIZE_SCALAR;
329 /* If we're concocting the pixelsize array from a scalar,
330 we will need to normalize element 0 for the pixel shape.
331 This is done in FontFileCompleteXLFD(). */
332 matrix[0] = matrix[3];
333 matrix[1] = matrix[2] = 0.0;
337 if (which == POINTSIZE_MASK)
338 vals->values_supplied |= POINTSIZE_WILDCARD;
340 vals->values_supplied |= PIXELSIZE_WILDCARD;
349 append_ranges(char *fname, int nranges, fsRange *ranges)
356 for (i = 0; i < nranges && strlen(fname) < 1010; i++)
358 if (i) strcat(fname, " ");
359 sprintf(fname + strlen(fname), "%d",
361 if (ranges[i].min_char_low ==
362 ranges[i].max_char_low &&
363 ranges[i].min_char_high ==
364 ranges[i].max_char_high) continue;
365 sprintf(fname + strlen(fname), "_%d",
373 FontParseXLFDName(char *fname, FontScalablePtr vals, int subst)
381 FontScalableRec tmpvals;
382 char replaceChar = '0';
388 bzero(&tmpvals, sizeof(tmpvals));
389 if (subst != FONT_XLFD_REPLACE_VALUE)
392 if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) || /* fndry */
393 !(ptr = strchr(ptr + 1, '-')) || /* family_name */
394 !(ptr1 = ptr = strchr(ptr + 1, '-')) || /* weight_name */
395 !(ptr = strchr(ptr + 1, '-')) || /* slant */
396 !(ptr = strchr(ptr + 1, '-')) || /* setwidth_name */
397 !(ptr = strchr(ptr + 1, '-')) || /* add_style_name */
398 !(ptr = strchr(ptr + 1, '-')) || /* pixel_size */
399 !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) ||
400 !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) ||
401 !(ptr = GetInt(ptr + 1, &tmpvals.x)) || /* resolution_x */
402 !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) || /* resolution_y */
403 !(ptr4 = ptr = strchr(ptr + 1, '-')) || /* spacing */
404 !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */
405 !(ptr = strchr(ptr + 1, '-')) || /* charset_registry */
406 strchr(ptr + 1, '-'))/* charset_encoding */
409 /* Lop off HP charset subsetting enhancement. Interpreting this
410 field requires allocating some space in which to return the
411 results. So, to prevent memory leaks, this procedure will simply
412 lop off and ignore charset subsetting, and initialize the
413 relevant vals fields to zero. It's up to the caller to make its
414 own call to FontParseRanges() if it's interested in the charset
417 if (subst != FONT_XLFD_REPLACE_NONE &&
418 (p = strchr(strrchr(fname, '-'), '[')))
420 tmpvals.values_supplied |= CHARSUBSET_SPECIFIED;
424 /* Fill in deprecated fields for the benefit of rasterizers that care
426 tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ?
427 (int)(tmpvals.pixel_matrix[3] + .5) :
428 (int)(tmpvals.pixel_matrix[3] - .5);
429 tmpvals.point = (tmpvals.point_matrix[3] >= 0) ?
430 (int)(tmpvals.point_matrix[3] * 10 + .5) :
431 (int)(tmpvals.point_matrix[3] * 10 - .5);
433 spacingLen = ptr4 - ptr3 + 1;
436 case FONT_XLFD_REPLACE_NONE:
439 case FONT_XLFD_REPLACE_STAR:
441 case FONT_XLFD_REPLACE_ZERO:
442 strcpy(tmpBuf, ptr2);
443 ptr5 = tmpBuf + (ptr5 - ptr2);
444 ptr3 = tmpBuf + (ptr3 - ptr2);
448 ptr = strchr(ptr, '-') + 1; /* skip weight */
449 ptr = strchr(ptr, '-') + 1; /* skip slant */
450 ptr = strchr(ptr, '-') + 1; /* skip setwidth_name */
451 ptr = strchr(ptr, '-') + 1; /* skip add_style_name */
453 if ((ptr - fname) + spacingLen + strlen(ptr5) + 10 >= (unsigned)1024)
455 *ptr++ = replaceChar;
457 *ptr++ = replaceChar;
464 memmove(ptr, ptr3, spacingLen);
473 *ptr++ = replaceChar;
477 case FONT_XLFD_REPLACE_VALUE:
478 if (vals->values_supplied & PIXELSIZE_MASK)
480 tmpvals.values_supplied =
481 (tmpvals.values_supplied & ~PIXELSIZE_MASK) |
482 (vals->values_supplied & PIXELSIZE_MASK);
483 tmpvals.pixel_matrix[0] = vals->pixel_matrix[0];
484 tmpvals.pixel_matrix[1] = vals->pixel_matrix[1];
485 tmpvals.pixel_matrix[2] = vals->pixel_matrix[2];
486 tmpvals.pixel_matrix[3] = vals->pixel_matrix[3];
488 if (vals->values_supplied & POINTSIZE_MASK)
490 tmpvals.values_supplied =
491 (tmpvals.values_supplied & ~POINTSIZE_MASK) |
492 (vals->values_supplied & POINTSIZE_MASK);
493 tmpvals.point_matrix[0] = vals->point_matrix[0];
494 tmpvals.point_matrix[1] = vals->point_matrix[1];
495 tmpvals.point_matrix[2] = vals->point_matrix[2];
496 tmpvals.point_matrix[3] = vals->point_matrix[3];
502 if (vals->width >= 0)
503 tmpvals.width = vals->width;
504 else if (vals->width < -1) /* overload: -1 means wildcard */
505 tmpvals.width = -vals->width;
508 p = ptr1 + 1; /* weight field */
509 l = strchr(p, '-') - p;
510 sprintf(tmpBuf, "%*.*s", l, l, p);
512 p += l + 1; /* slant field */
513 l = strchr(p, '-') - p;
514 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
516 p += l + 1; /* setwidth_name */
517 l = strchr(p, '-') - p;
518 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
520 p += l + 1; /* add_style_name field */
521 l = strchr(p, '-') - p;
522 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p);
525 if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY)
529 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[0],
531 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[1],
533 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[2],
535 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[3],
541 sprintf(tmpBuf + strlen(tmpBuf), "%d",
542 (int)(tmpvals.pixel_matrix[3] + .5));
545 if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY)
549 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[0],
551 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[1],
553 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[2],
555 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[3],
561 sprintf(tmpBuf + strlen(tmpBuf), "%d",
562 (int)(tmpvals.point_matrix[3] * 10.0 + .5));
564 sprintf(tmpBuf + strlen(tmpBuf), "-%d-%d%*.*s%d%s",
565 tmpvals.x, tmpvals.y,
566 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5);
567 strcpy(ptr1 + 1, tmpBuf);
568 if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges)
571 append_ranges(fname, vals->nranges, vals->ranges);
577 fsRange *FontParseRanges(char *name, int *nranges)
582 fsRange *result = (fsRange *)0;
584 name = strchr(name, '-');
585 for (n = 1; name && n < 14; n++)
586 name = strchr(name + 1, '-');
589 if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0;
592 while (*p1 && *p1 != ']')
596 l = strtol(p1, &p2, 0);
597 if (p2 == p1 || l > 0xffff) break;
598 thisrange.max_char_low = thisrange.min_char_low = l & 0xff;
599 thisrange.max_char_high = thisrange.min_char_high = l >> 8;
602 if (*p1 == ']' || *p1 == ' ')
604 while (*p1 == ' ') p1++;
605 if (add_range(&thisrange, nranges, &result, TRUE) != Successful)
610 l = strtol(++p1, &p2, 0);
611 if (p2 == p1 || l > 0xffff) break;
612 thisrange.max_char_low = l & 0xff;
613 thisrange.max_char_high = l >> 8;
615 if (*p1 == ']' || *p1 == ' ')
617 while (*p1 == ' ') p1++;
618 if (add_range(&thisrange, nranges, &result, TRUE) != Successful)