1ea6ae205Smrg/*
2ea6ae205Smrg  Copyright (c) 2002-2003 by Juliusz Chroboczek
3ea6ae205Smrg
4ea6ae205Smrg  Permission is hereby granted, free of charge, to any person obtaining a copy
5ea6ae205Smrg  of this software and associated documentation files (the "Software"), to deal
6ea6ae205Smrg  in the Software without restriction, including without limitation the rights
7ea6ae205Smrg  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8ea6ae205Smrg  copies of the Software, and to permit persons to whom the Software is
9ea6ae205Smrg  furnished to do so, subject to the following conditions:
10ea6ae205Smrg
11ea6ae205Smrg  The above copyright notice and this permission notice shall be included in
12ea6ae205Smrg  all copies or substantial portions of the Software.
13ea6ae205Smrg
14ea6ae205Smrg  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15ea6ae205Smrg  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16ea6ae205Smrg  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17ea6ae205Smrg  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18ea6ae205Smrg  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19ea6ae205Smrg  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20ea6ae205Smrg  THE SOFTWARE.
21ea6ae205Smrg*/
22ea6ae205Smrg
2340cc5db4Smrg#ifdef HAVE_CONFIG_H
242d6e8b77Smrg#include "config.h"
2540cc5db4Smrg#endif
262d6e8b77Smrg
27ea6ae205Smrg#include <stdio.h>
28ea6ae205Smrg#include <stdlib.h>
29ea6ae205Smrg#include <string.h>
30329eaa64Smrg#include <strings.h>
31ea6ae205Smrg
32ea6ae205Smrg#include <sys/types.h>
332d6e8b77Smrg#include <sys/stat.h>
34ea6ae205Smrg#include <dirent.h>
35ea6ae205Smrg#include <unistd.h>
36ea6ae205Smrg#include <errno.h>
37ea6ae205Smrg#include <ctype.h>
38ea6ae205Smrg
39ea6ae205Smrg#include <X11/Xos.h>
40af7d3019Smrg#include <X11/Xfuncproto.h>
41ea6ae205Smrg#include <X11/fonts/fontenc.h>
42ea6ae205Smrg#include <ft2build.h>
43ea6ae205Smrg#include FT_FREETYPE_H
44ea6ae205Smrg#include FT_SFNT_NAMES_H
45ea6ae205Smrg#include FT_TRUETYPE_TABLES_H
46ea6ae205Smrg#include FT_TRUETYPE_IDS_H
47ea6ae205Smrg#include FT_TYPE1_TABLES_H
48ea6ae205Smrg#include FT_BDF_H
49ea6ae205Smrg#include FT_XFREE86_H
50ea6ae205Smrg
51ea6ae205Smrg#include "list.h"
527c5a9b20Smrg#include "constlist.h"
53ea6ae205Smrg#include "hash.h"
54ea6ae205Smrg#include "data.h"
55ea6ae205Smrg#include "ident.h"
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
66245f6787Smrg/* Two levels of macro calls are needed so that we stringify the value
67245f6787Smrg   of MAXFONT... and not the string "MAXFONT..." */
68245f6787Smrg#define QUOTE(x)	#x
69245f6787Smrg#define STRINGIFY(x)	QUOTE(x)
70245f6787Smrg
716ae2c069Smrgstatic const char *encodings_array[] = { "ascii-0",
726ae2c069Smrg    "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5",
736ae2c069Smrg    "iso8859-6", "iso8859-6.8", "iso8859-6.8x", "iso8859-6.16",
746ae2c069Smrg    "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10",
756ae2c069Smrg    "iso8859-11", "iso8859-12", "iso8859-13", "iso8859-14",
766ae2c069Smrg    "iso8859-15", "iso8859-16",
776ae2c069Smrg    "ansi-1251", "koi8-r", "koi8-u", "koi8-ru", "koi8-e", "koi8-uni",
786ae2c069Smrg    "tis620-2",
796ae2c069Smrg    "sun.unicode.india-0", "suneu-greek",
806ae2c069Smrg    "adobe-standard", "adobe-symbol",
816ae2c069Smrg    "ibm-cp437", "ibm-cp850", "ibm-cp852", "ibm-cp866", "microsoft-cp1252",
826ae2c069Smrg    /* But not "adobe-dingbats", as it uses generic glyph names. */
836ae2c069Smrg    "cns11643-1", "cns11643-2", "cns11643-3",
846ae2c069Smrg    "jisx0201.1976-0", "jisx0208.1983-0", "jisx0208.1990-0",
856ae2c069Smrg    "jisx0212.1990-0", "big5-0", "big5.eten-0", "big5hkscs-0",
866ae2c069Smrg    "gb2312.1980-0", "gb18030.2000-0", "gb18030.2000-1",
876ae2c069Smrg    "ksc5601.1987-0", "ksc5601.1992-3"
886ae2c069Smrg};
89ea6ae205Smrg
908b165ca7Smrgstatic const char *extra_encodings_array[] =
91ea6ae205Smrg    { "iso10646-1", "adobe-fontspecific", "microsoft-symbol" };
92ea6ae205Smrg
937c5a9b20Smrgstatic ConstListPtr encodings, extra_encodings;
94663cdc11Smrgstatic const char *outfilename;
95ea6ae205Smrg
96ea6ae205Smrg#define countof(_a) (sizeof(_a)/sizeof((_a)[0]))
97ea6ae205Smrg
986ae2c069Smrgstatic int doDirectory(const char *, int, ListPtr);
997c5a9b20Smrgstatic int checkEncoding(FT_Face face, const char *encoding_name);
1006ae2c069Smrgstatic int checkExtraEncoding(FT_Face face, const char *encoding_name,
1016ae2c069Smrg                              int found);
102ea6ae205Smrgstatic int find_cmap(int type, int pid, int eid, FT_Face face);
1036ae2c069Smrgstatic const char *notice_foundry(const char *notice);
1046ae2c069Smrgstatic const char *vendor_foundry(const signed char *vendor);
105ea6ae205Smrgstatic int readFontScale(HashTablePtr entries, char *dirname);
106ea6ae205SmrgListPtr makeXLFD(char *filename, FT_Face face, int);
1076ae2c069Smrgstatic int readEncodings(ListPtr *encodingsToDo, char *dirname);
108ea6ae205Smrg
109ea6ae205Smrgstatic FT_Library ft_library;
1106ae2c069Smrgstatic float bigEncodingFuzz = 0.02f;
111ea6ae205Smrg
112ea6ae205Smrgstatic int relative;
113ea6ae205Smrgstatic int doScalable;
114ea6ae205Smrgstatic int doBitmaps;
115ea6ae205Smrgstatic int doISO10646_1_encoding;
116ea6ae205Smrgstatic int onlyEncodings;
117ea6ae205Smrgstatic int reencodeLegacy;
118ea6ae205Smrgstatic char *encodingPrefix;
119ea6ae205Smrgstatic char *exclusionSuffix;
120af7d3019Smrgstatic char *ProgramName;
121ea6ae205Smrg
122af7d3019Smrgstatic void _X_NORETURN _X_COLD
123ea6ae205Smrgusage(void)
124ea6ae205Smrg{
125af7d3019Smrg    fprintf(stderr, "Usage:\n"
126ea6ae205Smrg            "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n"
127af7d3019Smrg            "            [ -a encoding ] [ -f fuzz ] [ -l ]\n"
128ea6ae205Smrg            "            [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n"
129af7d3019Smrg            "            [-u] [-U] [-v] [ directory ]...\n");
130af7d3019Smrg    exit(1);
131af7d3019Smrg}
132af7d3019Smrg
133af7d3019Smrgstatic void _X_NORETURN _X_COLD
1346ae2c069Smrgmissing_arg(const char *option)
135af7d3019Smrg{
136af7d3019Smrg    fprintf(stderr, "%s: %s requires an argument\n", ProgramName, option);
137af7d3019Smrg    usage();
138ea6ae205Smrg}
139ea6ae205Smrg
140ea6ae205Smrgint
141ea6ae205Smrgmain(int argc, char **argv)
142ea6ae205Smrg{
143ea6ae205Smrg    int argn;
144ea6ae205Smrg    FT_Error ftrc;
1456ae2c069Smrg    int ll = 0;
1466ae2c069Smrg    ListPtr encodingsToDo;
147ea6ae205Smrg    char prefix[NPREFIX];
148ea6ae205Smrg
149af7d3019Smrg    ProgramName = argv[0];
150ea6ae205Smrg    encodingPrefix = NULL;
151ea6ae205Smrg    exclusionSuffix = NULL;
152ea6ae205Smrg
1536ae2c069Smrg    if (getcwd(prefix, NPREFIX - 1) == NULL) {
154ea6ae205Smrg        perror("Couldn't get cwd");
155ea6ae205Smrg        exit(1);
156ea6ae205Smrg    }
1576ae2c069Smrg    if (prefix[strlen(prefix) - 1] != '/')
1587c5a9b20Smrg        encodingPrefix = dsprintf("%s/", prefix);
1597c5a9b20Smrg    else
1607c5a9b20Smrg        encodingPrefix = strdup(prefix);
161ea6ae205Smrg
162ea6ae205Smrg    outfilename = NULL;
163ea6ae205Smrg
1646ae2c069Smrg    encodings =
1656ae2c069Smrg        makeConstList(encodings_array, countof(encodings_array), NULL, 0);
166ea6ae205Smrg
1677c5a9b20Smrg    extra_encodings = makeConstList(extra_encodings_array,
1686ae2c069Smrg                                    countof(extra_encodings_array), NULL, 0);
169ea6ae205Smrg    doBitmaps = 0;
170ea6ae205Smrg    doISO10646_1_encoding = 1;
171ea6ae205Smrg    doScalable = 1;
172ea6ae205Smrg    onlyEncodings = 0;
173ea6ae205Smrg    relative = 0;
174ea6ae205Smrg    reencodeLegacy = 1;
175ea6ae205Smrg    encodingsToDo = NULL;
176ea6ae205Smrg
177ea6ae205Smrg    argn = 1;
1786ae2c069Smrg    while (argn < argc) {
1796ae2c069Smrg        if (argv[argn][0] == '\0' || argv[argn][0] != '-')
180ea6ae205Smrg            break;
1816ae2c069Smrg        if (argv[argn][1] == '-') {
182ea6ae205Smrg            argn++;
183ea6ae205Smrg            break;
1846ae2c069Smrg        }
1856ae2c069Smrg        else if (strcmp(argv[argn], "-x") == 0) {
1866ae2c069Smrg            if (argn >= argc - 1) {
187af7d3019Smrg                missing_arg("-x");
188ea6ae205Smrg            }
189ea6ae205Smrg            exclusionSuffix = argv[argn + 1];
190ea6ae205Smrg            argn += 2;
1916ae2c069Smrg        }
1926ae2c069Smrg        else if (strcmp(argv[argn], "-a") == 0) {
1936ae2c069Smrg            if (argn >= argc - 1) {
194af7d3019Smrg                missing_arg("-a");
195ea6ae205Smrg            }
1966ae2c069Smrg            makeConstList((const char **) &argv[argn + 1], 1, encodings, 0);
197ea6ae205Smrg            argn += 2;
1986ae2c069Smrg        }
1996ae2c069Smrg        else if (strcmp(argv[argn], "-p") == 0) {
2006ae2c069Smrg            if (argn >= argc - 1) {
201af7d3019Smrg                missing_arg("-p");
202ea6ae205Smrg            }
2036ae2c069Smrg            if (strlen(argv[argn + 1]) > NPREFIX - 1) {
204af7d3019Smrg                fprintf(stderr, "%s: argument to -p cannot be longer than "
205af7d3019Smrg                        "%d characters\n", ProgramName, NPREFIX - 1);
206ea6ae205Smrg                usage();
207ea6ae205Smrg            }
208ea6ae205Smrg            free(encodingPrefix);
2097c5a9b20Smrg            encodingPrefix = strdup(argv[argn + 1]);
210ea6ae205Smrg            argn += 2;
2116ae2c069Smrg        }
2126ae2c069Smrg        else if (strcmp(argv[argn], "-e") == 0) {
2136ae2c069Smrg            int rc;
2146ae2c069Smrg
2156ae2c069Smrg            if (argn >= argc - 1) {
216af7d3019Smrg                missing_arg("-e");
217ea6ae205Smrg            }
2186ae2c069Smrg            rc = readEncodings(&encodingsToDo, argv[argn + 1]);
2196ae2c069Smrg            if (rc < 0)
220ea6ae205Smrg                exit(1);
221ea6ae205Smrg            argn += 2;
2226ae2c069Smrg        }
2236ae2c069Smrg        else if (strcmp(argv[argn], "-b") == 0) {
224ea6ae205Smrg            doBitmaps = 1;
225ea6ae205Smrg            argn++;
2266ae2c069Smrg        }
2276ae2c069Smrg        else if (strcmp(argv[argn], "-u") == 0) {
228ea6ae205Smrg            doISO10646_1_encoding = 0;
229ea6ae205Smrg            argn++;
2306ae2c069Smrg        }
2316ae2c069Smrg        else if (strcmp(argv[argn], "-U") == 0) {
232ea6ae205Smrg            doISO10646_1_encoding = 1;
233663cdc11Smrg            argn++;
2346ae2c069Smrg        }
2356ae2c069Smrg        else if (strcmp(argv[argn], "-s") == 0) {
236ea6ae205Smrg            doScalable = 0;
237ea6ae205Smrg            argn++;
2386ae2c069Smrg        }
2396ae2c069Smrg        else if (strcmp(argv[argn], "-n") == 0) {
240ea6ae205Smrg            onlyEncodings = 1;
241ea6ae205Smrg            argn++;
2426ae2c069Smrg        }
2436ae2c069Smrg        else if (strcmp(argv[argn], "-r") == 0) {
244ea6ae205Smrg            relative = 1;
245ea6ae205Smrg            argn++;
2466ae2c069Smrg        }
2476ae2c069Smrg        else if (strcmp(argv[argn], "-l") == 0) {
248ea6ae205Smrg            reencodeLegacy = !reencodeLegacy;
249ea6ae205Smrg            argn++;
2506ae2c069Smrg        }
2516ae2c069Smrg        else if (strcmp(argv[argn], "-o") == 0) {
2526ae2c069Smrg            if (argn >= argc - 1) {
253af7d3019Smrg                missing_arg("-o");
254ea6ae205Smrg            }
255ea6ae205Smrg            outfilename = argv[argn + 1];
256ea6ae205Smrg            argn += 2;
2576ae2c069Smrg        }
2586ae2c069Smrg        else if (strcmp(argv[argn], "-f") == 0) {
2596ae2c069Smrg            if (argn >= argc - 1) {
260af7d3019Smrg                missing_arg("-f");
261ea6ae205Smrg            }
2626ae2c069Smrg            bigEncodingFuzz = strtof(argv[argn + 1], NULL) / 100.0f;
263ea6ae205Smrg            argn += 2;
2646ae2c069Smrg        }
2656ae2c069Smrg        else if (strcmp(argv[argn], "-v") == 0) {
2666ae2c069Smrg            printf("%s\n", PACKAGE_STRING);
2676ae2c069Smrg            exit(0);
2686ae2c069Smrg        }
2696ae2c069Smrg        else {
270ea6ae205Smrg            usage();
271ea6ae205Smrg        }
272ea6ae205Smrg    }
273ea6ae205Smrg
2746ae2c069Smrg    if (outfilename == NULL) {
2756ae2c069Smrg        if (doBitmaps)
276ea6ae205Smrg            outfilename = "fonts.dir";
277663cdc11Smrg        else
278ea6ae205Smrg            outfilename = "fonts.scale";
279ea6ae205Smrg    }
280ea6ae205Smrg
281ea6ae205Smrg    ftrc = FT_Init_FreeType(&ft_library);
2826ae2c069Smrg    if (ftrc) {
283ea6ae205Smrg        fprintf(stderr, "Could not initialise FreeType library: %d\n", ftrc);
284ea6ae205Smrg        exit(1);
285ea6ae205Smrg    }
286ea6ae205Smrg
287ea6ae205Smrg    ll = listLength(encodingsToDo);
288ea6ae205Smrg
289ea6ae205Smrg    if (argn == argc)
290ea6ae205Smrg        doDirectory(".", ll, encodingsToDo);
291ea6ae205Smrg    else
2926ae2c069Smrg        while (argn < argc) {
293ea6ae205Smrg            doDirectory(argv[argn], ll, encodingsToDo);
294ea6ae205Smrg            argn++;
295ea6ae205Smrg        }
296ea6ae205Smrg    return 0;
297ea6ae205Smrg}
298ea6ae205Smrg
299ea6ae205Smrgstatic int
300ea6ae205SmrggetNameHelper(FT_Face face, int nid, int pid, int eid,
301ea6ae205Smrg              FT_SfntName *name_return)
302ea6ae205Smrg{
303ea6ae205Smrg    FT_SfntName name;
3046ae2c069Smrg    int n;
305ea6ae205Smrg
306ea6ae205Smrg    n = FT_Get_Sfnt_Name_Count(face);
3076ae2c069Smrg    if (n <= 0)
308ea6ae205Smrg        return 0;
309ea6ae205Smrg
3106ae2c069Smrg    for (int i = 0; i < n; i++) {
3116ae2c069Smrg        if (FT_Get_Sfnt_Name(face, i, &name))
312ea6ae205Smrg            continue;
3136ae2c069Smrg        if (name.name_id == nid &&
3146ae2c069Smrg            name.platform_id == pid && (eid < 0 || name.encoding_id == eid)) {
3156ae2c069Smrg            switch (name.platform_id) {
316ea6ae205Smrg            case TT_PLATFORM_APPLE_UNICODE:
317ea6ae205Smrg            case TT_PLATFORM_MACINTOSH:
3186ae2c069Smrg                if (name.language_id != TT_MAC_LANGID_ENGLISH)
319ea6ae205Smrg                    continue;
320ea6ae205Smrg                break;
321ea6ae205Smrg            case TT_PLATFORM_MICROSOFT:
3226ae2c069Smrg                if (name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
3236ae2c069Smrg                    name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
324ea6ae205Smrg                    continue;
325ea6ae205Smrg                break;
326ea6ae205Smrg            default:
327ea6ae205Smrg                continue;
328ea6ae205Smrg            }
3296ae2c069Smrg            if (name.string_len > 0) {
330ea6ae205Smrg                *name_return = name;
331ea6ae205Smrg                return 1;
332ea6ae205Smrg            }
333ea6ae205Smrg        }
334ea6ae205Smrg    }
335ea6ae205Smrg    return 0;
336ea6ae205Smrg}
337ea6ae205Smrg
338ea6ae205Smrgstatic char *
339ea6ae205SmrggetName(FT_Face face, int nid)
340ea6ae205Smrg{
341ea6ae205Smrg    FT_SfntName name;
342ea6ae205Smrg
3436ae2c069Smrg    if (getNameHelper(face, nid,
3446ae2c069Smrg                      TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) ||
3456ae2c069Smrg        getNameHelper(face, nid, TT_PLATFORM_APPLE_UNICODE, -1, &name)) {
3466ae2c069Smrg        unsigned int i;
3476ae2c069Smrg        char *string = malloc(name.string_len / 2 + 1);
3486ae2c069Smrg        if (string == NULL) {
349ea6ae205Smrg            fprintf(stderr, "Couldn't allocate name\n");
350ea6ae205Smrg            exit(1);
351ea6ae205Smrg        }
3526ae2c069Smrg        for (i = 0; i < name.string_len / 2; i++) {
3536ae2c069Smrg            if (name.string[2 * i] != 0)
354ea6ae205Smrg                string[i] = '?';
355ea6ae205Smrg            else
356ea6ae205Smrg                string[i] = name.string[2 * i + 1];
357ea6ae205Smrg        }
358ea6ae205Smrg        string[i] = '\0';
359ea6ae205Smrg        return string;
360ea6ae205Smrg    }
361ea6ae205Smrg
362ea6ae205Smrg    /* Pretend that Apple Roman is ISO 8859-1. */
3636ae2c069Smrg    if (getNameHelper(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, &name)) {
3646ae2c069Smrg        char *string = malloc(name.string_len + 1);
3656ae2c069Smrg        if (string == NULL) {
366ea6ae205Smrg            fprintf(stderr, "Couldn't allocate name\n");
367ea6ae205Smrg            exit(1);
368ea6ae205Smrg        }
369ea6ae205Smrg        memcpy(string, name.string, name.string_len);
370ea6ae205Smrg        string[name.string_len] = '\0';
371ea6ae205Smrg        return string;
372ea6ae205Smrg    }
373ea6ae205Smrg
374ea6ae205Smrg    return NULL;
375ea6ae205Smrg}
376ea6ae205Smrg
3776ae2c069Smrgstatic const char *
378ea6ae205Smrgos2Weight(int weight)
379ea6ae205Smrg{
3806ae2c069Smrg    if (weight < 150)
381ea6ae205Smrg        return "thin";
3826ae2c069Smrg    else if (weight < 250)
383ea6ae205Smrg        return "extralight";
3846ae2c069Smrg    else if (weight < 350)
385ea6ae205Smrg        return "light";
3866ae2c069Smrg    else if (weight < 450)
387ea6ae205Smrg        return "medium";        /* officially "normal" */
3886ae2c069Smrg    else if (weight < 550)
389ea6ae205Smrg        return "medium";
3906ae2c069Smrg    else if (weight < 650)
391ea6ae205Smrg        return "semibold";
3926ae2c069Smrg    else if (weight < 750)
393ea6ae205Smrg        return "bold";
3946ae2c069Smrg    else if (weight < 850)
395ea6ae205Smrg        return "extrabold";
396663cdc11Smrg    else
397ea6ae205Smrg        return "black";
398ea6ae205Smrg}
399ea6ae205Smrg
4006ae2c069Smrgstatic const char *
401ea6ae205Smrgos2Width(int width)
402ea6ae205Smrg{
4036ae2c069Smrg    if (width <= 1)
404ea6ae205Smrg        return "ultracondensed";
4056ae2c069Smrg    else if (width <= 2)
406ea6ae205Smrg        return "extracondensed";
4076ae2c069Smrg    else if (width <= 3)
408ea6ae205Smrg        return "condensed";
4096ae2c069Smrg    else if (width <= 4)
410ea6ae205Smrg        return "semicondensed";
4116ae2c069Smrg    else if (width <= 5)
412ea6ae205Smrg        return "normal";
4136ae2c069Smrg    else if (width <= 6)
414ea6ae205Smrg        return "semiexpanded";
4156ae2c069Smrg    else if (width <= 7)
416ea6ae205Smrg        return "expanded";
4176ae2c069Smrg    else if (width <= 8)
418ea6ae205Smrg        return "extraexpanded";
419ea6ae205Smrg    else
420ea6ae205Smrg        return "ultraexpanded";
421ea6ae205Smrg}
422ea6ae205Smrg
423663cdc11Smrgstatic const char *widths[] = {
424ea6ae205Smrg    "ultracondensed", "extracondensed", "condensed", "semicondensed",
425663cdc11Smrg    "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded"
426ea6ae205Smrg};
427ea6ae205Smrg
428ea6ae205Smrg#define NUMWIDTHS (sizeof(widths) / sizeof(widths[0]))
429ea6ae205Smrg
4306ae2c069Smrgstatic const char *
431663cdc11SmrgnameWidth(const char *name)
432ea6ae205Smrg{
433ea6ae205Smrg    char buf[500];
4347c5a9b20Smrg    unsigned int i;
4357c5a9b20Smrg    size_t n = strlen(name);
436ea6ae205Smrg
4376ae2c069Smrg    if (n >= 499)
4386ae2c069Smrg        return NULL;
4396ae2c069Smrg    for (i = 0; i < n; i++)
440ea6ae205Smrg        buf[i] = tolower(name[i]);
441ea6ae205Smrg    buf[i] = '\0';
442ea6ae205Smrg
4436ae2c069Smrg    for (i = 0; i < NUMWIDTHS; i++)
4446ae2c069Smrg        if (strstr(buf, widths[i]))
445ea6ae205Smrg            return widths[i];
446ea6ae205Smrg    return NULL;
447ea6ae205Smrg}
448ea6ae205Smrg
4496ae2c069Smrgstatic const char *
450663cdc11Smrgt1Weight(const char *weight)
451ea6ae205Smrg{
4526ae2c069Smrg    if (!weight)
453ea6ae205Smrg        return NULL;
4546ae2c069Smrg    if (strcasecmp(weight, "Thin") == 0)
455ea6ae205Smrg        return "thin";
4566ae2c069Smrg    if (strcasecmp(weight, "ExtraLight") == 0)  /* FontForge uses this for 200 */
457663cdc11Smrg        return "extralight";
4586ae2c069Smrg    if (strcasecmp(weight, "Light") == 0)
459ea6ae205Smrg        return "light";
4606ae2c069Smrg    if (strcasecmp(weight, "Regular") == 0)
461ea6ae205Smrg        return "medium";
4626ae2c069Smrg    if (strcasecmp(weight, "Normal") == 0)
463ea6ae205Smrg        return "medium";
4646ae2c069Smrg    if (strcasecmp(weight, "Plain") == 0)
465329eaa64Smrg        return "medium";
4666ae2c069Smrg    if (strcasecmp(weight, "Medium") == 0)
467ea6ae205Smrg        return "medium";
4686ae2c069Smrg    if (strcasecmp(weight, "Book") == 0)
469ea6ae205Smrg        return "medium";
4706ae2c069Smrg    if (strcasecmp(weight, "Roman") == 0)       /* Some URW++ fonts do that! */
47119108c71Smaya        return "medium";
4726ae2c069Smrg    if (strcasecmp(weight, "Demi") == 0)
473ea6ae205Smrg        return "semibold";
4746ae2c069Smrg    if (strcasecmp(weight, "DemiBold") == 0)
475ea6ae205Smrg        return "semibold";
4766ae2c069Smrg    if (strcasecmp(weight, "SemiBold") == 0)    /* some TeX fonts apparently do that */
477ea6ae205Smrg        return "semibold";
4786ae2c069Smrg    else if (strcasecmp(weight, "Bold") == 0)
479ea6ae205Smrg        return "bold";
4806ae2c069Smrg    else if (strcasecmp(weight, "ExtraBold") == 0)      /* freefonts uses this */
481663cdc11Smrg        return "extrabold";
4826ae2c069Smrg    else if (strcasecmp(weight, "Heavy") == 0)  /* FontForge uses this for 800 */
483329eaa64Smrg        return "extrabold";
4846ae2c069Smrg    else if (strcasecmp(weight, "Black") == 0)
485ea6ae205Smrg        return "black";
486ea6ae205Smrg    else {
487ea6ae205Smrg        fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight);
488ea6ae205Smrg        return NULL;
489ea6ae205Smrg    }
490ea6ae205Smrg}
491ea6ae205Smrg
492ea6ae205Smrgstatic int
493ea6ae205Smrgunsafe(char c)
494ea6ae205Smrg{
495663cdc11Smrg    return
496ea6ae205Smrg        c < 0x20 || c > 0x7E ||
497ea6ae205Smrg        c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-';
498ea6ae205Smrg}
499ea6ae205Smrg
500663cdc11Smrgstatic const char *
5016ae2c069Smrgsafe(const char *s)
502ea6ae205Smrg{
5036ae2c069Smrg    unsigned int i, len, safe_flag = 1;
504ea6ae205Smrg    char *t;
505ea6ae205Smrg
506ea6ae205Smrg    i = 0;
5076ae2c069Smrg    while (s[i] != '\0') {
5086ae2c069Smrg        if (unsafe(s[i]))
509ea6ae205Smrg            safe_flag = 0;
510ea6ae205Smrg        i++;
511ea6ae205Smrg    }
512ea6ae205Smrg
5136ae2c069Smrg    if (safe_flag)
5146ae2c069Smrg        return strdup(s);
515ea6ae205Smrg
516ea6ae205Smrg    len = i;
517ea6ae205Smrg    t = malloc(len + 1);
5186ae2c069Smrg    if (t == NULL) {
519ea6ae205Smrg        perror("Couldn't allocate string");
520ea6ae205Smrg        exit(1);
521ea6ae205Smrg    }
522ea6ae205Smrg
5236ae2c069Smrg    for (i = 0; i < len; i++) {
5246ae2c069Smrg        if (unsafe(s[i]))
525ea6ae205Smrg            t[i] = ' ';
526ea6ae205Smrg        else
527ea6ae205Smrg            t[i] = s[i];
528ea6ae205Smrg    }
529ea6ae205Smrg    t[i] = '\0';
530ea6ae205Smrg    return t;
531ea6ae205Smrg}
532ea6ae205Smrg
533ea6ae205SmrgListPtr
534ea6ae205SmrgmakeXLFD(char *filename, FT_Face face, int isBitmap)
535ea6ae205Smrg{
536ea6ae205Smrg    ListPtr xlfd = NULL;
537663cdc11Smrg    const char *foundry, *family, *weight, *slant, *sWidth, *adstyle,
538af7d3019Smrg        *spacing, *full_name, *tmp;
539ea6ae205Smrg    TT_Header *head;
540ea6ae205Smrg    TT_HoriHeader *hhea;
541ea6ae205Smrg    TT_OS2 *os2;
542ea6ae205Smrg    TT_Postscript *post;
543ea6ae205Smrg    PS_FontInfoRec *t1info, t1info_rec;
544ea6ae205Smrg    int rc;
545ea6ae205Smrg
546ea6ae205Smrg    foundry = NULL;
547ea6ae205Smrg    family = NULL;
548ea6ae205Smrg    weight = NULL;
549ea6ae205Smrg    slant = NULL;
550ea6ae205Smrg    sWidth = NULL;
551ea6ae205Smrg    adstyle = NULL;
552ea6ae205Smrg    spacing = NULL;
553ea6ae205Smrg    full_name = NULL;
554ea6ae205Smrg
555ea6ae205Smrg    head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
556ea6ae205Smrg    hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
557ea6ae205Smrg    os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
558ea6ae205Smrg    post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
559ea6ae205Smrg
560ea6ae205Smrg    rc = FT_Get_PS_Font_Info(face, &t1info_rec);
5616ae2c069Smrg    if (rc == 0)
562ea6ae205Smrg        t1info = &t1info_rec;
563ea6ae205Smrg    else
564ea6ae205Smrg        t1info = NULL;
565663cdc11Smrg
5666ae2c069Smrg    if (!family)
567ea6ae205Smrg        family = getName(face, TT_NAME_ID_FONT_FAMILY);
5686ae2c069Smrg    if (!family)
569ea6ae205Smrg        family = getName(face, TT_NAME_ID_FULL_NAME);
5706ae2c069Smrg    if (!family)
571ea6ae205Smrg        family = getName(face, TT_NAME_ID_PS_NAME);
572ea6ae205Smrg
5736ae2c069Smrg    if (!full_name)
574ea6ae205Smrg        full_name = getName(face, TT_NAME_ID_FULL_NAME);
5756ae2c069Smrg    if (!full_name)
576ea6ae205Smrg        full_name = getName(face, TT_NAME_ID_PS_NAME);
577ea6ae205Smrg
5786ae2c069Smrg    if (os2 && os2->version != 0xFFFF) {
5796ae2c069Smrg        if (!weight)
580ea6ae205Smrg            weight = os2Weight(os2->usWeightClass);
5816ae2c069Smrg        if (!sWidth)
582ea6ae205Smrg            sWidth = os2Width(os2->usWidthClass);
5836ae2c069Smrg        if (!foundry)
584ea6ae205Smrg            foundry = vendor_foundry(os2->achVendID);
5856ae2c069Smrg        if (!slant)
586ea6ae205Smrg            slant = os2->fsSelection & 1 ? "i" : "r";
587ea6ae205Smrg    }
588ea6ae205Smrg
5896ae2c069Smrg    if (post) {
5906ae2c069Smrg        if (!spacing) {
5916ae2c069Smrg            if (post->isFixedPitch) {
5926ae2c069Smrg                if (hhea->min_Left_Side_Bearing >= 0 &&
5936ae2c069Smrg                    hhea->xMax_Extent <= hhea->advance_Width_Max) {
594ea6ae205Smrg                    spacing = "c";
5956ae2c069Smrg                }
5966ae2c069Smrg                else {
597ea6ae205Smrg                    spacing = "m";
598ea6ae205Smrg                }
5996ae2c069Smrg            }
6006ae2c069Smrg            else {
601ea6ae205Smrg                spacing = "p";
602ea6ae205Smrg            }
603ea6ae205Smrg        }
604ea6ae205Smrg    }
605663cdc11Smrg
6066ae2c069Smrg    if (t1info) {
6076ae2c069Smrg        if (!family && t1info->family_name)
608af7d3019Smrg            family = strdup(t1info->family_name);
6096ae2c069Smrg        if (!family && t1info->full_name)
610af7d3019Smrg            family = strdup(t1info->full_name);
611eaa89f16Smrg        /* Hershey fonts miss /FamilyName */
6126ae2c069Smrg        if (!family && face->family_name)
613eaa89f16Smrg            family = strdup(face->family_name);
6146ae2c069Smrg        if (!full_name && t1info->full_name)
615af7d3019Smrg            full_name = strdup(t1info->full_name);
6166ae2c069Smrg        if (!foundry)
617ea6ae205Smrg            foundry = notice_foundry(t1info->notice);
6186ae2c069Smrg        if (!weight)
619ea6ae205Smrg            weight = t1Weight(t1info->weight);
6206ae2c069Smrg        if (!spacing)
621ea6ae205Smrg            spacing = t1info->is_fixed_pitch ? "m" : "p";
6226ae2c069Smrg        if (!slant) {
623ea6ae205Smrg            /* Bitstream fonts have positive italic angle. */
624ea6ae205Smrg            slant =
625ea6ae205Smrg                t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ?
626ea6ae205Smrg                "i" : "r";
627ea6ae205Smrg        }
628ea6ae205Smrg    }
629ea6ae205Smrg
6306ae2c069Smrg    if (!full_name) {
631ea6ae205Smrg        fprintf(stderr, "Couldn't determine full name for %s\n", filename);
632af7d3019Smrg        full_name = strdup(filename);
633ea6ae205Smrg    }
634ea6ae205Smrg
6356ae2c069Smrg    if (head) {
6366ae2c069Smrg        if (!slant)
637ea6ae205Smrg            slant = head->Mac_Style & 2 ? "i" : "r";
6386ae2c069Smrg        if (!weight)
639ea6ae205Smrg            weight = head->Mac_Style & 1 ? "bold" : "medium";
640ea6ae205Smrg    }
641ea6ae205Smrg
6426ae2c069Smrg    if (!slant) {
643ea6ae205Smrg        fprintf(stderr, "Couldn't determine slant for %s\n", filename);
644ea6ae205Smrg        slant = "r";
645ea6ae205Smrg    }
646ea6ae205Smrg
6476ae2c069Smrg    if (!weight) {
648ea6ae205Smrg        fprintf(stderr, "Couldn't determine weight for %s\n", filename);
649ea6ae205Smrg        weight = "medium";
650ea6ae205Smrg    }
651ea6ae205Smrg
6526ae2c069Smrg    if (!foundry) {
653ea6ae205Smrg        char *notice;
6546ae2c069Smrg
655ea6ae205Smrg        notice = getName(face, TT_NAME_ID_TRADEMARK);
6566ae2c069Smrg        if (notice) {
657ea6ae205Smrg            foundry = notice_foundry(notice);
658af7d3019Smrg            free(notice);
659ea6ae205Smrg        }
6606ae2c069Smrg        if (!foundry) {
661ea6ae205Smrg            notice = getName(face, TT_NAME_ID_MANUFACTURER);
6626ae2c069Smrg            if (notice) {
663ea6ae205Smrg                foundry = notice_foundry(notice);
664af7d3019Smrg                free(notice);
665ea6ae205Smrg            }
666ea6ae205Smrg        }
667ea6ae205Smrg    }
668ea6ae205Smrg
6696ae2c069Smrg    if (strcmp(slant, "i") == 0) {
6706ae2c069Smrg        if (strstr(full_name, "Oblique"))
671ea6ae205Smrg            slant = "o";
6726ae2c069Smrg        if (strstr(full_name, "Slanted"))
673ea6ae205Smrg            slant = "o";
674ea6ae205Smrg    }
675ea6ae205Smrg
6766ae2c069Smrg    if (!sWidth)
677ea6ae205Smrg        sWidth = nameWidth(full_name);
678ea6ae205Smrg
6796ae2c069Smrg    if (!foundry)
6806ae2c069Smrg        foundry = "misc";
6816ae2c069Smrg    if (!family) {
682ea6ae205Smrg        fprintf(stderr, "Couldn't get family name for %s\n", filename);
683af7d3019Smrg        family = strdup(filename);
684ea6ae205Smrg    }
685ea6ae205Smrg
6866ae2c069Smrg    if (!weight)
6876ae2c069Smrg        weight = "medium";
6886ae2c069Smrg    if (!slant)
6896ae2c069Smrg        slant = "r";
6906ae2c069Smrg    if (!sWidth)
6916ae2c069Smrg        sWidth = "normal";
6926ae2c069Smrg    if (!adstyle)
6936ae2c069Smrg        adstyle = "";
6946ae2c069Smrg    if (!spacing)
6956ae2c069Smrg        spacing = "p";
696ea6ae205Smrg
697ea6ae205Smrg    foundry = safe(foundry);
698af7d3019Smrg
699af7d3019Smrg    tmp = family;
700ea6ae205Smrg    family = safe(family);
7016ae2c069Smrg    free((void *) tmp);
702ea6ae205Smrg
7036ae2c069Smrg    if (!isBitmap) {
704ea6ae205Smrg        xlfd = listConsF(xlfd,
705ea6ae205Smrg                         "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0",
706ea6ae205Smrg                         foundry, family,
707ea6ae205Smrg                         weight, slant, sWidth, adstyle, spacing);
7086ae2c069Smrg    }
7096ae2c069Smrg    else {
7106ae2c069Smrg        for (int i = 0; i < face->num_fixed_sizes; i++) {
7116ae2c069Smrg            int w = face->available_sizes[i].width;
7126ae2c069Smrg            int h = face->available_sizes[i].height;
7136ae2c069Smrg            int xres = 75;
7146ae2c069Smrg            int yres = (double) h / w * xres;
715ea6ae205Smrg            xlfd = listConsF(xlfd,
716ea6ae205Smrg                             "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d",
717ea6ae205Smrg                             foundry, family,
718ea6ae205Smrg                             weight, slant, sWidth, adstyle,
7196ae2c069Smrg                             h, (int) (h / (double) yres * 72.27 * 10 + 0.5),
7206ae2c069Smrg                             xres, yres, spacing, 60);
721ea6ae205Smrg        }
722ea6ae205Smrg    }
723af7d3019Smrg
7246ae2c069Smrg    free((void *) family);
7256ae2c069Smrg    free((void *) foundry);
7266ae2c069Smrg    free((void *) full_name);
727ea6ae205Smrg    return xlfd;
728ea6ae205Smrg}
729ea6ae205Smrg
730ea6ae205Smrgstatic int
731ea6ae205SmrgreadFontScale(HashTablePtr entries, char *dirname)
732ea6ae205Smrg{
7337c5a9b20Smrg    size_t n = strlen(dirname);
734ea6ae205Smrg    char *filename;
735ea6ae205Smrg    FILE *in;
7366ae2c069Smrg    int rc, count;
7376ae2c069Smrg    char file[MAXFONTFILENAMELEN + 1], font[MAXFONTNAMELEN + 1];
738ea6ae205Smrg
7396ae2c069Smrg    if (dirname[n - 1] == '/')
740ea6ae205Smrg        filename = dsprintf("%sfonts.scale", dirname);
741ea6ae205Smrg    else
742ea6ae205Smrg        filename = dsprintf("%s/fonts.scale", dirname);
7436ae2c069Smrg    if (filename == NULL)
744ea6ae205Smrg        return -1;
745ea6ae205Smrg
746ea6ae205Smrg    in = fopen(filename, "r");
747ea6ae205Smrg    free(filename);
7486ae2c069Smrg    if (in == NULL) {
7496ae2c069Smrg        if (errno != ENOENT)
750ea6ae205Smrg            perror("open(fonts.scale)");
751ea6ae205Smrg        return -1;
752ea6ae205Smrg    }
753ea6ae205Smrg
754ea6ae205Smrg    rc = fscanf(in, "%d\n", &count);
7556ae2c069Smrg    if (rc != 1) {
756ea6ae205Smrg        fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname);
757ea6ae205Smrg        fclose(in);
758ea6ae205Smrg        return -1;
759ea6ae205Smrg    }
760ea6ae205Smrg
7616ae2c069Smrg    for (int i = 0; i < count; i++) {
762245f6787Smrg        rc = fscanf(in,
7636ae2c069Smrg                    "%" STRINGIFY(MAXFONTFILENAMELEN) "s "
7646ae2c069Smrg                    "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n",
7656ae2c069Smrg                    file, font);
7666ae2c069Smrg        if (rc != 2)
767ea6ae205Smrg            break;
768ea6ae205Smrg        putHash(entries, font, file, 100);
769ea6ae205Smrg    }
770ea6ae205Smrg    fclose(in);
771ea6ae205Smrg    return 1;
772ea6ae205Smrg}
773ea6ae205Smrg
774ea6ae205Smrgstatic int
775ea6ae205SmrgfilePrio(char *filename)
776ea6ae205Smrg{
7777c5a9b20Smrg    size_t n = strlen(filename);
7786ae2c069Smrg
7796ae2c069Smrg    if (n < 4)
780ea6ae205Smrg        return 0;
7816ae2c069Smrg    if (strcmp(filename + n - 4, ".otf") == 0)
782ea6ae205Smrg        return 6;
7836ae2c069Smrg    if (strcmp(filename + n - 4, ".OTF") == 0)
784ea6ae205Smrg        return 6;
7856ae2c069Smrg    if (strcmp(filename + n - 4, ".ttf") == 0)
786ea6ae205Smrg        return 5;
7876ae2c069Smrg    if (strcmp(filename + n - 4, ".TTF") == 0)
788ea6ae205Smrg        return 5;
7896ae2c069Smrg    if (strcmp(filename + n - 4, ".pcf") == 0)
790ea6ae205Smrg        return 4;
7916ae2c069Smrg    if (strcmp(filename + n - 4, ".PCF") == 0)
792ea6ae205Smrg        return 4;
7936ae2c069Smrg    if (strcmp(filename + n - 3, ".gz") == 0)
794ea6ae205Smrg        return 3;
7957978d3cdSmrg#ifdef X_BZIP2_FONT_COMPRESSION
7966ae2c069Smrg    if (strcmp(filename + n - 4, ".bz2") == 0)
7977978d3cdSmrg        return 2;
7987978d3cdSmrg#endif
7996ae2c069Smrg    if (strcmp(filename + n - 2, ".Z") == 0)
800ea6ae205Smrg        return 2;
8016ae2c069Smrg    if (strcmp(filename + n - 4, ".bdf") == 0)
802ea6ae205Smrg        return 1;
8036ae2c069Smrg    if (strcmp(filename + n - 4, ".BDF") == 0)
804ea6ae205Smrg        return 1;
805ea6ae205Smrg    return 0;
806ea6ae205Smrg}
807ea6ae205Smrg
808ea6ae205Smrgstatic int
809663cdc11SmrgdoDirectory(const char *dirname_given, int numEncodings, ListPtr encodingsToDo)
810ea6ae205Smrg{
811ea6ae205Smrg    char *dirname, *fontscale_name, *filename, *encdir;
812ea6ae205Smrg    FILE *fontscale, *encfile;
8136ae2c069Smrg    struct dirent **namelist;
814ea6ae205Smrg    FT_Error ftrc;
815ea6ae205Smrg    FT_Face face;
8167c5a9b20Smrg    ConstListPtr encoding;
8177c5a9b20Smrg    ListPtr xlfd, lp;
818ea6ae205Smrg    HashTablePtr entries;
819ea6ae205Smrg    HashBucketPtr *array;
8207c5a9b20Smrg    int i, n, dirn, diri, found, rc;
8216ae2c069Smrg    int isBitmap = 0;
8226ae2c069Smrg    size_t d, xl = 0;
823ea6ae205Smrg
824ea6ae205Smrg    if (exclusionSuffix)
8256ae2c069Smrg        xl = strlen(exclusionSuffix);
826ea6ae205Smrg
8277c5a9b20Smrg    d = strlen(dirname_given);
8286ae2c069Smrg    if (d == 0)
829ea6ae205Smrg        dirname = dsprintf("./");
8306ae2c069Smrg    else if (dirname_given[d - 1] != '/')
831ea6ae205Smrg        dirname = dsprintf("%s/", dirname_given);
832ea6ae205Smrg    else
8337c5a9b20Smrg        dirname = strdup(dirname_given);
834ea6ae205Smrg
8356ae2c069Smrg    if (dirname == NULL) {
836ea6ae205Smrg        perror("dirname");
837ea6ae205Smrg        exit(1);
838ea6ae205Smrg    }
839ea6ae205Smrg
840663cdc11Smrg    if (onlyEncodings)
8416ae2c069Smrg        goto encodings;
842663cdc11Smrg
843ea6ae205Smrg    entries = makeHashTable();
8446ae2c069Smrg    if (doBitmaps && !doScalable) {
845ea6ae205Smrg        readFontScale(entries, dirname);
846ea6ae205Smrg    }
847ea6ae205Smrg
8486ae2c069Smrg    if (strcmp(outfilename, "-") == 0)
849ea6ae205Smrg        fontscale_name = NULL;
850ea6ae205Smrg    else {
8516ae2c069Smrg        if (outfilename[0] == '/')
8527c5a9b20Smrg            fontscale_name = strdup(outfilename);
853ea6ae205Smrg        else
854ea6ae205Smrg            fontscale_name = dsprintf("%s%s", dirname, outfilename);
8556ae2c069Smrg        if (fontscale_name == NULL) {
856ea6ae205Smrg            perror("fontscale_name");
857ea6ae205Smrg            exit(1);
858ea6ae205Smrg        }
859ea6ae205Smrg    }
860ea6ae205Smrg
8617c5a9b20Smrg    dirn = scandir(dirname, &namelist, NULL, alphasort);
8626ae2c069Smrg    if (dirn < 0) {
863ea6ae205Smrg        fprintf(stderr, "%s: ", dirname);
8647c5a9b20Smrg        perror("scandir");
865ea6ae205Smrg        return 0;
866ea6ae205Smrg    }
867ea6ae205Smrg
8686ae2c069Smrg    if (fontscale_name == NULL)
869ea6ae205Smrg        fontscale = stdout;
870ea6ae205Smrg    else
871ea6ae205Smrg        fontscale = fopen(fontscale_name, "wb");
872ea6ae205Smrg
8736ae2c069Smrg    if (fontscale == NULL) {
874ea6ae205Smrg        fprintf(stderr, "%s: ", fontscale_name);
875ea6ae205Smrg        perror("fopen(w)");
876ea6ae205Smrg        return 0;
877ea6ae205Smrg    }
878ea6ae205Smrg
8796ae2c069Smrg    for (diri = dirn - 1; diri >= 0; diri--) {
8807c5a9b20Smrg        struct dirent *entry = namelist[diri];
881ea6ae205Smrg        int have_face = 0;
882ea6ae205Smrg        char *xlfd_name = NULL;
8836ae2c069Smrg        struct stat f_stat;
8846ae2c069Smrg        int tprio = 1;
8852d6e8b77Smrg
886ea6ae205Smrg        xlfd = NULL;
887ea6ae205Smrg
8886ae2c069Smrg        if (xl) {
8896ae2c069Smrg            size_t dl = strlen(entry->d_name);
8906ae2c069Smrg
8916ae2c069Smrg            if (strcmp(entry->d_name + dl - xl, exclusionSuffix) == 0)
8926ae2c069Smrg                continue;
8936ae2c069Smrg        }
894ea6ae205Smrg
895ea6ae205Smrg        filename = dsprintf("%s%s", dirname, entry->d_name);
896ea6ae205Smrg
8972d6e8b77Smrg#define PRIO(x) ((x << 1) + tprio)
8982d6e8b77Smrg#ifdef DT_LNK
8996ae2c069Smrg        if (entry->d_type != DT_UNKNOWN) {
9006ae2c069Smrg            if (entry->d_type == DT_LNK)
9016ae2c069Smrg                tprio = 0;
9026ae2c069Smrg        }
9036ae2c069Smrg        else
9042d6e8b77Smrg#endif
9052d6e8b77Smrg#ifdef S_ISLNK
9066ae2c069Smrg        {
9076ae2c069Smrg            if (lstat(filename, &f_stat))
9086ae2c069Smrg                goto done;
9096ae2c069Smrg            if (S_ISLNK(f_stat.st_mode))
9106ae2c069Smrg                tprio = 0;
9116ae2c069Smrg        }
9122d6e8b77Smrg#else
9136ae2c069Smrg            ;
9142d6e8b77Smrg#endif
9156ae2c069Smrg        if (doBitmaps)
916ea6ae205Smrg            rc = bitmapIdentify(filename, &xlfd_name);
917ea6ae205Smrg        else
918ea6ae205Smrg            rc = 0;
919ea6ae205Smrg
9206ae2c069Smrg        if (rc < 0)
921ea6ae205Smrg            goto done;
922ea6ae205Smrg
9236ae2c069Smrg        if (rc == 0) {
924ea6ae205Smrg            ftrc = FT_New_Face(ft_library, filename, 0, &face);
9256ae2c069Smrg            if (ftrc)
926ea6ae205Smrg                goto done;
927ea6ae205Smrg            have_face = 1;
928ea6ae205Smrg
929ea6ae205Smrg            isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0);
930ea6ae205Smrg
9316ae2c069Smrg            if (!isBitmap) {
932ea6ae205Smrg                /* Workaround for bitmap-only SFNT fonts */
9336ae2c069Smrg                if (FT_IS_SFNT(face) && face->num_fixed_sizes > 0 &&
9346ae2c069Smrg                    strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) {
935ea6ae205Smrg                    TT_MaxProfile *maxp;
9366ae2c069Smrg
937ea6ae205Smrg                    maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp);
9386ae2c069Smrg                    if (maxp != NULL && maxp->maxContours == 0)
939ea6ae205Smrg                        isBitmap = 1;
940ea6ae205Smrg                }
941ea6ae205Smrg            }
942663cdc11Smrg
9436ae2c069Smrg            if (isBitmap) {
9446ae2c069Smrg                if (!doBitmaps)
945ea6ae205Smrg                    goto done;
9466ae2c069Smrg            }
9476ae2c069Smrg            else {
9486ae2c069Smrg                if (!doScalable)
949ea6ae205Smrg                    goto done;
950ea6ae205Smrg            }
951ea6ae205Smrg
9526ae2c069Smrg            if (isBitmap) {
953ea6ae205Smrg                BDF_PropertyRec prop;
9546ae2c069Smrg
955ea6ae205Smrg                rc = FT_Get_BDF_Property(face, "FONT", &prop);
9566ae2c069Smrg                if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
9572d6e8b77Smrg                    xlfd_name = strdup(prop.u.atom);
9586ae2c069Smrg                    if (xlfd_name == NULL)
959ea6ae205Smrg                        goto done;
960ea6ae205Smrg                }
961ea6ae205Smrg            }
962ea6ae205Smrg        }
963ea6ae205Smrg
9646ae2c069Smrg        if (xlfd_name) {
965ea6ae205Smrg            /* We know it's a bitmap font, and we know its XLFD */
9667c5a9b20Smrg            size_t l = strlen(xlfd_name);
9676ae2c069Smrg
9686ae2c069Smrg            if (reencodeLegacy &&
9696ae2c069Smrg                l >= 12 && strcasecmp(xlfd_name + l - 11, "-iso10646-1") == 0) {
970ea6ae205Smrg                char *s;
971ea6ae205Smrg
9727c5a9b20Smrg                s = malloc(l - 10);
9736ae2c069Smrg                if (s == NULL) {
9746ae2c069Smrg                    fprintf(stderr, "Couldn't allocate xlfd name\n");
9756ae2c069Smrg                    exit(1);
9766ae2c069Smrg                }
9777c5a9b20Smrg                memcpy(s, xlfd_name, l - 11);
9787c5a9b20Smrg                s[l - 11] = '\0';
979ea6ae205Smrg                xlfd = listCons(s, xlfd);
9806ae2c069Smrg            }
9816ae2c069Smrg            else {
982ea6ae205Smrg                /* Not a reencodable font -- skip all the rest of the loop body */
9836ae2c069Smrg                putHash(entries, xlfd_name, entry->d_name,
9846ae2c069Smrg                        PRIO(filePrio(entry->d_name)));
985ea6ae205Smrg                goto done;
986ea6ae205Smrg            }
987ea6ae205Smrg        }
988ea6ae205Smrg
9896ae2c069Smrg        if (!have_face) {
990ea6ae205Smrg            ftrc = FT_New_Face(ft_library, filename, 0, &face);
9916ae2c069Smrg            if (ftrc)
992ea6ae205Smrg                goto done;
993ea6ae205Smrg            have_face = 1;
994ea6ae205Smrg            isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0);
995ea6ae205Smrg
9966ae2c069Smrg            if (!isBitmap) {
9976ae2c069Smrg                if (face->num_fixed_sizes > 0) {
998ea6ae205Smrg                    TT_MaxProfile *maxp;
9996ae2c069Smrg
1000ea6ae205Smrg                    maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp);
10016ae2c069Smrg                    if (maxp != NULL && maxp->maxContours == 0)
1002ea6ae205Smrg                        isBitmap = 1;
1003ea6ae205Smrg                }
1004ea6ae205Smrg            }
1005ea6ae205Smrg        }
1006ea6ae205Smrg
10076ae2c069Smrg        if (xlfd == NULL)
1008ea6ae205Smrg            xlfd = makeXLFD(entry->d_name, face, isBitmap);
1009ea6ae205Smrg
1010ea6ae205Smrg        found = 0;
1011ea6ae205Smrg
10126ae2c069Smrg        for (lp = xlfd; lp; lp = lp->next) {
1013ea6ae205Smrg            char buf[MAXFONTNAMELEN];
10146ae2c069Smrg
10156ae2c069Smrg            for (encoding = encodings; encoding; encoding = encoding->next) {
10166ae2c069Smrg                if (checkEncoding(face, encoding->value)) {
1017ea6ae205Smrg                    found = 1;
1018ea6ae205Smrg                    snprintf(buf, MAXFONTNAMELEN, "%s-%s",
10196ae2c069Smrg                             lp->value, encoding->value);
10206ae2c069Smrg                    putHash(entries, buf, entry->d_name,
10216ae2c069Smrg                            PRIO(filePrio(entry->d_name)));
1022ea6ae205Smrg                }
1023ea6ae205Smrg            }
10246ae2c069Smrg            for (encoding = extra_encodings; encoding;
10256ae2c069Smrg                 encoding = encoding->next) {
10266ae2c069Smrg                if (checkExtraEncoding(face, encoding->value, found)) {
1027ea6ae205Smrg                    /* Do not set found! */
1028ea6ae205Smrg                    snprintf(buf, MAXFONTNAMELEN, "%s-%s",
10296ae2c069Smrg                             lp->value, encoding->value);
10306ae2c069Smrg                    putHash(entries, buf, entry->d_name,
10316ae2c069Smrg                            PRIO(filePrio(entry->d_name)));
1032ea6ae205Smrg                }
1033ea6ae205Smrg            }
1034ea6ae205Smrg        }
10356ae2c069Smrg done:
10366ae2c069Smrg        if (have_face)
1037ea6ae205Smrg            FT_Done_Face(face);
1038ea6ae205Smrg        deepDestroyList(xlfd);
1039ea6ae205Smrg        xlfd = NULL;
1040ea6ae205Smrg        free(filename);
10412d6e8b77Smrg#undef PRIO
1042ea6ae205Smrg    }
1043ea6ae205Smrg
10446ae2c069Smrg    while (dirn--)
10457c5a9b20Smrg        free(namelist[dirn]);
10467c5a9b20Smrg    free(namelist);
1047ea6ae205Smrg    n = hashElements(entries);
1048ea6ae205Smrg    fprintf(fontscale, "%d\n", n);
1049ea6ae205Smrg    array = hashArray(entries, 1);
10506ae2c069Smrg    for (i = 0; i < n; i++)
1051ea6ae205Smrg        fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key);
1052ea6ae205Smrg    destroyHashArray(array);
1053ea6ae205Smrg    entries = NULL;
10546ae2c069Smrg    if (fontscale_name) {
1055ea6ae205Smrg        fclose(fontscale);
1056ea6ae205Smrg        free(fontscale_name);
1057ea6ae205Smrg    }
1058ea6ae205Smrg
1059ea6ae205Smrg encodings:
1060ea6ae205Smrg    encdir = dsprintf("%s%s", dirname, "encodings.dir");
1061ea6ae205Smrg
10626ae2c069Smrg    if (encdir == NULL) {
10636ae2c069Smrg        perror("encodings");
10646ae2c069Smrg        exit(1);
1065ea6ae205Smrg    }
1066ea6ae205Smrg    unlink(encdir);
1067ea6ae205Smrg
1068ea6ae205Smrg    if (numEncodings) {
10696ae2c069Smrg        encfile = fopen(encdir, "w");
10706ae2c069Smrg        if (encfile == NULL) {
10716ae2c069Smrg            perror("open(encodings.dir)");
10726ae2c069Smrg            exit(1);
10736ae2c069Smrg        }
1074ea6ae205Smrg        fprintf(encfile, "%d\n", numEncodings);
1075245f6787Smrg        encodingsToDo = sortList(encodingsToDo);
10766ae2c069Smrg        for (lp = encodingsToDo; lp; lp = lp->next) {
1077ea6ae205Smrg            fprintf(encfile, "%s\n", lp->value);
1078ea6ae205Smrg        }
10796ae2c069Smrg        fclose(encfile);
1080ea6ae205Smrg    }
1081ea6ae205Smrg
1082ea6ae205Smrg    free(dirname);
1083ea6ae205Smrg    return 1;
1084ea6ae205Smrg}
1085ea6ae205Smrg
1086ea6ae205Smrg#define CODE_IGNORED(c) ((c) < 0x20 || \
1087ea6ae205Smrg                         ((c) >= 0x7F && (c) <= 0xA0) || \
1088ea6ae205Smrg                         (c) == 0xAD || (c) == 0xF71B)
1089663cdc11Smrg
1090ea6ae205Smrgstatic int
10917c5a9b20SmrgcheckEncoding(FT_Face face, const char *encoding_name)
1092ea6ae205Smrg{
1093ea6ae205Smrg    FontEncPtr encoding;
1094ea6ae205Smrg    FontMapPtr mapping;
1095ea6ae205Smrg
1096ea6ae205Smrg    encoding = FontEncFind(encoding_name, NULL);
10976ae2c069Smrg    if (!encoding)
1098ea6ae205Smrg        return 0;
1099ea6ae205Smrg
1100ea6ae205Smrg    /* An encoding is ``small'' if one of the following is true:
11016ae2c069Smrg       - it is linear and has no more than 256 codepoints; or
11026ae2c069Smrg       - it is a matrix encoding and has no more than one column.
1103663cdc11Smrg
1104ea6ae205Smrg       For small encodings using Unicode indices, we require perfect
1105ea6ae205Smrg       coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility.
1106ea6ae205Smrg
1107ea6ae205Smrg       For large encodings, we require coverage up to bigEncodingFuzz.
1108ea6ae205Smrg
1109ea6ae205Smrg       For encodings using PS names (currently Adobe Standard and
1110ea6ae205Smrg       Adobe Symbol only), we require perfect coverage. */
1111ea6ae205Smrg
11126ae2c069Smrg    if (FT_Has_PS_Glyph_Names(face)) {
11136ae2c069Smrg        for (mapping = encoding->mappings; mapping; mapping = mapping->next) {
11146ae2c069Smrg            if (mapping->type == FONT_ENCODING_POSTSCRIPT) {
11156ae2c069Smrg                if (encoding->row_size > 0) {
11166ae2c069Smrg                    for (int i = encoding->first; i < encoding->size; i++) {
11176ae2c069Smrg                        for (int j = encoding->first_col;
11186ae2c069Smrg                             j < encoding->row_size; j++) {
11196ae2c069Smrg                            char *n = FontEncName((i << 8) | j, mapping);
11206ae2c069Smrg                            if (n && FT_Get_Name_Index(face, n) == 0) {
1121ea6ae205Smrg                                return 0;
1122ea6ae205Smrg                            }
1123ea6ae205Smrg                        }
1124ea6ae205Smrg                    }
1125ea6ae205Smrg                    return 1;
11266ae2c069Smrg                }
11276ae2c069Smrg                else {
11286ae2c069Smrg                    for (int i = encoding->first; i < encoding->size; i++) {
11296ae2c069Smrg                        char *n = FontEncName(i, mapping);
11306ae2c069Smrg                        if (n && FT_Get_Name_Index(face, n) == 0) {
1131ea6ae205Smrg                            return 0;
1132ea6ae205Smrg                        }
1133ea6ae205Smrg                    }
1134ea6ae205Smrg                    return 1;
1135ea6ae205Smrg                }
1136ea6ae205Smrg            }
1137ea6ae205Smrg        }
1138ea6ae205Smrg    }
1139ea6ae205Smrg
11406ae2c069Smrg    for (mapping = encoding->mappings; mapping; mapping = mapping->next) {
11416ae2c069Smrg        if (find_cmap(mapping->type, mapping->pid, mapping->eid, face)) {
1142ea6ae205Smrg            int total = 0, failed = 0;
11436ae2c069Smrg
11446ae2c069Smrg            if (encoding->row_size > 0) {
1145663cdc11Smrg                int estimate =
1146ea6ae205Smrg                    (encoding->size - encoding->first) *
1147ea6ae205Smrg                    (encoding->row_size - encoding->first_col);
11486ae2c069Smrg                for (int i = encoding->first; i < encoding->size; i++) {
11496ae2c069Smrg                    for (int j = encoding->first_col; j < encoding->row_size;
11506ae2c069Smrg                         j++) {
11516ae2c069Smrg                        int c = FontEncRecode((i << 8) | j, mapping);
11526ae2c069Smrg                        if (CODE_IGNORED(c)) {
1153ea6ae205Smrg                            continue;
11546ae2c069Smrg                        }
11556ae2c069Smrg                        else {
11566ae2c069Smrg                            if (FT_Get_Char_Index(face, c) == 0) {
1157ea6ae205Smrg                                failed++;
1158ea6ae205Smrg                            }
1159ea6ae205Smrg                            total++;
11606ae2c069Smrg                            if ((encoding->size <= 1 && failed > 0) ||
11616ae2c069Smrg                                ((float) failed >=
11626ae2c069Smrg                                 bigEncodingFuzz * estimate)) {
1163ea6ae205Smrg                                return 0;
1164ea6ae205Smrg                            }
1165ea6ae205Smrg                        }
1166ea6ae205Smrg                    }
1167ea6ae205Smrg                }
11686ae2c069Smrg                if ((float) failed >= total * bigEncodingFuzz)
1169ea6ae205Smrg                    return 0;
1170ea6ae205Smrg                else
1171ea6ae205Smrg                    return 1;
11726ae2c069Smrg            }
11736ae2c069Smrg            else {
1174ea6ae205Smrg                int estimate = encoding->size - encoding->first;
11756ae2c069Smrg                int koi8;
11766ae2c069Smrg
1177ea6ae205Smrg                /* For the KOI8 encodings, we ignore the lack of
1178ea6ae205Smrg                   linedrawing and pseudo-math characters */
11796ae2c069Smrg                if (strncmp(encoding->name, "koi8-", 5) == 0)
1180ea6ae205Smrg                    koi8 = 1;
1181ea6ae205Smrg                else
1182ea6ae205Smrg                    koi8 = 0;
11836ae2c069Smrg                for (int i = encoding->first; i < encoding->size; i++) {
11846ae2c069Smrg                    unsigned int c = FontEncRecode(i, mapping);
11856ae2c069Smrg                    if (CODE_IGNORED(c) ||
11866ae2c069Smrg                        (koi8 &&
11876ae2c069Smrg                         ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) {
1188ea6ae205Smrg                        continue;
11896ae2c069Smrg                    }
11906ae2c069Smrg                    else {
11916ae2c069Smrg                        if (FT_Get_Char_Index(face, c) == 0) {
1192ea6ae205Smrg                            failed++;
1193ea6ae205Smrg                        }
1194ea6ae205Smrg                        total++;
11956ae2c069Smrg                        if ((encoding->size <= 256 && failed > 0) ||
11966ae2c069Smrg                            ((float) failed >= bigEncodingFuzz * estimate)) {
1197ea6ae205Smrg                            return 0;
1198ea6ae205Smrg                        }
1199ea6ae205Smrg                    }
1200ea6ae205Smrg                }
12016ae2c069Smrg                if ((float) failed >= total * bigEncodingFuzz)
1202ea6ae205Smrg                    return 0;
1203ea6ae205Smrg                else
1204ea6ae205Smrg                    return 1;
1205ea6ae205Smrg            }
1206ea6ae205Smrg        }
1207ea6ae205Smrg    }
1208ea6ae205Smrg    return 0;
1209ea6ae205Smrg}
1210ea6ae205Smrg
1211663cdc11Smrgstatic int
1212ea6ae205Smrgfind_cmap(int type, int pid, int eid, FT_Face face)
1213ea6ae205Smrg{
12146ae2c069Smrg    int n = face->num_charmaps;
12156ae2c069Smrg
12166ae2c069Smrg    switch (type) {
12176ae2c069Smrg    case FONT_ENCODING_TRUETYPE:       /* specific cmap */
12186ae2c069Smrg        for (int i = 0; i < n; i++) {
12196ae2c069Smrg            FT_CharMap cmap = face->charmaps[i];
12206ae2c069Smrg            if (cmap->platform_id == pid && cmap->encoding_id == eid) {
12216ae2c069Smrg                int rc = FT_Set_Charmap(face, cmap);
12226ae2c069Smrg                if (rc == 0)
1223ea6ae205Smrg                    return 1;
1224ea6ae205Smrg            }
1225ea6ae205Smrg        }
1226ea6ae205Smrg        break;
12276ae2c069Smrg    case FONT_ENCODING_UNICODE:        /* any Unicode cmap */
1228ea6ae205Smrg        /* prefer Microsoft Unicode */
12296ae2c069Smrg        for (int i = 0; i < n; i++) {
12306ae2c069Smrg            FT_CharMap cmap = face->charmaps[i];
12316ae2c069Smrg            if (cmap->platform_id == TT_PLATFORM_MICROSOFT &&
12326ae2c069Smrg                cmap->encoding_id == TT_MS_ID_UNICODE_CS) {
12336ae2c069Smrg                int rc = FT_Set_Charmap(face, cmap);
12346ae2c069Smrg                if (rc == 0)
1235ea6ae205Smrg                    return 1;
1236ea6ae205Smrg            }
1237ea6ae205Smrg        }
1238ea6ae205Smrg        /* Try Apple Unicode */
12396ae2c069Smrg        for (int i = 0; i < n; i++) {
12406ae2c069Smrg            FT_CharMap cmap = face->charmaps[i];
12416ae2c069Smrg            if (cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) {
12426ae2c069Smrg                int rc = FT_Set_Charmap(face, cmap);
12436ae2c069Smrg                if (rc == 0)
1244ea6ae205Smrg                    return 1;
1245ea6ae205Smrg            }
1246ea6ae205Smrg        }
1247ea6ae205Smrg        /* ISO Unicode? */
12486ae2c069Smrg        for (int i = 0; i < n; i++) {
12496ae2c069Smrg            FT_CharMap cmap = face->charmaps[i];
12506ae2c069Smrg            if (cmap->platform_id == TT_PLATFORM_ISO) {
12516ae2c069Smrg                int rc = FT_Set_Charmap(face, cmap);
12526ae2c069Smrg                if (rc == 0)
1253ea6ae205Smrg                    return 1;
1254ea6ae205Smrg            }
1255ea6ae205Smrg        }
1256ea6ae205Smrg        break;
1257ea6ae205Smrg    default:
1258ea6ae205Smrg        return 0;
1259ea6ae205Smrg    }
1260ea6ae205Smrg    return 0;
1261ea6ae205Smrg}
1262ea6ae205Smrg
1263ea6ae205Smrgstatic int
12647c5a9b20SmrgcheckExtraEncoding(FT_Face face, const char *encoding_name, int found)
1265ea6ae205Smrg{
12666ae2c069Smrg    if (strcasecmp(encoding_name, "iso10646-1") == 0) {
12676ae2c069Smrg        if (doISO10646_1_encoding &&
12686ae2c069Smrg            find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) {
12697c5a9b20Smrg            int cfound = 0;
12706ae2c069Smrg
12716ae2c069Smrg            /* Export as Unicode if there are at least 15 BMP
1272ea6ae205Smrg               characters that are not a space or ignored. */
12736ae2c069Smrg            for (unsigned int c = 0x21; c < 0x10000; c++) {
12746ae2c069Smrg                if (CODE_IGNORED(c))
1275ea6ae205Smrg                    continue;
12766ae2c069Smrg                if (FT_Get_Char_Index(face, c) > 0)
12777c5a9b20Smrg                    cfound++;
12786ae2c069Smrg                if (cfound >= 15)
1279ea6ae205Smrg                    return 1;
1280ea6ae205Smrg            }
1281ea6ae205Smrg            return 0;
12826ae2c069Smrg        }
12836ae2c069Smrg        else
1284ea6ae205Smrg            return 0;
12856ae2c069Smrg    }
12866ae2c069Smrg    else if (strcasecmp(encoding_name, "microsoft-symbol") == 0) {
12876ae2c069Smrg        if (find_cmap(FONT_ENCODING_TRUETYPE,
12886ae2c069Smrg                      TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, face))
1289ea6ae205Smrg            return 1;
1290ea6ae205Smrg        else
1291ea6ae205Smrg            return 0;
12926ae2c069Smrg    }
12936ae2c069Smrg    else if (strcasecmp(encoding_name, "adobe-fontspecific") == 0) {
12946ae2c069Smrg        if (!found) {
12956ae2c069Smrg            if (FT_Has_PS_Glyph_Names(face))
1296ea6ae205Smrg                return 1;
1297ea6ae205Smrg            else
1298ea6ae205Smrg                return 0;
12996ae2c069Smrg        }
13006ae2c069Smrg        else
1301ea6ae205Smrg            return 0;
13026ae2c069Smrg    }
13036ae2c069Smrg    else {
1304ea6ae205Smrg        fprintf(stderr, "Unknown extra encoding %s\n", encoding_name);
1305ea6ae205Smrg        return 0;
1306ea6ae205Smrg    }
1307ea6ae205Smrg}
1308ea6ae205Smrg
13096ae2c069Smrgstatic const char *
1310663cdc11Smrgnotice_foundry(const char *notice)
1311ea6ae205Smrg{
13126ae2c069Smrg    for (unsigned int i = 0; i < countof(notice_foundries); i++)
13136ae2c069Smrg        if (notice && strstr(notice, notice_foundries[i][0]))
1314ea6ae205Smrg            return notice_foundries[i][1];
1315ea6ae205Smrg    return NULL;
1316ea6ae205Smrg}
1317ea6ae205Smrg
1318ea6ae205Smrgstatic int
1319663cdc11Smrgvendor_match(const signed char *vendor, const char *vendor_string)
1320ea6ae205Smrg{
1321ea6ae205Smrg    /* vendor is not necessarily NUL-terminated. */
13227c5a9b20Smrg    size_t i, len;
13236ae2c069Smrg
1324ea6ae205Smrg    len = strlen(vendor_string);
13256ae2c069Smrg    if (memcmp(vendor, vendor_string, len) != 0)
1326ea6ae205Smrg        return 0;
13276ae2c069Smrg    for (i = len; i < 4; i++)
13286ae2c069Smrg        if (vendor[i] != ' ' && vendor[i] != '\0')
1329ea6ae205Smrg            return 0;
1330ea6ae205Smrg    return 1;
1331ea6ae205Smrg}
1332ea6ae205Smrg
13336ae2c069Smrgstatic const char *
1334663cdc11Smrgvendor_foundry(const signed char *vendor)
1335ea6ae205Smrg{
13366ae2c069Smrg    for (unsigned int i = 0; i < countof(vendor_foundries); i++)
13376ae2c069Smrg        if (vendor_match(vendor, vendor_foundries[i][0]))
1338ea6ae205Smrg            return vendor_foundries[i][1];
1339ea6ae205Smrg    return NULL;
1340ea6ae205Smrg}
1341ea6ae205Smrg
1342ea6ae205Smrgstatic int
13436ae2c069SmrgreadEncodings(ListPtr *encodingsToDo, char *dirname)
1344ea6ae205Smrg{
1345ea6ae205Smrg    DIR *dirp;
1346ea6ae205Smrg    struct dirent *file;
1347ea6ae205Smrg
13486ae2c069Smrg    if (strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/')
1349ea6ae205Smrg        dirname[strlen(dirname) - 1] = '\0';
1350ea6ae205Smrg
1351ea6ae205Smrg    dirp = opendir(dirname);
13526ae2c069Smrg    if (dirp == NULL) {
1353ea6ae205Smrg        perror("opendir");
1354ea6ae205Smrg        return -1;
1355ea6ae205Smrg    }
1356ea6ae205Smrg
13576ae2c069Smrg    while ((file = readdir(dirp)) != NULL) {
13586ae2c069Smrg        char *fullname = dsprintf("%s/%s", dirname, file->d_name);
13596ae2c069Smrg        char **names;
13606ae2c069Smrg
13616ae2c069Smrg        if (fullname == NULL) {
1362ea6ae205Smrg            fprintf(stderr, "Couldn't allocate fullname\n");
1363ea6ae205Smrg            closedir(dirp);
1364ea6ae205Smrg            return -1;
1365ea6ae205Smrg        }
1366663cdc11Smrg
1367ea6ae205Smrg        names = FontEncIdentify(fullname);
13686ae2c069Smrg        if (!names)
1369ea6ae205Smrg            continue;
1370ea6ae205Smrg
13716ae2c069Smrg        for (char **name = names; *name; name++) {
13726ae2c069Smrg            if (fullname[0] != '/' && !relative) {
1373ea6ae205Smrg                char *n;
13746ae2c069Smrg
1375ea6ae205Smrg                n = dsprintf("%s%s", encodingPrefix, fullname);
13766ae2c069Smrg                if (n == NULL) {
1377ea6ae205Smrg                    fprintf(stderr, "Couldn't allocate name\n");
1378ea6ae205Smrg                    closedir(dirp);
1379ea6ae205Smrg                    return -1;
1380ea6ae205Smrg                }
13816ae2c069Smrg                *encodingsToDo = listConsF(*encodingsToDo, "%s %s", *name, n);
1382ea6ae205Smrg                free(n);
1383ea6ae205Smrg            }
13846ae2c069Smrg            else {
13856ae2c069Smrg                *encodingsToDo =
13866ae2c069Smrg                    listConsF(*encodingsToDo, "%s %s", *name, fullname);
13876ae2c069Smrg            }
13886ae2c069Smrg            if (*encodingsToDo == NULL) {
1389ea6ae205Smrg                fprintf(stderr, "Couldn't allocate encodings\n");
1390ea6ae205Smrg                closedir(dirp);
1391ea6ae205Smrg                return -1;
1392ea6ae205Smrg            }
1393ea6ae205Smrg        }
1394ea6ae205Smrg        free(names);            /* only the spine */
1395ea6ae205Smrg    }
1396ea6ae205Smrg    closedir(dirp);
1397ea6ae205Smrg    return 0;
1398ea6ae205Smrg}
1399