mkfontscale.c revision 663cdc11
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
23ea6ae205Smrg#include <stdio.h>
24ea6ae205Smrg#include <stdlib.h>
25ea6ae205Smrg#include <string.h>
26ea6ae205Smrg
27ea6ae205Smrg#include <sys/types.h>
28ea6ae205Smrg#include <dirent.h>
29ea6ae205Smrg#include <unistd.h>
30ea6ae205Smrg#include <errno.h>
31ea6ae205Smrg#include <ctype.h>
32ea6ae205Smrg
33ea6ae205Smrg#include <X11/Xos.h>
34ea6ae205Smrg#include <X11/fonts/fontenc.h>
35ea6ae205Smrg#include <ft2build.h>
36ea6ae205Smrg#include FT_FREETYPE_H
37ea6ae205Smrg#include FT_SFNT_NAMES_H
38ea6ae205Smrg#include FT_TRUETYPE_TABLES_H
39ea6ae205Smrg#include FT_TRUETYPE_IDS_H
40ea6ae205Smrg#include FT_TYPE1_TABLES_H
41ea6ae205Smrg#include FT_BDF_H
42ea6ae205Smrg#include FT_XFREE86_H
43ea6ae205Smrg
44ea6ae205Smrg#include "list.h"
45ea6ae205Smrg#include "hash.h"
46ea6ae205Smrg#include "data.h"
47ea6ae205Smrg#include "ident.h"
48ea6ae205Smrg
49ea6ae205Smrg#define NPREFIX 1024
50ea6ae205Smrg
51ea6ae205Smrg#ifndef MAXFONTFILENAMELEN
52ea6ae205Smrg#define MAXFONTFILENAMELEN 1024
53ea6ae205Smrg#endif
54ea6ae205Smrg#ifndef MAXFONTNAMELEN
55ea6ae205Smrg#define MAXFONTNAMELEN 1024
56ea6ae205Smrg#endif
57ea6ae205Smrg
58245f6787Smrg/* Two levels of macro calls are needed so that we stringify the value
59245f6787Smrg   of MAXFONT... and not the string "MAXFONT..." */
60245f6787Smrg#define QUOTE(x)	#x
61245f6787Smrg#define STRINGIFY(x)	QUOTE(x)
62245f6787Smrg
63663cdc11Smrgstatic const char *encodings_array[] =
64ea6ae205Smrg    { "ascii-0",
65ea6ae205Smrg      "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
66ea6ae205Smrg      "iso8859-6", "iso8859-6.8", "iso8859-6.8x", "iso8859-6.16",
67ea6ae205Smrg      "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10",
68ea6ae205Smrg      "iso8859-11", "iso8859-12", "iso8859-13", "iso8859-14",
69ea6ae205Smrg      "iso8859-15", "iso8859-16",
70ea6ae205Smrg      "ansi-1251", "koi8-r", "koi8-u", "koi8-ru", "koi8-e", "koi8-uni",
71ea6ae205Smrg      "tis620-2",
72ea6ae205Smrg      "sun.unicode.india-0", "suneu-greek",
73ea6ae205Smrg      "adobe-standard", "adobe-symbol",
74ea6ae205Smrg      "ibm-cp437", "ibm-cp850", "ibm-cp852", "ibm-cp866", "microsoft-cp1252",
75ea6ae205Smrg      /* But not "adobe-dingbats", as it uses generic glyph names. */
76ea6ae205Smrg      "cns11643-1", "cns11643-2", "cns11643-3",
77ea6ae205Smrg      "jisx0201.1976-0", "jisx0208.1983-0", "jisx0208.1990-0",
78ea6ae205Smrg      "jisx0212.1990-0", "big5-0", "big5.eten-0", "big5hkscs-0",
79ea6ae205Smrg      "gb2312.1980-0", "gb18030.2000-0", "gb18030.2000-1",
80ea6ae205Smrg      "ksc5601.1987-0", "ksc5601.1992-3"};
81ea6ae205Smrg
82663cdc11Smrgstatic const char *extra_encodings_array[] =
83ea6ae205Smrg    { "iso10646-1", "adobe-fontspecific", "microsoft-symbol" };
84ea6ae205Smrg
85e83ac88aSmrgstatic ListPtr encodings, extra_encodings;
86663cdc11Smrgstatic const char *outfilename;
87ea6ae205Smrg
88ea6ae205Smrg#define countof(_a) (sizeof(_a)/sizeof((_a)[0]))
89ea6ae205Smrg
90663cdc11Smrgstatic int doDirectory(const char*, int, ListPtr);
91ea6ae205Smrgstatic int checkEncoding(FT_Face face, char *encoding_name);
92ea6ae205Smrgstatic int checkExtraEncoding(FT_Face face, char *encoding_name, int found);
93ea6ae205Smrgstatic int find_cmap(int type, int pid, int eid, FT_Face face);
94663cdc11Smrgstatic const char* notice_foundry(const char *notice);
95663cdc11Smrgstatic const char* vendor_foundry(const signed char *vendor);
96ea6ae205Smrgstatic int readFontScale(HashTablePtr entries, char *dirname);
97ea6ae205SmrgListPtr makeXLFD(char *filename, FT_Face face, int);
98ea6ae205Smrgstatic int readEncodings(ListPtr encodings, char *dirname);
99ea6ae205Smrg
100ea6ae205Smrgstatic FT_Library ft_library;
101ea6ae205Smrgstatic float bigEncodingFuzz = 0.02;
102ea6ae205Smrg
103ea6ae205Smrgstatic int relative;
104ea6ae205Smrgstatic int doScalable;
105ea6ae205Smrgstatic int doBitmaps;
106ea6ae205Smrgstatic int doISO10646_1_encoding;
107ea6ae205Smrgstatic int onlyEncodings;
108ea6ae205Smrgstatic ListPtr encodingsToDo;
109ea6ae205Smrgstatic int reencodeLegacy;
110ea6ae205Smrgstatic char *encodingPrefix;
111ea6ae205Smrgstatic char *exclusionSuffix;
112ea6ae205Smrg
113ea6ae205Smrgstatic void
114ea6ae205Smrgusage(void)
115ea6ae205Smrg{
116663cdc11Smrg    fprintf(stderr,
117ea6ae205Smrg            "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n"
118ea6ae205Smrg            "            [ -a encoding ] [ -f fuzz ] [ -l ] "
119ea6ae205Smrg            "            [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n"
120ea6ae205Smrg            "            [-u] [-U] [ directory ]...\n");
121ea6ae205Smrg}
122ea6ae205Smrg
123ea6ae205Smrgint
124ea6ae205Smrgmain(int argc, char **argv)
125ea6ae205Smrg{
126ea6ae205Smrg    int argn;
127ea6ae205Smrg    FT_Error ftrc;
128ea6ae205Smrg    int rc, ll = 0;
129ea6ae205Smrg    char prefix[NPREFIX];
130ea6ae205Smrg
131ea6ae205Smrg    encodingPrefix = NULL;
132ea6ae205Smrg    exclusionSuffix = NULL;
133ea6ae205Smrg
134ea6ae205Smrg    if(getcwd(prefix, NPREFIX - 1) == NULL) {
135ea6ae205Smrg        perror("Couldn't get cwd");
136ea6ae205Smrg        exit(1);
137ea6ae205Smrg    }
138ea6ae205Smrg    if(prefix[strlen(prefix) - 1] != '/')
139ea6ae205Smrg        strcat(prefix, "/");
140ea6ae205Smrg    encodingPrefix = dsprintf("%s", prefix);
141ea6ae205Smrg
142ea6ae205Smrg    outfilename = NULL;
143ea6ae205Smrg
144ea6ae205Smrg    encodings = makeList(encodings_array, countof(encodings_array), NULL, 0);
145ea6ae205Smrg
146663cdc11Smrg    extra_encodings = makeList(extra_encodings_array,
147ea6ae205Smrg                               countof(extra_encodings_array),
148ea6ae205Smrg                               NULL, 0);
149ea6ae205Smrg    doBitmaps = 0;
150ea6ae205Smrg    doISO10646_1_encoding = 1;
151ea6ae205Smrg    doScalable = 1;
152ea6ae205Smrg    onlyEncodings = 0;
153ea6ae205Smrg    relative = 0;
154ea6ae205Smrg    reencodeLegacy = 1;
155ea6ae205Smrg    encodingsToDo = NULL;
156ea6ae205Smrg
157ea6ae205Smrg    argn = 1;
158ea6ae205Smrg    while(argn < argc) {
159ea6ae205Smrg        if(argv[argn][0] == '\0' || argv[argn][0] != '-')
160ea6ae205Smrg            break;
161ea6ae205Smrg        if(argv[argn][1] == '-') {
162ea6ae205Smrg            argn++;
163ea6ae205Smrg            break;
164ea6ae205Smrg        } else if (strcmp(argv[argn], "-x") == 0) {
165ea6ae205Smrg            if(argn >= argc - 1) {
166ea6ae205Smrg                usage();
167ea6ae205Smrg                exit(1);
168ea6ae205Smrg            }
169ea6ae205Smrg            exclusionSuffix = argv[argn + 1];
170ea6ae205Smrg            argn += 2;
171ea6ae205Smrg        } else if(strcmp(argv[argn], "-a") == 0) {
172ea6ae205Smrg            if(argn >= argc - 1) {
173ea6ae205Smrg                usage();
174ea6ae205Smrg                exit(1);
175ea6ae205Smrg            }
176ea6ae205Smrg            makeList(&argv[argn + 1], 1, encodings, 0);
177ea6ae205Smrg            argn += 2;
178ea6ae205Smrg        } else if(strcmp(argv[argn], "-p") == 0) {
179ea6ae205Smrg            if(argn >= argc - 1) {
180ea6ae205Smrg                usage();
181ea6ae205Smrg                exit(1);
182ea6ae205Smrg            }
183ea6ae205Smrg            if(strlen(argv[argn + 1]) > NPREFIX - 1) {
184ea6ae205Smrg                usage();
185ea6ae205Smrg                exit(1);
186ea6ae205Smrg            }
187ea6ae205Smrg            free(encodingPrefix);
188ea6ae205Smrg            encodingPrefix = dsprintf("%s", argv[argn + 1]);
189ea6ae205Smrg            argn += 2;
190ea6ae205Smrg        } else if(strcmp(argv[argn], "-e") == 0) {
191ea6ae205Smrg            if(argn >= argc - 1) {
192ea6ae205Smrg                usage();
193ea6ae205Smrg                exit(1);
194ea6ae205Smrg            }
195ea6ae205Smrg            rc = readEncodings(encodingsToDo, argv[argn + 1]);
196ea6ae205Smrg            if(rc < 0)
197ea6ae205Smrg                exit(1);
198ea6ae205Smrg            argn += 2;
199ea6ae205Smrg        } else if(strcmp(argv[argn], "-b") == 0) {
200ea6ae205Smrg            doBitmaps = 1;
201ea6ae205Smrg            argn++;
202ea6ae205Smrg        } else if(strcmp(argv[argn], "-u") == 0) {
203ea6ae205Smrg            doISO10646_1_encoding = 0;
204ea6ae205Smrg            argn++;
205ea6ae205Smrg        } else if(strcmp(argv[argn], "-U") == 0) {
206ea6ae205Smrg            doISO10646_1_encoding = 1;
207663cdc11Smrg            argn++;
208ea6ae205Smrg        } else if(strcmp(argv[argn], "-s") == 0) {
209ea6ae205Smrg            doScalable = 0;
210ea6ae205Smrg            argn++;
211ea6ae205Smrg        } else if(strcmp(argv[argn], "-n") == 0) {
212ea6ae205Smrg            onlyEncodings = 1;
213ea6ae205Smrg            argn++;
214ea6ae205Smrg        } else if(strcmp(argv[argn], "-r") == 0) {
215ea6ae205Smrg            relative = 1;
216ea6ae205Smrg            argn++;
217ea6ae205Smrg        } else if(strcmp(argv[argn], "-l") == 0) {
218ea6ae205Smrg            reencodeLegacy = !reencodeLegacy;
219ea6ae205Smrg            argn++;
220ea6ae205Smrg        } else if(strcmp(argv[argn], "-o") == 0) {
221ea6ae205Smrg            if(argn >= argc - 1) {
222ea6ae205Smrg                usage();
223ea6ae205Smrg                exit(1);
224ea6ae205Smrg            }
225ea6ae205Smrg            outfilename = argv[argn + 1];
226ea6ae205Smrg            argn += 2;
227ea6ae205Smrg        } else if(strcmp(argv[argn], "-f") == 0) {
228ea6ae205Smrg            if(argn >= argc - 1) {
229ea6ae205Smrg                usage();
230ea6ae205Smrg                exit(1);
231ea6ae205Smrg            }
232ea6ae205Smrg            bigEncodingFuzz = atof(argv[argn + 1]) / 100.0;
233ea6ae205Smrg            argn += 2;
234ea6ae205Smrg        } else if (strcmp(argv[argn], "-r") == 0) { /* ignore for now */
235ea6ae205Smrg	    argn++;
236ea6ae205Smrg	} else if (strcmp(argv[argn], "-n") == 0) {
237ea6ae205Smrg	    argn++;
238ea6ae205Smrg	} else {
239ea6ae205Smrg            usage();
240ea6ae205Smrg            exit(1);
241ea6ae205Smrg        }
242ea6ae205Smrg    }
243ea6ae205Smrg
244ea6ae205Smrg    if(outfilename == NULL) {
245ea6ae205Smrg        if(doBitmaps)
246ea6ae205Smrg            outfilename = "fonts.dir";
247663cdc11Smrg        else
248ea6ae205Smrg            outfilename = "fonts.scale";
249ea6ae205Smrg    }
250ea6ae205Smrg
251ea6ae205Smrg    ftrc = FT_Init_FreeType(&ft_library);
252ea6ae205Smrg    if(ftrc) {
253ea6ae205Smrg        fprintf(stderr, "Could not initialise FreeType library: %d\n", ftrc);
254ea6ae205Smrg        exit(1);
255ea6ae205Smrg    }
256ea6ae205Smrg
257ea6ae205Smrg    ll = listLength(encodingsToDo);
258ea6ae205Smrg
259ea6ae205Smrg    if (argn == argc)
260ea6ae205Smrg        doDirectory(".", ll, encodingsToDo);
261ea6ae205Smrg    else
262ea6ae205Smrg        while(argn < argc) {
263ea6ae205Smrg            doDirectory(argv[argn], ll, encodingsToDo);
264ea6ae205Smrg            argn++;
265ea6ae205Smrg        }
266ea6ae205Smrg    return 0;
267ea6ae205Smrg}
268ea6ae205Smrg
269ea6ae205Smrgstatic int
270ea6ae205SmrggetNameHelper(FT_Face face, int nid, int pid, int eid,
271ea6ae205Smrg              FT_SfntName *name_return)
272ea6ae205Smrg{
273ea6ae205Smrg    FT_SfntName name;
274ea6ae205Smrg    int n, i;
275ea6ae205Smrg
276ea6ae205Smrg    n = FT_Get_Sfnt_Name_Count(face);
277ea6ae205Smrg    if(n <= 0)
278ea6ae205Smrg        return 0;
279ea6ae205Smrg
280ea6ae205Smrg    for(i = 0; i < n; i++) {
281ea6ae205Smrg        if(FT_Get_Sfnt_Name(face, i, &name))
282ea6ae205Smrg            continue;
283ea6ae205Smrg        if(name.name_id == nid &&
284ea6ae205Smrg           name.platform_id == pid &&
285ea6ae205Smrg           (eid < 0 || name.encoding_id == eid)) {
286ea6ae205Smrg            switch(name.platform_id) {
287ea6ae205Smrg            case TT_PLATFORM_APPLE_UNICODE:
288ea6ae205Smrg            case TT_PLATFORM_MACINTOSH:
289ea6ae205Smrg                if(name.language_id != TT_MAC_LANGID_ENGLISH)
290ea6ae205Smrg                    continue;
291ea6ae205Smrg                break;
292ea6ae205Smrg            case TT_PLATFORM_MICROSOFT:
293ea6ae205Smrg                if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
294ea6ae205Smrg                   name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
295ea6ae205Smrg                    continue;
296ea6ae205Smrg                break;
297ea6ae205Smrg            default:
298ea6ae205Smrg                continue;
299ea6ae205Smrg            }
300ea6ae205Smrg            if(name.string_len > 0) {
301ea6ae205Smrg                *name_return = name;
302ea6ae205Smrg                return 1;
303ea6ae205Smrg            }
304ea6ae205Smrg        }
305ea6ae205Smrg    }
306ea6ae205Smrg    return 0;
307ea6ae205Smrg}
308ea6ae205Smrg
309ea6ae205Smrgstatic char *
310ea6ae205SmrggetName(FT_Face face, int nid)
311ea6ae205Smrg{
312ea6ae205Smrg    FT_SfntName name;
313ea6ae205Smrg    char *string;
314ea6ae205Smrg    int i;
315ea6ae205Smrg
316663cdc11Smrg    if(getNameHelper(face, nid,
317ea6ae205Smrg                     TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) ||
318663cdc11Smrg       getNameHelper(face, nid,
319ea6ae205Smrg                     TT_PLATFORM_APPLE_UNICODE, -1, &name)) {
320ea6ae205Smrg        string = malloc(name.string_len / 2 + 1);
321ea6ae205Smrg        if(string == NULL) {
322ea6ae205Smrg            fprintf(stderr, "Couldn't allocate name\n");
323ea6ae205Smrg            exit(1);
324ea6ae205Smrg        }
325ea6ae205Smrg        for(i = 0; i < name.string_len / 2; i++) {
326ea6ae205Smrg            if(name.string[2 * i] != 0)
327ea6ae205Smrg                string[i] = '?';
328ea6ae205Smrg            else
329ea6ae205Smrg                string[i] = name.string[2 * i + 1];
330ea6ae205Smrg        }
331ea6ae205Smrg        string[i] = '\0';
332ea6ae205Smrg        return string;
333ea6ae205Smrg    }
334ea6ae205Smrg
335ea6ae205Smrg    /* Pretend that Apple Roman is ISO 8859-1. */
336ea6ae205Smrg    if(getNameHelper(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN,
337ea6ae205Smrg                     &name)) {
338ea6ae205Smrg        string = malloc(name.string_len + 1);
339ea6ae205Smrg        if(string == NULL) {
340ea6ae205Smrg            fprintf(stderr, "Couldn't allocate name\n");
341ea6ae205Smrg            exit(1);
342ea6ae205Smrg        }
343ea6ae205Smrg        memcpy(string, name.string, name.string_len);
344ea6ae205Smrg        string[name.string_len] = '\0';
345ea6ae205Smrg        return string;
346ea6ae205Smrg    }
347ea6ae205Smrg
348ea6ae205Smrg    return NULL;
349ea6ae205Smrg}
350ea6ae205Smrg
351663cdc11Smrgstatic const char*
352ea6ae205Smrgos2Weight(int weight)
353ea6ae205Smrg{
354ea6ae205Smrg    if(weight < 150)
355ea6ae205Smrg        return "thin";
356ea6ae205Smrg    else if(weight < 250)
357ea6ae205Smrg        return "extralight";
358ea6ae205Smrg    else if(weight < 350)
359ea6ae205Smrg        return "light";
360ea6ae205Smrg    else if(weight < 450)
361ea6ae205Smrg        return "medium";        /* officially "normal" */
362ea6ae205Smrg    else if(weight < 550)
363ea6ae205Smrg        return "medium";
364ea6ae205Smrg    else if(weight < 650)
365ea6ae205Smrg        return "semibold";
366ea6ae205Smrg    else if(weight < 750)
367ea6ae205Smrg        return "bold";
368ea6ae205Smrg    else if(weight < 850)
369ea6ae205Smrg        return "extrabold";
370663cdc11Smrg    else
371ea6ae205Smrg        return "black";
372ea6ae205Smrg}
373ea6ae205Smrg
374663cdc11Smrgstatic const char*
375ea6ae205Smrgos2Width(int width)
376ea6ae205Smrg{
377ea6ae205Smrg    if(width <= 1)
378ea6ae205Smrg        return "ultracondensed";
379ea6ae205Smrg    else if(width <= 2)
380ea6ae205Smrg        return "extracondensed";
381ea6ae205Smrg    else if(width <= 3)
382ea6ae205Smrg        return "condensed";
383ea6ae205Smrg    else if(width <= 4)
384ea6ae205Smrg        return "semicondensed";
385ea6ae205Smrg    else if(width <= 5)
386ea6ae205Smrg        return "normal";
387ea6ae205Smrg    else if(width <= 6)
388ea6ae205Smrg        return "semiexpanded";
389ea6ae205Smrg    else if(width <= 7)
390ea6ae205Smrg        return "expanded";
391ea6ae205Smrg    else if(width <= 8)
392ea6ae205Smrg        return "extraexpanded";
393ea6ae205Smrg    else
394ea6ae205Smrg        return "ultraexpanded";
395ea6ae205Smrg}
396ea6ae205Smrg
397663cdc11Smrgstatic const char *widths[] = {
398ea6ae205Smrg    "ultracondensed", "extracondensed", "condensed", "semicondensed",
399663cdc11Smrg    "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded"
400ea6ae205Smrg};
401ea6ae205Smrg
402ea6ae205Smrg#define NUMWIDTHS (sizeof(widths) / sizeof(widths[0]))
403ea6ae205Smrg
404663cdc11Smrgstatic const char*
405663cdc11SmrgnameWidth(const char *name)
406ea6ae205Smrg{
407ea6ae205Smrg    char buf[500];
408ea6ae205Smrg    int i;
409ea6ae205Smrg    int n = strlen(name);
410ea6ae205Smrg
411ea6ae205Smrg    if(n >= 499) return NULL;
412ea6ae205Smrg    for(i = 0; i < n; i++)
413ea6ae205Smrg        buf[i] = tolower(name[i]);
414ea6ae205Smrg    buf[i] = '\0';
415ea6ae205Smrg
416ea6ae205Smrg    for(i = 0; i < NUMWIDTHS; i++)
417ea6ae205Smrg        if(strstr(buf, widths[i]))
418ea6ae205Smrg            return widths[i];
419ea6ae205Smrg    return NULL;
420ea6ae205Smrg}
421ea6ae205Smrg
422663cdc11Smrgstatic const char*
423663cdc11Smrgt1Weight(const char *weight)
424ea6ae205Smrg{
425ea6ae205Smrg    if(!weight)
426ea6ae205Smrg        return NULL;
427ea6ae205Smrg    if(strcmp(weight, "Thin") == 0)
428ea6ae205Smrg        return "thin";
429663cdc11Smrg    if(strcmp(weight, "ExtraLight") == 0) /* FontForge uses this for 200*/
430663cdc11Smrg        return "extralight";
431ea6ae205Smrg    if(strcmp(weight, "Light") == 0)
432ea6ae205Smrg        return "light";
433ea6ae205Smrg    if(strcmp(weight, "Regular") == 0)
434ea6ae205Smrg        return "medium";
435ea6ae205Smrg    if(strcmp(weight, "Normal") == 0)
436ea6ae205Smrg        return "medium";
437ea6ae205Smrg    if(strcmp(weight, "Medium") == 0)
438ea6ae205Smrg        return "medium";
439ea6ae205Smrg    if(strcmp(weight, "Book") == 0)
440ea6ae205Smrg        return "medium";
441ea6ae205Smrg    if(strcmp(weight, "Roman") == 0) /* Some URW++ fonts do that! */
442ea6ae205Smrg        return "medium";
443ea6ae205Smrg    if(strcmp(weight, "Demi") == 0)
444ea6ae205Smrg        return "semibold";
445ea6ae205Smrg    if(strcmp(weight, "DemiBold") == 0)
446ea6ae205Smrg        return "semibold";
447ea6ae205Smrg    if(strcmp(weight, "SemiBold") == 0) /* some TeX fonts apparently do that */
448ea6ae205Smrg        return "semibold";
449ea6ae205Smrg    else if(strcmp(weight, "Bold") == 0)
450ea6ae205Smrg        return "bold";
451663cdc11Smrg    else if(strcmp(weight, "Heavy") == 0) /* FontForge uses this for 800*/
452663cdc11Smrg        return "extrabold";
453ea6ae205Smrg    else if(strcmp(weight, "Black") == 0)
454ea6ae205Smrg        return "black";
455ea6ae205Smrg    else {
456ea6ae205Smrg        fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight);
457ea6ae205Smrg        return NULL;
458ea6ae205Smrg    }
459ea6ae205Smrg}
460ea6ae205Smrg
461ea6ae205Smrgstatic int
462ea6ae205Smrgunsafe(char c)
463ea6ae205Smrg{
464663cdc11Smrg    return
465ea6ae205Smrg        c < 0x20 || c > 0x7E ||
466ea6ae205Smrg        c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-';
467ea6ae205Smrg}
468ea6ae205Smrg
469663cdc11Smrgstatic const char *
470663cdc11Smrgsafe(const char* s)
471ea6ae205Smrg{
472ea6ae205Smrg    int i, len, safe_flag = 1;
473ea6ae205Smrg    char *t;
474ea6ae205Smrg
475ea6ae205Smrg    i = 0;
476ea6ae205Smrg    while(s[i] != '\0') {
477ea6ae205Smrg        if(unsafe(s[i]))
478ea6ae205Smrg            safe_flag = 0;
479ea6ae205Smrg        i++;
480ea6ae205Smrg    }
481ea6ae205Smrg
482ea6ae205Smrg    if(safe_flag) return s;
483ea6ae205Smrg
484ea6ae205Smrg    len = i;
485ea6ae205Smrg    t = malloc(len + 1);
486ea6ae205Smrg    if(t == NULL) {
487ea6ae205Smrg        perror("Couldn't allocate string");
488ea6ae205Smrg        exit(1);
489ea6ae205Smrg    }
490ea6ae205Smrg
491ea6ae205Smrg    for(i = 0; i < len; i++) {
492ea6ae205Smrg        if(unsafe(s[i]))
493ea6ae205Smrg            t[i] = ' ';
494ea6ae205Smrg        else
495ea6ae205Smrg            t[i] = s[i];
496ea6ae205Smrg    }
497ea6ae205Smrg    t[i] = '\0';
498ea6ae205Smrg    return t;
499ea6ae205Smrg}
500ea6ae205Smrg
501ea6ae205SmrgListPtr
502ea6ae205SmrgmakeXLFD(char *filename, FT_Face face, int isBitmap)
503ea6ae205Smrg{
504ea6ae205Smrg    ListPtr xlfd = NULL;
505663cdc11Smrg    const char *foundry, *family, *weight, *slant, *sWidth, *adstyle,
506ea6ae205Smrg        *spacing, *full_name;
507ea6ae205Smrg    TT_Header *head;
508ea6ae205Smrg    TT_HoriHeader *hhea;
509ea6ae205Smrg    TT_OS2 *os2;
510ea6ae205Smrg    TT_Postscript *post;
511ea6ae205Smrg    PS_FontInfoRec *t1info, t1info_rec;
512ea6ae205Smrg    int rc;
513ea6ae205Smrg
514ea6ae205Smrg    foundry = NULL;
515ea6ae205Smrg    family = NULL;
516ea6ae205Smrg    weight = NULL;
517ea6ae205Smrg    slant = NULL;
518ea6ae205Smrg    sWidth = NULL;
519ea6ae205Smrg    adstyle = NULL;
520ea6ae205Smrg    spacing = NULL;
521ea6ae205Smrg    full_name = NULL;
522ea6ae205Smrg
523ea6ae205Smrg    head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
524ea6ae205Smrg    hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
525ea6ae205Smrg    os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
526ea6ae205Smrg    post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
527ea6ae205Smrg
528ea6ae205Smrg    rc = FT_Get_PS_Font_Info(face, &t1info_rec);
529ea6ae205Smrg    if(rc == 0)
530ea6ae205Smrg        t1info = &t1info_rec;
531ea6ae205Smrg    else
532ea6ae205Smrg        t1info = NULL;
533663cdc11Smrg
534ea6ae205Smrg    if(!family)
535ea6ae205Smrg        family = getName(face, TT_NAME_ID_FONT_FAMILY);
536ea6ae205Smrg    if(!family)
537ea6ae205Smrg        family = getName(face, TT_NAME_ID_FULL_NAME);
538ea6ae205Smrg    if(!family)
539ea6ae205Smrg        family = getName(face, TT_NAME_ID_PS_NAME);
540ea6ae205Smrg
541ea6ae205Smrg    if(!full_name)
542ea6ae205Smrg        full_name = getName(face, TT_NAME_ID_FULL_NAME);
543ea6ae205Smrg    if(!full_name)
544ea6ae205Smrg        full_name = getName(face, TT_NAME_ID_PS_NAME);
545ea6ae205Smrg
546ea6ae205Smrg    if(os2 && os2->version != 0xFFFF) {
547ea6ae205Smrg        if(!weight)
548ea6ae205Smrg            weight = os2Weight(os2->usWeightClass);
549ea6ae205Smrg        if(!sWidth)
550ea6ae205Smrg            sWidth = os2Width(os2->usWidthClass);
551ea6ae205Smrg        if(!foundry)
552ea6ae205Smrg            foundry = vendor_foundry(os2->achVendID);
553ea6ae205Smrg        if(!slant)
554ea6ae205Smrg            slant = os2->fsSelection & 1 ? "i" : "r";
555ea6ae205Smrg    }
556ea6ae205Smrg
557ea6ae205Smrg    if(post) {
558ea6ae205Smrg        if(!spacing) {
559ea6ae205Smrg            if(post->isFixedPitch) {
560ea6ae205Smrg                if(hhea->min_Left_Side_Bearing >= 0 &&
561ea6ae205Smrg                   hhea->xMax_Extent <= hhea->advance_Width_Max) {
562ea6ae205Smrg                    spacing = "c";
563ea6ae205Smrg                } else {
564ea6ae205Smrg                    spacing = "m";
565ea6ae205Smrg                }
566ea6ae205Smrg            } else {
567ea6ae205Smrg                spacing = "p";
568ea6ae205Smrg            }
569ea6ae205Smrg        }
570ea6ae205Smrg    }
571663cdc11Smrg
572ea6ae205Smrg    if(t1info) {
573ea6ae205Smrg        if(!family)
574ea6ae205Smrg            family = t1info->family_name;
575ea6ae205Smrg        if(!family)
576ea6ae205Smrg            family = t1info->full_name;
577ea6ae205Smrg        if(!full_name)
578ea6ae205Smrg            full_name = t1info->full_name;
579ea6ae205Smrg        if(!foundry)
580ea6ae205Smrg            foundry = notice_foundry(t1info->notice);
581ea6ae205Smrg        if(!weight)
582ea6ae205Smrg            weight = t1Weight(t1info->weight);
583ea6ae205Smrg        if(!spacing)
584ea6ae205Smrg            spacing = t1info->is_fixed_pitch ? "m" : "p";
585ea6ae205Smrg        if(!slant) {
586ea6ae205Smrg            /* Bitstream fonts have positive italic angle. */
587ea6ae205Smrg            slant =
588ea6ae205Smrg                t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ?
589ea6ae205Smrg                "i" : "r";
590ea6ae205Smrg        }
591ea6ae205Smrg    }
592ea6ae205Smrg
593ea6ae205Smrg    if(!full_name) {
594ea6ae205Smrg        fprintf(stderr, "Couldn't determine full name for %s\n", filename);
595ea6ae205Smrg        full_name = filename;
596ea6ae205Smrg    }
597ea6ae205Smrg
598ea6ae205Smrg    if(head) {
599ea6ae205Smrg        if(!slant)
600ea6ae205Smrg            slant = head->Mac_Style & 2 ? "i" : "r";
601ea6ae205Smrg        if(!weight)
602ea6ae205Smrg            weight = head->Mac_Style & 1 ? "bold" : "medium";
603ea6ae205Smrg    }
604ea6ae205Smrg
605ea6ae205Smrg    if(!slant) {
606ea6ae205Smrg        fprintf(stderr, "Couldn't determine slant for %s\n", filename);
607ea6ae205Smrg        slant = "r";
608ea6ae205Smrg    }
609ea6ae205Smrg
610ea6ae205Smrg    if(!weight) {
611ea6ae205Smrg        fprintf(stderr, "Couldn't determine weight for %s\n", filename);
612ea6ae205Smrg        weight = "medium";
613ea6ae205Smrg    }
614ea6ae205Smrg
615ea6ae205Smrg    if(!foundry) {
616ea6ae205Smrg        char *notice;
617ea6ae205Smrg        notice = getName(face, TT_NAME_ID_TRADEMARK);
618ea6ae205Smrg        if(notice) {
619ea6ae205Smrg            foundry = notice_foundry(notice);
620ea6ae205Smrg        }
621ea6ae205Smrg        if(!foundry) {
622ea6ae205Smrg            notice = getName(face, TT_NAME_ID_MANUFACTURER);
623ea6ae205Smrg            if(notice) {
624ea6ae205Smrg                foundry = notice_foundry(notice);
625ea6ae205Smrg            }
626ea6ae205Smrg        }
627ea6ae205Smrg    }
628ea6ae205Smrg
629ea6ae205Smrg    if(strcmp(slant, "i") == 0) {
630ea6ae205Smrg        if(strstr(full_name, "Oblique"))
631ea6ae205Smrg            slant = "o";
632ea6ae205Smrg        if(strstr(full_name, "Slanted"))
633ea6ae205Smrg            slant = "o";
634ea6ae205Smrg    }
635ea6ae205Smrg
636ea6ae205Smrg    if(!sWidth)
637ea6ae205Smrg        sWidth = nameWidth(full_name);
638ea6ae205Smrg
639ea6ae205Smrg    if(!foundry) foundry = "misc";
640ea6ae205Smrg    if(!family) {
641ea6ae205Smrg        fprintf(stderr, "Couldn't get family name for %s\n", filename);
642ea6ae205Smrg        family = filename;
643ea6ae205Smrg    }
644ea6ae205Smrg
645ea6ae205Smrg    if(!weight) weight = "medium";
646ea6ae205Smrg    if(!slant) slant = "r";
647ea6ae205Smrg    if(!sWidth) sWidth = "normal";
648ea6ae205Smrg    if(!adstyle) adstyle = "";
649ea6ae205Smrg    if(!spacing) spacing = "p";
650ea6ae205Smrg
651ea6ae205Smrg    /* Yes, it's a memory leak. */
652ea6ae205Smrg    foundry = safe(foundry);
653ea6ae205Smrg    family = safe(family);
654ea6ae205Smrg
655ea6ae205Smrg    if(!isBitmap) {
656ea6ae205Smrg        xlfd = listConsF(xlfd,
657ea6ae205Smrg                         "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0",
658ea6ae205Smrg                         foundry, family,
659ea6ae205Smrg                         weight, slant, sWidth, adstyle, spacing);
660ea6ae205Smrg    } else {
661ea6ae205Smrg        int i, w, h, xres, yres;
662ea6ae205Smrg        for(i = 0; i < face->num_fixed_sizes; i++) {
663ea6ae205Smrg            w = face->available_sizes[i].width;
664ea6ae205Smrg            h = face->available_sizes[i].height;
665ea6ae205Smrg            xres = 75;
666ea6ae205Smrg            yres = (double)h / w * xres;
667ea6ae205Smrg            xlfd = listConsF(xlfd,
668ea6ae205Smrg                             "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d",
669ea6ae205Smrg                             foundry, family,
670ea6ae205Smrg                             weight, slant, sWidth, adstyle,
671ea6ae205Smrg                             h, (int)(h / (double)yres * 72.27 * 10 + 0.5),
672ea6ae205Smrg                             xres, yres,
673ea6ae205Smrg                             spacing, 60);
674ea6ae205Smrg        }
675ea6ae205Smrg    }
676ea6ae205Smrg    return xlfd;
677ea6ae205Smrg}
678ea6ae205Smrg
679ea6ae205Smrgstatic int
680ea6ae205SmrgreadFontScale(HashTablePtr entries, char *dirname)
681ea6ae205Smrg{
682ea6ae205Smrg    int n = strlen(dirname);
683ea6ae205Smrg    char *filename;
684ea6ae205Smrg    FILE *in;
685ea6ae205Smrg    int rc, count, i;
686245f6787Smrg    char file[MAXFONTFILENAMELEN+1], font[MAXFONTNAMELEN+1];
687ea6ae205Smrg
688ea6ae205Smrg    if(dirname[n - 1] == '/')
689ea6ae205Smrg        filename = dsprintf("%sfonts.scale", dirname);
690ea6ae205Smrg    else
691ea6ae205Smrg        filename = dsprintf("%s/fonts.scale", dirname);
692ea6ae205Smrg    if(filename == NULL)
693ea6ae205Smrg        return -1;
694ea6ae205Smrg
695ea6ae205Smrg    in = fopen(filename, "r");
696ea6ae205Smrg    free(filename);
697ea6ae205Smrg    if(in == NULL) {
698ea6ae205Smrg        if(errno != ENOENT)
699ea6ae205Smrg            perror("open(fonts.scale)");
700ea6ae205Smrg        return -1;
701ea6ae205Smrg    }
702ea6ae205Smrg
703ea6ae205Smrg    rc = fscanf(in, "%d\n", &count);
704ea6ae205Smrg    if(rc != 1) {
705ea6ae205Smrg        fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname);
706ea6ae205Smrg        fclose(in);
707ea6ae205Smrg        return -1;
708ea6ae205Smrg    }
709ea6ae205Smrg
710ea6ae205Smrg    for(i = 0; i < count; i++) {
711245f6787Smrg        rc = fscanf(in,
712245f6787Smrg		    "%" STRINGIFY(MAXFONTFILENAMELEN) "s "
713245f6787Smrg		    "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n",
714245f6787Smrg		    file, font);
715ea6ae205Smrg        if(rc != 2)
716ea6ae205Smrg            break;
717ea6ae205Smrg        putHash(entries, font, file, 100);
718ea6ae205Smrg    }
719ea6ae205Smrg    fclose(in);
720ea6ae205Smrg    return 1;
721ea6ae205Smrg}
722ea6ae205Smrg
723ea6ae205Smrgstatic int
724ea6ae205SmrgfilePrio(char *filename)
725ea6ae205Smrg{
726ea6ae205Smrg    int n = strlen(filename);
727ea6ae205Smrg    if(n < 4)
728ea6ae205Smrg        return 0;
729ea6ae205Smrg    if(strcmp(filename + n - 4, ".otf") == 0)
730ea6ae205Smrg        return 6;
731ea6ae205Smrg    if(strcmp(filename + n - 4, ".OTF") == 0)
732ea6ae205Smrg        return 6;
733ea6ae205Smrg    if(strcmp(filename + n - 4, ".ttf") == 0)
734ea6ae205Smrg        return 5;
735ea6ae205Smrg    if(strcmp(filename + n - 4, ".TTF") == 0)
736ea6ae205Smrg        return 5;
737ea6ae205Smrg    if(strcmp(filename + n - 4, ".pcf") == 0)
738ea6ae205Smrg        return 4;
739ea6ae205Smrg    if(strcmp(filename + n - 4, ".PCF") == 0)
740ea6ae205Smrg        return 4;
741ea6ae205Smrg    if(strcmp(filename + n - 3, ".gz") == 0)
742ea6ae205Smrg        return 3;
7437978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION
7447978d3cdSmrg    if(strcmp(filename + n - 4, ".bz2") == 0)
7457978d3cdSmrg        return 2;
7467978d3cdSmrg#endif
747ea6ae205Smrg    if(strcmp(filename + n - 2, ".Z") == 0)
748ea6ae205Smrg        return 2;
749ea6ae205Smrg    if(strcmp(filename + n - 4, ".bdf") == 0)
750ea6ae205Smrg        return 1;
751ea6ae205Smrg    if(strcmp(filename + n - 4, ".BDF") == 0)
752ea6ae205Smrg        return 1;
753ea6ae205Smrg    return 0;
754ea6ae205Smrg}
755ea6ae205Smrg
756ea6ae205Smrgstatic int
757663cdc11SmrgdoDirectory(const char *dirname_given, int numEncodings, ListPtr encodingsToDo)
758ea6ae205Smrg{
759ea6ae205Smrg    char *dirname, *fontscale_name, *filename, *encdir;
760ea6ae205Smrg    FILE *fontscale, *encfile;
761ea6ae205Smrg    DIR *dirp;
762ea6ae205Smrg    struct dirent *entry;
763ea6ae205Smrg    FT_Error ftrc;
764ea6ae205Smrg    FT_Face face;
765ea6ae205Smrg    ListPtr encoding, xlfd, lp;
766ea6ae205Smrg    HashTablePtr entries;
767ea6ae205Smrg    HashBucketPtr *array;
768ea6ae205Smrg    int i, n, found, rc;
769ea6ae205Smrg    int isBitmap=0,xl=0;
770ea6ae205Smrg
771ea6ae205Smrg    if (exclusionSuffix)
772ea6ae205Smrg        xl = strlen (exclusionSuffix);
773ea6ae205Smrg
774ea6ae205Smrg    i = strlen(dirname_given);
775ea6ae205Smrg    if(i == 0)
776ea6ae205Smrg        dirname = dsprintf("./");
777ea6ae205Smrg    else if(dirname_given[i - 1] != '/')
778ea6ae205Smrg        dirname = dsprintf("%s/", dirname_given);
779ea6ae205Smrg    else
780ea6ae205Smrg        dirname = dsprintf("%s", dirname_given);
781ea6ae205Smrg
782ea6ae205Smrg    if(dirname == NULL) {
783ea6ae205Smrg        perror("dirname");
784ea6ae205Smrg        exit(1);
785ea6ae205Smrg    }
786ea6ae205Smrg
787663cdc11Smrg    if (onlyEncodings)
788ea6ae205Smrg	goto encodings;
789663cdc11Smrg
790ea6ae205Smrg    entries = makeHashTable();
791ea6ae205Smrg    if(doBitmaps && !doScalable) {
792ea6ae205Smrg        readFontScale(entries, dirname);
793ea6ae205Smrg    }
794ea6ae205Smrg
795ea6ae205Smrg    if(strcmp(outfilename, "-") == 0)
796ea6ae205Smrg        fontscale_name = NULL;
797ea6ae205Smrg    else {
798ea6ae205Smrg        if(outfilename[0] == '/')
799ea6ae205Smrg            fontscale_name = dsprintf("%s", outfilename);
800ea6ae205Smrg        else
801ea6ae205Smrg            fontscale_name = dsprintf("%s%s", dirname, outfilename);
802ea6ae205Smrg        if(fontscale_name == NULL) {
803ea6ae205Smrg            perror("fontscale_name");
804ea6ae205Smrg            exit(1);
805ea6ae205Smrg        }
806ea6ae205Smrg    }
807ea6ae205Smrg
808ea6ae205Smrg    dirp = opendir(dirname);
809ea6ae205Smrg    if(dirp == NULL) {
810ea6ae205Smrg        fprintf(stderr, "%s: ", dirname);
811ea6ae205Smrg        perror("opendir");
812ea6ae205Smrg        return 0;
813ea6ae205Smrg    }
814ea6ae205Smrg
815ea6ae205Smrg    if(fontscale_name == NULL)
816ea6ae205Smrg        fontscale = stdout;
817ea6ae205Smrg    else
818ea6ae205Smrg        fontscale = fopen(fontscale_name, "wb");
819ea6ae205Smrg
820ea6ae205Smrg    if(fontscale == NULL) {
821ea6ae205Smrg        fprintf(stderr, "%s: ", fontscale_name);
822ea6ae205Smrg        perror("fopen(w)");
823ea6ae205Smrg        return 0;
824ea6ae205Smrg    }
825ea6ae205Smrg
826ea6ae205Smrg    while((entry = readdir(dirp)) != NULL) {
827ea6ae205Smrg        int have_face = 0;
828ea6ae205Smrg        char *xlfd_name = NULL;
829ea6ae205Smrg        xlfd = NULL;
830ea6ae205Smrg
831ea6ae205Smrg	if (xl) {
832ea6ae205Smrg	    int dl = strlen (entry->d_name);
833ea6ae205Smrg	    if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0)
834ea6ae205Smrg		continue;
835ea6ae205Smrg	}
836ea6ae205Smrg
837ea6ae205Smrg        filename = dsprintf("%s%s", dirname, entry->d_name);
838ea6ae205Smrg
839ea6ae205Smrg        if(doBitmaps)
840ea6ae205Smrg            rc = bitmapIdentify(filename, &xlfd_name);
841ea6ae205Smrg        else
842ea6ae205Smrg            rc = 0;
843ea6ae205Smrg
844ea6ae205Smrg        if(rc < 0)
845ea6ae205Smrg            goto done;
846ea6ae205Smrg
847ea6ae205Smrg        if(rc == 0) {
848ea6ae205Smrg            ftrc = FT_New_Face(ft_library, filename, 0, &face);
849ea6ae205Smrg            if(ftrc)
850ea6ae205Smrg                goto done;
851ea6ae205Smrg            have_face = 1;
852ea6ae205Smrg
853ea6ae205Smrg            isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0);
854ea6ae205Smrg
855ea6ae205Smrg            if(!isBitmap) {
856ea6ae205Smrg                /* Workaround for bitmap-only SFNT fonts */
857ea6ae205Smrg                if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 &&
858ea6ae205Smrg                   strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) {
859ea6ae205Smrg                    TT_MaxProfile *maxp;
860ea6ae205Smrg                    maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp);
861ea6ae205Smrg                    if(maxp != NULL && maxp->maxContours == 0)
862ea6ae205Smrg                        isBitmap = 1;
863ea6ae205Smrg                }
864ea6ae205Smrg            }
865663cdc11Smrg
866ea6ae205Smrg            if(isBitmap) {
867ea6ae205Smrg                if(!doBitmaps)
868ea6ae205Smrg                    goto done;
869ea6ae205Smrg            } else {
870ea6ae205Smrg                if(!doScalable)
871ea6ae205Smrg                    goto done;
872ea6ae205Smrg            }
873ea6ae205Smrg
874ea6ae205Smrg            if(isBitmap) {
875ea6ae205Smrg                BDF_PropertyRec prop;
876ea6ae205Smrg                rc = FT_Get_BDF_Property(face, "FONT", &prop);
877ea6ae205Smrg                if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
878ea6ae205Smrg                    xlfd_name = malloc(strlen(prop.u.atom) + 1);
879ea6ae205Smrg                    if(xlfd_name == NULL)
880ea6ae205Smrg                        goto done;
881ea6ae205Smrg                    strcpy(xlfd_name, prop.u.atom);
882ea6ae205Smrg                }
883ea6ae205Smrg            }
884ea6ae205Smrg        }
885ea6ae205Smrg
886ea6ae205Smrg        if(xlfd_name) {
887ea6ae205Smrg            /* We know it's a bitmap font, and we know its XLFD */
888ea6ae205Smrg            int n = strlen(xlfd_name);
889ea6ae205Smrg            if(reencodeLegacy &&
890ea6ae205Smrg               n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) {
891ea6ae205Smrg                char *s;
892ea6ae205Smrg
893ea6ae205Smrg                s = malloc(n - 10);
894ea6ae205Smrg                memcpy(s, xlfd_name, n - 11);
895ea6ae205Smrg                s[n - 11] = '\0';
896ea6ae205Smrg                xlfd = listCons(s, xlfd);
897ea6ae205Smrg            } else {
898ea6ae205Smrg                /* Not a reencodable font -- skip all the rest of the loop body */
899ea6ae205Smrg                putHash(entries, xlfd_name, entry->d_name, filePrio(entry->d_name));
900ea6ae205Smrg                goto done;
901ea6ae205Smrg            }
902ea6ae205Smrg        }
903ea6ae205Smrg
904ea6ae205Smrg        if(!have_face) {
905ea6ae205Smrg            ftrc = FT_New_Face(ft_library, filename, 0, &face);
906ea6ae205Smrg            if(ftrc)
907ea6ae205Smrg                goto done;
908ea6ae205Smrg            have_face = 1;
909ea6ae205Smrg            isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0);
910ea6ae205Smrg
911ea6ae205Smrg            if(!isBitmap) {
912ea6ae205Smrg                if(face->num_fixed_sizes > 0) {
913ea6ae205Smrg                    TT_MaxProfile *maxp;
914ea6ae205Smrg                    maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp);
915ea6ae205Smrg                    if(maxp != NULL && maxp->maxContours == 0)
916ea6ae205Smrg                        isBitmap = 1;
917ea6ae205Smrg                }
918ea6ae205Smrg            }
919ea6ae205Smrg        }
920ea6ae205Smrg
921ea6ae205Smrg        if(xlfd == NULL)
922ea6ae205Smrg            xlfd = makeXLFD(entry->d_name, face, isBitmap);
923ea6ae205Smrg
924ea6ae205Smrg        found = 0;
925ea6ae205Smrg
926ea6ae205Smrg        for(lp = xlfd; lp; lp = lp->next) {
927ea6ae205Smrg            char buf[MAXFONTNAMELEN];
928ea6ae205Smrg            for(encoding = encodings; encoding; encoding = encoding->next) {
929ea6ae205Smrg                if(checkEncoding(face, encoding->value)) {
930ea6ae205Smrg                    found = 1;
931ea6ae205Smrg                    snprintf(buf, MAXFONTNAMELEN, "%s-%s",
932ea6ae205Smrg                            lp->value, encoding->value);
933ea6ae205Smrg                    putHash(entries, buf, entry->d_name, filePrio(entry->d_name));
934ea6ae205Smrg                }
935ea6ae205Smrg            }
936663cdc11Smrg            for(encoding = extra_encodings; encoding;
937ea6ae205Smrg                encoding = encoding->next) {
938ea6ae205Smrg                if(checkExtraEncoding(face, encoding->value, found)) {
939ea6ae205Smrg                    /* Do not set found! */
940ea6ae205Smrg                    snprintf(buf, MAXFONTNAMELEN, "%s-%s",
941ea6ae205Smrg                            lp->value, encoding->value);
942ea6ae205Smrg                    putHash(entries, buf, entry->d_name, filePrio(entry->d_name));
943ea6ae205Smrg                }
944ea6ae205Smrg            }
945ea6ae205Smrg        }
946ea6ae205Smrg    done:
947245f6787Smrg        if(have_face)
948ea6ae205Smrg            FT_Done_Face(face);
949ea6ae205Smrg        deepDestroyList(xlfd);
950ea6ae205Smrg        xlfd = NULL;
951ea6ae205Smrg        free(filename);
952ea6ae205Smrg    }
953ea6ae205Smrg
954ea6ae205Smrg    closedir(dirp);
955ea6ae205Smrg    n = hashElements(entries);
956ea6ae205Smrg    fprintf(fontscale, "%d\n", n);
957ea6ae205Smrg    array = hashArray(entries, 1);
958ea6ae205Smrg    for(i = 0; i < n; i++)
959ea6ae205Smrg        fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key);
960ea6ae205Smrg    destroyHashArray(array);
961ea6ae205Smrg    entries = NULL;
962ea6ae205Smrg    if(fontscale_name) {
963ea6ae205Smrg        fclose(fontscale);
964ea6ae205Smrg        free(fontscale_name);
965ea6ae205Smrg    }
966ea6ae205Smrg
967ea6ae205Smrg encodings:
968ea6ae205Smrg    encdir = dsprintf("%s%s", dirname, "encodings.dir");
969ea6ae205Smrg
970ea6ae205Smrg    if(encdir == NULL) {
971ea6ae205Smrg	perror("encodings");
972ea6ae205Smrg	exit(1);
973ea6ae205Smrg    }
974ea6ae205Smrg    unlink(encdir);
975ea6ae205Smrg
976ea6ae205Smrg    if (numEncodings) {
977ea6ae205Smrg	encfile = fopen(encdir, "w");
978ea6ae205Smrg	if(encfile == NULL) {
979ea6ae205Smrg	    perror("open(encodings.dir)");
980ea6ae205Smrg	    exit(1);
981ea6ae205Smrg	}
982ea6ae205Smrg        fprintf(encfile, "%d\n", numEncodings);
983245f6787Smrg        encodingsToDo = sortList(encodingsToDo);
984ea6ae205Smrg        for(lp = encodingsToDo; lp; lp = lp->next) {
985ea6ae205Smrg            fprintf(encfile, "%s\n", lp->value);
986ea6ae205Smrg        }
987ea6ae205Smrg	fclose (encfile);
988ea6ae205Smrg    }
989ea6ae205Smrg
990ea6ae205Smrg    free(dirname);
991ea6ae205Smrg    return 1;
992ea6ae205Smrg}
993ea6ae205Smrg
994ea6ae205Smrg#define CODE_IGNORED(c) ((c) < 0x20 || \
995ea6ae205Smrg                         ((c) >= 0x7F && (c) <= 0xA0) || \
996ea6ae205Smrg                         (c) == 0xAD || (c) == 0xF71B)
997663cdc11Smrg
998ea6ae205Smrgstatic int
999ea6ae205SmrgcheckEncoding(FT_Face face, char *encoding_name)
1000ea6ae205Smrg{
1001ea6ae205Smrg    FontEncPtr encoding;
1002ea6ae205Smrg    FontMapPtr mapping;
1003ea6ae205Smrg    int i, j, c, koi8;
1004ea6ae205Smrg    char *n;
1005ea6ae205Smrg
1006ea6ae205Smrg    encoding = FontEncFind(encoding_name, NULL);
1007ea6ae205Smrg    if(!encoding)
1008ea6ae205Smrg        return 0;
1009ea6ae205Smrg
1010ea6ae205Smrg    /* An encoding is ``small'' if one of the following is true:
1011ea6ae205Smrg         - it is linear and has no more than 256 codepoints; or
1012ea6ae205Smrg         - it is a matrix encoding and has no more than one column.
1013663cdc11Smrg
1014ea6ae205Smrg       For small encodings using Unicode indices, we require perfect
1015ea6ae205Smrg       coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility.
1016ea6ae205Smrg
1017ea6ae205Smrg       For large encodings, we require coverage up to bigEncodingFuzz.
1018ea6ae205Smrg
1019ea6ae205Smrg       For encodings using PS names (currently Adobe Standard and
1020ea6ae205Smrg       Adobe Symbol only), we require perfect coverage. */
1021ea6ae205Smrg
1022ea6ae205Smrg
1023ea6ae205Smrg    if(FT_Has_PS_Glyph_Names(face)) {
1024ea6ae205Smrg        for(mapping = encoding->mappings; mapping; mapping = mapping->next) {
1025ea6ae205Smrg            if(mapping->type == FONT_ENCODING_POSTSCRIPT) {
1026ea6ae205Smrg                if(encoding->row_size > 0) {
1027ea6ae205Smrg                    for(i = encoding->first; i < encoding->size; i++) {
1028663cdc11Smrg                        for(j = encoding->first_col;
1029663cdc11Smrg                            j < encoding->row_size;
1030ea6ae205Smrg                            j++) {
1031ea6ae205Smrg                            n = FontEncName((i<<8) | j, mapping);
1032ea6ae205Smrg                            if(n && FT_Get_Name_Index(face, n) == 0) {
1033ea6ae205Smrg                                return 0;
1034ea6ae205Smrg                            }
1035ea6ae205Smrg                        }
1036ea6ae205Smrg                    }
1037ea6ae205Smrg                    return 1;
1038ea6ae205Smrg                } else {
1039ea6ae205Smrg                    for(i = encoding->first; i < encoding->size; i++) {
1040ea6ae205Smrg                        n = FontEncName(i, mapping);
1041ea6ae205Smrg                        if(n && FT_Get_Name_Index(face, n) == 0) {
1042ea6ae205Smrg                            return 0;
1043ea6ae205Smrg                        }
1044ea6ae205Smrg                    }
1045ea6ae205Smrg                    return 1;
1046ea6ae205Smrg                }
1047ea6ae205Smrg            }
1048ea6ae205Smrg        }
1049ea6ae205Smrg    }
1050ea6ae205Smrg
1051ea6ae205Smrg    for(mapping = encoding->mappings; mapping; mapping = mapping->next) {
1052ea6ae205Smrg        if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) {
1053ea6ae205Smrg            int total = 0, failed = 0;
1054ea6ae205Smrg            if(encoding->row_size > 0) {
1055663cdc11Smrg                int estimate =
1056ea6ae205Smrg                    (encoding->size - encoding->first) *
1057ea6ae205Smrg                    (encoding->row_size - encoding->first_col);
1058ea6ae205Smrg                for(i = encoding->first; i < encoding->size; i++) {
1059663cdc11Smrg                    for(j = encoding->first_col;
1060663cdc11Smrg                        j < encoding->row_size;
1061ea6ae205Smrg                        j++) {
1062ea6ae205Smrg                        c = FontEncRecode((i<<8) | j, mapping);
1063ea6ae205Smrg                        if(CODE_IGNORED(c)) {
1064ea6ae205Smrg                            continue;
1065ea6ae205Smrg                        } else {
1066ea6ae205Smrg                            if(FT_Get_Char_Index(face, c) == 0) {
1067ea6ae205Smrg                                failed++;
1068ea6ae205Smrg                            }
1069ea6ae205Smrg                            total++;
1070ea6ae205Smrg                            if((encoding->size <= 1 && failed > 0) ||
1071ea6ae205Smrg                               ((float)failed >= bigEncodingFuzz * estimate)) {
1072ea6ae205Smrg                                return 0;
1073ea6ae205Smrg                            }
1074ea6ae205Smrg                        }
1075ea6ae205Smrg                    }
1076ea6ae205Smrg                }
1077ea6ae205Smrg                if((float)failed >= total * bigEncodingFuzz)
1078ea6ae205Smrg                    return 0;
1079ea6ae205Smrg                else
1080ea6ae205Smrg                    return 1;
1081ea6ae205Smrg            } else {
1082ea6ae205Smrg                int estimate = encoding->size - encoding->first;
1083ea6ae205Smrg                /* For the KOI8 encodings, we ignore the lack of
1084ea6ae205Smrg                   linedrawing and pseudo-math characters */
1085ea6ae205Smrg                if(strncmp(encoding->name, "koi8-", 5) == 0)
1086ea6ae205Smrg                    koi8 = 1;
1087ea6ae205Smrg                else
1088ea6ae205Smrg                    koi8 = 0;
1089ea6ae205Smrg                for(i = encoding->first; i < encoding->size; i++) {
1090ea6ae205Smrg                    c = FontEncRecode(i, mapping);
1091ea6ae205Smrg                    if(CODE_IGNORED(c) ||
1092ea6ae205Smrg                       (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) {
1093ea6ae205Smrg                        continue;
1094ea6ae205Smrg                    } else {
1095ea6ae205Smrg                        if(FT_Get_Char_Index(face, c) == 0) {
1096ea6ae205Smrg                            failed++;
1097ea6ae205Smrg                        }
1098ea6ae205Smrg                        total++;
1099ea6ae205Smrg                        if((encoding->size <= 256 && failed > 0) ||
1100ea6ae205Smrg                           ((float)failed >= bigEncodingFuzz * estimate)) {
1101ea6ae205Smrg                            return 0;
1102ea6ae205Smrg                        }
1103ea6ae205Smrg                    }
1104ea6ae205Smrg                }
1105ea6ae205Smrg                if((float)failed >= total * bigEncodingFuzz)
1106ea6ae205Smrg                    return 0;
1107ea6ae205Smrg                else
1108ea6ae205Smrg                    return 1;
1109ea6ae205Smrg            }
1110ea6ae205Smrg        }
1111ea6ae205Smrg    }
1112ea6ae205Smrg    return 0;
1113ea6ae205Smrg}
1114ea6ae205Smrg
1115663cdc11Smrgstatic int
1116ea6ae205Smrgfind_cmap(int type, int pid, int eid, FT_Face face)
1117ea6ae205Smrg{
1118ea6ae205Smrg    int i, n, rc;
1119ea6ae205Smrg    FT_CharMap cmap = NULL;
1120ea6ae205Smrg
1121ea6ae205Smrg    n = face->num_charmaps;
1122ea6ae205Smrg
1123ea6ae205Smrg    switch(type) {
1124ea6ae205Smrg    case FONT_ENCODING_TRUETYPE:  /* specific cmap */
1125ea6ae205Smrg        for(i=0; i<n; i++) {
1126ea6ae205Smrg            cmap = face->charmaps[i];
1127ea6ae205Smrg            if(cmap->platform_id == pid && cmap->encoding_id == eid) {
1128ea6ae205Smrg                rc = FT_Set_Charmap(face, cmap);
1129ea6ae205Smrg                if(rc == 0)
1130ea6ae205Smrg                    return 1;
1131ea6ae205Smrg            }
1132ea6ae205Smrg        }
1133ea6ae205Smrg        break;
1134ea6ae205Smrg    case FONT_ENCODING_UNICODE:   /* any Unicode cmap */
1135ea6ae205Smrg        /* prefer Microsoft Unicode */
1136ea6ae205Smrg        for(i=0; i<n; i++) {
1137ea6ae205Smrg            cmap = face->charmaps[i];
1138663cdc11Smrg            if(cmap->platform_id == TT_PLATFORM_MICROSOFT &&
1139ea6ae205Smrg               cmap->encoding_id == TT_MS_ID_UNICODE_CS) {
1140ea6ae205Smrg                rc = FT_Set_Charmap(face, cmap);
1141ea6ae205Smrg                if(rc == 0)
1142ea6ae205Smrg                    return 1;
1143ea6ae205Smrg            }
1144ea6ae205Smrg        }
1145ea6ae205Smrg        /* Try Apple Unicode */
1146ea6ae205Smrg        for(i=0; i<n; i++) {
1147ea6ae205Smrg            cmap = face->charmaps[i];
1148ea6ae205Smrg            if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) {
1149ea6ae205Smrg                rc = FT_Set_Charmap(face, cmap);
1150ea6ae205Smrg                if(rc == 0)
1151ea6ae205Smrg                    return 1;
1152ea6ae205Smrg            }
1153ea6ae205Smrg        }
1154ea6ae205Smrg        /* ISO Unicode? */
1155ea6ae205Smrg        for(i=0; i<n; i++) {
1156ea6ae205Smrg            cmap = face->charmaps[i];
1157ea6ae205Smrg            if(cmap->platform_id == TT_PLATFORM_ISO) {
1158ea6ae205Smrg                rc = FT_Set_Charmap(face, cmap);
1159ea6ae205Smrg                if(rc == 0)
1160ea6ae205Smrg                    return 1;
1161ea6ae205Smrg            }
1162ea6ae205Smrg        }
1163ea6ae205Smrg        break;
1164ea6ae205Smrg    default:
1165ea6ae205Smrg        return 0;
1166ea6ae205Smrg    }
1167ea6ae205Smrg    return 0;
1168ea6ae205Smrg}
1169ea6ae205Smrg
1170ea6ae205Smrgstatic int
1171ea6ae205SmrgcheckExtraEncoding(FT_Face face, char *encoding_name, int found)
1172ea6ae205Smrg{
1173ea6ae205Smrg    int c;
1174ea6ae205Smrg
1175ea6ae205Smrg    if(strcasecmp(encoding_name, "iso10646-1") == 0) {
1176ea6ae205Smrg        if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) {
1177ea6ae205Smrg            int found = 0;
1178ea6ae205Smrg             /* Export as Unicode if there are at least 15 BMP
1179ea6ae205Smrg               characters that are not a space or ignored. */
1180ea6ae205Smrg            for(c = 0x21; c < 0x10000; c++) {
1181ea6ae205Smrg                if(CODE_IGNORED(c))
1182ea6ae205Smrg                    continue;
1183ea6ae205Smrg                if(FT_Get_Char_Index(face, c) > 0)
1184ea6ae205Smrg                    found++;
1185ea6ae205Smrg                if(found >= 15)
1186ea6ae205Smrg                    return 1;
1187ea6ae205Smrg            }
1188ea6ae205Smrg            return 0;
1189ea6ae205Smrg        } else
1190ea6ae205Smrg            return 0;
1191ea6ae205Smrg    } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) {
1192ea6ae205Smrg        if(find_cmap(FONT_ENCODING_TRUETYPE,
1193ea6ae205Smrg                     TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS,
1194ea6ae205Smrg                     face))
1195ea6ae205Smrg            return 1;
1196ea6ae205Smrg        else
1197ea6ae205Smrg            return 0;
1198ea6ae205Smrg    } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) {
1199ea6ae205Smrg        if(!found) {
1200ea6ae205Smrg            if(FT_Has_PS_Glyph_Names(face))
1201ea6ae205Smrg                return 1;
1202ea6ae205Smrg            else
1203ea6ae205Smrg                return 0;
1204ea6ae205Smrg        } else
1205ea6ae205Smrg            return 0;
1206ea6ae205Smrg    } else {
1207ea6ae205Smrg        fprintf(stderr, "Unknown extra encoding %s\n", encoding_name);
1208ea6ae205Smrg        return 0;
1209ea6ae205Smrg    }
1210ea6ae205Smrg}
1211ea6ae205Smrg
1212663cdc11Smrgstatic const char*
1213663cdc11Smrgnotice_foundry(const char *notice)
1214ea6ae205Smrg{
1215ea6ae205Smrg    int i;
1216ea6ae205Smrg    for(i = 0; i < countof(notice_foundries); i++)
1217ea6ae205Smrg        if(notice && strstr(notice, notice_foundries[i][0]))
1218ea6ae205Smrg            return notice_foundries[i][1];
1219ea6ae205Smrg    return NULL;
1220ea6ae205Smrg}
1221ea6ae205Smrg
1222ea6ae205Smrgstatic int
1223663cdc11Smrgvendor_match(const signed char *vendor, const char *vendor_string)
1224ea6ae205Smrg{
1225ea6ae205Smrg    /* vendor is not necessarily NUL-terminated. */
1226ea6ae205Smrg    int i, len;
1227ea6ae205Smrg    len = strlen(vendor_string);
1228ea6ae205Smrg    if(memcmp(vendor, vendor_string, len) != 0)
1229ea6ae205Smrg        return 0;
1230ea6ae205Smrg    for(i = len; i < 4; i++)
1231ea6ae205Smrg        if(vendor[i] != ' ' && vendor[i] != '\0')
1232ea6ae205Smrg            return 0;
1233ea6ae205Smrg    return 1;
1234ea6ae205Smrg}
1235ea6ae205Smrg
1236663cdc11Smrgstatic const char*
1237663cdc11Smrgvendor_foundry(const signed char *vendor)
1238ea6ae205Smrg{
1239ea6ae205Smrg    int i;
1240ea6ae205Smrg    for(i = 0; i < countof(vendor_foundries); i++)
1241ea6ae205Smrg        if(vendor_match(vendor, vendor_foundries[i][0]))
1242ea6ae205Smrg            return vendor_foundries[i][1];
1243ea6ae205Smrg    return NULL;
1244ea6ae205Smrg}
1245ea6ae205Smrg
1246ea6ae205Smrgstatic int
1247ea6ae205SmrgreadEncodings(ListPtr encodings, char *dirname)
1248ea6ae205Smrg{
1249ea6ae205Smrg    char *fullname;
1250ea6ae205Smrg    DIR *dirp;
1251ea6ae205Smrg    struct dirent *file;
1252ea6ae205Smrg    char **names, **name;
1253ea6ae205Smrg
1254ea6ae205Smrg    if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/')
1255ea6ae205Smrg        dirname[strlen(dirname) - 1] = '\0';
1256ea6ae205Smrg
1257ea6ae205Smrg    dirp = opendir(dirname);
1258ea6ae205Smrg    if(dirp == NULL) {
1259ea6ae205Smrg        perror("opendir");
1260ea6ae205Smrg        return -1;
1261ea6ae205Smrg    }
1262ea6ae205Smrg
1263ea6ae205Smrg    while((file = readdir(dirp)) != NULL) {
1264ea6ae205Smrg        fullname = dsprintf("%s/%s", dirname, file->d_name);
1265ea6ae205Smrg        if(fullname == NULL) {
1266ea6ae205Smrg            fprintf(stderr, "Couldn't allocate fullname\n");
1267ea6ae205Smrg            closedir(dirp);
1268ea6ae205Smrg            return -1;
1269ea6ae205Smrg        }
1270663cdc11Smrg
1271ea6ae205Smrg        names = FontEncIdentify(fullname);
1272ea6ae205Smrg        if(!names)
1273ea6ae205Smrg            continue;
1274ea6ae205Smrg
1275ea6ae205Smrg        for(name = names; *name; name++) {
1276ea6ae205Smrg            if(fullname[0] != '/' && !relative) {
1277ea6ae205Smrg                char *n;
1278ea6ae205Smrg                n = dsprintf("%s%s", encodingPrefix, fullname);
1279ea6ae205Smrg                if(n == NULL) {
1280ea6ae205Smrg                    fprintf(stderr, "Couldn't allocate name\n");
1281ea6ae205Smrg                    closedir(dirp);
1282ea6ae205Smrg                    return -1;
1283ea6ae205Smrg                }
1284ea6ae205Smrg                encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n);
1285ea6ae205Smrg                free(n);
1286ea6ae205Smrg            } else {
1287663cdc11Smrg                encodingsToDo =
1288ea6ae205Smrg                    listConsF(encodingsToDo, "%s %s", *name, fullname);
1289ea6ae205Smrg            }
1290ea6ae205Smrg            if(encodingsToDo == NULL) {
1291ea6ae205Smrg                fprintf(stderr, "Couldn't allocate encodings\n");
1292ea6ae205Smrg                closedir(dirp);
1293ea6ae205Smrg                return -1;
1294ea6ae205Smrg            }
1295ea6ae205Smrg        }
1296ea6ae205Smrg        free(names);            /* only the spine */
1297ea6ae205Smrg    }
1298ea6ae205Smrg    closedir(dirp);
1299ea6ae205Smrg    return 0;
1300ea6ae205Smrg}
1301