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