fontxlfd.c revision 23a0898a
1/* $Xorg: fontxlfd.c,v 1.4 2001/02/09 02:04:04 xorgcvs Exp $ */ 2 3/* 4 5Copyright 1990, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of The Open Group shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from The Open Group. 28 29*/ 30/* $XFree86: xc/lib/font/util/fontxlfd.c,v 3.16tsi Exp $ */ 31 32/* 33 * Author: Keith Packard, MIT X Consortium 34 */ 35 36#ifdef HAVE_CONFIG_H 37#include <config.h> 38#endif 39#include <X11/fonts/fontmisc.h> 40#include <X11/fonts/fontstruct.h> 41#include <X11/fonts/fontxlfd.h> 42#include <X11/fonts/fontutil.h> 43#include <X11/Xos.h> 44#include <math.h> 45#include <stdlib.h> 46#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV) 47#define NO_LOCALE 48#endif 49#ifndef NO_LOCALE 50#include <locale.h> 51#endif 52#include <ctype.h> 53#include <stdio.h> /* for sprintf() */ 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 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 119static char * 120xlfd_double_to_text(double value, char *buffer, int space_required) 121{ 122 char formatbuf[40]; 123 register char *p1; 124 int ndigits, exponent; 125 126#ifndef NO_LOCALE 127 if (!locale) 128 { 129 locale = localeconv(); 130 if (locale->decimal_point && *locale->decimal_point) 131 radix = locale->decimal_point; 132 if (locale->positive_sign && *locale->positive_sign) 133 plus = locale->positive_sign; 134 if (locale->negative_sign && *locale->negative_sign) 135 minus = locale->negative_sign; 136 } 137#endif 138 /* Compute a format to use to render the number */ 139 sprintf(formatbuf, "%%.%dle", XLFD_NDIGITS); 140 141 if (space_required) 142 *buffer++ = ' '; 143 144 /* Render the number using printf's idea of formatting */ 145 sprintf(buffer, formatbuf, 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(*p1) || *p1 == '0')) p1--; 155 ndigits = 0; 156 while (p1 >= buffer) if (isdigit(*p1--)) ndigits++; 157 158 /* Figure out notation to use */ 159 if (exponent >= XLFD_NDIGITS || ndigits - exponent > XLFD_NDIGITS + 1) 160 { 161 /* Scientific */ 162 sprintf(formatbuf, "%%.%dle", ndigits - 1); 163 sprintf(buffer, formatbuf, value); 164 } 165 else 166 { 167 /* Fixed */ 168 ndigits -= exponent + 1; 169 if (ndigits < 0) ndigits = 0; 170 sprintf(formatbuf, "%%.%dlf", ndigits); 171 sprintf(buffer, formatbuf, value); 172 if (exponent < 0) 173 { 174 p1 = buffer; 175 while (*p1 && *p1 != '0') p1++; 176 while (*p1++) p1[-1] = *p1; 177 } 178 } 179 180 /* Last step, convert the locale-specific sign and radix characters 181 to our own. */ 182 for (p1 = buffer; *p1; p1++) 183 { 184 if (*p1 == *minus) *p1 = '~'; 185 else if (*p1 == *plus) *p1 = '+'; 186 else if (*p1 == *radix) *p1 = '.'; 187 } 188 189 return buffer - space_required; 190} 191 192double 193xlfd_round_double(double x) 194{ 195 /* Utility for XLFD users to round numbers to XLFD_NDIGITS 196 significant digits. How do you round to n significant digits on 197 a binary machine? */ 198 199#if defined(i386) || defined(__i386__) || \ 200 defined(ia64) || defined(__ia64__) || \ 201 defined(__alpha__) || defined(__alpha) || \ 202 defined(__hppa__) || \ 203 defined(__amd64__) || defined(__amd64) || \ 204 defined(sgi) 205#if !defined(__UNIXOS2__) 206#include <float.h> 207 208/* if we have IEEE 754 fp, we can round to binary digits... */ 209 210#if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53) 211 212#ifndef M_LN2 213#define M_LN2 0.69314718055994530942 214#endif 215#ifndef M_LN10 216#define M_LN10 2.30258509299404568402 217#endif 218 219/* convert # of decimal digits to # of binary digits */ 220#define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5)) 221 222 union conv_d { 223 double d; 224 unsigned char b[8]; 225 } d; 226 int i,j,k,d_exp; 227 228 if (x == 0) 229 return x; 230 231 /* do minor sanity check for IEEE 754 fp and correct byte order */ 232 d.d = 1.0; 233 if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) { 234 235 /* 236 * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits 237 */ 238 239 d.d = x; 240 d_exp = (d.b[7] << 4) | (d.b[6] >> 4); 241 242 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3; 243 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07); 244 for (; i<7; i++) { 245 k = d.b[i] + j; 246 d.b[i] = k; 247 if (k & 0x100) j = 1; 248 else break; 249 } 250 if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) { 251 /* mantissa overflow: increment exponent */ 252 d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1); 253 d.b[7] = d_exp >> 4; 254 d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4); 255 } 256 257 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3; 258 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07); 259 d.b[i] &= ~(j-1); 260 for (;--i>=0;) d.b[i] = 0; 261 262 return d.d; 263 } 264 else 265#endif 266#endif /* !__UNIXOS2__ */ 267#endif /* i386 || __i386__ */ 268 { 269 /* 270 * If not IEEE 754: Let printf() do it for you. 271 */ 272 273 char formatbuf[40], buffer[40]; 274 275 sprintf(formatbuf, "%%.%dlg", XLFD_NDIGITS); 276 sprintf(buffer, formatbuf, x); 277 return atof(buffer); 278 } 279} 280 281static char * 282GetMatrix(char *ptr, FontScalablePtr vals, int which) 283{ 284 double *matrix; 285 286 if (which == PIXELSIZE_MASK) 287 matrix = vals->pixel_matrix; 288 else if (which == POINTSIZE_MASK) 289 matrix = vals->point_matrix; 290 else return (char *)0; 291 292 while (isspace(*ptr)) ptr++; 293 if (*ptr == '[') 294 { 295 /* This is a matrix containing real numbers. It would be nice 296 to use strtod() or sscanf() to read the numbers, but those 297 don't handle '~' for minus and we cannot force them to use a 298 "." for the radix. We'll have to do the hard work ourselves 299 (in readreal()). */ 300 301 if ((ptr = readreal(++ptr, matrix + 0)) && 302 (ptr = readreal(ptr, matrix + 1)) && 303 (ptr = readreal(ptr, matrix + 2)) && 304 (ptr = readreal(ptr, matrix + 3))) 305 { 306 while (isspace(*ptr)) ptr++; 307 if (*ptr != ']') 308 ptr = (char *)0; 309 else 310 { 311 ptr++; 312 while (isspace(*ptr)) ptr++; 313 if (*ptr == '-') 314 { 315 if (which == POINTSIZE_MASK) 316 vals->values_supplied |= POINTSIZE_ARRAY; 317 else 318 vals->values_supplied |= PIXELSIZE_ARRAY; 319 } 320 else ptr = (char *)0; 321 } 322 } 323 } 324 else 325 { 326 int value; 327 if ((ptr = GetInt(ptr, &value))) 328 { 329 vals->values_supplied &= ~which; 330 if (value > 0) 331 { 332 matrix[3] = (double)value; 333 if (which == POINTSIZE_MASK) 334 { 335 matrix[3] /= 10.0; 336 vals->values_supplied |= POINTSIZE_SCALAR; 337 } 338 else 339 vals->values_supplied |= PIXELSIZE_SCALAR; 340 /* If we're concocting the pixelsize array from a scalar, 341 we will need to normalize element 0 for the pixel shape. 342 This is done in FontFileCompleteXLFD(). */ 343 matrix[0] = matrix[3]; 344 matrix[1] = matrix[2] = 0.0; 345 } 346 else if (value < 0) 347 { 348 if (which == POINTSIZE_MASK) 349 vals->values_supplied |= POINTSIZE_WILDCARD; 350 else 351 vals->values_supplied |= PIXELSIZE_WILDCARD; 352 } 353 } 354 } 355 return ptr; 356} 357 358 359static void 360append_ranges(char *fname, int nranges, fsRange *ranges) 361{ 362 if (nranges) 363 { 364 int i; 365 366 strcat(fname, "["); 367 for (i = 0; i < nranges && strlen(fname) < 1010; i++) 368 { 369 if (i) strcat(fname, " "); 370 sprintf(fname + strlen(fname), "%d", 371 minchar(ranges[i])); 372 if (ranges[i].min_char_low == 373 ranges[i].max_char_low && 374 ranges[i].min_char_high == 375 ranges[i].max_char_high) continue; 376 sprintf(fname + strlen(fname), "_%d", 377 maxchar(ranges[i])); 378 } 379 strcat(fname, "]"); 380 } 381} 382 383Bool 384FontParseXLFDName(char *fname, FontScalablePtr vals, int subst) 385{ 386 register char *ptr; 387 register char *ptr1, 388 *ptr2, 389 *ptr3, 390 *ptr4; 391 register char *ptr5; 392 FontScalableRec tmpvals; 393 char replaceChar = '0'; 394 char tmpBuf[1024]; 395 int spacingLen; 396 int l; 397 char *p; 398 399 bzero(&tmpvals, sizeof(tmpvals)); 400 if (subst != FONT_XLFD_REPLACE_VALUE) 401 *vals = tmpvals; 402 403 if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) || /* fndry */ 404 !(ptr = strchr(ptr + 1, '-')) || /* family_name */ 405 !(ptr1 = ptr = strchr(ptr + 1, '-')) || /* weight_name */ 406 !(ptr = strchr(ptr + 1, '-')) || /* slant */ 407 !(ptr = strchr(ptr + 1, '-')) || /* setwidth_name */ 408 !(ptr = strchr(ptr + 1, '-')) || /* add_style_name */ 409 !(ptr = strchr(ptr + 1, '-')) || /* pixel_size */ 410 !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) || 411 !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) || 412 !(ptr = GetInt(ptr + 1, &tmpvals.x)) || /* resolution_x */ 413 !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) || /* resolution_y */ 414 !(ptr4 = ptr = strchr(ptr + 1, '-')) || /* spacing */ 415 !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */ 416 !(ptr = strchr(ptr + 1, '-')) || /* charset_registry */ 417 strchr(ptr + 1, '-'))/* charset_encoding */ 418 return FALSE; 419 420 /* Lop off HP charset subsetting enhancement. Interpreting this 421 field requires allocating some space in which to return the 422 results. So, to prevent memory leaks, this procedure will simply 423 lop off and ignore charset subsetting, and initialize the 424 relevant vals fields to zero. It's up to the caller to make its 425 own call to FontParseRanges() if it's interested in the charset 426 subsetting. */ 427 428 if (subst != FONT_XLFD_REPLACE_NONE && 429 (p = strchr(strrchr(fname, '-'), '['))) 430 { 431 tmpvals.values_supplied |= CHARSUBSET_SPECIFIED; 432 *p = '\0'; 433 } 434 435 /* Fill in deprecated fields for the benefit of rasterizers that care 436 about them. */ 437 tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ? 438 (int)(tmpvals.pixel_matrix[3] + .5) : 439 (int)(tmpvals.pixel_matrix[3] - .5); 440 tmpvals.point = (tmpvals.point_matrix[3] >= 0) ? 441 (int)(tmpvals.point_matrix[3] * 10 + .5) : 442 (int)(tmpvals.point_matrix[3] * 10 - .5); 443 444 spacingLen = ptr4 - ptr3 + 1; 445 446 switch (subst) { 447 case FONT_XLFD_REPLACE_NONE: 448 *vals = tmpvals; 449 break; 450 case FONT_XLFD_REPLACE_STAR: 451 replaceChar = '*'; 452 case FONT_XLFD_REPLACE_ZERO: 453 strcpy(tmpBuf, ptr2); 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 strcpy(ptr, ptr5); 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 sprintf(tmpBuf, "%*.*s", l, l, p); 522 523 p += l + 1; /* slant field */ 524 l = strchr(p, '-') - p; 525 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 526 527 p += l + 1; /* setwidth_name */ 528 l = strchr(p, '-') - p; 529 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 530 531 p += l + 1; /* add_style_name field */ 532 l = strchr(p, '-') - p; 533 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 534 535 strcat(tmpBuf, "-"); 536 if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) 537 { 538 char buffer[80]; 539 strcat(tmpBuf, "["); 540 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[0], 541 buffer, 0)); 542 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[1], 543 buffer, 1)); 544 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[2], 545 buffer, 1)); 546 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[3], 547 buffer, 1)); 548 strcat(tmpBuf, "]"); 549 } 550 else 551 { 552 sprintf(tmpBuf + strlen(tmpBuf), "%d", 553 (int)(tmpvals.pixel_matrix[3] + .5)); 554 } 555 strcat(tmpBuf, "-"); 556 if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) 557 { 558 char buffer[80]; 559 strcat(tmpBuf, "["); 560 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[0], 561 buffer, 0)); 562 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[1], 563 buffer, 1)); 564 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[2], 565 buffer, 1)); 566 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[3], 567 buffer, 1)); 568 strcat(tmpBuf, "]"); 569 } 570 else 571 { 572 sprintf(tmpBuf + strlen(tmpBuf), "%d", 573 (int)(tmpvals.point_matrix[3] * 10.0 + .5)); 574 } 575 sprintf(tmpBuf + strlen(tmpBuf), "-%d-%d%*.*s%d%s", 576 tmpvals.x, tmpvals.y, 577 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5); 578 strcpy(ptr1 + 1, tmpBuf); 579 if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges) 580 strcat(fname, "[]"); 581 else 582 append_ranges(fname, vals->nranges, vals->ranges); 583 break; 584 } 585 return TRUE; 586} 587 588fsRange *FontParseRanges(char *name, int *nranges) 589{ 590 int n; 591 unsigned long l; 592 char *p1, *p2; 593 fsRange *result = (fsRange *)0; 594 595 name = strchr(name, '-'); 596 for (n = 1; name && n < 14; n++) 597 name = strchr(name + 1, '-'); 598 599 *nranges = 0; 600 if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0; 601 p1++; 602 603 while (*p1 && *p1 != ']') 604 { 605 fsRange thisrange; 606 607 l = strtol(p1, &p2, 0); 608 if (p2 == p1 || l > 0xffff) break; 609 thisrange.max_char_low = thisrange.min_char_low = l & 0xff; 610 thisrange.max_char_high = thisrange.min_char_high = l >> 8; 611 612 p1 = p2; 613 if (*p1 == ']' || *p1 == ' ') 614 { 615 while (*p1 == ' ') p1++; 616 if (add_range(&thisrange, nranges, &result, TRUE) != Successful) 617 break; 618 } 619 else if (*p1 == '_') 620 { 621 l = strtol(++p1, &p2, 0); 622 if (p2 == p1 || l > 0xffff) break; 623 thisrange.max_char_low = l & 0xff; 624 thisrange.max_char_high = l >> 8; 625 p1 = p2; 626 if (*p1 == ']' || *p1 == ' ') 627 { 628 while (*p1 == ' ') p1++; 629 if (add_range(&thisrange, nranges, &result, TRUE) != Successful) 630 break; 631 } 632 } 633 else break; 634 } 635 636 return result; 637} 638