4 |
* convert X font metrics into troff font metrics |
* convert X font metrics into troff font metrics |
5 |
*/ |
*/ |
6 |
|
|
7 |
#include <X11/Xlib.h> |
#ifdef HAVE_CONFIG_H |
8 |
#include <stdio.h> |
#include <config.h> |
|
#include <ctype.h> |
|
|
#include <unistd.h> |
|
|
#include <stdlib.h> |
|
|
#include <getopt.h> |
|
|
#include <string.h> |
|
|
#include <fcntl.h> |
|
|
#include "XFontName.h" |
|
|
#include "DviChar.h" |
|
|
|
|
|
#ifdef X_NOT_STDC_ENV |
|
|
char *malloc(); |
|
|
#else |
|
|
#include <stdlib.h> |
|
9 |
#endif |
#endif |
10 |
|
|
11 |
#define charWidth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].width) |
#include <X11/Xlib.h> |
12 |
#define charHeight(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].ascent) |
#include <stdio.h> |
13 |
#define charDepth(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].descent) |
#include <ctype.h> |
14 |
#define charLBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].lbearing) |
#include <unistd.h> |
15 |
#define charRBearing(fi,c) ((fi)->per_char[(c) - (fi)->min_char_or_byte2].rbearing) |
#include <stdlib.h> |
16 |
|
#include <getopt.h> |
17 |
Display *dpy; |
#include <string.h> |
18 |
int groff_flag = 0; |
#include <fcntl.h> |
19 |
unsigned resolution = 75; |
#include <limits.h> |
20 |
unsigned point_size = 10; |
#include "XFontName.h" |
21 |
|
#include "DviChar.h" |
22 |
|
|
23 |
|
#define charWidth(fi,c) \ |
24 |
|
((fi)->per_char[(c) - (fi)->min_char_or_byte2].width) |
25 |
|
#define charHeight(fi,c) \ |
26 |
|
((fi)->per_char[(c) - (fi)->min_char_or_byte2].ascent) |
27 |
|
#define charDepth(fi,c) \ |
28 |
|
((fi)->per_char[(c) - (fi)->min_char_or_byte2].descent) |
29 |
|
#define charLBearing(fi,c) \ |
30 |
|
((fi)->per_char[(c) - (fi)->min_char_or_byte2].lbearing) |
31 |
|
#define charRBearing(fi,c) \ |
32 |
|
((fi)->per_char[(c) - (fi)->min_char_or_byte2].rbearing) |
33 |
|
|
34 |
|
extern const char *Version_string; |
35 |
|
static char *program_name; |
36 |
|
|
37 |
|
Display *dpy; |
38 |
|
unsigned resolution = 75; |
39 |
|
unsigned point_size = 10; |
40 |
|
|
41 |
int charExists (XFontStruct *fi, int c) |
int charExists(XFontStruct * fi, int c) |
42 |
{ |
{ |
43 |
XCharStruct *p; |
XCharStruct *p; |
44 |
|
|
45 |
/* `c' is always >= 0 */ |
/* `c' is always >= 0 */ |
46 |
if ((unsigned int)c < fi->min_char_or_byte2 |
if ((unsigned int) c < fi->min_char_or_byte2 |
47 |
|| (unsigned int)c > fi->max_char_or_byte2) |
|| (unsigned int) c > fi->max_char_or_byte2) |
48 |
return 0; |
return 0; |
49 |
p = fi->per_char + (c - fi->min_char_or_byte2); |
p = fi->per_char + (c - fi->min_char_or_byte2); |
50 |
return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0 |
return p->lbearing != 0 || p->rbearing != 0 || p->width != 0 |
51 |
|| p->ascent != 0 || p->descent != 0 || p->attributes != 0); |
|| p->ascent != 0 || p->descent != 0 || p->attributes != 0; |
52 |
} |
} |
53 |
|
|
54 |
/* Canonicalize the font name by replacing scalable parts by *s. */ |
/* Canonicalize the font name by replacing scalable parts by *s. */ |
55 |
|
|
56 |
static int |
static int CanonicalizeFontName(char *font_name, char *canon_font_name) |
|
CanonicalizeFontName (char *font_name, char *canon_font_name) |
|
57 |
{ |
{ |
58 |
unsigned int attributes; |
unsigned int attributes; |
59 |
XFontName parsed; |
XFontName parsed; |
|
|
|
|
if (!XParseFontName(font_name, &parsed, &attributes)) { |
|
|
fprintf (stderr, "not a standard name: %s\n", font_name); |
|
|
return 0; |
|
|
} |
|
60 |
|
|
61 |
attributes &= ~(FontNamePixelSize|FontNameAverageWidth |
if (!XParseFontName(font_name, &parsed, &attributes)) { |
62 |
|FontNamePointSize |
fprintf(stderr, "not a standard name: %s\n", font_name); |
63 |
|FontNameResolutionX|FontNameResolutionY); |
return 0; |
64 |
XFormatFontName(&parsed, attributes, canon_font_name); |
} |
65 |
return 1; |
|
66 |
|
attributes &= ~(FontNamePixelSize | FontNameAverageWidth |
67 |
|
| FontNamePointSize |
68 |
|
| FontNameResolutionX | FontNameResolutionY); |
69 |
|
XFormatFontName(&parsed, attributes, canon_font_name); |
70 |
|
return 1; |
71 |
} |
} |
72 |
|
|
73 |
static int |
static int |
74 |
FontNamesAmbiguous(const char *font_name, char **names, int count) |
FontNamesAmbiguous(const char *font_name, char **names, int count) |
75 |
{ |
{ |
76 |
char name1[2048], name2[2048]; |
char name1[2048], name2[2048]; |
77 |
int i; |
int i; |
|
|
|
|
if (count == 1) |
|
|
return 0; |
|
78 |
|
|
79 |
for (i = 0; i < count; i++) { |
if (count == 1) |
80 |
if (!CanonicalizeFontName(names[i], i == 0 ? name1 : name2)) { |
return 0; |
|
fprintf(stderr, "bad font name: %s\n", names[i]); |
|
|
return 1; |
|
|
} |
|
|
if (i > 0 && strcmp(name1, name2) != 0) { |
|
|
fprintf(stderr, "ambiguous font name: %s\n", font_name); |
|
|
fprintf(stderr, " matches %s\n", names[0]); |
|
|
fprintf(stderr, " and %s\n", names[i]); |
|
|
return 1; |
|
|
} |
|
81 |
|
|
82 |
} |
for (i = 0; i < count; i++) { |
83 |
return 0; |
if (!CanonicalizeFontName(names[i], i == 0 ? name1 : name2)) { |
84 |
|
fprintf(stderr, "bad font name: %s\n", names[i]); |
85 |
|
return 1; |
86 |
|
} |
87 |
|
if (i > 0 && strcmp(name1, name2) != 0) { |
88 |
|
fprintf(stderr, "ambiguous font name: %s\n", font_name); |
89 |
|
fprintf(stderr, " matches %s\n", names[0]); |
90 |
|
fprintf(stderr, " and %s\n", names[i]); |
91 |
|
return 1; |
92 |
|
} |
93 |
|
} |
94 |
|
return 0; |
95 |
} |
} |
96 |
|
|
97 |
static int |
static int MapFont(char *font_name, const char *troff_name) |
|
MapFont (char *font_name, const char *troff_name) |
|
98 |
{ |
{ |
99 |
XFontStruct *fi; |
XFontStruct *fi; |
100 |
int count; |
int count; |
101 |
char **names; |
char **names; |
102 |
FILE *out; |
FILE *out; |
103 |
unsigned int c; |
unsigned int c; |
104 |
unsigned int attributes; |
unsigned int attributes; |
105 |
XFontName parsed; |
XFontName parsed; |
106 |
int j, k; |
int j, k; |
107 |
DviCharNameMap *char_map; |
DviCharNameMap *char_map; |
108 |
char encoding[256]; |
char encoding[256]; |
109 |
char *s; |
char *s; |
110 |
int wid; |
int wid; |
111 |
char name_string[2048]; |
char name_string[2048]; |
112 |
|
|
113 |
if (!XParseFontName(font_name, &parsed, &attributes)) { |
if (!XParseFontName(font_name, &parsed, &attributes)) { |
114 |
fprintf (stderr, "not a standard name: %s\n", font_name); |
fprintf(stderr, "not a standard name: %s\n", font_name); |
115 |
return 0; |
return 0; |
116 |
} |
} |
117 |
|
|
118 |
attributes &= ~(FontNamePixelSize|FontNameAverageWidth); |
attributes &= ~(FontNamePixelSize | FontNameAverageWidth); |
119 |
attributes |= FontNameResolutionX; |
attributes |= FontNameResolutionX; |
120 |
attributes |= FontNameResolutionY; |
attributes |= FontNameResolutionY; |
121 |
attributes |= FontNamePointSize; |
attributes |= FontNamePointSize; |
122 |
parsed.ResolutionX = resolution; |
parsed.ResolutionX = resolution; |
123 |
parsed.ResolutionY = resolution; |
parsed.ResolutionY = resolution; |
124 |
parsed.PointSize = point_size*10; |
parsed.PointSize = point_size * 10; |
125 |
XFormatFontName(&parsed, attributes, name_string); |
XFormatFontName(&parsed, attributes, name_string); |
126 |
|
|
127 |
names = XListFonts (dpy, name_string, 100000, &count); |
names = XListFonts(dpy, name_string, 100000, &count); |
128 |
if (count < 1) { |
if (count < 1) { |
129 |
fprintf (stderr, "bad font name: %s\n", font_name); |
fprintf(stderr, "bad font name: %s\n", font_name); |
130 |
return 0; |
return 0; |
131 |
} |
} |
132 |
|
|
133 |
if (FontNamesAmbiguous(font_name, names, count)) |
if (FontNamesAmbiguous(font_name, names, count)) |
134 |
return 0; |
return 0; |
135 |
|
|
136 |
XParseFontName(names[0], &parsed, &attributes); |
XParseFontName(names[0], &parsed, &attributes); |
137 |
sprintf (encoding, "%s-%s", parsed.CharSetRegistry, |
sprintf(encoding, "%s-%s", parsed.CharSetRegistry, |
138 |
parsed.CharSetEncoding); |
parsed.CharSetEncoding); |
139 |
for (s = encoding; *s; s++) |
for (s = encoding; *s; s++) |
140 |
if (isupper (*s)) |
if (isupper(*s)) |
141 |
*s = tolower (*s); |
*s = tolower(*s); |
142 |
char_map = DviFindMap (encoding); |
char_map = DviFindMap(encoding); |
143 |
if (!char_map) { |
if (!char_map) { |
144 |
fprintf (stderr, "not a standard encoding: %s\n", encoding); |
fprintf(stderr, "not a standard encoding: %s\n", encoding); |
145 |
return 0; |
return 0; |
146 |
} |
} |
147 |
|
|
148 |
fi = XLoadQueryFont (dpy, names[0]); |
fi = XLoadQueryFont(dpy, names[0]); |
149 |
if (!fi) { |
if (!fi) { |
150 |
fprintf (stderr, "font does not exist: %s\n", names[0]); |
fprintf(stderr, "font does not exist: %s\n", names[0]); |
151 |
return 0; |
return 0; |
152 |
} |
} |
153 |
|
|
154 |
printf ("%s -> %s\n", names[0], troff_name); |
printf("%s -> %s\n", names[0], troff_name); |
155 |
|
|
156 |
{ /* Avoid race while opening file */ |
{ /* Avoid race while opening file */ |
157 |
int fd; |
int fd; |
158 |
(void) unlink (troff_name); |
(void) unlink(troff_name); |
159 |
fd = open (troff_name, O_WRONLY | O_CREAT | O_EXCL, 0600); |
fd = open(troff_name, O_WRONLY | O_CREAT | O_EXCL, 0600); |
160 |
out = fdopen (fd, "w"); |
out = fdopen(fd, "w"); |
161 |
} |
} |
162 |
|
|
163 |
if (!out) { |
if (!out) { |
164 |
perror (troff_name); |
perror(troff_name); |
165 |
return 0; |
return 0; |
166 |
} |
} |
167 |
fprintf (out, "name %s\n", troff_name); |
fprintf(out, "name %s\n", troff_name); |
168 |
if (!strcmp (char_map->encoding, "adobe-fontspecific")) |
if (!strcmp(char_map->encoding, "adobe-fontspecific")) |
169 |
fprintf (out, "special\n"); |
fprintf(out, "special\n"); |
170 |
if (charExists (fi, ' ')) { |
if (charExists(fi, ' ')) { |
171 |
int w = charWidth (fi, ' '); |
int w = charWidth(fi, ' '); |
172 |
if (w > 0) |
if (w > 0) |
173 |
fprintf (out, "spacewidth %d\n", w); |
fprintf(out, "spacewidth %d\n", w); |
174 |
} |
} |
175 |
fprintf (out, "charset\n"); |
fprintf(out, "charset\n"); |
176 |
for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) { |
for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) { |
177 |
const char *name = DviCharName (char_map, c, 0); |
const char *name = DviCharName(char_map, c, 0); |
178 |
if (charExists (fi, c) && (groff_flag || name)) { |
if (charExists(fi, c)) { |
179 |
|
wid = charWidth(fi, c); |
180 |
wid = charWidth (fi, c); |
|
181 |
|
fprintf(out, "%s\t%d", name ? name : "---", wid); |
182 |
fprintf (out, "%s\t%d", |
int param[5]; |
183 |
name ? name : "---", |
param[0] = charHeight(fi, c); |
184 |
wid); |
param[1] = charDepth(fi, c); |
185 |
if (groff_flag) { |
param[2] = 0; /* charRBearing (fi, c) - wid */ |
186 |
int param[5]; |
param[3] = 0; /* charLBearing (fi, c) */ |
187 |
param[0] = charHeight (fi, c); |
param[4] = 0; /* XXX */ |
188 |
param[1] = charDepth (fi, c); |
for (j = 0; j < 5; j++) |
189 |
param[2] = 0 /* charRBearing (fi, c) - wid */; |
if (param[j] < 0) |
190 |
param[3] = 0 /* charLBearing (fi, c) */; |
param[j] = 0; |
191 |
param[4] = 0; /* XXX */ |
for (j = 4; j >= 0; j--) |
192 |
for (j = 0; j < 5; j++) |
if (param[j] != 0) |
193 |
if (param[j] < 0) |
break; |
194 |
param[j] = 0; |
for (k = 0; k <= j; k++) |
195 |
for (j = 4; j >= 0; j--) |
fprintf(out, ",%d", param[k]); |
196 |
if (param[j] != 0) |
fprintf(out, "\t0\t0%o\n", c); |
197 |
break; |
|
198 |
for (k = 0; k <= j; k++) |
if (name) { |
199 |
fprintf (out, ",%d", param[k]); |
for (k = 1; DviCharName(char_map, c, k); k++) { |
200 |
} |
fprintf(out, "%s\t\"\n", DviCharName(char_map, c, k)); |
201 |
fprintf (out, "\t0\t0%o\n", c); |
} |
202 |
|
} |
203 |
if (name) { |
} |
204 |
for (k = 1; DviCharName(char_map,c,k); k++) { |
} |
205 |
fprintf (out, "%s\t\"\n", |
XUnloadFont(dpy, fi->fid); |
206 |
DviCharName (char_map,c,k)); |
fclose(out); |
207 |
} |
return 1; |
|
} |
|
|
} |
|
|
} |
|
|
XUnloadFont (dpy, fi->fid); |
|
|
fclose (out); |
|
|
return 1; |
|
208 |
} |
} |
209 |
|
|
210 |
static void |
static void usage(FILE *stream) |
|
usage(const char *prog) |
|
211 |
{ |
{ |
212 |
fprintf (stderr, |
fprintf(stream, |
213 |
"usage: %s [-g] [-r resolution] [-s pointsize] FontMap\n", |
"usage: %s [-r resolution] [-s pointsize] FontMap\n", |
214 |
prog); |
program_name); |
|
exit (1); |
|
215 |
} |
} |
216 |
|
|
217 |
int |
int main(int argc, char **argv) |
|
main (int argc, char **argv) |
|
218 |
{ |
{ |
219 |
char troff_name[1024]; |
char troff_name[1024]; |
220 |
char font_name[1024]; |
char font_name[1024]; |
221 |
char line[1024]; |
char line[1024]; |
222 |
char *a, *b, c; |
char *a, *b, c; |
223 |
int position; |
FILE *map; |
224 |
FILE *map; |
int opt; |
225 |
int opt; |
static const struct option long_options[] = { |
226 |
|
{ "help", no_argument, 0, CHAR_MAX + 1 }, |
227 |
while ((opt = getopt(argc, argv, "gr:s:")) != EOF) { |
{ "version", no_argument, 0, 'v' }, |
228 |
switch (opt) { |
{ NULL, 0, 0, 0 } |
229 |
case 'g': |
}; |
230 |
groff_flag = 1; |
|
231 |
break; |
program_name = argv[0]; |
232 |
case 'r': |
|
233 |
sscanf(optarg, "%u", &resolution); |
while ((opt = getopt_long(argc, argv, "gr:s:v", long_options, |
234 |
break; |
NULL)) != EOF) { |
235 |
case 's': |
switch (opt) { |
236 |
sscanf(optarg, "%u", &point_size); |
case 'g': |
237 |
break; |
/* unused; just for compatibility */ |
238 |
default: |
break; |
239 |
usage(argv[0]); |
case 'r': |
240 |
} |
sscanf(optarg, "%u", &resolution); |
241 |
} |
break; |
242 |
if (argc - optind != 1) |
case 's': |
243 |
usage(argv[0]); |
sscanf(optarg, "%u", &point_size); |
244 |
|
break; |
245 |
dpy = XOpenDisplay (0); |
case 'v': |
246 |
if (!dpy) { |
printf("xtotroff (groff) version %s\n", Version_string); |
247 |
fprintf (stderr, "Can't connect to the X server.\n"); |
exit(0); |
248 |
fprintf (stderr, "Make sure the DISPLAY environment variable is set correctly.\n"); |
break; |
249 |
exit (1); |
case CHAR_MAX + 1: /* --help */ |
250 |
} |
usage(stdout); |
251 |
position = 1; |
exit(0); |
252 |
|
break; |
253 |
map = fopen (argv[optind], "r"); |
case '?': |
254 |
if (map == NULL) { |
usage(stderr); |
255 |
perror (argv[optind]); |
exit(1); |
256 |
exit (1); |
break; |
257 |
} |
} |
258 |
|
} |
259 |
while (fgets (line, sizeof (line), map)) { |
if (argc - optind != 1) { |
260 |
for (a=line,b=troff_name; *a; a++,b++) { |
usage(stderr); |
261 |
c = (*b = *a); |
exit(1); |
262 |
if (c == ' ' || c == '\t') |
} |
263 |
break; |
|
264 |
} |
dpy = XOpenDisplay(0); |
265 |
*b = '\0'; |
if (!dpy) { |
266 |
while (*a && (*a == ' ' || *a == '\t')) |
fprintf(stderr, "Can't connect to the X server.\n"); |
267 |
++a; |
fprintf(stderr, |
268 |
for (b=font_name; *a; a++,b++) |
"Make sure the DISPLAY environment variable is set correctly.\n"); |
269 |
if ((*b = *a) == '\n') |
exit(1); |
270 |
break; |
} |
271 |
*b = '\0'; |
|
272 |
if (!MapFont (font_name, troff_name)) |
map = fopen(argv[optind], "r"); |
273 |
exit (1); |
if (map == NULL) { |
274 |
++position; |
perror(argv[optind]); |
275 |
} |
exit(1); |
276 |
exit (0); |
} |
277 |
|
|
278 |
|
while (fgets(line, sizeof(line), map)) { |
279 |
|
for (a = line, b = troff_name; *a; a++, b++) { |
280 |
|
c = (*b = *a); |
281 |
|
if (c == ' ' || c == '\t') |
282 |
|
break; |
283 |
|
} |
284 |
|
*b = '\0'; |
285 |
|
while (*a && (*a == ' ' || *a == '\t')) |
286 |
|
++a; |
287 |
|
for (b = font_name; *a; a++, b++) |
288 |
|
if ((*b = *a) == '\n') |
289 |
|
break; |
290 |
|
*b = '\0'; |
291 |
|
if (!MapFont(font_name, troff_name)) |
292 |
|
exit(1); |
293 |
|
} |
294 |
|
exit(0); |
295 |
} |
} |
|
|
|
|
/* |
|
|
Local Variables: |
|
|
c-indent-level: 8 |
|
|
c-continued-statement-offset: 8 |
|
|
c-brace-offset: -8 |
|
|
c-argdecl-indent: 8 |
|
|
c-label-offset: -8 |
|
|
c-tab-always-indent: nil |
|
|
End: |
|
|
*/ |
|