fontxlfd.c revision 7f7f5e4e
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#include <float.h> 206 207/* if we have IEEE 754 fp, we can round to binary digits... */ 208 209#if (FLT_RADIX == 2) && (DBL_DIG == 15) && (DBL_MANT_DIG == 53) 210 211#ifndef M_LN2 212#define M_LN2 0.69314718055994530942 213#endif 214#ifndef M_LN10 215#define M_LN10 2.30258509299404568402 216#endif 217 218/* convert # of decimal digits to # of binary digits */ 219#define XLFD_NDIGITS_2 ((int)(XLFD_NDIGITS * M_LN10 / M_LN2 + 0.5)) 220 221 union conv_d { 222 double d; 223 unsigned char b[8]; 224 } d; 225 int i,j,k,d_exp; 226 227 if (x == 0) 228 return x; 229 230 /* do minor sanity check for IEEE 754 fp and correct byte order */ 231 d.d = 1.0; 232 if (sizeof(double) == 8 && d.b[7] == 0x3f && d.b[6] == 0xf0) { 233 234 /* 235 * this code will round IEEE 754 double to XLFD_NDIGITS_2 binary digits 236 */ 237 238 d.d = x; 239 d_exp = (d.b[7] << 4) | (d.b[6] >> 4); 240 241 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3; 242 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07); 243 for (; i<7; i++) { 244 k = d.b[i] + j; 245 d.b[i] = k; 246 if (k & 0x100) j = 1; 247 else break; 248 } 249 if ((i==7) && ((d.b[6] & 0xf0) != ((d_exp<<4) & 0xf0))) { 250 /* mantissa overflow: increment exponent */ 251 d_exp = (d_exp & 0x800 ) | ((d_exp & 0x7ff) + 1); 252 d.b[7] = d_exp >> 4; 253 d.b[6] = (d.b[6] & 0x0f) | (d_exp << 4); 254 } 255 256 i = (DBL_MANT_DIG-XLFD_NDIGITS_2) >> 3; 257 j = 1 << ((DBL_MANT_DIG-XLFD_NDIGITS_2) & 0x07); 258 d.b[i] &= ~(j-1); 259 for (;--i>=0;) d.b[i] = 0; 260 261 return d.d; 262 } 263 else 264#endif 265#endif /* i386 || __i386__ */ 266 { 267 /* 268 * If not IEEE 754: Let printf() do it for you. 269 */ 270 271 char formatbuf[40], buffer[40]; 272 273 sprintf(formatbuf, "%%.%dlg", XLFD_NDIGITS); 274 sprintf(buffer, formatbuf, x); 275 return atof(buffer); 276 } 277} 278 279static char * 280GetMatrix(char *ptr, FontScalablePtr vals, int which) 281{ 282 double *matrix; 283 284 if (which == PIXELSIZE_MASK) 285 matrix = vals->pixel_matrix; 286 else if (which == POINTSIZE_MASK) 287 matrix = vals->point_matrix; 288 else return (char *)0; 289 290 while (isspace(*ptr)) ptr++; 291 if (*ptr == '[') 292 { 293 /* This is a matrix containing real numbers. It would be nice 294 to use strtod() or sscanf() to read the numbers, but those 295 don't handle '~' for minus and we cannot force them to use a 296 "." for the radix. We'll have to do the hard work ourselves 297 (in readreal()). */ 298 299 if ((ptr = readreal(++ptr, matrix + 0)) && 300 (ptr = readreal(ptr, matrix + 1)) && 301 (ptr = readreal(ptr, matrix + 2)) && 302 (ptr = readreal(ptr, matrix + 3))) 303 { 304 while (isspace(*ptr)) ptr++; 305 if (*ptr != ']') 306 ptr = (char *)0; 307 else 308 { 309 ptr++; 310 while (isspace(*ptr)) ptr++; 311 if (*ptr == '-') 312 { 313 if (which == POINTSIZE_MASK) 314 vals->values_supplied |= POINTSIZE_ARRAY; 315 else 316 vals->values_supplied |= PIXELSIZE_ARRAY; 317 } 318 else ptr = (char *)0; 319 } 320 } 321 } 322 else 323 { 324 int value; 325 if ((ptr = GetInt(ptr, &value))) 326 { 327 vals->values_supplied &= ~which; 328 if (value > 0) 329 { 330 matrix[3] = (double)value; 331 if (which == POINTSIZE_MASK) 332 { 333 matrix[3] /= 10.0; 334 vals->values_supplied |= POINTSIZE_SCALAR; 335 } 336 else 337 vals->values_supplied |= PIXELSIZE_SCALAR; 338 /* If we're concocting the pixelsize array from a scalar, 339 we will need to normalize element 0 for the pixel shape. 340 This is done in FontFileCompleteXLFD(). */ 341 matrix[0] = matrix[3]; 342 matrix[1] = matrix[2] = 0.0; 343 } 344 else if (value < 0) 345 { 346 if (which == POINTSIZE_MASK) 347 vals->values_supplied |= POINTSIZE_WILDCARD; 348 else 349 vals->values_supplied |= PIXELSIZE_WILDCARD; 350 } 351 } 352 } 353 return ptr; 354} 355 356 357static void 358append_ranges(char *fname, int nranges, fsRange *ranges) 359{ 360 if (nranges) 361 { 362 int i; 363 364 strcat(fname, "["); 365 for (i = 0; i < nranges && strlen(fname) < 1010; i++) 366 { 367 if (i) strcat(fname, " "); 368 sprintf(fname + strlen(fname), "%d", 369 minchar(ranges[i])); 370 if (ranges[i].min_char_low == 371 ranges[i].max_char_low && 372 ranges[i].min_char_high == 373 ranges[i].max_char_high) continue; 374 sprintf(fname + strlen(fname), "_%d", 375 maxchar(ranges[i])); 376 } 377 strcat(fname, "]"); 378 } 379} 380 381Bool 382FontParseXLFDName(char *fname, FontScalablePtr vals, int subst) 383{ 384 register char *ptr; 385 register char *ptr1, 386 *ptr2, 387 *ptr3, 388 *ptr4; 389 register char *ptr5; 390 FontScalableRec tmpvals; 391 char replaceChar = '0'; 392 char tmpBuf[1024]; 393 int spacingLen; 394 int l; 395 char *p; 396 397 bzero(&tmpvals, sizeof(tmpvals)); 398 if (subst != FONT_XLFD_REPLACE_VALUE) 399 *vals = tmpvals; 400 401 if (!(*(ptr = fname) == '-' || (*ptr++ == '*' && *ptr == '-')) || /* fndry */ 402 !(ptr = strchr(ptr + 1, '-')) || /* family_name */ 403 !(ptr1 = ptr = strchr(ptr + 1, '-')) || /* weight_name */ 404 !(ptr = strchr(ptr + 1, '-')) || /* slant */ 405 !(ptr = strchr(ptr + 1, '-')) || /* setwidth_name */ 406 !(ptr = strchr(ptr + 1, '-')) || /* add_style_name */ 407 !(ptr = strchr(ptr + 1, '-')) || /* pixel_size */ 408 !(ptr = GetMatrix(ptr + 1, &tmpvals, PIXELSIZE_MASK)) || 409 !(ptr2 = ptr = GetMatrix(ptr + 1, &tmpvals, POINTSIZE_MASK)) || 410 !(ptr = GetInt(ptr + 1, &tmpvals.x)) || /* resolution_x */ 411 !(ptr3 = ptr = GetInt(ptr + 1, &tmpvals.y)) || /* resolution_y */ 412 !(ptr4 = ptr = strchr(ptr + 1, '-')) || /* spacing */ 413 !(ptr5 = ptr = GetInt(ptr + 1, &tmpvals.width)) || /* average_width */ 414 !(ptr = strchr(ptr + 1, '-')) || /* charset_registry */ 415 strchr(ptr + 1, '-'))/* charset_encoding */ 416 return FALSE; 417 418 /* Lop off HP charset subsetting enhancement. Interpreting this 419 field requires allocating some space in which to return the 420 results. So, to prevent memory leaks, this procedure will simply 421 lop off and ignore charset subsetting, and initialize the 422 relevant vals fields to zero. It's up to the caller to make its 423 own call to FontParseRanges() if it's interested in the charset 424 subsetting. */ 425 426 if (subst != FONT_XLFD_REPLACE_NONE && 427 (p = strchr(strrchr(fname, '-'), '['))) 428 { 429 tmpvals.values_supplied |= CHARSUBSET_SPECIFIED; 430 *p = '\0'; 431 } 432 433 /* Fill in deprecated fields for the benefit of rasterizers that care 434 about them. */ 435 tmpvals.pixel = (tmpvals.pixel_matrix[3] >= 0) ? 436 (int)(tmpvals.pixel_matrix[3] + .5) : 437 (int)(tmpvals.pixel_matrix[3] - .5); 438 tmpvals.point = (tmpvals.point_matrix[3] >= 0) ? 439 (int)(tmpvals.point_matrix[3] * 10 + .5) : 440 (int)(tmpvals.point_matrix[3] * 10 - .5); 441 442 spacingLen = ptr4 - ptr3 + 1; 443 444 switch (subst) { 445 case FONT_XLFD_REPLACE_NONE: 446 *vals = tmpvals; 447 break; 448 case FONT_XLFD_REPLACE_STAR: 449 replaceChar = '*'; 450 case FONT_XLFD_REPLACE_ZERO: 451 strcpy(tmpBuf, ptr2); 452 ptr5 = tmpBuf + (ptr5 - ptr2); 453 ptr3 = tmpBuf + (ptr3 - ptr2); 454 ptr2 = tmpBuf; 455 ptr = ptr1 + 1; 456 457 ptr = strchr(ptr, '-') + 1; /* skip weight */ 458 ptr = strchr(ptr, '-') + 1; /* skip slant */ 459 ptr = strchr(ptr, '-') + 1; /* skip setwidth_name */ 460 ptr = strchr(ptr, '-') + 1; /* skip add_style_name */ 461 462 if ((ptr - fname) + spacingLen + strlen(ptr5) + 10 >= (unsigned)1024) 463 return FALSE; 464 *ptr++ = replaceChar; 465 *ptr++ = '-'; 466 *ptr++ = replaceChar; 467 *ptr++ = '-'; 468 *ptr++ = '*'; 469 *ptr++ = '-'; 470 *ptr++ = '*'; 471 if (spacingLen > 2) 472 { 473 memmove(ptr, ptr3, spacingLen); 474 ptr += spacingLen; 475 } 476 else 477 { 478 *ptr++ = '-'; 479 *ptr++ = '*'; 480 *ptr++ = '-'; 481 } 482 *ptr++ = replaceChar; 483 strcpy(ptr, ptr5); 484 *vals = tmpvals; 485 break; 486 case FONT_XLFD_REPLACE_VALUE: 487 if (vals->values_supplied & PIXELSIZE_MASK) 488 { 489 tmpvals.values_supplied = 490 (tmpvals.values_supplied & ~PIXELSIZE_MASK) | 491 (vals->values_supplied & PIXELSIZE_MASK); 492 tmpvals.pixel_matrix[0] = vals->pixel_matrix[0]; 493 tmpvals.pixel_matrix[1] = vals->pixel_matrix[1]; 494 tmpvals.pixel_matrix[2] = vals->pixel_matrix[2]; 495 tmpvals.pixel_matrix[3] = vals->pixel_matrix[3]; 496 } 497 if (vals->values_supplied & POINTSIZE_MASK) 498 { 499 tmpvals.values_supplied = 500 (tmpvals.values_supplied & ~POINTSIZE_MASK) | 501 (vals->values_supplied & POINTSIZE_MASK); 502 tmpvals.point_matrix[0] = vals->point_matrix[0]; 503 tmpvals.point_matrix[1] = vals->point_matrix[1]; 504 tmpvals.point_matrix[2] = vals->point_matrix[2]; 505 tmpvals.point_matrix[3] = vals->point_matrix[3]; 506 } 507 if (vals->x >= 0) 508 tmpvals.x = vals->x; 509 if (vals->y >= 0) 510 tmpvals.y = vals->y; 511 if (vals->width >= 0) 512 tmpvals.width = vals->width; 513 else if (vals->width < -1) /* overload: -1 means wildcard */ 514 tmpvals.width = -vals->width; 515 516 517 p = ptr1 + 1; /* weight field */ 518 l = strchr(p, '-') - p; 519 sprintf(tmpBuf, "%*.*s", l, l, p); 520 521 p += l + 1; /* slant field */ 522 l = strchr(p, '-') - p; 523 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 524 525 p += l + 1; /* setwidth_name */ 526 l = strchr(p, '-') - p; 527 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 528 529 p += l + 1; /* add_style_name field */ 530 l = strchr(p, '-') - p; 531 sprintf(tmpBuf + strlen(tmpBuf), "-%*.*s", l, l, p); 532 533 strcat(tmpBuf, "-"); 534 if ((tmpvals.values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) 535 { 536 char buffer[80]; 537 strcat(tmpBuf, "["); 538 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[0], 539 buffer, 0)); 540 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[1], 541 buffer, 1)); 542 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[2], 543 buffer, 1)); 544 strcat(tmpBuf, xlfd_double_to_text(tmpvals.pixel_matrix[3], 545 buffer, 1)); 546 strcat(tmpBuf, "]"); 547 } 548 else 549 { 550 sprintf(tmpBuf + strlen(tmpBuf), "%d", 551 (int)(tmpvals.pixel_matrix[3] + .5)); 552 } 553 strcat(tmpBuf, "-"); 554 if ((tmpvals.values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) 555 { 556 char buffer[80]; 557 strcat(tmpBuf, "["); 558 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[0], 559 buffer, 0)); 560 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[1], 561 buffer, 1)); 562 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[2], 563 buffer, 1)); 564 strcat(tmpBuf, xlfd_double_to_text(tmpvals.point_matrix[3], 565 buffer, 1)); 566 strcat(tmpBuf, "]"); 567 } 568 else 569 { 570 sprintf(tmpBuf + strlen(tmpBuf), "%d", 571 (int)(tmpvals.point_matrix[3] * 10.0 + .5)); 572 } 573 sprintf(tmpBuf + strlen(tmpBuf), "-%d-%d%*.*s%d%s", 574 tmpvals.x, tmpvals.y, 575 spacingLen, spacingLen, ptr3, tmpvals.width, ptr5); 576 strcpy(ptr1 + 1, tmpBuf); 577 if ((vals->values_supplied & CHARSUBSET_SPECIFIED) && !vals->nranges) 578 strcat(fname, "[]"); 579 else 580 append_ranges(fname, vals->nranges, vals->ranges); 581 break; 582 } 583 return TRUE; 584} 585 586fsRange *FontParseRanges(char *name, int *nranges) 587{ 588 int n; 589 unsigned long l; 590 char *p1, *p2; 591 fsRange *result = (fsRange *)0; 592 593 name = strchr(name, '-'); 594 for (n = 1; name && n < 14; n++) 595 name = strchr(name + 1, '-'); 596 597 *nranges = 0; 598 if (!name || !(p1 = strchr(name, '['))) return (fsRange *)0; 599 p1++; 600 601 while (*p1 && *p1 != ']') 602 { 603 fsRange thisrange; 604 605 l = strtol(p1, &p2, 0); 606 if (p2 == p1 || l > 0xffff) break; 607 thisrange.max_char_low = thisrange.min_char_low = l & 0xff; 608 thisrange.max_char_high = thisrange.min_char_high = l >> 8; 609 610 p1 = p2; 611 if (*p1 == ']' || *p1 == ' ') 612 { 613 while (*p1 == ' ') p1++; 614 if (add_range(&thisrange, nranges, &result, TRUE) != Successful) 615 break; 616 } 617 else if (*p1 == '_') 618 { 619 l = strtol(++p1, &p2, 0); 620 if (p2 == p1 || l > 0xffff) break; 621 thisrange.max_char_low = l & 0xff; 622 thisrange.max_char_high = l >> 8; 623 p1 = p2; 624 if (*p1 == ']' || *p1 == ' ') 625 { 626 while (*p1 == ' ') p1++; 627 if (add_range(&thisrange, nranges, &result, TRUE) != Successful) 628 break; 629 } 630 } 631 else break; 632 } 633 634 return result; 635} 636