diff options
Diffstat (limited to 'src/utils/xtotroff')
-rw-r--r-- | src/utils/xtotroff/xtotroff.1.man | 237 | ||||
-rw-r--r-- | src/utils/xtotroff/xtotroff.am | 41 | ||||
-rw-r--r-- | src/utils/xtotroff/xtotroff.c | 368 |
3 files changed, 646 insertions, 0 deletions
diff --git a/src/utils/xtotroff/xtotroff.1.man b/src/utils/xtotroff/xtotroff.1.man new file mode 100644 index 0000000..17fb0db --- /dev/null +++ b/src/utils/xtotroff/xtotroff.1.man @@ -0,0 +1,237 @@ +.TH xtotroff @MAN1EXT@ "@MDATE@" "groff @VERSION@" +.SH Name +xtotroff \- convert X font metrics into +.I groff +font metrics +. +. +.\" ==================================================================== +.\" Legal Terms +.\" ==================================================================== +.\" +.\" Copyright (C) 2004-2022 Free Software Foundation, Inc. +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of +.\" this manual under the conditions for verbatim copying, provided that +.\" the entire resulting derived work is distributed under the terms of +.\" a permission notice identical to this one. +.\" +.\" Permission is granted to copy and distribute translations of this +.\" manual into another language, under the above conditions for +.\" modified versions, except that this permission notice may be +.\" included in translations approved by the Free Software Foundation +.\" instead of in the original English. +. +. +.\" Save and disable compatibility mode (for, e.g., Solaris 10/11). +.do nr *groff_xtotroff_1_man_C \n[.cp] +.cp 0 +. +.\" Define fallback for groff 1.23's MR macro if the system lacks it. +.nr do-fallback 0 +.if !\n(.f .nr do-fallback 1 \" mandoc +.if \n(.g .if !d MR .nr do-fallback 1 \" older groff +.if !\n(.g .nr do-fallback 1 \" non-groff *roff +.if \n[do-fallback] \{\ +. de MR +. ie \\n(.$=1 \ +. I \%\\$1 +. el \ +. IR \%\\$1 (\\$2)\\$3 +. . +.\} +.rr do-fallback +. +. +.\" ==================================================================== +.SH Synopsis +.\" ==================================================================== +. +.SY xtotroff +.RB [ \-d\~\c +.IR destination-directory ] +.RB [ \-r\~\c +.IR resolution ] +.RB [ \-s\~\c +.IR type-size ] +.I font-map +.YS +. +. +.SY xtotroff +.B \-\-help +.YS +. +. +.SY xtotroff +.B \-v +. +.SY xtotroff +.B \-\-version +.YS +. +. +.\" ==================================================================== +.SH Description +.\" ==================================================================== +. +.I xtotroff +uses +.I font-map +to create +.MR groff @MAN1EXT@ +font description files from X11 fonts. +. +Each line in +.I font-map +consists of a series of lines of paired +.I groff +font names and X font names as X Logical Font Description (XLFD) +patterns, +with the pair members separated by spaces and/or tabs. +. +For example, +an input +.I font-map +file consisting of the line +. +.RS +.EX +TB \-adobe\-times\-bold\-r\-normal\-\-*\-*\-*\-*\-p\-*\-iso8859\-1 +.EE +.RE +. +maps the XLFD on the right to the +.I groff +font name +.BR TB , +conventionally \[lq]Times bold\[rq]. +. +. +.PP +.I xtotroff +opens a connection to the running X server to query its font catalog, +and aborts if it cannot. +. +If necessary, +the wildcards in the XLFD patterns are populated with the arguments to +the +.B \-r +and +.B \-s +options. +. +If a font name is still ambiguous, +.I xtotroff +aborts. +. +For each successful mapping, +.I xtotroff +creates a +.I groff +font description file in the current working directory +(or that specified by the +.B -d +option) +named for each +.I groff +font, +and reports the mapping to the standard output stream. +. +. +.\" ==================================================================== +.SH Options +.\" ==================================================================== +. +.B \-\-help +displays a usage message, +while +.B \-v +and +.B \-\-version +show version information; +all exit afterward. +. +. +.TP +.BI \-d\~ destination-directory +Write font descriptions to +.I destination-directory +rather than the current working directory. +. +. +.TP +.BI \-r\~ resolution +Set the resolution for all font patterns in +.IR font-map . +. +The value is used for both the horizontal and vertical motion quanta. +. +If not specified, +a resolution of 75dpi is assumed. +. +. +.TP +.BI \-s\~ type-size +Set the type size in points for all font patterns in +.IR font-map . +. +If not specified, +a size of 10 points is assumed. +. +. +.\" ==================================================================== +.SH Files +.\" ==================================================================== +. +.TP +.I @FONTDIR@/\:\%FontMap\-X11 +is the font mapping file used to produce the pre-generated font +description files, +supplied with +.IR groff , +of X11 core fonts corresponding to the 13 base Type\~1 fonts for +PostScript level 1. +. +. +.\" ==================================================================== +.SH Bugs +.\" ==================================================================== +. +The only supported font encodings are \[lq]iso8859\-1\[rq] and +\%\[lq]adobe\-\:fontspecific\[rq]. +. +. +.\" ==================================================================== +.SH "See also" +.\" ==================================================================== +. +.UR https://\:www\:.x\:.org/\:releases/\:X11R7.6/\:doc/\:xorg\-docs/\ +\:specs/\:XLFD/xlfd\:.html +\[lq]X Logical Font Description Conventions\[rq] +.UE , +by Jim Flowers and Stephen Gildea. +. +. +.PP +.MR X 7 , +.MR groff @MAN1EXT@ , +.MR gxditview @MAN1EXT@ , +.MR troff @MAN1EXT@ , +.MR groff_font @MAN5EXT@ +. +. +.\" Restore compatibility mode (for, e.g., Solaris 10/11). +.cp \n[*groff_xtotroff_1_man_C] +.do rr *groff_xtotroff_1_man_C +. +. +.\" Local Variables: +.\" fill-column: 72 +.\" mode: nroff +.\" End: +.\" vim: set filetype=groff textwidth=72: diff --git a/src/utils/xtotroff/xtotroff.am b/src/utils/xtotroff/xtotroff.am new file mode 100644 index 0000000..734d143 --- /dev/null +++ b/src/utils/xtotroff/xtotroff.am @@ -0,0 +1,41 @@ +# Copyright (C) 2014-2020 Free Software Foundation, Inc. +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +if WITHOUT_X11 +XTOTROFF_MAN1 = +else +XTOTROFF_MAN1 = src/utils/xtotroff/xtotroff.1 +bin_PROGRAMS += xtotroff +man1_MANS += $(XTOTROFF_MAN1) +xtotroff_SOURCES = src/utils/xtotroff/xtotroff.c +XLIBS=$(LIBXUTIL) $(LIBGROFF) +xtotroff_LDADD = libxutil.a libgroff.a $(X_LIBS) $(X_PRE_LIBS) \ + -lXaw -lXt -lX11 $(X_EXTRA_LIBS) $(LIBM) lib/libgnu.a +xtotroff_CPPFLAGS = $(AM_CPPFLAGS) $(X_CFLAGS) +endif +EXTRA_DIST += src/utils/xtotroff/xtotroff.1.man + +# Define variable needed only for the targets that regenerate +# descriptions of X11 core fonts (used in "maintainer mode"). +xtotroff=$(top_builddir)/xtotroff + + +# Local Variables: +# fill-column: 72 +# mode: makefile-automake +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/src/utils/xtotroff/xtotroff.c b/src/utils/xtotroff/xtotroff.c new file mode 100644 index 0000000..368761f --- /dev/null +++ b/src/utils/xtotroff/xtotroff.c @@ -0,0 +1,368 @@ +/* Copyright (C) 1992-2022 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* + * xtotroff + * + * convert X font metrics into troff font metrics + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define __GETOPT_PREFIX groff_ + +#include <X11/Xlib.h> +#include <stdbool.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <limits.h> + +#include <getopt.h> + +#include "XFontName.h" +#include "DviChar.h" + +#define charWidth(fi,c) \ + ((fi)->per_char[(c) - (fi)->min_char_or_byte2].width) +#define charHeight(fi,c) \ + ((fi)->per_char[(c) - (fi)->min_char_or_byte2].ascent) +#define charDepth(fi,c) \ + ((fi)->per_char[(c) - (fi)->min_char_or_byte2].descent) +#define charLBearing(fi,c) \ + ((fi)->per_char[(c) - (fi)->min_char_or_byte2].lbearing) +#define charRBearing(fi,c) \ + ((fi)->per_char[(c) - (fi)->min_char_or_byte2].rbearing) + +extern const char *Version_string; +static char *program_name; + +Display *dpy; +unsigned resolution = 75; +unsigned point_size = 10; +char *destdir = NULL; + +static bool charExists(XFontStruct * fi, int c) +{ + XCharStruct *p; + + /* 'c' is always >= 0 */ + if ((unsigned int) c < fi->min_char_or_byte2 + || (unsigned int) c > fi->max_char_or_byte2) + return false; + p = fi->per_char + (c - fi->min_char_or_byte2); + return p->lbearing != 0 || p->rbearing != 0 || p->width != 0 + || p->ascent != 0 || p->descent != 0 || p->attributes != 0; +} + +/* Canonicalize the font name by replacing scalable parts by *s. */ + +static bool CanonicalizeFontName(char *font_name, char *canon_font_name) +{ + unsigned int attributes; + XFontName parsed; + + if (!XParseFontName(font_name, &parsed, &attributes)) { + fprintf(stderr, "%s: not a standard font name: \"%s\"\n", + program_name, font_name); + return false; + } + + attributes &= ~(FontNamePixelSize | FontNameAverageWidth + | FontNamePointSize + | FontNameResolutionX | FontNameResolutionY); + XFormatFontName(&parsed, attributes, canon_font_name); + return true; +} + +static bool +FontNamesAmbiguous(const char *font_name, char **names, int count) +{ + char name1[2048], name2[2048]; + int i; + + if (1 == count) + return false; + + for (i = 0; i < count; i++) { + if (!CanonicalizeFontName(names[i], 0 == i ? name1 : name2)) { + fprintf(stderr, "%s: invalid font name: \"%s\"\n", program_name, + names[i]); + return true; + } + if (i > 0 && strcmp(name1, name2) != 0) { + fprintf(stderr, "%s: ambiguous font name: \"%s\"", program_name, + font_name); + fprintf(stderr, " matches \"%s\"", names[0]); + fprintf(stderr, " and \"%s\"", names[i]); + return true; + } + } + return false; +} + +static void xtotroff_exit(int status) +{ + free(destdir); + exit(status); +} + +static bool MapFont(char *font_name, const char *troff_name) +{ + XFontStruct *fi; + int count; + char **names; + FILE *out; + unsigned int c; + unsigned int attributes; + XFontName parsed; + int j, k; + DviCharNameMap *char_map; + /* 'encoding' needs to hold a CharSetRegistry (256), a CharSetEncoding + (256) [both from XFontName.h], a dash, and a null terminator. */ + char encoding[256 * 2 + 1 + 1]; + char *s; + int wid; + char name_string[2048]; + + if (!XParseFontName(font_name, &parsed, &attributes)) { + fprintf(stderr, "%s: not a standard font name: \"%s\"\n", + program_name, font_name); + return false; + } + + attributes &= ~(FontNamePixelSize | FontNameAverageWidth); + attributes |= FontNameResolutionX; + attributes |= FontNameResolutionY; + attributes |= FontNamePointSize; + parsed.ResolutionX = resolution; + parsed.ResolutionY = resolution; + parsed.PointSize = point_size * 10; + XFormatFontName(&parsed, attributes, name_string); + + names = XListFonts(dpy, name_string, 100000, &count); + if (count < 1) { + fprintf(stderr, "%s: invalid font name: \"%s\"\n", program_name, + font_name); + return false; + } + + if (FontNamesAmbiguous(font_name, names, count)) + return false; + + XParseFontName(names[0], &parsed, &attributes); + size_t sz = sizeof encoding; + snprintf(encoding, sz, "%s-%s", parsed.CharSetRegistry, + parsed.CharSetEncoding); + for (s = encoding; *s; s++) + if (isupper(*s)) + *s = tolower(*s); + char_map = DviFindMap(encoding); + if (!char_map) { + fprintf(stderr, "%s: not a standard encoding: \"%s\"\n", + program_name, encoding); + return false; + } + + fi = XLoadQueryFont(dpy, names[0]); + if (!fi) { + fprintf(stderr, "%s: font does not exist: \"%s\"\n", program_name, + names[0]); + return false; + } + + printf("%s -> %s\n", names[0], troff_name); + char *file_name = (char *)troff_name; + size_t dirlen = strlen(destdir); + + if (dirlen > 0) { + size_t baselen = strlen(troff_name); + file_name = malloc(dirlen + baselen + 2 /* '/' and '\0' */); + if (NULL == file_name) { + fprintf(stderr, "%s: fatal error: unable to allocate memory\n", + program_name); + xtotroff_exit(EXIT_FAILURE); + } + (void) strcpy(file_name, destdir); + file_name[dirlen] = '/'; + (void) strcpy((file_name + dirlen + 1), troff_name); + } + + { /* Avoid race while opening file */ + int fd; + (void) unlink(file_name); + fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL, 0600); + out = fdopen(fd, "w"); + } + + if (NULL == out) { + fprintf(stderr, "%s: unable to create '%s': %s\n", program_name, + file_name, strerror(errno)); + free(file_name); + return false; + } + fprintf(out, "name %s\n", troff_name); + if (!strcmp(char_map->encoding, "adobe-fontspecific")) + fprintf(out, "special\n"); + if (charExists(fi, ' ')) { + int w = charWidth(fi, ' '); + if (w > 0) + fprintf(out, "spacewidth %d\n", w); + } + fprintf(out, "charset\n"); + for (c = fi->min_char_or_byte2; c <= fi->max_char_or_byte2; c++) { + const char *name = DviCharName(char_map, c, 0); + if (charExists(fi, c)) { + int param[5]; + + wid = charWidth(fi, c); + + fprintf(out, "%s\t%d", name ? name : "---", wid); + param[0] = charHeight(fi, c); + param[1] = charDepth(fi, c); + param[2] = 0; /* charRBearing (fi, c) - wid */ + param[3] = 0; /* charLBearing (fi, c) */ + param[4] = 0; /* XXX */ + for (j = 0; j < 5; j++) + if (param[j] < 0) + param[j] = 0; + for (j = 4; j >= 0; j--) + if (param[j] != 0) + break; + for (k = 0; k <= j; k++) + fprintf(out, ",%d", param[k]); + fprintf(out, "\t0\t0%o\n", c); + + if (name) { + for (k = 1; DviCharName(char_map, c, k); k++) { + fprintf(out, "%s\t\"\n", DviCharName(char_map, c, k)); + } + } + } + } + XUnloadFont(dpy, fi->fid); + fclose(out); + free(file_name); + return true; +} + +static void usage(FILE *stream) +{ + fprintf(stream, + "usage: %s [-d destination-directory] [-r resolution]" + " [-s type-size] font-map\n" + "usage: %s {-v | --version}\n" + "usage: %s --help\n", + program_name, program_name, program_name); +} + +int main(int argc, char **argv) +{ + char troff_name[1024]; + char font_name[1024]; + char line[1024]; + char *a, *b, c; + FILE *map; + int opt; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + + program_name = argv[0]; + + while ((opt = getopt_long(argc, argv, "d:gr:s:v", long_options, + NULL)) != EOF) { + switch (opt) { + case 'd': + destdir = strdup(optarg); + break; + case 'g': + /* unused; just for compatibility */ + break; + case 'r': + sscanf(optarg, "%u", &resolution); + break; + case 's': + sscanf(optarg, "%u", &point_size); + break; + case 'v': + printf("GNU xtotroff (groff) version %s\n", Version_string); + xtotroff_exit(EXIT_SUCCESS); + break; + case CHAR_MAX + 1: /* --help */ + usage(stdout); + xtotroff_exit(EXIT_SUCCESS); + break; + case '?': + usage(stderr); + xtotroff_exit(EXIT_FAILURE); + break; + } + } + if (argc - optind != 1) { + usage(stderr); + xtotroff_exit(EXIT_FAILURE); + } + + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s: fatal error: can't connect to the X server;" + " make sure the DISPLAY environment variable is set" + " correctly\n", program_name); + xtotroff_exit(EXIT_FAILURE); + } + + map = fopen(argv[optind], "r"); + if (NULL == map) { + fprintf(stderr, "%s: fatal error: unable to open map file '%s':" + " %s\n", program_name, argv[optind], strerror(errno)); + xtotroff_exit(EXIT_FAILURE); + } + + while (fgets(line, sizeof(line), map)) { + for (a = line, b = troff_name; *a; a++, b++) { + c = (*b = *a); + if (' ' == c || '\t' == c) + break; + } + *b = '\0'; + while (*a && (' ' == *a || '\t' == *a)) + ++a; + for (b = font_name; *a; a++, b++) + if ((*b = *a) == '\n') + break; + *b = '\0'; + if (!MapFont(font_name, troff_name)) + xtotroff_exit(EXIT_FAILURE); + } + xtotroff_exit(EXIT_SUCCESS); +} + +// Local Variables: +// fill-column: 72 +// mode: C +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: |