| /* |
| * Copyright 2001 Ian Pilcher |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| |
| #include <sys/types.h> |
| #ifdef HAVE_DIRENT_H |
| # include <dirent.h> |
| #endif |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| |
| |
| /* |
| * The array of glyph information |
| */ |
| |
| typedef struct |
| { |
| int UV; |
| int index; /* in PSDRV_AGLGlyphNames */ |
| const char *name; |
| const char *comment; |
| |
| } GLYPHINFO; |
| |
| static GLYPHINFO glyphs[1500]; |
| static int num_glyphs = 0; |
| |
| |
| /* |
| * Functions to search and sort the array |
| */ |
| |
| static int cmp_by_UV(const void *a, const void *b) |
| { |
| return ((const GLYPHINFO *)a)->UV - ((const GLYPHINFO *)b)->UV; |
| } |
| |
| static int cmp_by_name(const void *a, const void *b) |
| { |
| return strcmp(((const GLYPHINFO *)a)->name, ((const GLYPHINFO *)b)->name); |
| } |
| |
| static inline void sort_by_UV(void) |
| { |
| qsort(glyphs, num_glyphs, sizeof(GLYPHINFO), cmp_by_UV); |
| } |
| |
| static inline void sort_by_name(void) |
| { |
| qsort(glyphs, num_glyphs, sizeof(GLYPHINFO), cmp_by_name); |
| } |
| |
| static inline GLYPHINFO *search_by_name(const char *name) |
| { |
| GLYPHINFO gi; |
| |
| gi.name = name; |
| |
| return (GLYPHINFO *)bsearch(&gi, glyphs, num_glyphs, sizeof(GLYPHINFO), |
| cmp_by_name); |
| } |
| |
| |
| /* |
| * Use the 'optimal' combination of tabs and spaces to position the cursor |
| */ |
| |
| static inline void fcpto(FILE *f, int newpos, int curpos) |
| { |
| int newtpos = newpos & ~7; |
| int curtpos = curpos & ~7; |
| |
| while (curtpos < newtpos) |
| { |
| fputc('\t', f); |
| curtpos += 8; |
| curpos = curtpos; |
| } |
| |
| while (curpos < newpos) |
| { |
| fputc(' ', f); |
| ++curpos; |
| } |
| } |
| |
| /* |
| * Make main() look "purty" |
| */ |
| |
| static inline void triple_space(FILE *f) |
| { |
| fputc('\n', f); fputc('\n', f); |
| } |
| |
| |
| /* |
| * Read the Adobe Glyph List from 'glyphlist.txt' |
| */ |
| |
| static void read_agl(void) |
| { |
| FILE *f = fopen("glyphlist.txt", "r"); |
| char linebuf[256], namebuf[128], commbuf[128]; |
| |
| if (f == NULL) |
| { |
| fprintf(stderr, "Error opening glyphlist.txt\n"); |
| exit(__LINE__); |
| } |
| |
| while (fgets(linebuf, sizeof(linebuf), f) != NULL) |
| { |
| unsigned int UV; |
| |
| if (linebuf[0] == '#') |
| continue; |
| |
| sscanf(linebuf, "%X;%[^;];%[^\n]", &UV, namebuf, commbuf); |
| |
| glyphs[num_glyphs].UV = (int)UV; |
| glyphs[num_glyphs].name = strdup(namebuf); |
| glyphs[num_glyphs].comment = strdup(commbuf); |
| |
| if (glyphs[num_glyphs].name == NULL || |
| glyphs[num_glyphs].comment == NULL) |
| { |
| fprintf(stderr, "Memory allocation failure\n"); |
| exit(__LINE__); |
| } |
| |
| ++num_glyphs; |
| } |
| |
| fclose(f); |
| |
| if (num_glyphs != 1051) |
| { |
| fprintf(stderr, "Read %i glyphs\n", num_glyphs); |
| exit(__LINE__); |
| } |
| } |
| |
| |
| /* |
| * Read glyph names from all AFM files in current directory |
| */ |
| |
| static void read_afms(FILE *f_c, FILE *f_h) |
| { |
| DIR *d = opendir("."); |
| struct dirent *de; |
| |
| fputs( "/*\n" |
| " * Built-in font metrics\n" |
| " */\n" |
| "\n" |
| "const AFM *const PSDRV_BuiltinAFMs[] =\n" |
| "{\n", f_c); |
| |
| |
| if (d == NULL) |
| { |
| fprintf(stderr, "Error opening current directory\n"); |
| exit(__LINE__); |
| } |
| |
| while ((de = readdir(d)) != NULL) |
| { |
| FILE *f; |
| char *cp, linebuf[256], font_family[128]; |
| int i, num_metrics; |
| |
| cp = strrchr(de->d_name, '.'); /* Does it end in */ |
| if (cp == NULL || strcasecmp(cp, ".afm") != 0) /* .afm or .AFM? */ |
| continue; |
| |
| f = fopen(de->d_name, "r"); |
| if (f == NULL) |
| { |
| fprintf(stderr, "Error opening %s\n", de->d_name); |
| exit(__LINE__); |
| } |
| |
| while (1) |
| { |
| if (fgets(linebuf, sizeof(linebuf), f) == NULL) |
| { |
| fprintf(stderr, "FontName not found in %s\n", de->d_name); |
| exit(__LINE__); |
| } |
| |
| if (strncmp(linebuf, "FontName ", 9) == 0) |
| break; |
| } |
| |
| sscanf(linebuf, "FontName %[^\r\n]", font_family); |
| |
| for (i = 0; font_family[i] != '\0'; ++i) |
| if (font_family[i] == '-') |
| font_family[i] = '_'; |
| |
| fprintf(f_h, "DECLSPEC_HIDDEN extern const AFM PSDRV_%s;\n", font_family); |
| fprintf(f_c, " &PSDRV_%s,\n", font_family); |
| |
| while (1) |
| { |
| if (fgets(linebuf, sizeof(linebuf), f) == NULL) |
| { |
| fprintf(stderr, "FamilyName not found in %s\n", de->d_name); |
| exit(__LINE__); |
| } |
| |
| if (strncmp(linebuf, "FamilyName ", 11) == 0) |
| break; |
| } |
| |
| sscanf(linebuf, "FamilyName %[^\r\n]", font_family); |
| |
| while (1) |
| { |
| if (fgets(linebuf, sizeof(linebuf), f) == NULL) |
| { |
| fprintf(stderr, "StartCharMetrics not found in %s\n", |
| de->d_name); |
| exit(__LINE__); |
| } |
| |
| if (strncmp(linebuf, "StartCharMetrics ", 17) == 0) |
| break; |
| } |
| |
| sscanf(linebuf, "StartCharMetrics %i", &num_metrics); |
| |
| for (i = 0; i < num_metrics; ++i) |
| { |
| char namebuf[128]; |
| |
| if (fgets(linebuf, sizeof(linebuf), f) == NULL) |
| { |
| fprintf(stderr, "Unexpected EOF after %i glyphs in %s\n", i, |
| de->d_name); |
| exit(__LINE__); |
| } |
| |
| cp = strchr(linebuf, 'N'); |
| if (cp == NULL || strlen(cp) < 3) |
| { |
| fprintf(stderr, "Parse error after %i glyphs in %s\n", i, |
| de->d_name); |
| exit(__LINE__); |
| } |
| |
| sscanf(cp, "N %s", namebuf); |
| if (search_by_name(namebuf) != NULL) |
| continue; |
| |
| sprintf(linebuf, "FONT FAMILY;%s", font_family); |
| |
| glyphs[num_glyphs].UV = -1; |
| glyphs[num_glyphs].name = strdup(namebuf); |
| glyphs[num_glyphs].comment = strdup(linebuf); |
| |
| if (glyphs[num_glyphs].name == NULL || |
| glyphs[num_glyphs].comment == NULL) |
| { |
| fprintf(stderr, "Memory allocation failure\n"); |
| exit(__LINE__); |
| } |
| |
| ++num_glyphs; |
| |
| sort_by_name(); |
| } |
| |
| fclose(f); |
| } |
| |
| closedir(d); |
| |
| fputs(" NULL\n};\n", f_c); |
| } |
| |
| |
| /* |
| * Write opening comments, etc. |
| */ |
| |
| static void write_header(FILE *f) |
| { |
| int i; |
| |
| fputc('/', f); |
| for (i = 0; i < 79; ++i) |
| fputc('*', f); |
| fputs("\n" |
| " *\n" |
| " *\tFont and glyph data for the Wine PostScript driver\n" |
| " *\n" |
| " *\tCopyright 2001 Ian Pilcher\n" |
| " *\n" |
| " *\n" |
| " *\tThis data is derived from the Adobe Glyph list at\n" |
| " *\n" |
| " *\t " |
| "http://partners.adobe.com/asn/developer/type/glyphlist.txt\n" |
| " *\n" |
| " *\tand the Adobe Font Metrics files at\n" |
| " *\n" |
| " *\t " |
| "ftp://ftp.adobe.com/pub/adobe/type/win/all/afmfiles/base35/\n" |
| " *\n" |
| " *\twhich are Copyright 1985-1998 Adobe Systems Incorporated.\n" |
| " *\n" |
| " */\n" |
| "\n" |
| "#include \"psdrv.h\"\n" |
| "#include \"data/agl.h\"\n", f); |
| } |
| |
| /* |
| * Write the array of glyph names (also populates indexes) |
| */ |
| |
| static void write_glyph_names(FILE *f_c, FILE *f_h) |
| { |
| int i, num_names = 0, index = 0; |
| |
| for (i = 0; i < num_glyphs; ++i) |
| if (i == 0 || strcmp(glyphs[i - 1].name, glyphs[i].name) != 0) |
| ++num_names; |
| |
| fputs( "/*\n" |
| " * Every glyph name in the AGL and the 35 core PostScript fonts\n" |
| " */\n" |
| "\n", f_c); |
| |
| fprintf(f_c, "const INT PSDRV_AGLGlyphNamesSize = %i;\n\n", num_names); |
| |
| fprintf(f_c, "GLYPHNAME PSDRV_AGLGlyphNames[%i] =\n{\n", num_names); |
| |
| for (i = 0; i < num_glyphs - 1; ++i) |
| { |
| int cp = 0; |
| |
| if (i == 0 || strcmp(glyphs[i - 1].name, glyphs[i].name) != 0) |
| { |
| fcpto(f_h, 32, fprintf(f_h, "#define GN_%s", glyphs[i].name)); |
| fprintf(f_h, "(PSDRV_AGLGlyphNames + %i)\n", index); |
| |
| cp = fprintf(f_c, " { %4i, \"%s\" },", index, glyphs[i].name); |
| glyphs[i].index = index; |
| ++index; |
| } |
| else |
| { |
| glyphs[i].index = glyphs[i - 1].index; |
| } |
| |
| fcpto(f_c, 40, cp); |
| |
| fprintf(f_c, "/* %s */\n", glyphs[i].comment); |
| } |
| |
| fcpto(f_h, 32, fprintf(f_h, "#define GN_%s", glyphs[i].name)); |
| fprintf(f_h, "(PSDRV_AGLGlyphNames + %i)\n", index); |
| |
| glyphs[i].index = index; |
| fcpto(f_c, 40, fprintf(f_c, " { %4i, \"%s\" }", index, glyphs[i].name)); |
| fprintf(f_c, "/* %s */\n};\n", glyphs[i].comment); |
| } |
| |
| |
| /* |
| * Write the AGL encoding vector, sorted by glyph name |
| */ |
| |
| static void write_encoding_by_name(FILE *f) |
| { |
| int i, size = 0, even = 1; |
| |
| for (i = 0; i < num_glyphs; ++i) |
| if (glyphs[i].UV != -1 && |
| (i == 0 || strcmp(glyphs[i - 1].name, glyphs[i].name) != 0)) |
| ++size; /* should be 1039 */ |
| |
| fputs( "/*\n" |
| " * The AGL encoding vector, sorted by glyph name - " |
| "duplicates omitted\n" |
| " */\n" |
| "\n", f); |
| |
| fprintf(f, "const INT PSDRV_AGLbyNameSize = %i;\n\n", size); |
| fprintf(f, "const UNICODEGLYPH PSDRV_AGLbyName[%i] =\n{\n", size); |
| |
| for (i = 0; i < num_glyphs - 1; ++i) |
| { |
| int cp; |
| |
| if (glyphs[i].UV == -1) |
| continue; |
| |
| if (i != 0 && strcmp(glyphs[i - 1].name, glyphs[i].name) == 0) |
| continue; |
| |
| cp = fprintf(f, " { 0x%.4x, GN_%s },", glyphs[i].UV, glyphs[i].name); |
| |
| even = !even; |
| if (even) |
| fputc('\n', f); |
| else |
| fcpto(f, 40, cp); |
| } |
| |
| fprintf(f, " { 0x%.4x, GN_%s }\n};\n", glyphs[i].UV, glyphs[i].name); |
| } |
| |
| /* |
| * Write the AGL encoding vector, sorted by Unicode value |
| */ |
| |
| static void write_encoding_by_UV(FILE *f) |
| { |
| int i, size = 0, even = 1; |
| |
| for (i = 0; i < num_glyphs; ++i) |
| if (glyphs[i].UV != -1) |
| ++size; /* better be 1051! */ |
| |
| sort_by_UV(); |
| |
| fputs( "/*\n" |
| " * The AGL encoding vector, sorted by Unicode value - " |
| "duplicates included\n" |
| " */\n" |
| "\n", f); |
| |
| fprintf(f, "const INT PSDRV_AGLbyUVSize = %i;\n\n", size); |
| fprintf(f, "const UNICODEGLYPH PSDRV_AGLbyUV[%i] =\n{\n", size); |
| |
| for (i = 0; i < num_glyphs - 1; ++i) |
| { |
| int cp; |
| |
| if (glyphs[i].UV == -1) |
| continue; |
| |
| cp = fprintf(f, " { 0x%.4x, GN_%s },", glyphs[i].UV, glyphs[i].name); |
| |
| even = !even; |
| if (even) |
| fputc('\n', f); |
| else |
| fcpto(f, 40, cp); |
| } |
| |
| fprintf(f, " { 0x%.4x, GN_%s }\n};\n", glyphs[i].UV, glyphs[i].name); |
| } |
| |
| |
| /* |
| * Do it! |
| */ |
| |
| int main(int argc, char *argv[]) |
| { |
| FILE *f_c, *f_h; |
| |
| if (argc < 3) |
| { |
| fprintf(stderr, "Usage: %s <C file> <header file>\n", argv[0]); |
| exit(__LINE__); |
| } |
| |
| f_c = fopen(argv[1], "w"); |
| if (f_c == NULL) |
| { |
| fprintf(stderr, "Error opening %s for writing\n", argv[1]); |
| exit(__LINE__); |
| } |
| |
| f_h = fopen(argv[2], "w"); |
| if (f_h == NULL) |
| { |
| fprintf(stderr, "Error opening %s for writing\n", argv[2]); |
| exit(__LINE__); |
| } |
| |
| write_header(f_c); |
| triple_space(f_c); |
| read_agl(); |
| read_afms(f_c, f_h); /* also writes font list */ |
| triple_space(f_c); |
| write_glyph_names(f_c, f_h); |
| triple_space(f_c); |
| write_encoding_by_name(f_c); |
| triple_space(f_c); |
| write_encoding_by_UV(f_c); |
| |
| /* Clean up */ |
| fclose(f_c); |
| fclose(f_h); |
| |
| return 0; |
| } |