mkfontscale.c revision eaa89f16
1ea6ae205Smrg/* 2ea6ae205Smrg Copyright (c) 2002-2003 by Juliusz Chroboczek 3ea6ae205Smrg 4ea6ae205Smrg Permission is hereby granted, free of charge, to any person obtaining a copy 5ea6ae205Smrg of this software and associated documentation files (the "Software"), to deal 6ea6ae205Smrg in the Software without restriction, including without limitation the rights 7ea6ae205Smrg to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8ea6ae205Smrg copies of the Software, and to permit persons to whom the Software is 9ea6ae205Smrg furnished to do so, subject to the following conditions: 10ea6ae205Smrg 11ea6ae205Smrg The above copyright notice and this permission notice shall be included in 12ea6ae205Smrg all copies or substantial portions of the Software. 13ea6ae205Smrg 14ea6ae205Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15ea6ae205Smrg IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16ea6ae205Smrg FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17ea6ae205Smrg AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18ea6ae205Smrg LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19ea6ae205Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20ea6ae205Smrg THE SOFTWARE. 21ea6ae205Smrg*/ 22ea6ae205Smrg 2340cc5db4Smrg#ifdef HAVE_CONFIG_H 242d6e8b77Smrg#include "config.h" 2540cc5db4Smrg#endif 262d6e8b77Smrg 27ea6ae205Smrg#include <stdio.h> 28ea6ae205Smrg#include <stdlib.h> 29ea6ae205Smrg#include <string.h> 30ea6ae205Smrg 31ea6ae205Smrg#include <sys/types.h> 322d6e8b77Smrg#include <sys/stat.h> 33ea6ae205Smrg#include <dirent.h> 34ea6ae205Smrg#include <unistd.h> 35ea6ae205Smrg#include <errno.h> 36ea6ae205Smrg#include <ctype.h> 37ea6ae205Smrg 38ea6ae205Smrg#include <X11/Xos.h> 39af7d3019Smrg#include <X11/Xfuncproto.h> 40ea6ae205Smrg#include <X11/fonts/fontenc.h> 41ea6ae205Smrg#include <ft2build.h> 42ea6ae205Smrg#include FT_FREETYPE_H 43ea6ae205Smrg#include FT_SFNT_NAMES_H 44ea6ae205Smrg#include FT_TRUETYPE_TABLES_H 45ea6ae205Smrg#include FT_TRUETYPE_IDS_H 46ea6ae205Smrg#include FT_TYPE1_TABLES_H 47ea6ae205Smrg#include FT_BDF_H 48ea6ae205Smrg#include FT_XFREE86_H 49ea6ae205Smrg 50ea6ae205Smrg#include "list.h" 51ea6ae205Smrg#include "hash.h" 52ea6ae205Smrg#include "data.h" 53ea6ae205Smrg#include "ident.h" 54ea6ae205Smrg 55ea6ae205Smrg#define NPREFIX 1024 56ea6ae205Smrg 57ea6ae205Smrg#ifndef MAXFONTFILENAMELEN 58ea6ae205Smrg#define MAXFONTFILENAMELEN 1024 59ea6ae205Smrg#endif 60ea6ae205Smrg#ifndef MAXFONTNAMELEN 61ea6ae205Smrg#define MAXFONTNAMELEN 1024 62ea6ae205Smrg#endif 63ea6ae205Smrg 64245f6787Smrg/* Two levels of macro calls are needed so that we stringify the value 65245f6787Smrg of MAXFONT... and not the string "MAXFONT..." */ 66245f6787Smrg#define QUOTE(x) #x 67245f6787Smrg#define STRINGIFY(x) QUOTE(x) 68245f6787Smrg 6914734546Smrgstatic char *encodings_array[] = 70ea6ae205Smrg { "ascii-0", 71ea6ae205Smrg "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5", 72ea6ae205Smrg "iso8859-6", "iso8859-6.8", "iso8859-6.8x", "iso8859-6.16", 73ea6ae205Smrg "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10", 74ea6ae205Smrg "iso8859-11", "iso8859-12", "iso8859-13", "iso8859-14", 75ea6ae205Smrg "iso8859-15", "iso8859-16", 76ea6ae205Smrg "ansi-1251", "koi8-r", "koi8-u", "koi8-ru", "koi8-e", "koi8-uni", 77ea6ae205Smrg "tis620-2", 78ea6ae205Smrg "sun.unicode.india-0", "suneu-greek", 79ea6ae205Smrg "adobe-standard", "adobe-symbol", 80ea6ae205Smrg "ibm-cp437", "ibm-cp850", "ibm-cp852", "ibm-cp866", "microsoft-cp1252", 81ea6ae205Smrg /* But not "adobe-dingbats", as it uses generic glyph names. */ 82ea6ae205Smrg "cns11643-1", "cns11643-2", "cns11643-3", 83ea6ae205Smrg "jisx0201.1976-0", "jisx0208.1983-0", "jisx0208.1990-0", 84ea6ae205Smrg "jisx0212.1990-0", "big5-0", "big5.eten-0", "big5hkscs-0", 85ea6ae205Smrg "gb2312.1980-0", "gb18030.2000-0", "gb18030.2000-1", 86ea6ae205Smrg "ksc5601.1987-0", "ksc5601.1992-3"}; 87ea6ae205Smrg 8814734546Smrgstatic char *extra_encodings_array[] = 89ea6ae205Smrg { "iso10646-1", "adobe-fontspecific", "microsoft-symbol" }; 90ea6ae205Smrg 91e83ac88aSmrgstatic ListPtr encodings, extra_encodings; 92663cdc11Smrgstatic const char *outfilename; 93ea6ae205Smrg 94ea6ae205Smrg#define countof(_a) (sizeof(_a)/sizeof((_a)[0])) 95ea6ae205Smrg 96663cdc11Smrgstatic int doDirectory(const char*, int, ListPtr); 97ea6ae205Smrgstatic int checkEncoding(FT_Face face, char *encoding_name); 98ea6ae205Smrgstatic int checkExtraEncoding(FT_Face face, char *encoding_name, int found); 99ea6ae205Smrgstatic int find_cmap(int type, int pid, int eid, FT_Face face); 100663cdc11Smrgstatic const char* notice_foundry(const char *notice); 101663cdc11Smrgstatic const char* vendor_foundry(const signed char *vendor); 102ea6ae205Smrgstatic int readFontScale(HashTablePtr entries, char *dirname); 103ea6ae205SmrgListPtr makeXLFD(char *filename, FT_Face face, int); 104ea6ae205Smrgstatic int readEncodings(ListPtr encodings, char *dirname); 105ea6ae205Smrg 106ea6ae205Smrgstatic FT_Library ft_library; 107ea6ae205Smrgstatic float bigEncodingFuzz = 0.02; 108ea6ae205Smrg 109ea6ae205Smrgstatic int relative; 110ea6ae205Smrgstatic int doScalable; 111ea6ae205Smrgstatic int doBitmaps; 112ea6ae205Smrgstatic int doISO10646_1_encoding; 113ea6ae205Smrgstatic int onlyEncodings; 114ea6ae205Smrgstatic ListPtr encodingsToDo; 115ea6ae205Smrgstatic int reencodeLegacy; 116ea6ae205Smrgstatic char *encodingPrefix; 117ea6ae205Smrgstatic char *exclusionSuffix; 118af7d3019Smrgstatic char *ProgramName; 119ea6ae205Smrg 120af7d3019Smrgstatic void _X_NORETURN _X_COLD 121ea6ae205Smrgusage(void) 122ea6ae205Smrg{ 123af7d3019Smrg fprintf(stderr, "Usage:\n" 124ea6ae205Smrg "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n" 125af7d3019Smrg " [ -a encoding ] [ -f fuzz ] [ -l ]\n" 126ea6ae205Smrg " [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n" 127af7d3019Smrg " [-u] [-U] [-v] [ directory ]...\n"); 128af7d3019Smrg exit(1); 129af7d3019Smrg} 130af7d3019Smrg 131af7d3019Smrgstatic void _X_NORETURN _X_COLD 132af7d3019Smrgmissing_arg (const char *option) 133af7d3019Smrg{ 134af7d3019Smrg fprintf(stderr, "%s: %s requires an argument\n", ProgramName, option); 135af7d3019Smrg usage(); 136ea6ae205Smrg} 137ea6ae205Smrg 138ea6ae205Smrgint 139ea6ae205Smrgmain(int argc, char **argv) 140ea6ae205Smrg{ 141ea6ae205Smrg int argn; 142ea6ae205Smrg FT_Error ftrc; 143ea6ae205Smrg int rc, ll = 0; 144ea6ae205Smrg char prefix[NPREFIX]; 145ea6ae205Smrg 146af7d3019Smrg ProgramName = argv[0]; 147ea6ae205Smrg encodingPrefix = NULL; 148ea6ae205Smrg exclusionSuffix = NULL; 149ea6ae205Smrg 150ea6ae205Smrg if(getcwd(prefix, NPREFIX - 1) == NULL) { 151ea6ae205Smrg perror("Couldn't get cwd"); 152ea6ae205Smrg exit(1); 153ea6ae205Smrg } 154ea6ae205Smrg if(prefix[strlen(prefix) - 1] != '/') 155ea6ae205Smrg strcat(prefix, "/"); 156ea6ae205Smrg encodingPrefix = dsprintf("%s", prefix); 157ea6ae205Smrg 158ea6ae205Smrg outfilename = NULL; 159ea6ae205Smrg 160ea6ae205Smrg encodings = makeList(encodings_array, countof(encodings_array), NULL, 0); 161ea6ae205Smrg 162663cdc11Smrg extra_encodings = makeList(extra_encodings_array, 163ea6ae205Smrg countof(extra_encodings_array), 164ea6ae205Smrg NULL, 0); 165ea6ae205Smrg doBitmaps = 0; 166ea6ae205Smrg doISO10646_1_encoding = 1; 167ea6ae205Smrg doScalable = 1; 168ea6ae205Smrg onlyEncodings = 0; 169ea6ae205Smrg relative = 0; 170ea6ae205Smrg reencodeLegacy = 1; 171ea6ae205Smrg encodingsToDo = NULL; 172ea6ae205Smrg 173ea6ae205Smrg argn = 1; 174ea6ae205Smrg while(argn < argc) { 175ea6ae205Smrg if(argv[argn][0] == '\0' || argv[argn][0] != '-') 176ea6ae205Smrg break; 177ea6ae205Smrg if(argv[argn][1] == '-') { 178ea6ae205Smrg argn++; 179ea6ae205Smrg break; 180ea6ae205Smrg } else if (strcmp(argv[argn], "-x") == 0) { 181ea6ae205Smrg if(argn >= argc - 1) { 182af7d3019Smrg missing_arg("-x"); 183ea6ae205Smrg } 184ea6ae205Smrg exclusionSuffix = argv[argn + 1]; 185ea6ae205Smrg argn += 2; 186ea6ae205Smrg } else if(strcmp(argv[argn], "-a") == 0) { 187ea6ae205Smrg if(argn >= argc - 1) { 188af7d3019Smrg missing_arg("-a"); 189ea6ae205Smrg } 190ea6ae205Smrg makeList(&argv[argn + 1], 1, encodings, 0); 191ea6ae205Smrg argn += 2; 192ea6ae205Smrg } else if(strcmp(argv[argn], "-p") == 0) { 193ea6ae205Smrg if(argn >= argc - 1) { 194af7d3019Smrg missing_arg("-p"); 195ea6ae205Smrg } 196ea6ae205Smrg if(strlen(argv[argn + 1]) > NPREFIX - 1) { 197af7d3019Smrg fprintf(stderr, "%s: argument to -p cannot be longer than " 198af7d3019Smrg "%d characters\n", ProgramName, NPREFIX - 1); 199ea6ae205Smrg usage(); 200ea6ae205Smrg } 201ea6ae205Smrg free(encodingPrefix); 202ea6ae205Smrg encodingPrefix = dsprintf("%s", argv[argn + 1]); 203ea6ae205Smrg argn += 2; 204ea6ae205Smrg } else if(strcmp(argv[argn], "-e") == 0) { 205ea6ae205Smrg if(argn >= argc - 1) { 206af7d3019Smrg missing_arg("-e"); 207ea6ae205Smrg } 208ea6ae205Smrg rc = readEncodings(encodingsToDo, argv[argn + 1]); 209ea6ae205Smrg if(rc < 0) 210ea6ae205Smrg exit(1); 211ea6ae205Smrg argn += 2; 212ea6ae205Smrg } else if(strcmp(argv[argn], "-b") == 0) { 213ea6ae205Smrg doBitmaps = 1; 214ea6ae205Smrg argn++; 215ea6ae205Smrg } else if(strcmp(argv[argn], "-u") == 0) { 216ea6ae205Smrg doISO10646_1_encoding = 0; 217ea6ae205Smrg argn++; 218ea6ae205Smrg } else if(strcmp(argv[argn], "-U") == 0) { 219ea6ae205Smrg doISO10646_1_encoding = 1; 220663cdc11Smrg argn++; 221ea6ae205Smrg } else if(strcmp(argv[argn], "-s") == 0) { 222ea6ae205Smrg doScalable = 0; 223ea6ae205Smrg argn++; 224ea6ae205Smrg } else if(strcmp(argv[argn], "-n") == 0) { 225ea6ae205Smrg onlyEncodings = 1; 226ea6ae205Smrg argn++; 227ea6ae205Smrg } else if(strcmp(argv[argn], "-r") == 0) { 228ea6ae205Smrg relative = 1; 229ea6ae205Smrg argn++; 230ea6ae205Smrg } else if(strcmp(argv[argn], "-l") == 0) { 231ea6ae205Smrg reencodeLegacy = !reencodeLegacy; 232ea6ae205Smrg argn++; 233ea6ae205Smrg } else if(strcmp(argv[argn], "-o") == 0) { 234ea6ae205Smrg if(argn >= argc - 1) { 235af7d3019Smrg missing_arg("-o"); 236ea6ae205Smrg } 237ea6ae205Smrg outfilename = argv[argn + 1]; 238ea6ae205Smrg argn += 2; 239ea6ae205Smrg } else if(strcmp(argv[argn], "-f") == 0) { 240ea6ae205Smrg if(argn >= argc - 1) { 241af7d3019Smrg missing_arg("-f"); 242ea6ae205Smrg } 243ea6ae205Smrg bigEncodingFuzz = atof(argv[argn + 1]) / 100.0; 244ea6ae205Smrg argn += 2; 245af7d3019Smrg } else if (strcmp(argv[argn], "-v") == 0) { 246af7d3019Smrg printf("%s\n", PACKAGE_STRING); 247af7d3019Smrg exit(0); 248ea6ae205Smrg } else { 249ea6ae205Smrg usage(); 250ea6ae205Smrg } 251ea6ae205Smrg } 252ea6ae205Smrg 253ea6ae205Smrg if(outfilename == NULL) { 254ea6ae205Smrg if(doBitmaps) 255ea6ae205Smrg outfilename = "fonts.dir"; 256663cdc11Smrg else 257ea6ae205Smrg outfilename = "fonts.scale"; 258ea6ae205Smrg } 259ea6ae205Smrg 260ea6ae205Smrg ftrc = FT_Init_FreeType(&ft_library); 261ea6ae205Smrg if(ftrc) { 262ea6ae205Smrg fprintf(stderr, "Could not initialise FreeType library: %d\n", ftrc); 263ea6ae205Smrg exit(1); 264ea6ae205Smrg } 265ea6ae205Smrg 266ea6ae205Smrg ll = listLength(encodingsToDo); 267ea6ae205Smrg 268ea6ae205Smrg if (argn == argc) 269ea6ae205Smrg doDirectory(".", ll, encodingsToDo); 270ea6ae205Smrg else 271ea6ae205Smrg while(argn < argc) { 272ea6ae205Smrg doDirectory(argv[argn], ll, encodingsToDo); 273ea6ae205Smrg argn++; 274ea6ae205Smrg } 275ea6ae205Smrg return 0; 276ea6ae205Smrg} 277ea6ae205Smrg 278ea6ae205Smrgstatic int 279ea6ae205SmrggetNameHelper(FT_Face face, int nid, int pid, int eid, 280ea6ae205Smrg FT_SfntName *name_return) 281ea6ae205Smrg{ 282ea6ae205Smrg FT_SfntName name; 283ea6ae205Smrg int n, i; 284ea6ae205Smrg 285ea6ae205Smrg n = FT_Get_Sfnt_Name_Count(face); 286ea6ae205Smrg if(n <= 0) 287ea6ae205Smrg return 0; 288ea6ae205Smrg 289ea6ae205Smrg for(i = 0; i < n; i++) { 290ea6ae205Smrg if(FT_Get_Sfnt_Name(face, i, &name)) 291ea6ae205Smrg continue; 292ea6ae205Smrg if(name.name_id == nid && 293ea6ae205Smrg name.platform_id == pid && 294ea6ae205Smrg (eid < 0 || name.encoding_id == eid)) { 295ea6ae205Smrg switch(name.platform_id) { 296ea6ae205Smrg case TT_PLATFORM_APPLE_UNICODE: 297ea6ae205Smrg case TT_PLATFORM_MACINTOSH: 298ea6ae205Smrg if(name.language_id != TT_MAC_LANGID_ENGLISH) 299ea6ae205Smrg continue; 300ea6ae205Smrg break; 301ea6ae205Smrg case TT_PLATFORM_MICROSOFT: 302ea6ae205Smrg if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES && 303ea6ae205Smrg name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM) 304ea6ae205Smrg continue; 305ea6ae205Smrg break; 306ea6ae205Smrg default: 307ea6ae205Smrg continue; 308ea6ae205Smrg } 309ea6ae205Smrg if(name.string_len > 0) { 310ea6ae205Smrg *name_return = name; 311ea6ae205Smrg return 1; 312ea6ae205Smrg } 313ea6ae205Smrg } 314ea6ae205Smrg } 315ea6ae205Smrg return 0; 316ea6ae205Smrg} 317ea6ae205Smrg 318ea6ae205Smrgstatic char * 319ea6ae205SmrggetName(FT_Face face, int nid) 320ea6ae205Smrg{ 321ea6ae205Smrg FT_SfntName name; 322ea6ae205Smrg char *string; 323ea6ae205Smrg int i; 324ea6ae205Smrg 325663cdc11Smrg if(getNameHelper(face, nid, 326ea6ae205Smrg TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) || 327663cdc11Smrg getNameHelper(face, nid, 328ea6ae205Smrg TT_PLATFORM_APPLE_UNICODE, -1, &name)) { 329ea6ae205Smrg string = malloc(name.string_len / 2 + 1); 330ea6ae205Smrg if(string == NULL) { 331ea6ae205Smrg fprintf(stderr, "Couldn't allocate name\n"); 332ea6ae205Smrg exit(1); 333ea6ae205Smrg } 334ea6ae205Smrg for(i = 0; i < name.string_len / 2; i++) { 335ea6ae205Smrg if(name.string[2 * i] != 0) 336ea6ae205Smrg string[i] = '?'; 337ea6ae205Smrg else 338ea6ae205Smrg string[i] = name.string[2 * i + 1]; 339ea6ae205Smrg } 340ea6ae205Smrg string[i] = '\0'; 341ea6ae205Smrg return string; 342ea6ae205Smrg } 343ea6ae205Smrg 344ea6ae205Smrg /* Pretend that Apple Roman is ISO 8859-1. */ 345ea6ae205Smrg if(getNameHelper(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, 346ea6ae205Smrg &name)) { 347ea6ae205Smrg string = malloc(name.string_len + 1); 348ea6ae205Smrg if(string == NULL) { 349ea6ae205Smrg fprintf(stderr, "Couldn't allocate name\n"); 350ea6ae205Smrg exit(1); 351ea6ae205Smrg } 352ea6ae205Smrg memcpy(string, name.string, name.string_len); 353ea6ae205Smrg string[name.string_len] = '\0'; 354ea6ae205Smrg return string; 355ea6ae205Smrg } 356ea6ae205Smrg 357ea6ae205Smrg return NULL; 358ea6ae205Smrg} 359ea6ae205Smrg 360663cdc11Smrgstatic const char* 361ea6ae205Smrgos2Weight(int weight) 362ea6ae205Smrg{ 363ea6ae205Smrg if(weight < 150) 364ea6ae205Smrg return "thin"; 365ea6ae205Smrg else if(weight < 250) 366ea6ae205Smrg return "extralight"; 367ea6ae205Smrg else if(weight < 350) 368ea6ae205Smrg return "light"; 369ea6ae205Smrg else if(weight < 450) 370ea6ae205Smrg return "medium"; /* officially "normal" */ 371ea6ae205Smrg else if(weight < 550) 372ea6ae205Smrg return "medium"; 373ea6ae205Smrg else if(weight < 650) 374ea6ae205Smrg return "semibold"; 375ea6ae205Smrg else if(weight < 750) 376ea6ae205Smrg return "bold"; 377ea6ae205Smrg else if(weight < 850) 378ea6ae205Smrg return "extrabold"; 379663cdc11Smrg else 380ea6ae205Smrg return "black"; 381ea6ae205Smrg} 382ea6ae205Smrg 383663cdc11Smrgstatic const char* 384ea6ae205Smrgos2Width(int width) 385ea6ae205Smrg{ 386ea6ae205Smrg if(width <= 1) 387ea6ae205Smrg return "ultracondensed"; 388ea6ae205Smrg else if(width <= 2) 389ea6ae205Smrg return "extracondensed"; 390ea6ae205Smrg else if(width <= 3) 391ea6ae205Smrg return "condensed"; 392ea6ae205Smrg else if(width <= 4) 393ea6ae205Smrg return "semicondensed"; 394ea6ae205Smrg else if(width <= 5) 395ea6ae205Smrg return "normal"; 396ea6ae205Smrg else if(width <= 6) 397ea6ae205Smrg return "semiexpanded"; 398ea6ae205Smrg else if(width <= 7) 399ea6ae205Smrg return "expanded"; 400ea6ae205Smrg else if(width <= 8) 401ea6ae205Smrg return "extraexpanded"; 402ea6ae205Smrg else 403ea6ae205Smrg return "ultraexpanded"; 404ea6ae205Smrg} 405ea6ae205Smrg 406663cdc11Smrgstatic const char *widths[] = { 407ea6ae205Smrg "ultracondensed", "extracondensed", "condensed", "semicondensed", 408663cdc11Smrg "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded" 409ea6ae205Smrg}; 410ea6ae205Smrg 411ea6ae205Smrg#define NUMWIDTHS (sizeof(widths) / sizeof(widths[0])) 412ea6ae205Smrg 413663cdc11Smrgstatic const char* 414663cdc11SmrgnameWidth(const char *name) 415ea6ae205Smrg{ 416ea6ae205Smrg char buf[500]; 417ea6ae205Smrg int i; 418ea6ae205Smrg int n = strlen(name); 419ea6ae205Smrg 420ea6ae205Smrg if(n >= 499) return NULL; 421ea6ae205Smrg for(i = 0; i < n; i++) 422ea6ae205Smrg buf[i] = tolower(name[i]); 423ea6ae205Smrg buf[i] = '\0'; 424ea6ae205Smrg 425ea6ae205Smrg for(i = 0; i < NUMWIDTHS; i++) 426ea6ae205Smrg if(strstr(buf, widths[i])) 427ea6ae205Smrg return widths[i]; 428ea6ae205Smrg return NULL; 429ea6ae205Smrg} 430ea6ae205Smrg 431663cdc11Smrgstatic const char* 432663cdc11Smrgt1Weight(const char *weight) 433ea6ae205Smrg{ 434ea6ae205Smrg if(!weight) 435ea6ae205Smrg return NULL; 436ea6ae205Smrg if(strcmp(weight, "Thin") == 0) 437ea6ae205Smrg return "thin"; 438663cdc11Smrg if(strcmp(weight, "ExtraLight") == 0) /* FontForge uses this for 200*/ 439663cdc11Smrg return "extralight"; 440ea6ae205Smrg if(strcmp(weight, "Light") == 0) 441ea6ae205Smrg return "light"; 442ea6ae205Smrg if(strcmp(weight, "Regular") == 0) 443ea6ae205Smrg return "medium"; 444ea6ae205Smrg if(strcmp(weight, "Normal") == 0) 445ea6ae205Smrg return "medium"; 446ea6ae205Smrg if(strcmp(weight, "Medium") == 0) 447ea6ae205Smrg return "medium"; 448ea6ae205Smrg if(strcmp(weight, "Book") == 0) 449ea6ae205Smrg return "medium"; 450ea6ae205Smrg if(strcmp(weight, "Roman") == 0) /* Some URW++ fonts do that! */ 451ea6ae205Smrg return "medium"; 452ea6ae205Smrg if(strcmp(weight, "Demi") == 0) 453ea6ae205Smrg return "semibold"; 454ea6ae205Smrg if(strcmp(weight, "DemiBold") == 0) 455ea6ae205Smrg return "semibold"; 456ea6ae205Smrg if(strcmp(weight, "SemiBold") == 0) /* some TeX fonts apparently do that */ 457ea6ae205Smrg return "semibold"; 458ea6ae205Smrg else if(strcmp(weight, "Bold") == 0) 459ea6ae205Smrg return "bold"; 460663cdc11Smrg else if(strcmp(weight, "Heavy") == 0) /* FontForge uses this for 800*/ 461663cdc11Smrg return "extrabold"; 462ea6ae205Smrg else if(strcmp(weight, "Black") == 0) 463ea6ae205Smrg return "black"; 464ea6ae205Smrg else { 465ea6ae205Smrg fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight); 466ea6ae205Smrg return NULL; 467ea6ae205Smrg } 468ea6ae205Smrg} 469ea6ae205Smrg 470ea6ae205Smrgstatic int 471ea6ae205Smrgunsafe(char c) 472ea6ae205Smrg{ 473663cdc11Smrg return 474ea6ae205Smrg c < 0x20 || c > 0x7E || 475ea6ae205Smrg c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-'; 476ea6ae205Smrg} 477ea6ae205Smrg 478663cdc11Smrgstatic const char * 479663cdc11Smrgsafe(const char* s) 480ea6ae205Smrg{ 481ea6ae205Smrg int i, len, safe_flag = 1; 482ea6ae205Smrg char *t; 483ea6ae205Smrg 484ea6ae205Smrg i = 0; 485ea6ae205Smrg while(s[i] != '\0') { 486ea6ae205Smrg if(unsafe(s[i])) 487ea6ae205Smrg safe_flag = 0; 488ea6ae205Smrg i++; 489ea6ae205Smrg } 490ea6ae205Smrg 491af7d3019Smrg if(safe_flag) return strdup(s); 492ea6ae205Smrg 493ea6ae205Smrg len = i; 494ea6ae205Smrg t = malloc(len + 1); 495ea6ae205Smrg if(t == NULL) { 496ea6ae205Smrg perror("Couldn't allocate string"); 497ea6ae205Smrg exit(1); 498ea6ae205Smrg } 499ea6ae205Smrg 500ea6ae205Smrg for(i = 0; i < len; i++) { 501ea6ae205Smrg if(unsafe(s[i])) 502ea6ae205Smrg t[i] = ' '; 503ea6ae205Smrg else 504ea6ae205Smrg t[i] = s[i]; 505ea6ae205Smrg } 506ea6ae205Smrg t[i] = '\0'; 507ea6ae205Smrg return t; 508ea6ae205Smrg} 509ea6ae205Smrg 510ea6ae205SmrgListPtr 511ea6ae205SmrgmakeXLFD(char *filename, FT_Face face, int isBitmap) 512ea6ae205Smrg{ 513ea6ae205Smrg ListPtr xlfd = NULL; 514663cdc11Smrg const char *foundry, *family, *weight, *slant, *sWidth, *adstyle, 515af7d3019Smrg *spacing, *full_name, *tmp; 516ea6ae205Smrg TT_Header *head; 517ea6ae205Smrg TT_HoriHeader *hhea; 518ea6ae205Smrg TT_OS2 *os2; 519ea6ae205Smrg TT_Postscript *post; 520ea6ae205Smrg PS_FontInfoRec *t1info, t1info_rec; 521ea6ae205Smrg int rc; 522ea6ae205Smrg 523ea6ae205Smrg foundry = NULL; 524ea6ae205Smrg family = NULL; 525ea6ae205Smrg weight = NULL; 526ea6ae205Smrg slant = NULL; 527ea6ae205Smrg sWidth = NULL; 528ea6ae205Smrg adstyle = NULL; 529ea6ae205Smrg spacing = NULL; 530ea6ae205Smrg full_name = NULL; 531ea6ae205Smrg 532ea6ae205Smrg head = FT_Get_Sfnt_Table(face, ft_sfnt_head); 533ea6ae205Smrg hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); 534ea6ae205Smrg os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 535ea6ae205Smrg post = FT_Get_Sfnt_Table(face, ft_sfnt_post); 536ea6ae205Smrg 537ea6ae205Smrg rc = FT_Get_PS_Font_Info(face, &t1info_rec); 538ea6ae205Smrg if(rc == 0) 539ea6ae205Smrg t1info = &t1info_rec; 540ea6ae205Smrg else 541ea6ae205Smrg t1info = NULL; 542663cdc11Smrg 543ea6ae205Smrg if(!family) 544ea6ae205Smrg family = getName(face, TT_NAME_ID_FONT_FAMILY); 545ea6ae205Smrg if(!family) 546ea6ae205Smrg family = getName(face, TT_NAME_ID_FULL_NAME); 547ea6ae205Smrg if(!family) 548ea6ae205Smrg family = getName(face, TT_NAME_ID_PS_NAME); 549ea6ae205Smrg 550ea6ae205Smrg if(!full_name) 551ea6ae205Smrg full_name = getName(face, TT_NAME_ID_FULL_NAME); 552ea6ae205Smrg if(!full_name) 553ea6ae205Smrg full_name = getName(face, TT_NAME_ID_PS_NAME); 554ea6ae205Smrg 555ea6ae205Smrg if(os2 && os2->version != 0xFFFF) { 556ea6ae205Smrg if(!weight) 557ea6ae205Smrg weight = os2Weight(os2->usWeightClass); 558ea6ae205Smrg if(!sWidth) 559ea6ae205Smrg sWidth = os2Width(os2->usWidthClass); 560ea6ae205Smrg if(!foundry) 561ea6ae205Smrg foundry = vendor_foundry(os2->achVendID); 562ea6ae205Smrg if(!slant) 563ea6ae205Smrg slant = os2->fsSelection & 1 ? "i" : "r"; 564ea6ae205Smrg } 565ea6ae205Smrg 566ea6ae205Smrg if(post) { 567ea6ae205Smrg if(!spacing) { 568ea6ae205Smrg if(post->isFixedPitch) { 569ea6ae205Smrg if(hhea->min_Left_Side_Bearing >= 0 && 570ea6ae205Smrg hhea->xMax_Extent <= hhea->advance_Width_Max) { 571ea6ae205Smrg spacing = "c"; 572ea6ae205Smrg } else { 573ea6ae205Smrg spacing = "m"; 574ea6ae205Smrg } 575ea6ae205Smrg } else { 576ea6ae205Smrg spacing = "p"; 577ea6ae205Smrg } 578ea6ae205Smrg } 579ea6ae205Smrg } 580663cdc11Smrg 581ea6ae205Smrg if(t1info) { 582eaa89f16Smrg if(!family && t1info->family_name) 583af7d3019Smrg family = strdup(t1info->family_name); 584eaa89f16Smrg if(!family && t1info->full_name) 585af7d3019Smrg family = strdup(t1info->full_name); 586eaa89f16Smrg /* Hershey fonts miss /FamilyName */ 587eaa89f16Smrg if(!family && face->family_name) 588eaa89f16Smrg family = strdup(face->family_name); 589eaa89f16Smrg if(!full_name && t1info->full_name) 590af7d3019Smrg full_name = strdup(t1info->full_name); 591ea6ae205Smrg if(!foundry) 592ea6ae205Smrg foundry = notice_foundry(t1info->notice); 593ea6ae205Smrg if(!weight) 594ea6ae205Smrg weight = t1Weight(t1info->weight); 595ea6ae205Smrg if(!spacing) 596ea6ae205Smrg spacing = t1info->is_fixed_pitch ? "m" : "p"; 597ea6ae205Smrg if(!slant) { 598ea6ae205Smrg /* Bitstream fonts have positive italic angle. */ 599ea6ae205Smrg slant = 600ea6ae205Smrg t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? 601ea6ae205Smrg "i" : "r"; 602ea6ae205Smrg } 603ea6ae205Smrg } 604ea6ae205Smrg 605ea6ae205Smrg if(!full_name) { 606ea6ae205Smrg fprintf(stderr, "Couldn't determine full name for %s\n", filename); 607af7d3019Smrg full_name = strdup(filename); 608ea6ae205Smrg } 609ea6ae205Smrg 610ea6ae205Smrg if(head) { 611ea6ae205Smrg if(!slant) 612ea6ae205Smrg slant = head->Mac_Style & 2 ? "i" : "r"; 613ea6ae205Smrg if(!weight) 614ea6ae205Smrg weight = head->Mac_Style & 1 ? "bold" : "medium"; 615ea6ae205Smrg } 616ea6ae205Smrg 617ea6ae205Smrg if(!slant) { 618ea6ae205Smrg fprintf(stderr, "Couldn't determine slant for %s\n", filename); 619ea6ae205Smrg slant = "r"; 620ea6ae205Smrg } 621ea6ae205Smrg 622ea6ae205Smrg if(!weight) { 623ea6ae205Smrg fprintf(stderr, "Couldn't determine weight for %s\n", filename); 624ea6ae205Smrg weight = "medium"; 625ea6ae205Smrg } 626ea6ae205Smrg 627ea6ae205Smrg if(!foundry) { 628ea6ae205Smrg char *notice; 629ea6ae205Smrg notice = getName(face, TT_NAME_ID_TRADEMARK); 630ea6ae205Smrg if(notice) { 631ea6ae205Smrg foundry = notice_foundry(notice); 632af7d3019Smrg free(notice); 633ea6ae205Smrg } 634ea6ae205Smrg if(!foundry) { 635ea6ae205Smrg notice = getName(face, TT_NAME_ID_MANUFACTURER); 636ea6ae205Smrg if(notice) { 637ea6ae205Smrg foundry = notice_foundry(notice); 638af7d3019Smrg free(notice); 639ea6ae205Smrg } 640ea6ae205Smrg } 641ea6ae205Smrg } 642ea6ae205Smrg 643ea6ae205Smrg if(strcmp(slant, "i") == 0) { 644ea6ae205Smrg if(strstr(full_name, "Oblique")) 645ea6ae205Smrg slant = "o"; 646ea6ae205Smrg if(strstr(full_name, "Slanted")) 647ea6ae205Smrg slant = "o"; 648ea6ae205Smrg } 649ea6ae205Smrg 650ea6ae205Smrg if(!sWidth) 651ea6ae205Smrg sWidth = nameWidth(full_name); 652ea6ae205Smrg 653ea6ae205Smrg if(!foundry) foundry = "misc"; 654ea6ae205Smrg if(!family) { 655ea6ae205Smrg fprintf(stderr, "Couldn't get family name for %s\n", filename); 656af7d3019Smrg family = strdup(filename); 657ea6ae205Smrg } 658ea6ae205Smrg 659ea6ae205Smrg if(!weight) weight = "medium"; 660ea6ae205Smrg if(!slant) slant = "r"; 661ea6ae205Smrg if(!sWidth) sWidth = "normal"; 662ea6ae205Smrg if(!adstyle) adstyle = ""; 663ea6ae205Smrg if(!spacing) spacing = "p"; 664ea6ae205Smrg 665ea6ae205Smrg foundry = safe(foundry); 666af7d3019Smrg 667af7d3019Smrg tmp = family; 668ea6ae205Smrg family = safe(family); 669af7d3019Smrg free((void *)tmp); 670ea6ae205Smrg 671ea6ae205Smrg if(!isBitmap) { 672ea6ae205Smrg xlfd = listConsF(xlfd, 673ea6ae205Smrg "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0", 674ea6ae205Smrg foundry, family, 675ea6ae205Smrg weight, slant, sWidth, adstyle, spacing); 676ea6ae205Smrg } else { 677ea6ae205Smrg int i, w, h, xres, yres; 678ea6ae205Smrg for(i = 0; i < face->num_fixed_sizes; i++) { 679ea6ae205Smrg w = face->available_sizes[i].width; 680ea6ae205Smrg h = face->available_sizes[i].height; 681ea6ae205Smrg xres = 75; 682ea6ae205Smrg yres = (double)h / w * xres; 683ea6ae205Smrg xlfd = listConsF(xlfd, 684ea6ae205Smrg "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d", 685ea6ae205Smrg foundry, family, 686ea6ae205Smrg weight, slant, sWidth, adstyle, 687ea6ae205Smrg h, (int)(h / (double)yres * 72.27 * 10 + 0.5), 688ea6ae205Smrg xres, yres, 689ea6ae205Smrg spacing, 60); 690ea6ae205Smrg } 691ea6ae205Smrg } 692af7d3019Smrg 693af7d3019Smrg free((void *)family); 694af7d3019Smrg free((void *)foundry); 695af7d3019Smrg free((void *)full_name); 696ea6ae205Smrg return xlfd; 697ea6ae205Smrg} 698ea6ae205Smrg 699ea6ae205Smrgstatic int 700ea6ae205SmrgreadFontScale(HashTablePtr entries, char *dirname) 701ea6ae205Smrg{ 702ea6ae205Smrg int n = strlen(dirname); 703ea6ae205Smrg char *filename; 704ea6ae205Smrg FILE *in; 705ea6ae205Smrg int rc, count, i; 706245f6787Smrg char file[MAXFONTFILENAMELEN+1], font[MAXFONTNAMELEN+1]; 707ea6ae205Smrg 708ea6ae205Smrg if(dirname[n - 1] == '/') 709ea6ae205Smrg filename = dsprintf("%sfonts.scale", dirname); 710ea6ae205Smrg else 711ea6ae205Smrg filename = dsprintf("%s/fonts.scale", dirname); 712ea6ae205Smrg if(filename == NULL) 713ea6ae205Smrg return -1; 714ea6ae205Smrg 715ea6ae205Smrg in = fopen(filename, "r"); 716ea6ae205Smrg free(filename); 717ea6ae205Smrg if(in == NULL) { 718ea6ae205Smrg if(errno != ENOENT) 719ea6ae205Smrg perror("open(fonts.scale)"); 720ea6ae205Smrg return -1; 721ea6ae205Smrg } 722ea6ae205Smrg 723ea6ae205Smrg rc = fscanf(in, "%d\n", &count); 724ea6ae205Smrg if(rc != 1) { 725ea6ae205Smrg fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname); 726ea6ae205Smrg fclose(in); 727ea6ae205Smrg return -1; 728ea6ae205Smrg } 729ea6ae205Smrg 730ea6ae205Smrg for(i = 0; i < count; i++) { 731245f6787Smrg rc = fscanf(in, 732245f6787Smrg "%" STRINGIFY(MAXFONTFILENAMELEN) "s " 733245f6787Smrg "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n", 734245f6787Smrg file, font); 735ea6ae205Smrg if(rc != 2) 736ea6ae205Smrg break; 737ea6ae205Smrg putHash(entries, font, file, 100); 738ea6ae205Smrg } 739ea6ae205Smrg fclose(in); 740ea6ae205Smrg return 1; 741ea6ae205Smrg} 742ea6ae205Smrg 743ea6ae205Smrgstatic int 744ea6ae205SmrgfilePrio(char *filename) 745ea6ae205Smrg{ 746ea6ae205Smrg int n = strlen(filename); 747ea6ae205Smrg if(n < 4) 748ea6ae205Smrg return 0; 749ea6ae205Smrg if(strcmp(filename + n - 4, ".otf") == 0) 750ea6ae205Smrg return 6; 751ea6ae205Smrg if(strcmp(filename + n - 4, ".OTF") == 0) 752ea6ae205Smrg return 6; 753ea6ae205Smrg if(strcmp(filename + n - 4, ".ttf") == 0) 754ea6ae205Smrg return 5; 755ea6ae205Smrg if(strcmp(filename + n - 4, ".TTF") == 0) 756ea6ae205Smrg return 5; 757ea6ae205Smrg if(strcmp(filename + n - 4, ".pcf") == 0) 758ea6ae205Smrg return 4; 759ea6ae205Smrg if(strcmp(filename + n - 4, ".PCF") == 0) 760ea6ae205Smrg return 4; 761ea6ae205Smrg if(strcmp(filename + n - 3, ".gz") == 0) 762ea6ae205Smrg return 3; 7637978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION 7647978d3cdSmrg if(strcmp(filename + n - 4, ".bz2") == 0) 7657978d3cdSmrg return 2; 7667978d3cdSmrg#endif 767ea6ae205Smrg if(strcmp(filename + n - 2, ".Z") == 0) 768ea6ae205Smrg return 2; 769ea6ae205Smrg if(strcmp(filename + n - 4, ".bdf") == 0) 770ea6ae205Smrg return 1; 771ea6ae205Smrg if(strcmp(filename + n - 4, ".BDF") == 0) 772ea6ae205Smrg return 1; 773ea6ae205Smrg return 0; 774ea6ae205Smrg} 775ea6ae205Smrg 776ea6ae205Smrgstatic int 777663cdc11SmrgdoDirectory(const char *dirname_given, int numEncodings, ListPtr encodingsToDo) 778ea6ae205Smrg{ 779ea6ae205Smrg char *dirname, *fontscale_name, *filename, *encdir; 780ea6ae205Smrg FILE *fontscale, *encfile; 781ea6ae205Smrg DIR *dirp; 782ea6ae205Smrg struct dirent *entry; 783ea6ae205Smrg FT_Error ftrc; 784ea6ae205Smrg FT_Face face; 785ea6ae205Smrg ListPtr encoding, xlfd, lp; 786ea6ae205Smrg HashTablePtr entries; 787ea6ae205Smrg HashBucketPtr *array; 788ea6ae205Smrg int i, n, found, rc; 789ea6ae205Smrg int isBitmap=0,xl=0; 790ea6ae205Smrg 791ea6ae205Smrg if (exclusionSuffix) 792ea6ae205Smrg xl = strlen (exclusionSuffix); 793ea6ae205Smrg 794ea6ae205Smrg i = strlen(dirname_given); 795ea6ae205Smrg if(i == 0) 796ea6ae205Smrg dirname = dsprintf("./"); 797ea6ae205Smrg else if(dirname_given[i - 1] != '/') 798ea6ae205Smrg dirname = dsprintf("%s/", dirname_given); 799ea6ae205Smrg else 800ea6ae205Smrg dirname = dsprintf("%s", dirname_given); 801ea6ae205Smrg 802ea6ae205Smrg if(dirname == NULL) { 803ea6ae205Smrg perror("dirname"); 804ea6ae205Smrg exit(1); 805ea6ae205Smrg } 806ea6ae205Smrg 807663cdc11Smrg if (onlyEncodings) 808ea6ae205Smrg goto encodings; 809663cdc11Smrg 810ea6ae205Smrg entries = makeHashTable(); 811ea6ae205Smrg if(doBitmaps && !doScalable) { 812ea6ae205Smrg readFontScale(entries, dirname); 813ea6ae205Smrg } 814ea6ae205Smrg 815ea6ae205Smrg if(strcmp(outfilename, "-") == 0) 816ea6ae205Smrg fontscale_name = NULL; 817ea6ae205Smrg else { 818ea6ae205Smrg if(outfilename[0] == '/') 819ea6ae205Smrg fontscale_name = dsprintf("%s", outfilename); 820ea6ae205Smrg else 821ea6ae205Smrg fontscale_name = dsprintf("%s%s", dirname, outfilename); 822ea6ae205Smrg if(fontscale_name == NULL) { 823ea6ae205Smrg perror("fontscale_name"); 824ea6ae205Smrg exit(1); 825ea6ae205Smrg } 826ea6ae205Smrg } 827ea6ae205Smrg 828ea6ae205Smrg dirp = opendir(dirname); 829ea6ae205Smrg if(dirp == NULL) { 830ea6ae205Smrg fprintf(stderr, "%s: ", dirname); 831ea6ae205Smrg perror("opendir"); 832ea6ae205Smrg return 0; 833ea6ae205Smrg } 834ea6ae205Smrg 835ea6ae205Smrg if(fontscale_name == NULL) 836ea6ae205Smrg fontscale = stdout; 837ea6ae205Smrg else 838ea6ae205Smrg fontscale = fopen(fontscale_name, "wb"); 839ea6ae205Smrg 840ea6ae205Smrg if(fontscale == NULL) { 841ea6ae205Smrg fprintf(stderr, "%s: ", fontscale_name); 842ea6ae205Smrg perror("fopen(w)"); 843ea6ae205Smrg return 0; 844ea6ae205Smrg } 845ea6ae205Smrg 846ea6ae205Smrg while((entry = readdir(dirp)) != NULL) { 847ea6ae205Smrg int have_face = 0; 848ea6ae205Smrg char *xlfd_name = NULL; 8492d6e8b77Smrg struct stat f_stat; 8502d6e8b77Smrg int tprio = 1; 8512d6e8b77Smrg 852ea6ae205Smrg xlfd = NULL; 853ea6ae205Smrg 854ea6ae205Smrg if (xl) { 855ea6ae205Smrg int dl = strlen (entry->d_name); 856ea6ae205Smrg if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0) 857ea6ae205Smrg continue; 858ea6ae205Smrg } 859ea6ae205Smrg 860ea6ae205Smrg filename = dsprintf("%s%s", dirname, entry->d_name); 861ea6ae205Smrg 8622d6e8b77Smrg#define PRIO(x) ((x << 1) + tprio) 8632d6e8b77Smrg#ifdef DT_LNK 8642d6e8b77Smrg if (entry->d_type != DT_UNKNOWN) { 8652d6e8b77Smrg if (entry->d_type == DT_LNK) 8662d6e8b77Smrg tprio = 0; 8672d6e8b77Smrg } else 8682d6e8b77Smrg#endif 8692d6e8b77Smrg#ifdef S_ISLNK 8702d6e8b77Smrg { 8712d6e8b77Smrg if (lstat(filename, &f_stat)) 8722d6e8b77Smrg goto done; 8732d6e8b77Smrg if (S_ISLNK(f_stat.st_mode)) 8742d6e8b77Smrg tprio = 0; 8752d6e8b77Smrg } 8762d6e8b77Smrg#else 8772d6e8b77Smrg ; 8782d6e8b77Smrg#endif 879ea6ae205Smrg if(doBitmaps) 880ea6ae205Smrg rc = bitmapIdentify(filename, &xlfd_name); 881ea6ae205Smrg else 882ea6ae205Smrg rc = 0; 883ea6ae205Smrg 884ea6ae205Smrg if(rc < 0) 885ea6ae205Smrg goto done; 886ea6ae205Smrg 887ea6ae205Smrg if(rc == 0) { 888ea6ae205Smrg ftrc = FT_New_Face(ft_library, filename, 0, &face); 889ea6ae205Smrg if(ftrc) 890ea6ae205Smrg goto done; 891ea6ae205Smrg have_face = 1; 892ea6ae205Smrg 893ea6ae205Smrg isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 894ea6ae205Smrg 895ea6ae205Smrg if(!isBitmap) { 896ea6ae205Smrg /* Workaround for bitmap-only SFNT fonts */ 897ea6ae205Smrg if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 && 898ea6ae205Smrg strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) { 899ea6ae205Smrg TT_MaxProfile *maxp; 900ea6ae205Smrg maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 901ea6ae205Smrg if(maxp != NULL && maxp->maxContours == 0) 902ea6ae205Smrg isBitmap = 1; 903ea6ae205Smrg } 904ea6ae205Smrg } 905663cdc11Smrg 906ea6ae205Smrg if(isBitmap) { 907ea6ae205Smrg if(!doBitmaps) 908ea6ae205Smrg goto done; 909ea6ae205Smrg } else { 910ea6ae205Smrg if(!doScalable) 911ea6ae205Smrg goto done; 912ea6ae205Smrg } 913ea6ae205Smrg 914ea6ae205Smrg if(isBitmap) { 915ea6ae205Smrg BDF_PropertyRec prop; 916ea6ae205Smrg rc = FT_Get_BDF_Property(face, "FONT", &prop); 917ea6ae205Smrg if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 9182d6e8b77Smrg xlfd_name = strdup(prop.u.atom); 919ea6ae205Smrg if(xlfd_name == NULL) 920ea6ae205Smrg goto done; 921ea6ae205Smrg } 922ea6ae205Smrg } 923ea6ae205Smrg } 924ea6ae205Smrg 925ea6ae205Smrg if(xlfd_name) { 926ea6ae205Smrg /* We know it's a bitmap font, and we know its XLFD */ 927ea6ae205Smrg int n = strlen(xlfd_name); 928ea6ae205Smrg if(reencodeLegacy && 929ea6ae205Smrg n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { 930ea6ae205Smrg char *s; 931ea6ae205Smrg 932ea6ae205Smrg s = malloc(n - 10); 933ea6ae205Smrg memcpy(s, xlfd_name, n - 11); 934ea6ae205Smrg s[n - 11] = '\0'; 935ea6ae205Smrg xlfd = listCons(s, xlfd); 936ea6ae205Smrg } else { 937ea6ae205Smrg /* Not a reencodable font -- skip all the rest of the loop body */ 9382d6e8b77Smrg putHash(entries, xlfd_name, entry->d_name, PRIO(filePrio(entry->d_name))); 939ea6ae205Smrg goto done; 940ea6ae205Smrg } 941ea6ae205Smrg } 942ea6ae205Smrg 943ea6ae205Smrg if(!have_face) { 944ea6ae205Smrg ftrc = FT_New_Face(ft_library, filename, 0, &face); 945ea6ae205Smrg if(ftrc) 946ea6ae205Smrg goto done; 947ea6ae205Smrg have_face = 1; 948ea6ae205Smrg isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 949ea6ae205Smrg 950ea6ae205Smrg if(!isBitmap) { 951ea6ae205Smrg if(face->num_fixed_sizes > 0) { 952ea6ae205Smrg TT_MaxProfile *maxp; 953ea6ae205Smrg maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 954ea6ae205Smrg if(maxp != NULL && maxp->maxContours == 0) 955ea6ae205Smrg isBitmap = 1; 956ea6ae205Smrg } 957ea6ae205Smrg } 958ea6ae205Smrg } 959ea6ae205Smrg 960ea6ae205Smrg if(xlfd == NULL) 961ea6ae205Smrg xlfd = makeXLFD(entry->d_name, face, isBitmap); 962ea6ae205Smrg 963ea6ae205Smrg found = 0; 964ea6ae205Smrg 965ea6ae205Smrg for(lp = xlfd; lp; lp = lp->next) { 966ea6ae205Smrg char buf[MAXFONTNAMELEN]; 967ea6ae205Smrg for(encoding = encodings; encoding; encoding = encoding->next) { 968ea6ae205Smrg if(checkEncoding(face, encoding->value)) { 969ea6ae205Smrg found = 1; 970ea6ae205Smrg snprintf(buf, MAXFONTNAMELEN, "%s-%s", 971ea6ae205Smrg lp->value, encoding->value); 9722d6e8b77Smrg putHash(entries, buf, entry->d_name, PRIO(filePrio(entry->d_name))); 973ea6ae205Smrg } 974ea6ae205Smrg } 975663cdc11Smrg for(encoding = extra_encodings; encoding; 976ea6ae205Smrg encoding = encoding->next) { 977ea6ae205Smrg if(checkExtraEncoding(face, encoding->value, found)) { 978ea6ae205Smrg /* Do not set found! */ 979ea6ae205Smrg snprintf(buf, MAXFONTNAMELEN, "%s-%s", 980ea6ae205Smrg lp->value, encoding->value); 9812d6e8b77Smrg putHash(entries, buf, entry->d_name, PRIO(filePrio(entry->d_name))); 982ea6ae205Smrg } 983ea6ae205Smrg } 984ea6ae205Smrg } 985ea6ae205Smrg done: 986245f6787Smrg if(have_face) 987ea6ae205Smrg FT_Done_Face(face); 988ea6ae205Smrg deepDestroyList(xlfd); 989ea6ae205Smrg xlfd = NULL; 990ea6ae205Smrg free(filename); 9912d6e8b77Smrg#undef PRIO 992ea6ae205Smrg } 993ea6ae205Smrg 994ea6ae205Smrg closedir(dirp); 995ea6ae205Smrg n = hashElements(entries); 996ea6ae205Smrg fprintf(fontscale, "%d\n", n); 997ea6ae205Smrg array = hashArray(entries, 1); 998ea6ae205Smrg for(i = 0; i < n; i++) 999ea6ae205Smrg fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); 1000ea6ae205Smrg destroyHashArray(array); 1001ea6ae205Smrg entries = NULL; 1002ea6ae205Smrg if(fontscale_name) { 1003ea6ae205Smrg fclose(fontscale); 1004ea6ae205Smrg free(fontscale_name); 1005ea6ae205Smrg } 1006ea6ae205Smrg 1007ea6ae205Smrg encodings: 1008ea6ae205Smrg encdir = dsprintf("%s%s", dirname, "encodings.dir"); 1009ea6ae205Smrg 1010ea6ae205Smrg if(encdir == NULL) { 1011ea6ae205Smrg perror("encodings"); 1012ea6ae205Smrg exit(1); 1013ea6ae205Smrg } 1014ea6ae205Smrg unlink(encdir); 1015ea6ae205Smrg 1016ea6ae205Smrg if (numEncodings) { 1017ea6ae205Smrg encfile = fopen(encdir, "w"); 1018ea6ae205Smrg if(encfile == NULL) { 1019ea6ae205Smrg perror("open(encodings.dir)"); 1020ea6ae205Smrg exit(1); 1021ea6ae205Smrg } 1022ea6ae205Smrg fprintf(encfile, "%d\n", numEncodings); 1023245f6787Smrg encodingsToDo = sortList(encodingsToDo); 1024ea6ae205Smrg for(lp = encodingsToDo; lp; lp = lp->next) { 1025ea6ae205Smrg fprintf(encfile, "%s\n", lp->value); 1026ea6ae205Smrg } 1027ea6ae205Smrg fclose (encfile); 1028ea6ae205Smrg } 1029ea6ae205Smrg 1030ea6ae205Smrg free(dirname); 1031ea6ae205Smrg return 1; 1032ea6ae205Smrg} 1033ea6ae205Smrg 1034ea6ae205Smrg#define CODE_IGNORED(c) ((c) < 0x20 || \ 1035ea6ae205Smrg ((c) >= 0x7F && (c) <= 0xA0) || \ 1036ea6ae205Smrg (c) == 0xAD || (c) == 0xF71B) 1037663cdc11Smrg 1038ea6ae205Smrgstatic int 1039ea6ae205SmrgcheckEncoding(FT_Face face, char *encoding_name) 1040ea6ae205Smrg{ 1041ea6ae205Smrg FontEncPtr encoding; 1042ea6ae205Smrg FontMapPtr mapping; 1043ea6ae205Smrg int i, j, c, koi8; 1044ea6ae205Smrg char *n; 1045ea6ae205Smrg 1046ea6ae205Smrg encoding = FontEncFind(encoding_name, NULL); 1047ea6ae205Smrg if(!encoding) 1048ea6ae205Smrg return 0; 1049ea6ae205Smrg 1050ea6ae205Smrg /* An encoding is ``small'' if one of the following is true: 1051ea6ae205Smrg - it is linear and has no more than 256 codepoints; or 1052ea6ae205Smrg - it is a matrix encoding and has no more than one column. 1053663cdc11Smrg 1054ea6ae205Smrg For small encodings using Unicode indices, we require perfect 1055ea6ae205Smrg coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility. 1056ea6ae205Smrg 1057ea6ae205Smrg For large encodings, we require coverage up to bigEncodingFuzz. 1058ea6ae205Smrg 1059ea6ae205Smrg For encodings using PS names (currently Adobe Standard and 1060ea6ae205Smrg Adobe Symbol only), we require perfect coverage. */ 1061ea6ae205Smrg 1062ea6ae205Smrg 1063ea6ae205Smrg if(FT_Has_PS_Glyph_Names(face)) { 1064ea6ae205Smrg for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1065ea6ae205Smrg if(mapping->type == FONT_ENCODING_POSTSCRIPT) { 1066ea6ae205Smrg if(encoding->row_size > 0) { 1067ea6ae205Smrg for(i = encoding->first; i < encoding->size; i++) { 1068663cdc11Smrg for(j = encoding->first_col; 1069663cdc11Smrg j < encoding->row_size; 1070ea6ae205Smrg j++) { 1071ea6ae205Smrg n = FontEncName((i<<8) | j, mapping); 1072ea6ae205Smrg if(n && FT_Get_Name_Index(face, n) == 0) { 1073ea6ae205Smrg return 0; 1074ea6ae205Smrg } 1075ea6ae205Smrg } 1076ea6ae205Smrg } 1077ea6ae205Smrg return 1; 1078ea6ae205Smrg } else { 1079ea6ae205Smrg for(i = encoding->first; i < encoding->size; i++) { 1080ea6ae205Smrg n = FontEncName(i, mapping); 1081ea6ae205Smrg if(n && FT_Get_Name_Index(face, n) == 0) { 1082ea6ae205Smrg return 0; 1083ea6ae205Smrg } 1084ea6ae205Smrg } 1085ea6ae205Smrg return 1; 1086ea6ae205Smrg } 1087ea6ae205Smrg } 1088ea6ae205Smrg } 1089ea6ae205Smrg } 1090ea6ae205Smrg 1091ea6ae205Smrg for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1092ea6ae205Smrg if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) { 1093ea6ae205Smrg int total = 0, failed = 0; 1094ea6ae205Smrg if(encoding->row_size > 0) { 1095663cdc11Smrg int estimate = 1096ea6ae205Smrg (encoding->size - encoding->first) * 1097ea6ae205Smrg (encoding->row_size - encoding->first_col); 1098ea6ae205Smrg for(i = encoding->first; i < encoding->size; i++) { 1099663cdc11Smrg for(j = encoding->first_col; 1100663cdc11Smrg j < encoding->row_size; 1101ea6ae205Smrg j++) { 1102ea6ae205Smrg c = FontEncRecode((i<<8) | j, mapping); 1103ea6ae205Smrg if(CODE_IGNORED(c)) { 1104ea6ae205Smrg continue; 1105ea6ae205Smrg } else { 1106ea6ae205Smrg if(FT_Get_Char_Index(face, c) == 0) { 1107ea6ae205Smrg failed++; 1108ea6ae205Smrg } 1109ea6ae205Smrg total++; 1110ea6ae205Smrg if((encoding->size <= 1 && failed > 0) || 1111ea6ae205Smrg ((float)failed >= bigEncodingFuzz * estimate)) { 1112ea6ae205Smrg return 0; 1113ea6ae205Smrg } 1114ea6ae205Smrg } 1115ea6ae205Smrg } 1116ea6ae205Smrg } 1117ea6ae205Smrg if((float)failed >= total * bigEncodingFuzz) 1118ea6ae205Smrg return 0; 1119ea6ae205Smrg else 1120ea6ae205Smrg return 1; 1121ea6ae205Smrg } else { 1122ea6ae205Smrg int estimate = encoding->size - encoding->first; 1123ea6ae205Smrg /* For the KOI8 encodings, we ignore the lack of 1124ea6ae205Smrg linedrawing and pseudo-math characters */ 1125ea6ae205Smrg if(strncmp(encoding->name, "koi8-", 5) == 0) 1126ea6ae205Smrg koi8 = 1; 1127ea6ae205Smrg else 1128ea6ae205Smrg koi8 = 0; 1129ea6ae205Smrg for(i = encoding->first; i < encoding->size; i++) { 1130ea6ae205Smrg c = FontEncRecode(i, mapping); 1131ea6ae205Smrg if(CODE_IGNORED(c) || 1132ea6ae205Smrg (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) { 1133ea6ae205Smrg continue; 1134ea6ae205Smrg } else { 1135ea6ae205Smrg if(FT_Get_Char_Index(face, c) == 0) { 1136ea6ae205Smrg failed++; 1137ea6ae205Smrg } 1138ea6ae205Smrg total++; 1139ea6ae205Smrg if((encoding->size <= 256 && failed > 0) || 1140ea6ae205Smrg ((float)failed >= bigEncodingFuzz * estimate)) { 1141ea6ae205Smrg return 0; 1142ea6ae205Smrg } 1143ea6ae205Smrg } 1144ea6ae205Smrg } 1145ea6ae205Smrg if((float)failed >= total * bigEncodingFuzz) 1146ea6ae205Smrg return 0; 1147ea6ae205Smrg else 1148ea6ae205Smrg return 1; 1149ea6ae205Smrg } 1150ea6ae205Smrg } 1151ea6ae205Smrg } 1152ea6ae205Smrg return 0; 1153ea6ae205Smrg} 1154ea6ae205Smrg 1155663cdc11Smrgstatic int 1156ea6ae205Smrgfind_cmap(int type, int pid, int eid, FT_Face face) 1157ea6ae205Smrg{ 1158ea6ae205Smrg int i, n, rc; 1159ea6ae205Smrg FT_CharMap cmap = NULL; 1160ea6ae205Smrg 1161ea6ae205Smrg n = face->num_charmaps; 1162ea6ae205Smrg 1163ea6ae205Smrg switch(type) { 1164ea6ae205Smrg case FONT_ENCODING_TRUETYPE: /* specific cmap */ 1165ea6ae205Smrg for(i=0; i<n; i++) { 1166ea6ae205Smrg cmap = face->charmaps[i]; 1167ea6ae205Smrg if(cmap->platform_id == pid && cmap->encoding_id == eid) { 1168ea6ae205Smrg rc = FT_Set_Charmap(face, cmap); 1169ea6ae205Smrg if(rc == 0) 1170ea6ae205Smrg return 1; 1171ea6ae205Smrg } 1172ea6ae205Smrg } 1173ea6ae205Smrg break; 1174ea6ae205Smrg case FONT_ENCODING_UNICODE: /* any Unicode cmap */ 1175ea6ae205Smrg /* prefer Microsoft Unicode */ 1176ea6ae205Smrg for(i=0; i<n; i++) { 1177ea6ae205Smrg cmap = face->charmaps[i]; 1178663cdc11Smrg if(cmap->platform_id == TT_PLATFORM_MICROSOFT && 1179ea6ae205Smrg cmap->encoding_id == TT_MS_ID_UNICODE_CS) { 1180ea6ae205Smrg rc = FT_Set_Charmap(face, cmap); 1181ea6ae205Smrg if(rc == 0) 1182ea6ae205Smrg return 1; 1183ea6ae205Smrg } 1184ea6ae205Smrg } 1185ea6ae205Smrg /* Try Apple Unicode */ 1186ea6ae205Smrg for(i=0; i<n; i++) { 1187ea6ae205Smrg cmap = face->charmaps[i]; 1188ea6ae205Smrg if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { 1189ea6ae205Smrg rc = FT_Set_Charmap(face, cmap); 1190ea6ae205Smrg if(rc == 0) 1191ea6ae205Smrg return 1; 1192ea6ae205Smrg } 1193ea6ae205Smrg } 1194ea6ae205Smrg /* ISO Unicode? */ 1195ea6ae205Smrg for(i=0; i<n; i++) { 1196ea6ae205Smrg cmap = face->charmaps[i]; 1197ea6ae205Smrg if(cmap->platform_id == TT_PLATFORM_ISO) { 1198ea6ae205Smrg rc = FT_Set_Charmap(face, cmap); 1199ea6ae205Smrg if(rc == 0) 1200ea6ae205Smrg return 1; 1201ea6ae205Smrg } 1202ea6ae205Smrg } 1203ea6ae205Smrg break; 1204ea6ae205Smrg default: 1205ea6ae205Smrg return 0; 1206ea6ae205Smrg } 1207ea6ae205Smrg return 0; 1208ea6ae205Smrg} 1209ea6ae205Smrg 1210ea6ae205Smrgstatic int 1211ea6ae205SmrgcheckExtraEncoding(FT_Face face, char *encoding_name, int found) 1212ea6ae205Smrg{ 1213ea6ae205Smrg int c; 1214ea6ae205Smrg 1215ea6ae205Smrg if(strcasecmp(encoding_name, "iso10646-1") == 0) { 1216ea6ae205Smrg if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) { 1217ea6ae205Smrg int found = 0; 1218ea6ae205Smrg /* Export as Unicode if there are at least 15 BMP 1219ea6ae205Smrg characters that are not a space or ignored. */ 1220ea6ae205Smrg for(c = 0x21; c < 0x10000; c++) { 1221ea6ae205Smrg if(CODE_IGNORED(c)) 1222ea6ae205Smrg continue; 1223ea6ae205Smrg if(FT_Get_Char_Index(face, c) > 0) 1224ea6ae205Smrg found++; 1225ea6ae205Smrg if(found >= 15) 1226ea6ae205Smrg return 1; 1227ea6ae205Smrg } 1228ea6ae205Smrg return 0; 1229ea6ae205Smrg } else 1230ea6ae205Smrg return 0; 1231ea6ae205Smrg } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { 1232ea6ae205Smrg if(find_cmap(FONT_ENCODING_TRUETYPE, 1233ea6ae205Smrg TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, 1234ea6ae205Smrg face)) 1235ea6ae205Smrg return 1; 1236ea6ae205Smrg else 1237ea6ae205Smrg return 0; 1238ea6ae205Smrg } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) { 1239ea6ae205Smrg if(!found) { 1240ea6ae205Smrg if(FT_Has_PS_Glyph_Names(face)) 1241ea6ae205Smrg return 1; 1242ea6ae205Smrg else 1243ea6ae205Smrg return 0; 1244ea6ae205Smrg } else 1245ea6ae205Smrg return 0; 1246ea6ae205Smrg } else { 1247ea6ae205Smrg fprintf(stderr, "Unknown extra encoding %s\n", encoding_name); 1248ea6ae205Smrg return 0; 1249ea6ae205Smrg } 1250ea6ae205Smrg} 1251ea6ae205Smrg 1252663cdc11Smrgstatic const char* 1253663cdc11Smrgnotice_foundry(const char *notice) 1254ea6ae205Smrg{ 1255ea6ae205Smrg int i; 1256ea6ae205Smrg for(i = 0; i < countof(notice_foundries); i++) 1257ea6ae205Smrg if(notice && strstr(notice, notice_foundries[i][0])) 1258ea6ae205Smrg return notice_foundries[i][1]; 1259ea6ae205Smrg return NULL; 1260ea6ae205Smrg} 1261ea6ae205Smrg 1262ea6ae205Smrgstatic int 1263663cdc11Smrgvendor_match(const signed char *vendor, const char *vendor_string) 1264ea6ae205Smrg{ 1265ea6ae205Smrg /* vendor is not necessarily NUL-terminated. */ 1266ea6ae205Smrg int i, len; 1267ea6ae205Smrg len = strlen(vendor_string); 1268ea6ae205Smrg if(memcmp(vendor, vendor_string, len) != 0) 1269ea6ae205Smrg return 0; 1270ea6ae205Smrg for(i = len; i < 4; i++) 1271ea6ae205Smrg if(vendor[i] != ' ' && vendor[i] != '\0') 1272ea6ae205Smrg return 0; 1273ea6ae205Smrg return 1; 1274ea6ae205Smrg} 1275ea6ae205Smrg 1276663cdc11Smrgstatic const char* 1277663cdc11Smrgvendor_foundry(const signed char *vendor) 1278ea6ae205Smrg{ 1279ea6ae205Smrg int i; 1280ea6ae205Smrg for(i = 0; i < countof(vendor_foundries); i++) 1281ea6ae205Smrg if(vendor_match(vendor, vendor_foundries[i][0])) 1282ea6ae205Smrg return vendor_foundries[i][1]; 1283ea6ae205Smrg return NULL; 1284ea6ae205Smrg} 1285ea6ae205Smrg 1286ea6ae205Smrgstatic int 1287ea6ae205SmrgreadEncodings(ListPtr encodings, char *dirname) 1288ea6ae205Smrg{ 1289ea6ae205Smrg char *fullname; 1290ea6ae205Smrg DIR *dirp; 1291ea6ae205Smrg struct dirent *file; 1292ea6ae205Smrg char **names, **name; 1293ea6ae205Smrg 1294ea6ae205Smrg if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/') 1295ea6ae205Smrg dirname[strlen(dirname) - 1] = '\0'; 1296ea6ae205Smrg 1297ea6ae205Smrg dirp = opendir(dirname); 1298ea6ae205Smrg if(dirp == NULL) { 1299ea6ae205Smrg perror("opendir"); 1300ea6ae205Smrg return -1; 1301ea6ae205Smrg } 1302ea6ae205Smrg 1303ea6ae205Smrg while((file = readdir(dirp)) != NULL) { 1304ea6ae205Smrg fullname = dsprintf("%s/%s", dirname, file->d_name); 1305ea6ae205Smrg if(fullname == NULL) { 1306ea6ae205Smrg fprintf(stderr, "Couldn't allocate fullname\n"); 1307ea6ae205Smrg closedir(dirp); 1308ea6ae205Smrg return -1; 1309ea6ae205Smrg } 1310663cdc11Smrg 1311ea6ae205Smrg names = FontEncIdentify(fullname); 1312ea6ae205Smrg if(!names) 1313ea6ae205Smrg continue; 1314ea6ae205Smrg 1315ea6ae205Smrg for(name = names; *name; name++) { 1316ea6ae205Smrg if(fullname[0] != '/' && !relative) { 1317ea6ae205Smrg char *n; 1318ea6ae205Smrg n = dsprintf("%s%s", encodingPrefix, fullname); 1319ea6ae205Smrg if(n == NULL) { 1320ea6ae205Smrg fprintf(stderr, "Couldn't allocate name\n"); 1321ea6ae205Smrg closedir(dirp); 1322ea6ae205Smrg return -1; 1323ea6ae205Smrg } 1324ea6ae205Smrg encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n); 1325ea6ae205Smrg free(n); 1326ea6ae205Smrg } else { 1327663cdc11Smrg encodingsToDo = 1328ea6ae205Smrg listConsF(encodingsToDo, "%s %s", *name, fullname); 1329ea6ae205Smrg } 1330ea6ae205Smrg if(encodingsToDo == NULL) { 1331ea6ae205Smrg fprintf(stderr, "Couldn't allocate encodings\n"); 1332ea6ae205Smrg closedir(dirp); 1333ea6ae205Smrg return -1; 1334ea6ae205Smrg } 1335ea6ae205Smrg } 1336ea6ae205Smrg free(names); /* only the spine */ 1337ea6ae205Smrg } 1338ea6ae205Smrg closedir(dirp); 1339ea6ae205Smrg return 0; 1340ea6ae205Smrg} 1341