encparse.c revision 2a53b785
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 302a53b785Smrg#ifdef HAVE_CONFIG_H 312a53b785Smrg#include <config.h> 322a53b785Smrg#endif 332a53b785Smrg 343da084b3Smrg#include <string.h> 353da084b3Smrg#include <strings.h> 3648c85eb7Smrg#include <stdio.h> 373da084b3Smrg 383da084b3Smrg#include <stdlib.h> 393da084b3Smrg 403da084b3Smrg#include "zlib.h" 413da084b3Smrgtypedef gzFile FontFilePtr; 42e1c0d025Smrg 433da084b3Smrg#define FontFileGetc(f) gzgetc(f) 443da084b3Smrg#define FontFileOpen(filename) gzopen(filename, "rb") 453da084b3Smrg#define FontFileClose(f) gzclose(f) 463da084b3Smrg 473da084b3Smrg#define MAXFONTFILENAMELEN 1024 483da084b3Smrg#define MAXFONTNAMELEN 1024 493da084b3Smrg 503da084b3Smrg#include <X11/fonts/fontenc.h> 513da084b3Smrg#include "fontencI.h" 522a53b785Smrg#include "reallocarray.h" 533da084b3Smrg 543da084b3Smrg#define MAXALIASES 20 553da084b3Smrg 563da084b3Smrg#define EOF_TOKEN -1 573da084b3Smrg#define ERROR_TOKEN -2 583da084b3Smrg#define EOL_TOKEN 0 593da084b3Smrg#define NUMBER_TOKEN 1 603da084b3Smrg#define KEYWORD_TOKEN 2 613da084b3Smrg 623da084b3Smrg#define EOF_LINE -1 633da084b3Smrg#define ERROR_LINE -2 643da084b3Smrg#define STARTENCODING_LINE 1 653da084b3Smrg#define STARTMAPPING_LINE 2 663da084b3Smrg#define ENDMAPPING_LINE 3 673da084b3Smrg#define CODE_LINE 4 683da084b3Smrg#define CODE_RANGE_LINE 5 693da084b3Smrg#define CODE_UNDEFINE_LINE 6 703da084b3Smrg#define NAME_LINE 7 713da084b3Smrg#define SIZE_LINE 8 723da084b3Smrg#define ALIAS_LINE 9 733da084b3Smrg#define FIRSTINDEX_LINE 10 743da084b3Smrg 753da084b3Smrg/* Return from lexer */ 763da084b3Smrg#define MAXKEYWORDLEN 100 773da084b3Smrg 783da084b3Smrgstatic long number_value; 79e1c0d025Smrgstatic char keyword_value[MAXKEYWORDLEN + 1]; 803da084b3Smrg 813da084b3Smrgstatic long value1, value2, value3; 823da084b3Smrg 833da084b3Smrg/* Lexer code */ 843da084b3Smrg 853da084b3Smrg/* Skip to the beginning of new line */ 863da084b3Smrgstatic void 873da084b3SmrgskipEndOfLine(FontFilePtr f, int c) 883da084b3Smrg{ 89e1c0d025Smrg if (c == 0) 903da084b3Smrg c = FontFileGetc(f); 9148c85eb7Smrg 92e1c0d025Smrg for (;;) 93e1c0d025Smrg if (c <= 0 || c == '\n') 943da084b3Smrg return; 953da084b3Smrg else 963da084b3Smrg c = FontFileGetc(f); 973da084b3Smrg} 983da084b3Smrg 993da084b3Smrg/* Get a number; we're at the first digit. */ 1003da084b3Smrgstatic unsigned 1013da084b3Smrggetnum(FontFilePtr f, int c, int *cp) 1023da084b3Smrg{ 1033da084b3Smrg unsigned n = 0; 1043da084b3Smrg int base = 10; 1053da084b3Smrg 1063da084b3Smrg /* look for `0' or `0x' prefix */ 107e1c0d025Smrg if (c == '0') { 1083da084b3Smrg c = FontFileGetc(f); 1093da084b3Smrg base = 8; 110e1c0d025Smrg if (c == 'x' || c == 'X') { 1113da084b3Smrg base = 16; 1123da084b3Smrg c = FontFileGetc(f); 1133da084b3Smrg } 1143da084b3Smrg } 1153da084b3Smrg 1163da084b3Smrg /* accumulate digits */ 117e1c0d025Smrg for (;;) { 1183da084b3Smrg if ('0' <= c && c <= '9') { 119e1c0d025Smrg n *= base; 120e1c0d025Smrg n += c - '0'; 121e1c0d025Smrg } 122e1c0d025Smrg else if ('a' <= c && c <= 'f') { 123e1c0d025Smrg n *= base; 124e1c0d025Smrg n += c - 'a' + 10; 125e1c0d025Smrg } 126e1c0d025Smrg else if ('A' <= c && c <= 'F') { 127e1c0d025Smrg n *= base; 128e1c0d025Smrg n += c - 'A' + 10; 129e1c0d025Smrg } 130e1c0d025Smrg else 1313da084b3Smrg break; 1323da084b3Smrg c = FontFileGetc(f); 1333da084b3Smrg } 1343da084b3Smrg 135e1c0d025Smrg *cp = c; 136e1c0d025Smrg return n; 1373da084b3Smrg} 13848c85eb7Smrg 1393da084b3Smrg/* Skip to beginning of new line; return 1 if only whitespace was found. */ 1403da084b3Smrgstatic int 1413da084b3SmrgendOfLine(FontFilePtr f, int c) 1423da084b3Smrg{ 143e1c0d025Smrg if (c == 0) 1443da084b3Smrg c = FontFileGetc(f); 1453da084b3Smrg 146e1c0d025Smrg for (;;) { 147e1c0d025Smrg if (c <= 0 || c == '\n') 1483da084b3Smrg return 1; 149e1c0d025Smrg else if (c == '#') { 150e1c0d025Smrg skipEndOfLine(f, c); 1513da084b3Smrg return 1; 1523da084b3Smrg } 153e1c0d025Smrg else if (c == ' ' || c == '\t') { 154e1c0d025Smrg skipEndOfLine(f, c); 1553da084b3Smrg return 0; 1563da084b3Smrg } 1573da084b3Smrg c = FontFileGetc(f); 1583da084b3Smrg } 1593da084b3Smrg} 1603da084b3Smrg 1613da084b3Smrg/* Get a token; we're at first char */ 1623da084b3Smrgstatic int 1633da084b3Smrggettoken(FontFilePtr f, int c, int *cp) 1643da084b3Smrg{ 1653da084b3Smrg char *p; 1663da084b3Smrg 167e1c0d025Smrg if (c <= 0) 168e1c0d025Smrg c = FontFileGetc(f); 1693da084b3Smrg 170e1c0d025Smrg if (c <= 0) { 1713da084b3Smrg return EOF_TOKEN; 1723da084b3Smrg } 1733da084b3Smrg 174e1c0d025Smrg while (c == ' ' || c == '\t') 1753da084b3Smrg c = FontFileGetc(f); 1763da084b3Smrg 177e1c0d025Smrg if (c == '\n') { 1783da084b3Smrg return EOL_TOKEN; 179e1c0d025Smrg } 180e1c0d025Smrg else if (c == '#') { 181e1c0d025Smrg skipEndOfLine(f, c); 1823da084b3Smrg return EOL_TOKEN; 183e1c0d025Smrg } 184e1c0d025Smrg else if (c >= '0' && c <= '9') { 185e1c0d025Smrg number_value = getnum(f, c, cp); 1863da084b3Smrg return NUMBER_TOKEN; 187e1c0d025Smrg } 188e1c0d025Smrg else if ((c >= 'A' && c <= 'Z') || 189e1c0d025Smrg (c >= 'a' && c <= 'z') || 190e1c0d025Smrg c == '/' || c == '_' || c == '-' || c == '.') { 1913da084b3Smrg p = keyword_value; 1923da084b3Smrg *p++ = c; 193e1c0d025Smrg while (p - keyword_value < MAXKEYWORDLEN) { 1943da084b3Smrg c = FontFileGetc(f); 195e1c0d025Smrg if (c <= ' ' || c > '~' || c == '#') 1963da084b3Smrg break; 1973da084b3Smrg *p++ = c; 1983da084b3Smrg } 1993da084b3Smrg *cp = c; 2003da084b3Smrg *p = '\0'; 2013da084b3Smrg return KEYWORD_TOKEN; 202e1c0d025Smrg } 203e1c0d025Smrg else { 2043da084b3Smrg *cp = c; 2053da084b3Smrg return ERROR_TOKEN; 2063da084b3Smrg } 2073da084b3Smrg} 2083da084b3Smrg 2093da084b3Smrg/* Parse a line. 2103da084b3Smrg * Always skips to the beginning of a new line, even if an error occurs */ 2113da084b3Smrgstatic int 2123da084b3Smrggetnextline(FontFilePtr f) 2133da084b3Smrg{ 2143da084b3Smrg int c, token; 215e1c0d025Smrg 2163da084b3Smrg c = FontFileGetc(f); 217e1c0d025Smrg if (c <= 0) 2183da084b3Smrg return EOF_LINE; 2193da084b3Smrg 220e1c0d025Smrg again: 221e1c0d025Smrg token = gettoken(f, c, &c); 2223da084b3Smrg 223e1c0d025Smrg switch (token) { 2243da084b3Smrg case EOF_TOKEN: 2253da084b3Smrg return EOF_LINE; 2263da084b3Smrg case EOL_TOKEN: 2273da084b3Smrg /* empty line */ 2283da084b3Smrg c = FontFileGetc(f); 2293da084b3Smrg goto again; 2303da084b3Smrg case NUMBER_TOKEN: 2313da084b3Smrg value1 = number_value; 232e1c0d025Smrg token = gettoken(f, c, &c); 233e1c0d025Smrg switch (token) { 2343da084b3Smrg case NUMBER_TOKEN: 2353da084b3Smrg value2 = number_value; 236e1c0d025Smrg token = gettoken(f, c, &c); 237e1c0d025Smrg switch (token) { 2383da084b3Smrg case NUMBER_TOKEN: 2393da084b3Smrg value3 = number_value; 2403da084b3Smrg return CODE_RANGE_LINE; 2413da084b3Smrg case EOL_TOKEN: 2423da084b3Smrg return CODE_LINE; 2433da084b3Smrg default: 244e1c0d025Smrg skipEndOfLine(f, c); 2453da084b3Smrg return ERROR_LINE; 2463da084b3Smrg } 2473da084b3Smrg case KEYWORD_TOKEN: 248e1c0d025Smrg if (!endOfLine(f, c)) 2493da084b3Smrg return ERROR_LINE; 2503da084b3Smrg else 2513da084b3Smrg return NAME_LINE; 2523da084b3Smrg default: 253e1c0d025Smrg skipEndOfLine(f, c); 2543da084b3Smrg return ERROR_LINE; 2553da084b3Smrg } 2563da084b3Smrg case KEYWORD_TOKEN: 257e1c0d025Smrg if (!strcasecmp(keyword_value, "STARTENCODING")) { 258e1c0d025Smrg token = gettoken(f, c, &c); 259e1c0d025Smrg if (token == KEYWORD_TOKEN) { 260e1c0d025Smrg if (endOfLine(f, c)) 2613da084b3Smrg return STARTENCODING_LINE; 2623da084b3Smrg else 2633da084b3Smrg return ERROR_LINE; 264e1c0d025Smrg } 265e1c0d025Smrg else { 266e1c0d025Smrg skipEndOfLine(f, c); 2673da084b3Smrg return ERROR_LINE; 2683da084b3Smrg } 269e1c0d025Smrg } 270e1c0d025Smrg else if (!strcasecmp(keyword_value, "ALIAS")) { 271e1c0d025Smrg token = gettoken(f, c, &c); 272e1c0d025Smrg if (token == KEYWORD_TOKEN) { 273e1c0d025Smrg if (endOfLine(f, c)) 2743da084b3Smrg return ALIAS_LINE; 2753da084b3Smrg else 2763da084b3Smrg return ERROR_LINE; 277e1c0d025Smrg } 278e1c0d025Smrg else { 279e1c0d025Smrg skipEndOfLine(f, c); 2803da084b3Smrg return ERROR_LINE; 2813da084b3Smrg } 282e1c0d025Smrg } 283e1c0d025Smrg else if (!strcasecmp(keyword_value, "SIZE")) { 284e1c0d025Smrg token = gettoken(f, c, &c); 285e1c0d025Smrg if (token == NUMBER_TOKEN) { 2863da084b3Smrg value1 = number_value; 287e1c0d025Smrg token = gettoken(f, c, &c); 288e1c0d025Smrg switch (token) { 2893da084b3Smrg case NUMBER_TOKEN: 2903da084b3Smrg value2 = number_value; 2913da084b3Smrg return SIZE_LINE; 2923da084b3Smrg case EOL_TOKEN: 293e1c0d025Smrg value2 = 0; 2943da084b3Smrg return SIZE_LINE; 2953da084b3Smrg default: 296e1c0d025Smrg skipEndOfLine(f, c); 2973da084b3Smrg return ERROR_LINE; 2983da084b3Smrg } 299e1c0d025Smrg } 300e1c0d025Smrg else { 301e1c0d025Smrg skipEndOfLine(f, c); 3023da084b3Smrg return ERROR_LINE; 3033da084b3Smrg } 304e1c0d025Smrg } 305e1c0d025Smrg else if (!strcasecmp(keyword_value, "FIRSTINDEX")) { 306e1c0d025Smrg token = gettoken(f, c, &c); 307e1c0d025Smrg if (token == NUMBER_TOKEN) { 3083da084b3Smrg value1 = number_value; 309e1c0d025Smrg token = gettoken(f, c, &c); 310e1c0d025Smrg switch (token) { 3113da084b3Smrg case NUMBER_TOKEN: 3123da084b3Smrg value2 = number_value; 3133da084b3Smrg return FIRSTINDEX_LINE; 3143da084b3Smrg case EOL_TOKEN: 3153da084b3Smrg value2 = 0; 3163da084b3Smrg return FIRSTINDEX_LINE; 3173da084b3Smrg default: 318e1c0d025Smrg skipEndOfLine(f, c); 3193da084b3Smrg return ERROR_LINE; 3203da084b3Smrg } 321e1c0d025Smrg } 322e1c0d025Smrg else { 323e1c0d025Smrg skipEndOfLine(f, c); 3243da084b3Smrg return ERROR_LINE; 3253da084b3Smrg } 326e1c0d025Smrg } 327e1c0d025Smrg else if (!strcasecmp(keyword_value, "STARTMAPPING")) { 3283da084b3Smrg keyword_value[0] = 0; 329e1c0d025Smrg value1 = 0; 330e1c0d025Smrg value2 = 0; 3313da084b3Smrg /* first a keyword */ 332e1c0d025Smrg token = gettoken(f, c, &c); 333e1c0d025Smrg if (token != KEYWORD_TOKEN) { 3343da084b3Smrg skipEndOfLine(f, c); 3353da084b3Smrg return ERROR_LINE; 3363da084b3Smrg } 3373da084b3Smrg 3383da084b3Smrg /* optional first integer */ 339e1c0d025Smrg token = gettoken(f, c, &c); 340e1c0d025Smrg if (token == NUMBER_TOKEN) { 3413da084b3Smrg value1 = number_value; 342e1c0d025Smrg } 343e1c0d025Smrg else if (token == EOL_TOKEN) { 3443da084b3Smrg return STARTMAPPING_LINE; 345e1c0d025Smrg } 346e1c0d025Smrg else { 3473da084b3Smrg skipEndOfLine(f, c); 3483da084b3Smrg return ERROR_LINE; 3493da084b3Smrg } 3503da084b3Smrg 3513da084b3Smrg /* optional second integer */ 352e1c0d025Smrg token = gettoken(f, c, &c); 353e1c0d025Smrg if (token == NUMBER_TOKEN) { 3543da084b3Smrg value2 = number_value; 355e1c0d025Smrg } 356e1c0d025Smrg else if (token == EOL_TOKEN) { 3573da084b3Smrg return STARTMAPPING_LINE; 358e1c0d025Smrg } 359e1c0d025Smrg else { 3603da084b3Smrg skipEndOfLine(f, c); 3613da084b3Smrg return ERROR_LINE; 3623da084b3Smrg } 3633da084b3Smrg 364e1c0d025Smrg if (!endOfLine(f, c)) 3653da084b3Smrg return ERROR_LINE; 3663da084b3Smrg else { 3673da084b3Smrg return STARTMAPPING_LINE; 3683da084b3Smrg } 369e1c0d025Smrg } 370e1c0d025Smrg else if (!strcasecmp(keyword_value, "UNDEFINE")) { 3713da084b3Smrg /* first integer */ 372e1c0d025Smrg token = gettoken(f, c, &c); 373e1c0d025Smrg if (token != NUMBER_TOKEN) { 374e1c0d025Smrg skipEndOfLine(f, c); 3753da084b3Smrg return ERROR_LINE; 3763da084b3Smrg } 3773da084b3Smrg value1 = number_value; 3783da084b3Smrg /* optional second integer */ 379e1c0d025Smrg token = gettoken(f, c, &c); 380e1c0d025Smrg if (token == EOL_TOKEN) { 3813da084b3Smrg value2 = value1; 3823da084b3Smrg return CODE_UNDEFINE_LINE; 383e1c0d025Smrg } 384e1c0d025Smrg else if (token == NUMBER_TOKEN) { 3853da084b3Smrg value2 = number_value; 386e1c0d025Smrg if (endOfLine(f, c)) { 3873da084b3Smrg return CODE_UNDEFINE_LINE; 388e1c0d025Smrg } 389e1c0d025Smrg else 3903da084b3Smrg return ERROR_LINE; 391e1c0d025Smrg } 392e1c0d025Smrg else { 393e1c0d025Smrg skipEndOfLine(f, c); 3943da084b3Smrg return ERROR_LINE; 3953da084b3Smrg } 396e1c0d025Smrg } 397e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDENCODING")) { 398e1c0d025Smrg if (endOfLine(f, c)) 3993da084b3Smrg return EOF_LINE; 4003da084b3Smrg else 4013da084b3Smrg return ERROR_LINE; 402e1c0d025Smrg } 403e1c0d025Smrg else if (!strcasecmp(keyword_value, "ENDMAPPING")) { 404e1c0d025Smrg if (endOfLine(f, c)) 4053da084b3Smrg return ENDMAPPING_LINE; 4063da084b3Smrg else 4073da084b3Smrg return ERROR_LINE; 408e1c0d025Smrg } 409e1c0d025Smrg else { 410e1c0d025Smrg skipEndOfLine(f, c); 4113da084b3Smrg return ERROR_LINE; 4123da084b3Smrg } 4133da084b3Smrg default: 4143da084b3Smrg return ERROR_LINE; 4153da084b3Smrg } 4163da084b3Smrg} 4173da084b3Smrg 41848c85eb7Smrgstatic void 4193da084b3Smrginstall_mapping(FontEncPtr encoding, FontMapPtr mapping) 4203da084b3Smrg{ 4213da084b3Smrg FontMapPtr m; 4223da084b3Smrg 423e1c0d025Smrg if (encoding->mappings == NULL) 4243da084b3Smrg encoding->mappings = mapping; 4253da084b3Smrg else { 4263da084b3Smrg m = encoding->mappings; 427e1c0d025Smrg while (m->next != NULL) 4283da084b3Smrg m = m->next; 4293da084b3Smrg m->next = mapping; 4303da084b3Smrg } 4313da084b3Smrg mapping->next = NULL; 4323da084b3Smrg mapping->encoding = encoding; 4333da084b3Smrg} 4343da084b3Smrg 4353da084b3Smrgstatic int 4363da084b3SmrgsetCode(unsigned from, unsigned to, unsigned row_size, 4373da084b3Smrg unsigned *first, unsigned *last, 4383da084b3Smrg unsigned *encsize, unsigned short **enc) 4393da084b3Smrg{ 4403da084b3Smrg unsigned index, i; 441e1c0d025Smrg 4423da084b3Smrg unsigned short *newenc; 4433da084b3Smrg 444e1c0d025Smrg if (from > 0xFFFF) 4453da084b3Smrg return 0; /* success */ 4463da084b3Smrg 447e1c0d025Smrg if (row_size == 0) 448e1c0d025Smrg index = from; 4493da084b3Smrg else { 450e1c0d025Smrg if ((value1 & 0xFF) >= row_size) 4513da084b3Smrg return 0; /* ignore out of range mappings */ 452e1c0d025Smrg index = (from >> 8) * row_size + (from & 0xFF); 4533da084b3Smrg } 4543da084b3Smrg 4553da084b3Smrg /* Optimize away useless identity mappings. This is only expected 4563da084b3Smrg to be useful with linear encodings. */ 457e1c0d025Smrg if (index == to && (index < *first || index > *last)) 4583da084b3Smrg return 0; 459e1c0d025Smrg if (*encsize == 0) { 4603da084b3Smrg *encsize = (index < 256) ? 256 : 0x10000; 4612a53b785Smrg *enc = Xmallocarray(*encsize, sizeof(unsigned short)); 462e1c0d025Smrg if (*enc == NULL) { 4633da084b3Smrg *encsize = 0; 4643da084b3Smrg return 1; 4653da084b3Smrg } 466e1c0d025Smrg } 467e1c0d025Smrg else if (*encsize <= index) { 4683da084b3Smrg *encsize = 0x10000; 4692a53b785Smrg newenc = Xreallocarray(*enc, *encsize, sizeof(unsigned short)); 4702a53b785Smrg if (newenc == NULL) 4713da084b3Smrg return 1; 4723da084b3Smrg *enc = newenc; 4733da084b3Smrg } 474e1c0d025Smrg if (*first > *last) { 4753da084b3Smrg *first = *last = index; 4763da084b3Smrg } 477e1c0d025Smrg if (index < *first) { 478e1c0d025Smrg for (i = index; i < *first; i++) 4793da084b3Smrg (*enc)[i] = i; 4803da084b3Smrg *first = index; 4813da084b3Smrg } 482e1c0d025Smrg if (index > *last) { 483e1c0d025Smrg for (i = *last + 1; i <= index; i++) 4843da084b3Smrg (*enc)[i] = i; 4853da084b3Smrg *last = index; 4863da084b3Smrg } 4873da084b3Smrg (*enc)[index] = to; 4883da084b3Smrg return 0; 4893da084b3Smrg} 4903da084b3Smrg 4913da084b3Smrg/* Parser. If headerOnly is true, we're only interested in the 4923da084b3Smrg data contained in the encoding file's header. */ 4933da084b3Smrg 4943da084b3Smrg/* As font encodings are currently never freed, the allocations done 4953da084b3Smrg by this function are mostly its private business. Note, however, 4963da084b3Smrg that FontEncIdentify needs to free the header fields -- so if you 4973da084b3Smrg change this function, you may need to change FontEncIdentify. */ 4983da084b3Smrg 4993da084b3Smrg/* I want a garbage collector. */ 5003da084b3Smrg 5013da084b3Smrgstatic FontEncPtr 5023da084b3SmrgparseEncodingFile(FontFilePtr f, int headerOnly) 5033da084b3Smrg{ 5043da084b3Smrg int line; 5053da084b3Smrg 506e1c0d025Smrg unsigned short *enc = NULL; 5073da084b3Smrg char **nam = NULL, **newnam; 508e1c0d025Smrg unsigned i, first = 0xFFFF, last = 0, encsize = 0, namsize = 0; 5093da084b3Smrg FontEncPtr encoding = NULL; 5103da084b3Smrg FontMapPtr mapping = NULL; 5113da084b3Smrg FontEncSimpleMapPtr sm; 5123da084b3Smrg FontEncSimpleNamePtr sn; 513e1c0d025Smrg char *aliases[MAXALIASES] = { NULL }; 514e1c0d025Smrg int numaliases = 0; 5153da084b3Smrg 5163da084b3Smrg#if 0 5173da084b3Smrg /* GCC complains about unused labels. Please fix GCC rather than 5183da084b3Smrg obfuscating my code. */ 519e1c0d025Smrg no_encoding: 5203da084b3Smrg#endif 5213da084b3Smrg line = getnextline(f); 522e1c0d025Smrg switch (line) { 5233da084b3Smrg case EOF_LINE: 5243da084b3Smrg goto error; 5253da084b3Smrg case STARTENCODING_LINE: 52655acc8fcSmrg encoding = malloc(sizeof(FontEncRec)); 527e1c0d025Smrg if (encoding == NULL) 5283da084b3Smrg goto error; 52955acc8fcSmrg encoding->name = strdup(keyword_value); 530e1c0d025Smrg if (encoding->name == NULL) 5313da084b3Smrg goto error; 5323da084b3Smrg encoding->size = 256; 5333da084b3Smrg encoding->row_size = 0; 5343da084b3Smrg encoding->mappings = NULL; 5353da084b3Smrg encoding->next = NULL; 536e1c0d025Smrg encoding->first = encoding->first_col = 0; 5373da084b3Smrg goto no_mapping; 5383da084b3Smrg default: 5393da084b3Smrg goto error; 5403da084b3Smrg } 5413da084b3Smrg 542e1c0d025Smrg no_mapping: 5433da084b3Smrg line = getnextline(f); 544e1c0d025Smrg switch (line) { 545e1c0d025Smrg case EOF_LINE: 546e1c0d025Smrg goto done; 5473da084b3Smrg case ALIAS_LINE: 548e1c0d025Smrg if (numaliases < MAXALIASES) { 54955acc8fcSmrg aliases[numaliases] = strdup(keyword_value); 550e1c0d025Smrg if (aliases[numaliases] == NULL) 5513da084b3Smrg goto error; 5523da084b3Smrg numaliases++; 5533da084b3Smrg } 5543da084b3Smrg goto no_mapping; 5553da084b3Smrg case SIZE_LINE: 5563da084b3Smrg encoding->size = value1; 5573da084b3Smrg encoding->row_size = value2; 5583da084b3Smrg goto no_mapping; 5593da084b3Smrg case FIRSTINDEX_LINE: 5603da084b3Smrg encoding->first = value1; 5613da084b3Smrg encoding->first_col = value2; 5623da084b3Smrg goto no_mapping; 5633da084b3Smrg case STARTMAPPING_LINE: 564e1c0d025Smrg if (headerOnly) 5653da084b3Smrg goto done; 566e1c0d025Smrg if (!strcasecmp(keyword_value, "unicode")) { 56755acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 568e1c0d025Smrg if (mapping == NULL) 5693da084b3Smrg goto error; 5703da084b3Smrg mapping->type = FONT_ENCODING_UNICODE; 5713da084b3Smrg mapping->pid = 0; 5723da084b3Smrg mapping->eid = 0; 5733da084b3Smrg mapping->recode = NULL; 5743da084b3Smrg mapping->name = NULL; 5753da084b3Smrg mapping->client_data = NULL; 5763da084b3Smrg mapping->next = NULL; 5773da084b3Smrg goto mapping; 578e1c0d025Smrg } 579e1c0d025Smrg else if (!strcasecmp(keyword_value, "cmap")) { 58055acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 581e1c0d025Smrg if (mapping == NULL) 5823da084b3Smrg goto error; 5833da084b3Smrg mapping->type = FONT_ENCODING_TRUETYPE; 5843da084b3Smrg mapping->pid = value1; 5853da084b3Smrg mapping->eid = value2; 5863da084b3Smrg mapping->recode = NULL; 5873da084b3Smrg mapping->name = NULL; 5883da084b3Smrg mapping->client_data = NULL; 5893da084b3Smrg mapping->next = NULL; 5903da084b3Smrg goto mapping; 591e1c0d025Smrg } 592e1c0d025Smrg else if (!strcasecmp(keyword_value, "postscript")) { 59355acc8fcSmrg mapping = malloc(sizeof(FontMapRec)); 594e1c0d025Smrg if (mapping == NULL) 5953da084b3Smrg goto error; 5963da084b3Smrg mapping->type = FONT_ENCODING_POSTSCRIPT; 5973da084b3Smrg mapping->pid = 0; 5983da084b3Smrg mapping->eid = 0; 5993da084b3Smrg mapping->recode = NULL; 6003da084b3Smrg mapping->name = NULL; 6013da084b3Smrg mapping->client_data = NULL; 6023da084b3Smrg mapping->next = NULL; 6033da084b3Smrg goto string_mapping; 604e1c0d025Smrg } 605e1c0d025Smrg else { /* unknown mapping type -- ignore */ 6063da084b3Smrg goto skipmapping; 6073da084b3Smrg } 6083da084b3Smrg /* NOTREACHED */ 6093da084b3Smrg goto error; 610e1c0d025Smrg default: 611e1c0d025Smrg goto no_mapping; /* ignore unknown lines */ 6123da084b3Smrg } 6133da084b3Smrg 614e1c0d025Smrg skipmapping: 6153da084b3Smrg line = getnextline(f); 616e1c0d025Smrg switch (line) { 6173da084b3Smrg case ENDMAPPING_LINE: 6183da084b3Smrg goto no_mapping; 6193da084b3Smrg case EOF_LINE: 6203da084b3Smrg goto error; 6213da084b3Smrg default: 6223da084b3Smrg goto skipmapping; 6233da084b3Smrg } 6243da084b3Smrg 625e1c0d025Smrg mapping: 6263da084b3Smrg line = getnextline(f); 627e1c0d025Smrg switch (line) { 628e1c0d025Smrg case EOF_LINE: 629e1c0d025Smrg goto error; 6303da084b3Smrg case ENDMAPPING_LINE: 6313da084b3Smrg mapping->recode = FontEncSimpleRecode; 6323da084b3Smrg mapping->name = FontEncUndefinedName; 63355acc8fcSmrg mapping->client_data = sm = malloc(sizeof(FontEncSimpleMapRec)); 634e1c0d025Smrg if (sm == NULL) 6353da084b3Smrg goto error; 6363da084b3Smrg sm->row_size = encoding->row_size; 637e1c0d025Smrg if (first <= last) { 6383da084b3Smrg unsigned short *newmap; 6393da084b3Smrg 6403da084b3Smrg sm->first = first; 641e1c0d025Smrg sm->len = last - first + 1; 6422a53b785Smrg newmap = Xmallocarray(sm->len, sizeof(unsigned short)); 643e1c0d025Smrg if (newmap == NULL) { 64455acc8fcSmrg free(sm); 6453da084b3Smrg mapping->client_data = sm = NULL; 6463da084b3Smrg goto error; 6473da084b3Smrg } 648e1c0d025Smrg for (i = 0; i < sm->len; i++) 649e1c0d025Smrg newmap[i] = enc[first + i]; 650e1c0d025Smrg sm->map = newmap; 651e1c0d025Smrg } 652e1c0d025Smrg else { 6533da084b3Smrg sm->first = 0; 6543da084b3Smrg sm->len = 0; 6553da084b3Smrg sm->map = NULL; 6563da084b3Smrg } 6573da084b3Smrg install_mapping(encoding, mapping); 6583da084b3Smrg mapping = NULL; 659e1c0d025Smrg first = 0xFFFF; 660e1c0d025Smrg last = 0; 6613da084b3Smrg goto no_mapping; 6623da084b3Smrg 6633da084b3Smrg case CODE_LINE: 664e1c0d025Smrg if (setCode(value1, value2, encoding->row_size, 665e1c0d025Smrg &first, &last, &encsize, &enc)) 6663da084b3Smrg goto error; 6673da084b3Smrg goto mapping; 6683da084b3Smrg 6693da084b3Smrg case CODE_RANGE_LINE: 670e1c0d025Smrg if (value1 > 0x10000) 6713da084b3Smrg value1 = 0x10000; 672e1c0d025Smrg if (value2 > 0x10000) 6733da084b3Smrg value2 = 0x10000; 674e1c0d025Smrg if (value2 < value1) 6753da084b3Smrg goto mapping; 6763da084b3Smrg /* Do the last value first to avoid having to realloc() */ 677e1c0d025Smrg if (setCode(value2, value3 + (value2 - value1), encoding->row_size, 678e1c0d025Smrg &first, &last, &encsize, &enc)) 6793da084b3Smrg goto error; 680e1c0d025Smrg for (i = value1; i < value2; i++) { 681e1c0d025Smrg if (setCode(i, value3 + (i - value1), encoding->row_size, 682e1c0d025Smrg &first, &last, &encsize, &enc)) 6833da084b3Smrg goto error; 6843da084b3Smrg } 6853da084b3Smrg goto mapping; 68648c85eb7Smrg 6873da084b3Smrg case CODE_UNDEFINE_LINE: 688e1c0d025Smrg if (value1 > 0x10000) 6893da084b3Smrg value1 = 0x10000; 690e1c0d025Smrg if (value2 > 0x10000) 6913da084b3Smrg value2 = 0x10000; 692e1c0d025Smrg if (value2 < value1) 6933da084b3Smrg goto mapping; 6943da084b3Smrg /* Do the last value first to avoid having to realloc() */ 695e1c0d025Smrg if (setCode(value2, 0, encoding->row_size, 696e1c0d025Smrg &first, &last, &encsize, &enc)) 6973da084b3Smrg goto error; 698e1c0d025Smrg for (i = value1; i < value2; i++) { 699e1c0d025Smrg if (setCode(i, 0, encoding->row_size, 700e1c0d025Smrg &first, &last, &encsize, &enc)) 7013da084b3Smrg goto error; 7023da084b3Smrg } 7033da084b3Smrg goto mapping; 7043da084b3Smrg 705e1c0d025Smrg default: 706e1c0d025Smrg goto mapping; /* ignore unknown lines */ 7073da084b3Smrg } 70848c85eb7Smrg 709e1c0d025Smrg string_mapping: 7103da084b3Smrg line = getnextline(f); 711e1c0d025Smrg switch (line) { 712e1c0d025Smrg case EOF_LINE: 713e1c0d025Smrg goto error; 7143da084b3Smrg case ENDMAPPING_LINE: 7153da084b3Smrg mapping->recode = FontEncUndefinedRecode; 7163da084b3Smrg mapping->name = FontEncSimpleName; 71755acc8fcSmrg mapping->client_data = sn = malloc(sizeof(FontEncSimpleNameRec)); 718e1c0d025Smrg if (sn == NULL) 7193da084b3Smrg goto error; 720e1c0d025Smrg if (first > last) { 72155acc8fcSmrg free(sn); 7223da084b3Smrg mapping->client_data = sn = NULL; 7233da084b3Smrg goto error; 7243da084b3Smrg } 7253da084b3Smrg sn->first = first; 7263da084b3Smrg sn->len = last - first + 1; 7272a53b785Smrg sn->map = Xmallocarray(sn->len, sizeof(char *)); 728e1c0d025Smrg if (sn->map == NULL) { 72955acc8fcSmrg free(sn); 7303da084b3Smrg mapping->client_data = sn = NULL; 7313da084b3Smrg goto error; 7323da084b3Smrg } 733e1c0d025Smrg for (i = 0; i < sn->len; i++) 734e1c0d025Smrg sn->map[i] = nam[first + i]; 735e1c0d025Smrg install_mapping(encoding, mapping); 7363da084b3Smrg mapping = NULL; 737e1c0d025Smrg first = 0xFFFF; 738e1c0d025Smrg last = 0; 7393da084b3Smrg goto no_mapping; 7403da084b3Smrg case NAME_LINE: 741e1c0d025Smrg if (value1 >= 0x10000) 742e1c0d025Smrg goto string_mapping; 743e1c0d025Smrg if (namsize == 0) { 7443da084b3Smrg namsize = (value1) < 256 ? 256 : 0x10000; 7452a53b785Smrg nam = Xmallocarray(namsize, sizeof(char *)); 746e1c0d025Smrg if (nam == NULL) { 747e1c0d025Smrg namsize = 0; 7483da084b3Smrg goto error; 7493da084b3Smrg } 750e1c0d025Smrg } 751e1c0d025Smrg else if (namsize <= value1) { 7523da084b3Smrg namsize = 0x10000; 753e1c0d025Smrg if ((newnam = (char **) realloc(nam, namsize)) == NULL) 7543da084b3Smrg goto error; 7553da084b3Smrg nam = newnam; 7563da084b3Smrg } 757e1c0d025Smrg if (first > last) { 7583da084b3Smrg first = last = value1; 7593da084b3Smrg } 760e1c0d025Smrg if (value1 < first) { 761e1c0d025Smrg for (i = value1; i < first; i++) 7623da084b3Smrg nam[i] = NULL; 7633da084b3Smrg first = value1; 7643da084b3Smrg } 765e1c0d025Smrg if (value1 > last) { 766e1c0d025Smrg for (i = last + 1; i <= value1; i++) 767e1c0d025Smrg nam[i] = NULL; 7683da084b3Smrg last = value1; 7693da084b3Smrg } 77055acc8fcSmrg nam[value1] = strdup(keyword_value); 771e1c0d025Smrg if (nam[value1] == NULL) { 7723da084b3Smrg goto error; 7733da084b3Smrg } 7743da084b3Smrg goto string_mapping; 7753da084b3Smrg 776e1c0d025Smrg default: 777e1c0d025Smrg goto string_mapping; /* ignore unknown lines */ 7783da084b3Smrg } 7793da084b3Smrg 780e1c0d025Smrg done: 781e1c0d025Smrg if (encsize) { 782e1c0d025Smrg free(enc); 783e1c0d025Smrg encsize = 0; 784e1c0d025Smrg enc = NULL; 785e1c0d025Smrg } 786e1c0d025Smrg if (namsize) { 787e1c0d025Smrg free(nam); /* don't free entries! */ 788e1c0d025Smrg namsize = 0; 789e1c0d025Smrg nam = NULL; 790e1c0d025Smrg } 7913da084b3Smrg 792e1c0d025Smrg encoding->aliases = NULL; 793e1c0d025Smrg if (numaliases) { 7942a53b785Smrg encoding->aliases = Xmallocarray(numaliases + 1, sizeof(char *)); 795e1c0d025Smrg if (encoding->aliases == NULL) 7963da084b3Smrg goto error; 797e1c0d025Smrg for (i = 0; i < numaliases; i++) 7983da084b3Smrg encoding->aliases[i] = aliases[i]; 799e1c0d025Smrg encoding->aliases[numaliases] = NULL; 8003da084b3Smrg } 8013da084b3Smrg 8023da084b3Smrg return encoding; 8033da084b3Smrg 804e1c0d025Smrg error: 805e1c0d025Smrg if (encsize) { 806e1c0d025Smrg free(enc); 807e1c0d025Smrg encsize = 0; 808e1c0d025Smrg } 809e1c0d025Smrg if (namsize) { 810e1c0d025Smrg for (i = first; i <= last; i++) 81155acc8fcSmrg free(nam[i]); 81255acc8fcSmrg free(nam); 8133da084b3Smrg } 814e1c0d025Smrg if (mapping) { 81555acc8fcSmrg free(mapping->client_data); 81655acc8fcSmrg free(mapping); 8173da084b3Smrg } 818e1c0d025Smrg if (encoding) { 819e1c0d025Smrg FontMapPtr nextmap; 820e1c0d025Smrg 821e1c0d025Smrg free(encoding->name); 822e1c0d025Smrg for (mapping = encoding->mappings; mapping; mapping = nextmap) { 823e1c0d025Smrg free(mapping->client_data); 824e1c0d025Smrg nextmap = mapping->next; 825e1c0d025Smrg free(mapping); 826e1c0d025Smrg } 827e1c0d025Smrg free(encoding); 828e1c0d025Smrg } 829e1c0d025Smrg for (i = 0; i < numaliases; i++) 83055acc8fcSmrg free(aliases[i]); 831e1c0d025Smrg /* We don't need to free sn and sm as they handled locally in the body. */ 8323da084b3Smrg return NULL; 8333da084b3Smrg} 8343da084b3Smrg 83552fd71cdSmrgconst char * 8363da084b3SmrgFontEncDirectory(void) 8373da084b3Smrg{ 83852fd71cdSmrg static const char *dir = NULL; 8393da084b3Smrg 840e1c0d025Smrg if (dir == NULL) { 84152fd71cdSmrg const char *c = getenv("FONT_ENCODINGS_DIRECTORY"); 842e1c0d025Smrg 843e1c0d025Smrg if (c) { 84455acc8fcSmrg dir = strdup(c); 845e1c0d025Smrg if (!dir) 8463da084b3Smrg return NULL; 847e1c0d025Smrg } 848e1c0d025Smrg else { 8493da084b3Smrg dir = FONT_ENCODINGS_DIRECTORY; 8503da084b3Smrg } 8513da084b3Smrg } 8523da084b3Smrg return dir; 8533da084b3Smrg} 8543da084b3Smrg 8553da084b3Smrgstatic void 8563da084b3SmrgparseFontFileName(const char *fontFileName, char *buf, char *dir) 8573da084b3Smrg{ 8583da084b3Smrg const char *p; 8593da084b3Smrg char *q, *lastslash; 86048c85eb7Smrg 861e1c0d025Smrg for (p = fontFileName, q = dir, lastslash = NULL; *p; p++, q++) { 8623da084b3Smrg *q = *p; 863e1c0d025Smrg if (*p == '/') 864e1c0d025Smrg lastslash = q + 1; 8653da084b3Smrg } 86648c85eb7Smrg 867e1c0d025Smrg if (!lastslash) 8683da084b3Smrg lastslash = dir; 86948c85eb7Smrg 8703da084b3Smrg *lastslash = '\0'; 8713da084b3Smrg 872e1c0d025Smrg if (buf && strlen(dir) + 14 < MAXFONTFILENAMELEN) { 873e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, "encodings.dir"); 8743da084b3Smrg } 8753da084b3Smrg} 8763da084b3Smrg 8773da084b3Smrgstatic FontEncPtr 87848c85eb7SmrgFontEncReallyReallyLoad(const char *charset, 8793da084b3Smrg const char *dirname, const char *dir) 8803da084b3Smrg{ 8813da084b3Smrg FontFilePtr f; 8823da084b3Smrg FILE *file; 8833da084b3Smrg FontEncPtr encoding; 8843da084b3Smrg char file_name[MAXFONTFILENAMELEN], encoding_name[MAXFONTNAMELEN], 8853da084b3Smrg buf[MAXFONTFILENAMELEN]; 8863da084b3Smrg int count, n; 8873da084b3Smrg static char format[24] = ""; 88848c85eb7Smrg 8893da084b3Smrg /* As we don't really expect to open encodings that often, we don't 8903da084b3Smrg take the trouble of caching encodings directories. */ 8913da084b3Smrg 892e1c0d025Smrg if ((file = fopen(dirname, "r")) == NULL) { 8933da084b3Smrg return NULL; 8943da084b3Smrg } 89548c85eb7Smrg 8963da084b3Smrg count = fscanf(file, "%d\n", &n); 897e1c0d025Smrg if (count == EOF || count != 1) { 8983da084b3Smrg fclose(file); 8993da084b3Smrg return NULL; 9003da084b3Smrg } 9013da084b3Smrg 9023da084b3Smrg encoding = NULL; 9033da084b3Smrg if (!format[0]) { 904e1c0d025Smrg snprintf(format, sizeof(format), "%%%ds %%%d[^\n]\n", 905e1c0d025Smrg (int) sizeof(encoding_name) - 1, (int) sizeof(file_name) - 1); 9063da084b3Smrg } 907e1c0d025Smrg for (;;) { 9083da084b3Smrg count = fscanf(file, format, encoding_name, file_name); 909e1c0d025Smrg if (count == EOF) 9103da084b3Smrg break; 911e1c0d025Smrg if (count != 2) 9123da084b3Smrg break; 9133da084b3Smrg 914e1c0d025Smrg if (!strcasecmp(encoding_name, charset)) { 9153da084b3Smrg /* Found it */ 916e1c0d025Smrg if (file_name[0] != '/') { 917e1c0d025Smrg if (strlen(dir) + strlen(file_name) >= MAXFONTFILENAMELEN) { 918e1c0d025Smrg fclose(file); 9193da084b3Smrg return NULL; 920e1c0d025Smrg } 921e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s%s", dir, file_name); 922e1c0d025Smrg } 923e1c0d025Smrg else { 924e1c0d025Smrg snprintf(buf, MAXFONTFILENAMELEN, "%s", file_name); 9253da084b3Smrg } 9263da084b3Smrg 9273da084b3Smrg f = FontFileOpen(buf); 928e1c0d025Smrg if (f == NULL) { 929e1c0d025Smrg fclose(file); 9303da084b3Smrg return NULL; 9313da084b3Smrg } 9323da084b3Smrg encoding = parseEncodingFile(f, 0); 9333da084b3Smrg FontFileClose(f); 9343da084b3Smrg break; 9353da084b3Smrg } 9363da084b3Smrg } 9373da084b3Smrg 9383da084b3Smrg fclose(file); 9393da084b3Smrg 9403da084b3Smrg return encoding; 9413da084b3Smrg} 9423da084b3Smrg 94348c85eb7Smrg/* Parser ntrypoint -- used by FontEncLoad */ 9443da084b3SmrgFontEncPtr 9453da084b3SmrgFontEncReallyLoad(const char *charset, const char *fontFileName) 9463da084b3Smrg{ 9473da084b3Smrg FontEncPtr encoding; 9483da084b3Smrg char dir[MAXFONTFILENAMELEN], dirname[MAXFONTFILENAMELEN]; 94952fd71cdSmrg const char *d; 9503da084b3Smrg 951e1c0d025Smrg if (fontFileName) { 9523da084b3Smrg parseFontFileName(fontFileName, dirname, dir); 9533da084b3Smrg encoding = FontEncReallyReallyLoad(charset, dirname, dir); 954e1c0d025Smrg if (encoding) 955e1c0d025Smrg return (encoding); 9563da084b3Smrg } 95748c85eb7Smrg 9583da084b3Smrg d = FontEncDirectory(); 959e1c0d025Smrg if (d) { 9603da084b3Smrg parseFontFileName(d, NULL, dir); 9613da084b3Smrg encoding = FontEncReallyReallyLoad(charset, d, dir); 9623da084b3Smrg return encoding; 9633da084b3Smrg } 96448c85eb7Smrg 9653da084b3Smrg return NULL; 9663da084b3Smrg} 9673da084b3Smrg 9683da084b3Smrg/* Return a NULL-terminated array of encoding names. Note that this 9693da084b3Smrg * function has incestuous knowledge of the allocations done by 9703da084b3Smrg * parseEncodingFile. */ 9713da084b3Smrg 9723da084b3Smrgchar ** 9733da084b3SmrgFontEncIdentify(const char *fileName) 9743da084b3Smrg{ 9753da084b3Smrg FontFilePtr f; 9763da084b3Smrg FontEncPtr encoding; 9773da084b3Smrg char **names, **name, **alias; 9783da084b3Smrg int numaliases; 97948c85eb7Smrg 980e1c0d025Smrg if ((f = FontFileOpen(fileName)) == NULL) { 9813da084b3Smrg return NULL; 9823da084b3Smrg } 9833da084b3Smrg encoding = parseEncodingFile(f, 1); 9843da084b3Smrg FontFileClose(f); 9853da084b3Smrg 986e1c0d025Smrg if (!encoding) 9873da084b3Smrg return NULL; 9883da084b3Smrg 9893da084b3Smrg numaliases = 0; 990e1c0d025Smrg if (encoding->aliases) 991e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++) 9923da084b3Smrg numaliases++; 9933da084b3Smrg 9942a53b785Smrg names = Xmallocarray(numaliases + 2, sizeof(char *)); 995e1c0d025Smrg if (names == NULL) { 99655acc8fcSmrg free(encoding->aliases); 99755acc8fcSmrg free(encoding); 9983da084b3Smrg return NULL; 9993da084b3Smrg } 10003da084b3Smrg 10013da084b3Smrg name = names; 10023da084b3Smrg *(name++) = encoding->name; 1003e1c0d025Smrg if (numaliases > 0) 1004e1c0d025Smrg for (alias = encoding->aliases; *alias; alias++, name++) 1005e1c0d025Smrg *name = *alias; 10063da084b3Smrg 10073da084b3Smrg *name = NULL; 100855acc8fcSmrg free(encoding->aliases); 100955acc8fcSmrg free(encoding); 10103da084b3Smrg 10113da084b3Smrg return names; 10123da084b3Smrg} 1013