summaryrefslogtreecommitdiffstats
path: root/src/utils/xtotroff
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/xtotroff')
-rw-r--r--src/utils/xtotroff/xtotroff.1.man237
-rw-r--r--src/utils/xtotroff/xtotroff.am41
-rw-r--r--src/utils/xtotroff/xtotroff.c368
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: