encparse.c revision e1c0d025
13da084b3Smrg/* 23da084b3SmrgCopyright (c) 1998-2001 by Juliusz Chroboczek 33da084b3Smrg 43da084b3SmrgPermission is hereby granted, free of charge, to any person obtaining a copy 53da084b3Smrgof this software and associated documentation files (the "Software"), to deal 63da084b3Smrgin the Software without restriction, including without limitation the rights 73da084b3Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell 83da084b3Smrgcopies of the Software, and to permit persons to whom the Software is 93da084b3Smrgfurnished to do so, subject to the following conditions: 103da084b3Smrg 113da084b3SmrgThe above copyright notice and this permission notice shall be included in 123da084b3Smrgall copies or substantial portions of the Software. 133da084b3Smrg 143da084b3SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 153da084b3SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 163da084b3SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 173da084b3SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 183da084b3SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 193da084b3SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 203da084b3SmrgTHE SOFTWARE. 213da084b3Smrg*/ 223da084b3Smrg 233da084b3Smrg/* Parser for encoding files */ 243da084b3Smrg 253da084b3Smrg/* This code assumes that we are using ASCII. We don't use the ctype 263da084b3Smrg functions, as they depend on the current locale. On the other 273da084b3Smrg hand, we do use strcasecmp, but only on strings that we've checked 283da084b3Smrg to be pure ASCII. Bloody ``Code Set Independence''. */ 293da084b3Smrg 303da084b3Smrg#include <string.h> 313da084b3Smrg#include <strings.h> 3248c85eb7Smrg#include <stdio.h> 333da084b3Smrg 343da084b3Smrg#include <stdlib.h> 353da084b3Smrg 363da084b3Smrg#include "zlib.h" 373da084b3Smrgtypedef gzFile FontFilePtr; 38e1c0d025Smrg 393da084b3Smrg#define FontFileGetc(f) gzgetc(f) 403da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb") 413da084b3Smrg#define FontFileClose(f) gzclose(f) 423da084b3Smrg 433da084b3Smrg#define MAXFONTFILENAMELEN 1024 443da084b3Smrg#define MAXFONTNAMELEN 1024 453da084b3Smrg 463da084b3Smrg#include <X11/fonts/fontenc.h> 473da084b3Smrg#include "fontencI.h" 483da084b3Smrg 493da084b3Smrg#define MAXALIASES 20 503da084b3Smrg 513da084b3Smrg#define EOF_TOKEN -1 523da084b3Smrg#define ERROR_TOKEN -2 533da084b3Smrg#define EOL_TOKEN 0 543da084b3Smrg#define NUMBER_TOKEN 1 553da084b3Smrg#define KEYWORD_TOKEN 2 563da084b3Smrg 573da084b3Smrg#define EOF_LINE -1 583da084b3Smrg#define ERROR_LINE -2 593da084b3Smrg#define STARTENCODING_LINE 1 603da084b3Smrg#define STARTMAPPING_LINE 2 613da084b3Smrg#define ENDMAPPING_LINE 3 623da084b3Smrg#define CODE_LINE 4 633da084b3Smrg#define CODE_RANGE_LINE 5 643da084b3Smrg#define CODE_UNDEFINE_LINE 6 653da084b3Smrg#define NAME_LINE 7 663da084b3Smrg#define SIZE_LINE 8 673da084b3Smrg#define ALIAS_LINE 9 683da084b3Smrg#define FIRSTINDEX_LINE 10 693da084b3Smrg 703da084b3Smrg/* Return from lexer */ 713da084b3Smrg#define MAXKEYWORDLEN 100 723da084b3Smrg 733da084b3Smrgstatic long number_value; 74e1c0d025Smrgstatic char keyword_value[MAXKEYWORDLEN + 1]; 753da084b3Smrg 763da084b3Smrgstatic long value1, value2, value3; 773da084b3Smrg 783da084b3Smrg/* Lexer code */ 793da084b3Smrg 803da084b3Smrg/* Skip to the beginning of new line */ 813da084b3Smrgstatic void 823da084b3SmrgskipEndOfLine(FontFilePtr f, int c) 833da084b3Smrg{ 84e1c0d025Smrg if (c == 0) 853da084b3Smrg c = FontFileGetc(f); 8648c85eb7Smrg 87e1c0d025Smrg for (;;) 88e1c0d025Smrg if (c <= 0 || c == '\n') 893da084b3Smrg return; 903da084b3Smrg else 913da084b3Smrg c = FontFileGetc(f); 923da084b3Smrg} 933da084b3Smrg 943da084b3Smrg/* Get a number; we're at the first digit. */ 953da084b3Smrgstatic unsigned 963da084b3Smrggetnum(FontFilePtr f, int c, int *cp) 973da084b3Smrg{ 983da084b3Smrg unsigned n = 0; 993da084b3Smrg int base = 10; 1003da084b3Smrg 1013da084b3Smrg /* look for `0' or `0x' prefix */ 102e1c0d025Smrg if (c == '0') { 1033da084b3Smrg c = FontFileGetc(f); 1043da084b3Smrg base = 8; 105e1c0d025Smrg if (c == 'x' || c == 'X') { 1063da084b3Smrg base = 16; 1073da084b3Smrg c = FontFileGetc(f); 1083da084b3Smrg } 1093da084b3Smrg } 1103da084b3Smrg 1113da084b3Smrg /* accumulate digits */ 112e1c0d025Smrg for (;;) { 1133da084b3Smrg if ('0' <= c && c <= '9') { 114e1c0d025Smrg n *= base; 115e1c0d025Smrg n += c - '0'; 116e1c0d025Smrg } 117e1c0d025Smrg else if ('a' <= c && c <= 'f') { 118e1c0d025Smrg n *= base; 119e1c0d025Smrg n += c - 'a' + 10; 120e1c0d025Smrg } 121e1c0d025Smrg else if ('A' <= c && c <= 'F') { 122e1c0d025Smrg n *= base; 123e1c0d025Smrg n += c - 'A' + 10; 124e1c0d025Smrg } 125e1c0d025Smrg else 1263da084b3Smrg break; 1273da084b3Smrg c = FontFileGetc(f); 1283da084b3Smrg } 1293da084b3Smrg 130e1c0d025Smrg *cp = c; 131e1c0d025Smrg return n; 1323da084b3Smrg} 13348c85eb7Smrg 1343da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */ 1353da084b3Smrgstatic int 1363da084b3SmrgendOfLine(FontFilePtr f, int c) 1373da084b3Smrg{ 138e1c0d025Smrg if (c == 0) 1393da084b3Smrg c = FontFileGetc(f); 1403da084b3Smrg 141e1c0d025Smrg for (;;) { 142e1c0d025Smrg if (c <= 0 || c == '\n') 1433da084b3Smrg return 1; 144e1c0d025Smrg else if (c == '#') { 145e1c0d025Smrg skipEndOfLine(f, c); 1463da084b3Smrg return 1; 1473da084b3Smrg } 148e1c0d025Smrg else if (c == ' ' || c == '\t') { 149e1c0d025Smrg skipEndOfLine(f, c); 1503da084b3Smrg return 0; 1513da084b3Smrg } 1523da084b3Smrg c = FontFileGetc(f); 1533da084b3Smrg } 1543da084b3Smrg} 1553da084b3Smrg 1563da084b3Smrg/* Get a token; we're at first char */ 1573da084b3Smrgstatic int 1583da084b3Smrggettoken(FontFilePtr f, int c, int *cp) 1593da084b3Smrg{ 1603da084b3Smrg char *p; 1613da084b3Smrg 162e1c0d025Smrg if (c <= 0) 163e1c0d025Smrg c = FontFileGetc(f); 1643da084b3Smrg 165e1c0d025Smrg if (c <= 0) { 1663da084b3Smrg return EOF_TOKEN; 1673da084b3Smrg } 1683da084b3Smrg 169e1c0d025Smrg while (c == ' ' || c == '\t') 1703da084b3Smrg c = FontFileGetc(f); 1713da084b3Smrg 172e1c0d025Smrg if (c == '\n') { 1733da084b3Smrg return EOL_TOKEN; 174e1c0d025Smrg } 175e1c0d025Smrg else if (c == '#') { 176e1c0d025Smrg skipEndOfLine(f, c); 1773da084b3Smrg return EOL_TOKEN; 178e1c0d025Smrg } 179e1c0d025Smrg else if (c >= '0' && c <= '9') { 180e1c0d025Smrg number_value = getnum(f, c, cp); 1813da084b3Smrg return NUMBER_TOKEN; 182e1c0d025Smrg } 183e1c0d025Smrg else if ((c >= 'A' && c <= 'Z') || 184e1c0d025Smrg (c >= 'a' && c <= 'z') || 185e1c0d025Smrg c == '/' || c == '_' || c == '-' || c == '.') { 1863da084b3Smrg p = keyword_value; 1873da084b3Smrg *p++ = c; 188e1c0d025Smrg while (p - keyword_value < MAXKEYWORDLEN) { 1893da084b3Smrg c = FontFileGetc(f); 190e1c0d025Smrg if (c <= ' ' || c > '~' || c == '#') 1913da084b3Smrg break; 1923da084b3Smrg *p++ = c; 1933da084b3Smrg } 1943da084b3Smrg *cp = c; 1953da084b3Smrg *p = '\0'; 1963da084b3Smrg return KEYWORD_TOKEN; 197e1c0d025Smrg } 198e1c0d025Smrg else { 1993da084b3Smrg *cp = c; 2003da084b3Smrg return ERROR_TOKEN; 2013da084b3Smrg } 2023da084b3Smrg} 2033da084b3Smrg 2043da084b3Smrg/* Parse a line. 2053da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */ 2063da084b3Smrgstatic int 2073da084b3Smrggetnextline(FontFilePtr f) 2083da084b3Smrg{ 2093da084b3Smrg int c, token; 210e1c0d025Smrg 2113da084b3Smrg c = FontFileGetc(f); 212e1c0d025Smrg if (c <= 0) 2133da084b3Smrg return EOF_LINE; 2143da084b3Smrg 215e1c0d025Smrg again: 216e1c0d025Smrg token = gettoken(f, c, &c); 2173da084b3Smrg 218e1c0d025Smrg switch (token) { 2193da084b3Smrg case EOF_TOKEN: 2203da084b3Smrg return EOF_LINE; 2213da084b3Smrg case EOL_TOKEN: 2223da084b3Smrg /* empty line */ 2233da084b3Smrg c = FontFileGetc(f); 2243da084b3Smrg goto again; 2253da084b3Smrg case NUMBER_TOKEN: 2263da084b3Smrg value1 = number_value; 227e1c0d025Smrg token = gettoken(f, c, &c); 228e1c0d025Smrg switch (token) { 2293da084b3Smrg case NUMBER_TOKEN: 2303da084b3Smrg value2 = number_value; 231e1c0d025Smrg token = gettoken(f, c, &c); 232e1c0d025Smrg switch (token) { 2333da084b3Smrg case NUMBER_TOKEN: 2343da084b3Smrg value3 = number_value; 2353da084b3Smrg return CODE_RANGE_LINE; 2363da084b3Smrg case EOL_TOKEN: 2373da084b3Smrg return CODE_LINE; 2383da084b3Smrg default: 239e1c0d025Smrg skipEndOfLine(f, c); 2403da084b3Smrg return ERROR_LINE; 2413da084b3Smrg } 2423da084b3Smrg case KEYWORD_TOKEN: 243e1c0d025Smrg if (!endOfLine(f, c)) 2443da084b3Smrg return ERROR_LINE; 2453da084b3Smrg else 2463da084b3Smrg return NAME_LINE; 2473da084b3Smrg default: 248e1c0d025Smrg skipEndOfLine(f, c); 2493da084b3Smrg return ERROR_LINE; 2503da084b3Smrg } 2513da084b3Smrg case KEYWORD_TOKEN: 252e1c0d025Smrg if (!strcasecmp(keyword_value, "STARTENCODING")) { 253e1c0d025Smrg token = gettoken(f, c, &c); 254e1c0d025Smrg if (token == KEYWORD_TOKEN) { 255e1c0d025Smrg if (endOfLine(f, c)) 2563da084b3Smrg return STARTENCODING_LINE; 2573da084b3Smrg else 2583da084b3Smrg return ERROR_LINE; 259e1c0d025Smrg } 260e1c0d025Smrg else { 261e1c0d025Smrg skipEndOfLine(f, c); 2623da084b3Smrg return ERROR_LINE; 2633da084b3Smrg } 264e1c0d025Smrg } 265e1c0d025Smrg else if (!strcasecmp(keyword_value, "ALIAS")) { 266e1c0d025Smrg token = gettoken(f, c, &c); 267e1c0d025Smrg if (token == KEYWORD_TOKEN) { 268e1c0d025Smrg if (endOfLine(f, c)) 2693da084b3Smrg return ALIAS_LINE; 2703da084b3Smrg else 2713da084b3Smrg return ERROR_LINE; 272e1c0d025Smrg } 273e1c0d025Smrg else { 274e1c0d025Smrg skipEndOfLine(f, c); 2753da084b3Smrg return ERROR_LINE; 2763da084b3Smrg } 277e1c0d025Smrg } 278e1c0d025Smrg else if (!strcasecmp(keyword_value, "SIZE")) { 279e1c0d025Smrg token = gettoken(f, c, &c); 280e1c0d025Smrg if (token == NUMBER_TOKEN) { 2813da084b3Smrg value1 = number_value; 282e1c0d025Smrg token = gettoken(f, c, &c); 283e1c0d025Smrg switch (token) { 2843da084b3Smrg case NUMBER_TOKEN: 2853da084b3Smrg value2 = number_value; 2863da084b3Smrg return SIZE_LINE; 2873da084b3Smrg case EOL_TOKEN: 288e1c0d025Smrg value2 = 0; 2893da084b3Smrg return SIZE_LINE; 2903da084b3Smrg default: 291e1c0d025Smrg skipEndOfLine(f, c); 2923da084b3Smrg return ERROR_LINE; 2933da084b3Smrg } 294e1c0d025Smrg } 295e1c0d025Smrg else { 296e1c0d025Smrg skipEndOfLine(f, c); 2973da084b3Smrg return ERROR_LINE; 2983da084b3Smrg } 299e1c0d025Smrg } 300e1c0d025Smrg else if (!strcasecmp(keyword_value, "FIRSTINDEX")) { 301e1c0d025Smrg token = gettoken(f, c, &c); 302e1c0d025Smrg if (token == NUMBER_TOKEN) { 3033da084b3Smrg value1 = number_value; 304e1c0d025Smrg token = gettoken(f, c, &c); 305e1c0d025Smrg switch (token) { 3063da084b3Smrg case NUMBER_TOKEN: 3073da084b3Smrg value2 = number_value; 3083da084b3Smrg return FIRSTINDEX_LINE; 3093da084b3Smrg case EOL_TOKEN: 3103da084b3Smrg value2 = 0; 3113da084b3Smrg return FIRSTINDEX_LINE; 3123da084b3Smrg default: 313e1c0d025Smrg skipEndOfLine(f, c); 3143da084b3Smrg return ERROR_LINE; 3153da084b3Smrg } 316e1c0d025Smrg } 317e1c0d025Smrg else { 318e1c0d025Smrg skipEndOfLine(f, c); 3193da084b3Smrg return ERROR_LINE; 3203da084b3Smrg } 321e1c0d025Smrg } 322e1c0d025Smrg else if (!strcasecmp(keyword_value, "STARTMAPPING")) { 3233da084b3Smrg keyword_value[0] = 0; 324e1c0d025Smrg value1 = 0; 325e1c0d025Smrg value2 = 0; 3263da084b3Smrg /* first a keyword */ 327e1c0d025Smrg token = gettoken(f, c, &c); 328e1c0d025Smrg if (token != KEYWORD_TOKEN) { 3293da084b3Smrg skipEndOfLine(f, c); 3303da084b3Smrg return ERROR_LINE; 3313da084b3Smrg } 3323da084b3Smrg 3333da084b3Smrg /* optional first integer */ 334e1c0d025Smrg token = gettoken(f, c, &c); 335e1c0d025Smrg if (token == NUMBER_TOKEN) { 3363da084b3Smrg value1 = number_value; 337e1c0d025Smrg } 338e1c0d025Smrg else if (token == EOL_TOKEN) { 3393da084b3Smrg return STARTMAPPING_LINE; 340e1c0d025Smrg } 341e1c0d025Smrg else { 3423da084b3Smrg skipEndOfLine(f, c); 3433da084b3Smrg return ERROR_LINE; 3443da084b3Smrg } 3453da084b3Smrg 3463da084b3Smrg /* optional second integer */ 347e1c0d025Smrg token = gettoken(f, c, &c); 348e1c0d025Smrg if (token == NUMBER_TOKEN) { 3493da084b3Smrg value2 = number_value; 350e1c0d025Smrg } 351e1c0d025Smrg else if (token == EOL_TOKEN) { 3523da084b3Smrg return STARTMAPPING_LINE; 353e1c0d025Smrg } 354e1c0d025Smrg else { 3553da084b3Smrg skipEndOfLine(f, c); 3563da084b3Smrg return ERROR_LINE; 3573da084b3Smrg } 3583da084b3Smrg 359e1c0d025Smrg if (!endOfLine(f, c)) 3603da084b3Smrg return ERROR_LINE; 3613da084b3Smrg else { 3623da084b3Smrg return STARTMAPPING_LINE; 3633da084b3Smrg } 364e1c0d025Smrg } 365e1c0d025Smrg else if (!strcasecmp(keyword_value, "UNDEFINE")) { 3663da084b3Smrg /* first integer */ 367e1c0d025Smrg token = gettoken(f, c, &c); 368e1c0d025Smrg if (token != NUMBER_TOKEN) { 369e1c0d025Smrg skipEndOfLine(f, c); 3703da084b3Smrg return ERROR_LINE; 3713da084b3Smrg } 3723da084b3Smrg value1 = number_value; 3733da084b3Smrg /* optional second integer */ 374e1c0d025Smrg token = gettoken(f, c, &c); 375e1c0d025Smrg if (token == EOL_TOKEN) { 3763da084b3Smrg value2 = value1; 3773da084b3Smrg return CODE_UNDEFINE_LINE; 378e1c0d025Smrg } 379e1c0d025Smrg else if (token == NUMBER_TOKEN) { 3803da084b3Smrg value2 = number_value; 381e1c0d025Smrg if (endOfLine(f, c)) { 3823da084b3Smrg return CODE_UNDEFINE_LINE; 383e1c0d025Smrg } 384e1c0d025Smrg else 3853da084b3Smrg return ERROR_LINE; 386e1c0d025Smrg } 387e1c0d025Smrg else { 388e1c0d025Smrg skipEndOfLine(f, c); 3893da084b3Smrg return ERROR_LINE; 3903da084b3Smrg } 391e1c0d025Smrg } 392e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDENCODING")) { 393e1c0d025Smrg if (endOfLine(f, c)) 3943da084b3Smrg return EOF_LINE; 3953da084b3Smrg else 3963da084b3Smrg return ERROR_LINE; 397e1c0d025Smrg } 398e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDMAPPING")) { 399e1c0d025Smrg if (endOfLine(f, c)) 4003da084b3Smrg return ENDMAPPING_LINE; 4013da084b3Smrg else 4023da084b3Smrg return ERROR_LINE; 403e1c0d025Smrg } 404e1c0d025Smrg else { 405e1c0d025Smrg skipEndOfLine(f, c); 4063da084b3Smrg return ERROR_LINE; 4073da084b3Smrg } 4083da084b3Smrg default: 4093da084b3Smrg return ERROR_LINE; 4103da084b3Smrg } 4113da084b3Smrg} 4123da084b3Smrg 41348c85eb7Smrgstatic void 4143da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping) 4153da084b3Smrg{ 4163da084b3Smrg FontMapPtr m; 4173da084b3Smrg 418e1c0d025Smrg if (encoding->mappings == NULL) 4193da084b3Smrg encoding->mappings = mapping; 4203da084b3Smrg else { 4213da084b3Smrg m = encoding->mappings; 422e1c0d025Smrg while (m->next != NULL) 4233da084b3Smrg m = m->next; 4243da084b3Smrg m->next = mapping; 4253da084b3Smrg } 4263da084b3Smrg mapping->next = NULL; 4273da084b3Smrg mapping->encoding = encoding; 4283da084b3Smrg} 4293da084b3Smrg 4303da084b3Smrgstatic int 4313da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size, 4323da084b3Smrg unsigned *first, unsigned *last, 4333da084b3Smrg unsigned *encsize, unsigned short **enc) 4343da084b3Smrg{ 4353da084b3Smrg unsigned index, i; 436e1c0d025Smrg 4373da084b3Smrg unsigned short *newenc; 4383da084b3Smrg 439e1c0d025Smrg if (from > 0xFFFF) 4403da084b3Smrg return 0; /* success */ 4413da084b3Smrg 442e1c0d025Smrg if (row_size == 0) 443e1c0d025Smrg index = from; 4443da084b3Smrg else { 445e1c0d025Smrg if ((value1 & 0xFF) >= row_size) 4463da084b3Smrg return 0; /* ignore out of range mappings */ 447e1c0d025Smrg index = (from >> 8) * row_size + (from & 0xFF); 4483da084b3Smrg } 4493da084b3Smrg 4503da084b3Smrg /* Optimize away useless identity mappings. This is only expected 4513da084b3Smrg to be useful with linear encodings. */ 452e1c0d025Smrg if (index == to && (index < *first || index > *last)) 4533da084b3Smrg return 0; 454e1c0d025Smrg if (*encsize == 0) { 4553da084b3Smrg *encsize = (index < 256) ? 256 : 0x10000; 45655acc8fcSmrg *enc = malloc((*encsize) * sizeof(unsigned short)); 457e1c0d025Smrg if (*enc == NULL) { 4583da084b3Smrg *encsize = 0; 4593da084b3Smrg return 1; 4603da084b3Smrg } 461e1c0d025Smrg } 462e1c0d025Smrg else if (*encsize <= index) { 4633da084b3Smrg *encsize = 0x10000; 464e1c0d025Smrg if ((newenc = 465e1c0d025Smrg realloc(*enc, (*encsize) * sizeof(unsigned short))) == NULL) 4663da084b3Smrg return 1; 4673da084b3Smrg *enc = newenc; 4683da084b3Smrg } 469e1c0d025Smrg if (*first > *last) { 4703da084b3Smrg *first = *last = index; 4713da084b3Smrg } 472e1c0d025Smrg if (index < *first) { 473e1c0d025Smrg for (i = index; i < *first; i++) 4743da084b3Smrg (*enc)[i] = i; 4753da084b3Smrg *first = index; 4763da084b3Smrg } 477e1c0d025Smrg if (index > *last) { 478e1c0d025Smrg for (i = *last + 1; i <= index; i++) 4793da084b3Smrg (*enc)[i] = i; 4803da084b3Smrg *last = index; 4813da084b3Smrg } 4823da084b3Smrg (*enc)[index] = to; 4833da084b3Smrg return 0; 4843da084b3Smrg} 4853da084b3Smrg 4863da084b3Smrg/* Parser. If headerOnly is true, we're only interested in the 4873da084b3Smrg data contained in the encoding file's header. */ 4883da084b3Smrg 4893da084b3Smrg/* As font encodings are currently never freed, the allocations done 4903da084b3Smrg by this function are mostly its private business. Note, however, 4913da084b3Smrg that FontEncIdentify needs to free the header fields -- so if you 4923da084b3Smrg change this function, you may need to change FontEncIdentify. */ 4933da084b3Smrg 4943da084b3Smrg/* I want a garbage collector. */ 4953da084b3Smrg 4963da084b3Smrgstatic FontEncPtr 4973da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly) 4983da084b3Smrg{ 4993da084b3Smrg int line; 5003da084b3Smrg 501e1c0d025Smrg unsigned short *enc = NULL; 5023da084b3Smrg char **nam = NULL, **newnam; 503e1c0d025Smrg unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0; 5043da084b3Smrg FontEncPtr encoding = NULL; 5053da084b3Smrg FontMapPtr mapping = NULL; 5063da084b3Smrg FontEncSimpleMapPtr sm; 5073da084b3Smrg FontEncSimpleNamePtr sn; 508e1c0d025Smrg char *aliases[MAXALIASES] = { NULL }; 509e1c0d025Smrg int numaliases = 0; 5103da084b3Smrg 5113da084b3Smrg#if 0 5123da084b3Smrg /* GCC complains about unused labels. Please fix GCC rather than 5133da084b3Smrg obfuscating my code. */ 514e1c0d025Smrg no_encoding: 5153da084b3Smrg#endif 5163da084b3Smrg line = getnextline(f); 517e1c0d025Smrg switch (line) { 5183da084b3Smrg case EOF_LINE: 5193da084b3Smrg goto error; 5203da084b3Smrg case STARTENCODING_LINE: 52155acc8fcSmrg encoding = malloc(sizeof(FontEncRec)); 522e1c0d025Smrg if (encoding == NULL) 5233da084b3Smrg goto error; 52455acc8fcSmrg encoding->name = strdup(keyword_value); 525e1c0d025Smrg if (encoding->name == NULL) 5263da084b3Smrg goto error; 5273da084b3Smrg encoding->size = 256; 5283da084b3Smrg encoding->row_size = 0; 5293da084b3Smrg encoding->mappings = NULL; 5303da084b3Smrg encoding->next = NULL; 531e1c0d025Smrg encoding->first = encoding->first_col = 0; 5323da084b3Smrg goto no_mapping; 5333da084b3Smrg default: 5343da084b3Smrg goto error; 5353da084b3Smrg } 5363da084b3Smrg 537e1c0d025Smrg no_mapping: 5383da084b3Smrg line = getnextline(f); 539e1c0d025Smrg switch (line) { 540e1c0d025Smrg case EOF_LINE: 541e1c0d025Smrg goto done; 5423da084b3Smrg case ALIAS_LINE: 543e1c0d025Smrg if (numaliases < MAXALIASES) { 54455acc8fcSmrg aliases[numaliases] = strdup(keyword_value); 545e1c0d025Smrg if (aliases[numaliases] == NULL) 5463da084b3Smrg goto error; 5473da084b3Smrg numaliases++; 5483da084b3Smrg } 5493da084b3Smrg goto no_mapping; 5503da084b3Smrg case SIZE_LINE: 5513da084b3Smrg encoding->size = value1; 5523da084b3Smrg encoding->row_size = value2; 5533da084b3Smrg goto no_mapping; 5543da084b3Smrg case FIRSTINDEX_LINE: 5553da084b3Smrg encoding->first = value1; 5563da084b3Smrg encoding->first_col = value2; 5573da084b3Smrg goto no_mapping; 5583da084b3Smrg case STARTMAPPING_LINE: 559e1c0d025Smrg if (headerOnly) 5603da084b3Smrg goto done; 561e1c0d025Smrg if (!strcasecmp(keyword_value, "unicode")) { 56255acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 563e1c0d025Smrg if (mapping == NULL) 5643da084b3Smrg goto error; 5653da084b3Smrg mapping->type = FONT_ENCODING_UNICODE; 5663da084b3Smrg mapping->pid = 0; 5673da084b3Smrg mapping->eid = 0; 5683da084b3Smrg mapping->recode = NULL; 5693da084b3Smrg mapping->name = NULL; 5703da084b3Smrg mapping->client_data = NULL; 5713da084b3Smrg mapping->next = NULL; 5723da084b3Smrg goto mapping; 573e1c0d025Smrg } 574e1c0d025Smrg else if (!strcasecmp(keyword_value, "cmap")) { 57555acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 576e1c0d025Smrg if (mapping == NULL) 5773da084b3Smrg goto error; 5783da084b3Smrg mapping->type = FONT_ENCODING_TRUETYPE; 5793da084b3Smrg mapping->pid = value1; 5803da084b3Smrg mapping->eid = value2; 5813da084b3Smrg mapping->recode = NULL; 5823da084b3Smrg mapping->name = NULL; 5833da084b3Smrg mapping->client_data = NULL; 5843da084b3Smrg mapping->next = NULL; 5853da084b3Smrg goto mapping; 586e1c0d025Smrg } 587e1c0d025Smrg else if (!strcasecmp(keyword_value, "postscript")) { 58855acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 589e1c0d025Smrg if (mapping == NULL) 5903da084b3Smrg goto error; 5913da084b3Smrg mapping->type = FONT_ENCODING_POSTSCRIPT; 5923da084b3Smrg mapping->pid = 0; 5933da084b3Smrg mapping->eid = 0; 5943da084b3Smrg mapping->recode = NULL; 5953da084b3Smrg mapping->name = NULL; 5963da084b3Smrg mapping->client_data = NULL; 5973da084b3Smrg mapping->next = NULL; 5983da084b3Smrg goto string_mapping; 599e1c0d025Smrg } 600e1c0d025Smrg else { /* unknown mapping type -- ignore */ 6013da084b3Smrg goto skipmapping; 6023da084b3Smrg } 6033da084b3Smrg /* NOTREACHED */ 6043da084b3Smrg goto error; 605e1c0d025Smrg default: 606e1c0d025Smrg goto no_mapping; /* ignore unknown lines */ 6073da084b3Smrg } 6083da084b3Smrg 609e1c0d025Smrg skipmapping: 6103da084b3Smrg line = getnextline(f); 611e1c0d025Smrg switch (line) { 6123da084b3Smrg case ENDMAPPING_LINE: 6133da084b3Smrg goto no_mapping; 6143da084b3Smrg case EOF_LINE: 6153da084b3Smrg goto error; 6163da084b3Smrg default: 6173da084b3Smrg goto skipmapping; 6183da084b3Smrg } 6193da084b3Smrg 620e1c0d025Smrg mapping: 6213da084b3Smrg line = getnextline(f); 622e1c0d025Smrg switch (line) { 623e1c0d025Smrg case EOF_LINE: 624e1c0d025Smrg goto error; 6253da084b3Smrg case ENDMAPPING_LINE: 6263da084b3Smrg mapping->recode = FontEncSimpleRecode; 6273da084b3Smrg mapping->name = FontEncUndefinedName; 62855acc8fcSmrg mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec)); 629e1c0d025Smrg if (sm == NULL) 6303da084b3Smrg goto error; 6313da084b3Smrg sm->row_size = encoding->row_size; 632e1c0d025Smrg if (first <= last) { 6333da084b3Smrg unsigned short *newmap; 6343da084b3Smrg 6353da084b3Smrg sm->first = first; 636e1c0d025Smrg sm->len = last - first + 1; 63755acc8fcSmrg newmap = malloc(sm->len * sizeof(unsigned short)); 638e1c0d025Smrg if (newmap == NULL) { 63955acc8fcSmrg free(sm); 6403da084b3Smrg mapping->client_data = sm = NULL; 6413da084b3Smrg goto error; 6423da084b3Smrg } 643e1c0d025Smrg for (i = 0; i < sm->len; i++) 644e1c0d025Smrg newmap[i] = enc[first + i]; 645e1c0d025Smrg sm->map = newmap; 646e1c0d025Smrg } 647e1c0d025Smrg else { 6483da084b3Smrg sm->first = 0; 6493da084b3Smrg sm->len = 0; 6503da084b3Smrg sm->map = NULL; 6513da084b3Smrg } 6523da084b3Smrg install_mapping(encoding, mapping); 6533da084b3Smrg mapping = NULL; 654e1c0d025Smrg first = 0xFFFF; 655e1c0d025Smrg last = 0; 6563da084b3Smrg goto no_mapping; 6573da084b3Smrg 6583da084b3Smrg case CODE_LINE: 659e1c0d025Smrg if (setCode(value1, value2, encoding->row_size, 660e1c0d025Smrg &first, &last, &encsize, &enc)) 6613da084b3Smrg goto error; 6623da084b3Smrg goto mapping; 6633da084b3Smrg 6643da084b3Smrg case CODE_RANGE_LINE: 665e1c0d025Smrg if (value1 > 0x10000) 6663da084b3Smrg value1 = 0x10000; 667e1c0d025Smrg if (value2 > 0x10000) 6683da084b3Smrg value2 = 0x10000; 669e1c0d025Smrg if (value2 < value1) 6703da084b3Smrg goto mapping; 6713da084b3Smrg /* Do the last value first to avoid having to realloc() */ 672e1c0d025Smrg if (setCode(value2, value3 + (value2 - value1), encoding->row_size, 673e1c0d025Smrg &first, &last, &encsize, &enc)) 6743da084b3Smrg goto error; 675e1c0d025Smrg for (i = value1; i < value2; i++) { 676e1c0d025Smrg if (setCode(i, value3 + (i - value1), encoding->row_size, 677e1c0d025Smrg &first, &last, &encsize, &enc)) 6783da084b3Smrg goto error; 6793da084b3Smrg } 6803da084b3Smrg goto mapping; 68148c85eb7Smrg 6823da084b3Smrg case CODE_UNDEFINE_LINE: 683e1c0d025Smrg if (value1 > 0x10000) 6843da084b3Smrg value1 = 0x10000; 685e1c0d025Smrg if (value2 > 0x10000) 6863da084b3Smrg value2 = 0x10000; 687e1c0d025Smrg if (value2 < value1) 6883da084b3Smrg goto mapping; 6893da084b3Smrg /* Do the last value first to avoid having to realloc() */ 690e1c0d025Smrg if (setCode(value2, 0, encoding->row_size, 691e1c0d025Smrg &first, &last, &encsize, &enc)) 6923da084b3Smrg goto error; 693e1c0d025Smrg for (i = value1; i < value2; i++) { 694e1c0d025Smrg if (setCode(i, 0, encoding->row_size, 695e1c0d025Smrg &first, &last, &encsize, &enc)) 6963da084b3Smrg goto error; 6973da084b3Smrg } 6983da084b3Smrg goto mapping; 6993da084b3Smrg 700e1c0d025Smrg default: 701e1c0d025Smrg goto mapping; /* ignore unknown lines */ 7023da084b3Smrg } 70348c85eb7Smrg 704e1c0d025Smrg string_mapping: 7053da084b3Smrg line = getnextline(f); 706e1c0d025Smrg switch (line) { 707e1c0d025Smrg case EOF_LINE: 708e1c0d025Smrg goto error; 7093da084b3Smrg case ENDMAPPING_LINE: 7103da084b3Smrg mapping->recode = FontEncUndefinedRecode; 7113da084b3Smrg mapping->name = FontEncSimpleName; 71255acc8fcSmrg mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec)); 713e1c0d025Smrg if (sn == NULL) 7143da084b3Smrg goto error; 715e1c0d025Smrg if (first > last) { 71655acc8fcSmrg free(sn); 7173da084b3Smrg mapping->client_data = sn = NULL; 7183da084b3Smrg goto error; 7193da084b3Smrg } 7203da084b3Smrg sn->first = first; 7213da084b3Smrg sn->len = last - first + 1; 722e1c0d025Smrg sn->map = malloc(sn->len * sizeof(char *)); 723e1c0d025Smrg if (sn->map == NULL) { 72455acc8fcSmrg free(sn); 7253da084b3Smrg mapping->client_data = sn = NULL; 7263da084b3Smrg goto error; 7273da084b3Smrg } 728e1c0d025Smrg for (i = 0; i < sn->len; i++) 729e1c0d025Smrg sn->map[i] = nam[first + i]; 730e1c0d025Smrg install_mapping(encoding, mapping); 7313da084b3Smrg mapping = NULL; 732e1c0d025Smrg first = 0xFFFF; 733e1c0d025Smrg last = 0; 7343da084b3Smrg goto no_mapping; 7353da084b3Smrg case NAME_LINE: 736e1c0d025Smrg if (value1 >= 0x10000) 737e1c0d025Smrg goto string_mapping; 738e1c0d025Smrg if (namsize == 0) { 7393da084b3Smrg namsize = (value1) < 256 ? 256 : 0x10000; 740e1c0d025Smrg nam = malloc(namsize * sizeof(char *)); 741e1c0d025Smrg if (nam == NULL) { 742e1c0d025Smrg namsize = 0; 7433da084b3Smrg goto error; 7443da084b3Smrg } 745e1c0d025Smrg } 746e1c0d025Smrg else if (namsize <= value1) { 7473da084b3Smrg namsize = 0x10000; 748e1c0d025Smrg if ((newnam = (char **) realloc(nam, namsize)) == NULL) 7493da084b3Smrg goto error; 7503da084b3Smrg nam = newnam; 7513da084b3Smrg } 752e1c0d025Smrg if (first > last) { 7533da084b3Smrg first = last = value1; 7543da084b3Smrg } 755e1c0d025Smrg if (value1 < first) { 756e1c0d025Smrg for (i = value1; i < first; i++) 7573da084b3Smrg nam[i] = NULL; 7583da084b3Smrg first = value1; 7593da084b3Smrg } 760e1c0d025Smrg if (value1 > last) { 761e1c0d025Smrg for (i = last + 1; i <= value1; i++) 762e1c0d025Smrg nam[i] = NULL; 7633da084b3Smrg last = value1; 7643da084b3Smrg } 76555acc8fcSmrg nam[value1] = strdup(keyword_value); 766e1c0d025Smrg if (nam[value1] == NULL) { 7673da084b3Smrg goto error; 7683da084b3Smrg } 7693da084b3Smrg goto string_mapping; 7703da084b3Smrg 771e1c0d025Smrg default: 772e1c0d025Smrg goto string_mapping; /* ignore unknown lines */ 7733da084b3Smrg } 7743da084b3Smrg 775e1c0d025Smrg done: 776e1c0d025Smrg if (encsize) { 777e1c0d025Smrg free(enc); 778e1c0d025Smrg encsize = 0; 779e1c0d025Smrg enc = NULL; 780e1c0d025Smrg } 781e1c0d025Smrg if (namsize) { 782e1c0d025Smrg free(nam); /* don't free entries! */ 783e1c0d025Smrg namsize = 0; 784e1c0d025Smrg nam = NULL; 785e1c0d025Smrg } 7863da084b3Smrg 787e1c0d025Smrg encoding->aliases = NULL; 788e1c0d025Smrg if (numaliases) { 789e1c0d025Smrg encoding->aliases = malloc((numaliases + 1) * sizeof(char *)); 790e1c0d025Smrg if (encoding->aliases == NULL) 7913da084b3Smrg goto error; 792e1c0d025Smrg for (i = 0; i < numaliases; i++) 7933da084b3Smrg encoding->aliases[i] = aliases[i]; 794e1c0d025Smrg encoding->aliases[numaliases] = NULL; 7953da084b3Smrg } 7963da084b3Smrg 7973da084b3Smrg return encoding; 7983da084b3Smrg 799e1c0d025Smrg error: 800e1c0d025Smrg if (encsize) { 801e1c0d025Smrg free(enc); 802e1c0d025Smrg encsize = 0; 803e1c0d025Smrg } 804e1c0d025Smrg if (namsize) { 805e1c0d025Smrg for (i = first; i <= last; i++) 80655acc8fcSmrg free(nam[i]); 80755acc8fcSmrg free(nam); 8083da084b3Smrg } 809e1c0d025Smrg if (mapping) { 81055acc8fcSmrg free(mapping->client_data); 81155acc8fcSmrg free(mapping); 8123da084b3Smrg } 813e1c0d025Smrg if (encoding) { 814e1c0d025Smrg FontMapPtr nextmap; 815e1c0d025Smrg 816e1c0d025Smrg free(encoding->name); 817e1c0d025Smrg for (mapping = encoding->mappings; mapping; mapping = nextmap) { 818e1c0d025Smrg free(mapping->client_data); 819e1c0d025Smrg nextmap = mapping->next; 820e1c0d025Smrg free(mapping); 821e1c0d025Smrg } 822e1c0d025Smrg free(encoding); 823e1c0d025Smrg } 824e1c0d025Smrg for (i = 0; i < numaliases; i++) 82555acc8fcSmrg free(aliases[i]); 826e1c0d025Smrg /* We don't need to free sn and sm as they handled locally in the body. */ 8273da084b3Smrg return NULL; 8283da084b3Smrg} 8293da084b3Smrg 830e1c0d025Smrgchar * 8313da084b3SmrgFontEncDirectory(void) 8323da084b3Smrg{ 833e1c0d025Smrg static char *dir = NULL; 8343da084b3Smrg 835e1c0d025Smrg if (dir == NULL) { 8363da084b3Smrg char *c = getenv("FONT_ENCODINGS_DIRECTORY"); 837e1c0d025Smrg 838e1c0d025Smrg if (c) { 83955acc8fcSmrg dir = strdup(c); 840e1c0d025Smrg if (!dir) 8413da084b3Smrg return NULL; 842e1c0d025Smrg } 843e1c0d025Smrg else { 8443da084b3Smrg dir = FONT_ENCODINGS_DIRECTORY; 8453da084b3Smrg } 8463da084b3Smrg } 8473da084b3Smrg return dir; 8483da084b3Smrg} 8493da084b3Smrg 8503da084b3Smrgstatic void 8513da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir) 8523da084b3Smrg{ 8533da084b3Smrg const char *p; 8543da084b3Smrg char *q, *lastslash; 85548c85eb7Smrg 856e1c0d025Smrg for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) { 8573da084b3Smrg *q = *p; 858e1c0d025Smrg if (*p == '/') 859e1c0d025Smrg lastslash = q + 1; 8603da084b3Smrg } 86148c85eb7Smrg 862e1c0d025Smrg if (!lastslash) 8633da084b3Smrg lastslash = dir; 86448c85eb7Smrg 8653da084b3Smrg *lastslash = '\0'; 8663da084b3Smrg 867e1c0d025Smrg if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) { 868e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir"); 8693da084b3Smrg } 8703da084b3Smrg} 8713da084b3Smrg 8723da084b3Smrgstatic FontEncPtr 87348c85eb7SmrgFontEncReallyReallyLoad(const char *charset, 8743da084b3Smrg const char *dirname, const char *dir) 8753da084b3Smrg{ 8763da084b3Smrg FontFilePtr f; 8773da084b3Smrg FILE *file; 8783da084b3Smrg FontEncPtr encoding; 8793da084b3Smrg char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN], 8803da084b3Smrg buf[MAXFONTFILENAMELEN]; 8813da084b3Smrg int count, n; 8823da084b3Smrg static char format[24] = ""; 88348c85eb7Smrg 8843da084b3Smrg /* As we don't really expect to open encodings that often, we don't 8853da084b3Smrg take the trouble of caching encodings directories. */ 8863da084b3Smrg 887e1c0d025Smrg if ((file = fopen(dirname, "r")) == NULL) { 8883da084b3Smrg return NULL; 8893da084b3Smrg } 89048c85eb7Smrg 8913da084b3Smrg count = fscanf(file, "%d\n", &n); 892e1c0d025Smrg if (count == EOF || count != 1) { 8933da084b3Smrg fclose(file); 8943da084b3Smrg return NULL; 8953da084b3Smrg } 8963da084b3Smrg 8973da084b3Smrg encoding = NULL; 8983da084b3Smrg if (!format[0]) { 899e1c0d025Smrg snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n", 900e1c0d025Smrg (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1); 9013da084b3Smrg } 902e1c0d025Smrg for (;;) { 9033da084b3Smrg count = fscanf(file, format, encoding_name, file_name); 904e1c0d025Smrg if (count == EOF) 9053da084b3Smrg break; 906e1c0d025Smrg if (count != 2) 9073da084b3Smrg break; 9083da084b3Smrg 909e1c0d025Smrg if (!strcasecmp(encoding_name, charset)) { 9103da084b3Smrg /* Found it */ 911e1c0d025Smrg if (file_name[0] != '/') { 912e1c0d025Smrg if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) { 913e1c0d025Smrg fclose(file); 9143da084b3Smrg return NULL; 915e1c0d025Smrg } 916e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name); 917e1c0d025Smrg } 918e1c0d025Smrg else { 919e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name); 9203da084b3Smrg } 9213da084b3Smrg 9223da084b3Smrg f = FontFileOpen(buf); 923e1c0d025Smrg if (f == NULL) { 924e1c0d025Smrg fclose(file); 9253da084b3Smrg return NULL; 9263da084b3Smrg } 9273da084b3Smrg encoding = parseEncodingFile(f, 0); 9283da084b3Smrg FontFileClose(f); 9293da084b3Smrg break; 9303da084b3Smrg } 9313da084b3Smrg } 9323da084b3Smrg 9333da084b3Smrg fclose(file); 9343da084b3Smrg 9353da084b3Smrg return encoding; 9363da084b3Smrg} 9373da084b3Smrg 93848c85eb7Smrg/* Parser ntrypoint -- used by FontEncLoad */ 9393da084b3SmrgFontEncPtr 9403da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName) 9413da084b3Smrg{ 9423da084b3Smrg FontEncPtr encoding; 9433da084b3Smrg char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN]; 9443da084b3Smrg char *d; 9453da084b3Smrg 946e1c0d025Smrg if (fontFileName) { 9473da084b3Smrg parseFontFileName(fontFileName, dirname, dir); 9483da084b3Smrg encoding = FontEncReallyReallyLoad(charset, dirname, dir); 949e1c0d025Smrg if (encoding) 950e1c0d025Smrg return (encoding); 9513da084b3Smrg } 95248c85eb7Smrg 9533da084b3Smrg d = FontEncDirectory(); 954e1c0d025Smrg if (d) { 9553da084b3Smrg parseFontFileName(d, NULL, dir); 9563da084b3Smrg encoding = FontEncReallyReallyLoad(charset, d, dir); 9573da084b3Smrg return encoding; 9583da084b3Smrg } 95948c85eb7Smrg 9603da084b3Smrg return NULL; 9613da084b3Smrg} 9623da084b3Smrg 9633da084b3Smrg/* Return a NULL-terminated array of encoding names. Note that this 9643da084b3Smrg * function has incestuous knowledge of the allocations done by 9653da084b3Smrg * parseEncodingFile. */ 9663da084b3Smrg 9673da084b3Smrgchar ** 9683da084b3SmrgFontEncIdentify(const char *fileName) 9693da084b3Smrg{ 9703da084b3Smrg FontFilePtr f; 9713da084b3Smrg FontEncPtr encoding; 9723da084b3Smrg char **names, **name, **alias; 9733da084b3Smrg int numaliases; 97448c85eb7Smrg 975e1c0d025Smrg if ((f = FontFileOpen(fileName)) == NULL) { 9763da084b3Smrg return NULL; 9773da084b3Smrg } 9783da084b3Smrg encoding = parseEncodingFile(f, 1); 9793da084b3Smrg FontFileClose(f); 9803da084b3Smrg 981e1c0d025Smrg if (!encoding) 9823da084b3Smrg return NULL; 9833da084b3Smrg 9843da084b3Smrg numaliases = 0; 985e1c0d025Smrg if (encoding->aliases) 986e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++) 9873da084b3Smrg numaliases++; 9883da084b3Smrg 989e1c0d025Smrg names = malloc((numaliases + 2) * sizeof(char *)); 990e1c0d025Smrg if (names == NULL) { 99155acc8fcSmrg free(encoding->aliases); 99255acc8fcSmrg free(encoding); 9933da084b3Smrg return NULL; 9943da084b3Smrg } 9953da084b3Smrg 9963da084b3Smrg name = names; 9973da084b3Smrg *(name++) = encoding->name; 998e1c0d025Smrg if (numaliases > 0) 999e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++, name++) 1000e1c0d025Smrg *name = *alias; 10013da084b3Smrg 10023da084b3Smrg *name = NULL; 100355acc8fcSmrg free(encoding->aliases); 100455acc8fcSmrg free(encoding); 10053da084b3Smrg 10063da084b3Smrg return names; 10073da084b3Smrg} 1008