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