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