1/* $NetBSD$ */ 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 39extern const char *Version_string; 40static char *program_name; 41 42Display *dpy; 43unsigned resolution = 75; 44unsigned point_size = 10; 45 46int 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 61static 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 78static int 79FontNamesAmbiguous(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 102static 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 216static void usage(FILE *stream) 217{ 218 fprintf(stream, 219 "usage: %s [-r resolution] [-s pointsize] FontMap\n", 220 program_name); 221} 222 223int 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