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 37extern const char *Version_string; 38static char *program_name; 39 40Display *dpy; 41unsigned resolution = 75; 42unsigned point_size = 10; 43 44int 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 59static 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 76static int 77FontNamesAmbiguous(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 100static 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 214static void usage(FILE *stream) 215{ 216 fprintf(stream, 217 "usage: %s [-r resolution] [-s pointsize] FontMap\n", 218 program_name); 219} 220 221int 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} 300