diff options
Diffstat (limited to 'contrib/groff/src/utils')
29 files changed, 5439 insertions, 0 deletions
diff --git a/contrib/groff/src/utils/addftinfo/Makefile.sub b/contrib/groff/src/utils/addftinfo/Makefile.sub new file mode 100644 index 0000000..23848d5 --- /dev/null +++ b/contrib/groff/src/utils/addftinfo/Makefile.sub @@ -0,0 +1,11 @@ +PROG=addftinfo +MAN1=addftinfo.n +XLIBS=$(LIBGROFF) +OBJS=\ + addftinfo.o \ + guess.o +CCSRCS=\ + $(srcdir)/addftinfo.cc \ + $(srcdir)/guess.cc +HDRS=\ + $(srcdir)/guess.h diff --git a/contrib/groff/src/utils/addftinfo/addftinfo.cc b/contrib/groff/src/utils/addftinfo/addftinfo.cc new file mode 100644 index 0000000..43a81bc --- /dev/null +++ b/contrib/groff/src/utils/addftinfo/addftinfo.cc @@ -0,0 +1,218 @@ +// -*- C++ -*- +/* Copyright (C) 1989-1992, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "cset.h" +#include "guess.h" + +static void usage(FILE *stream); +static void usage(); +static void version(); +static void convert_font(const font_params &, FILE *, FILE *); + +typedef int font_params::*param_t; + +static struct { + const char *name; + param_t par; +} param_table[] = { + { "x-height", &font_params::x_height }, + { "fig-height", &font_params::fig_height }, + { "asc-height", &font_params::asc_height }, + { "body-height", &font_params::body_height }, + { "cap-height", &font_params::cap_height }, + { "comma-depth", &font_params::comma_depth }, + { "desc-depth", &font_params::desc_depth }, + { "body-depth", &font_params::body_depth }, +}; + +// These are all in thousandths of an em. +// These values are correct for PostScript Times Roman. + +#define DEFAULT_X_HEIGHT 448 +#define DEFAULT_FIG_HEIGHT 676 +#define DEFAULT_ASC_HEIGHT 682 +#define DEFAULT_BODY_HEIGHT 676 +#define DEFAULT_CAP_HEIGHT 662 +#define DEFAULT_COMMA_DEPTH 143 +#define DEFAULT_DESC_DEPTH 217 +#define DEFAULT_BODY_DEPTH 177 + +int main(int argc, char **argv) +{ + program_name = argv[0]; + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-v") || !strcmp(argv[i],"--version")) + version(); + if (!strcmp(argv[i],"--help")) { + usage(stdout); + exit(0); + } + } + if (argc < 4) + usage(); + int resolution; + if (sscanf(argv[argc-3], "%d", &resolution) != 1) + usage(); + if (resolution <= 0) + fatal("resolution must be > 0"); + int unitwidth; + if (sscanf(argv[argc-2], "%d", &unitwidth) != 1) + usage(); + if (unitwidth <= 0) + fatal("unitwidth must be > 0"); + font_params param; + const char *font = argv[argc-1]; + param.italic = (font[0] != '\0' && strchr(font, '\0')[-1] == 'I'); + param.em = (resolution*unitwidth)/72; + param.x_height = DEFAULT_X_HEIGHT; + param.fig_height = DEFAULT_FIG_HEIGHT; + param.asc_height = DEFAULT_ASC_HEIGHT; + param.body_height = DEFAULT_BODY_HEIGHT; + param.cap_height = DEFAULT_CAP_HEIGHT; + param.comma_depth = DEFAULT_COMMA_DEPTH; + param.desc_depth = DEFAULT_DESC_DEPTH; + param.body_depth = DEFAULT_BODY_DEPTH; + int i; + for (i = 1; i < argc && argv[i][0] == '-'; i++) { + if (argv[i][1] == '-' && argv[i][2] == '\0') { + i++; + break; + } + if (i + 1 >= argc) + usage(); + int j; + for (j = 0;; j++) { + if (j >= sizeof(param_table)/sizeof(param_table[0])) + fatal("parameter `%1' not recognized", argv[i] + 1); + if (strcmp(param_table[j].name, argv[i] + 1) == 0) + break; + } + if (sscanf(argv[i+1], "%d", &(param.*(param_table[j].par))) != 1) + fatal("invalid argument `%1'", argv[i+1]); + i++; + } + if (argc - i != 3) + usage(); + errno = 0; + FILE *infp = fopen(font, "r"); + if (infp == 0) + fatal("can't open `%1': %2", font, strerror(errno)); + convert_font(param, infp, stdout); + return 0; +} + +static void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-v] [-param value] ... " + "resolution unitwidth font\n", + program_name); +} +static void usage() +{ + usage(stderr); + exit(1); +} + +static void version() +{ + extern const char *Version_string; + printf("GNU addftinfo (groff) version %s\n", Version_string); + exit(0); +} + +static int get_line(FILE *fp, string *p) +{ + int c; + p->clear(); + while ((c = getc(fp)) != EOF) { + *p += char(c); + if (c == '\n') + break; + } + return p->length() > 0; +} + +static void convert_font(const font_params ¶m, FILE *infp, FILE *outfp) +{ + string s; + while (get_line(infp, &s)) { + put_string(s, outfp); + if (s.length() >= 8 + && strncmp(&s[0], "charset", 7)) + break; + } + while (get_line(infp, &s)) { + s += '\0'; + string name; + const char *p = s.contents(); + while (csspace(*p)) + p++; + while (*p != '\0' && !csspace(*p)) + name += *p++; + while (csspace(*p)) + p++; + for (const char *q = s.contents(); q < p; q++) + putc(*q, outfp); + char *next; + char_metric metric; + metric.width = (int)strtol(p, &next, 10); + if (next != p) { + printf("%d", metric.width); + p = next; + metric.type = (int)strtol(p, &next, 10); + if (next != p) { + name += '\0'; + guess(name.contents(), param, &metric); + if (metric.sk == 0) { + if (metric.left_ic == 0) { + if (metric.ic == 0) { + if (metric.depth == 0) { + if (metric.height != 0) + printf(",%d", metric.height); + } + else + printf(",%d,%d", metric.height, metric.depth); + } + else + printf(",%d,%d,%d", metric.height, metric.depth, metric.ic); + } + else + printf(",%d,%d,%d,%d", metric.height, metric.depth, metric.ic, + metric.left_ic); + } + else + printf(",%d,%d,%d,%d,%d", metric.height, metric.depth, metric.ic, + metric.left_ic, metric.sk); + } + } + fputs(p, outfp); + } +} + diff --git a/contrib/groff/src/utils/addftinfo/addftinfo.man b/contrib/groff/src/utils/addftinfo/addftinfo.man new file mode 100644 index 0000000..921f633 --- /dev/null +++ b/contrib/groff/src/utils/addftinfo/addftinfo.man @@ -0,0 +1,107 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.TH ADDFTINFO @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +addftinfo \- add information to troff font files for use with groff +.SH SYNOPSIS +.B addftinfo +[ +.B \-v +] +[ +.BI \- param\ value\fR.\|.\|. +] +.I res +.I unitwidth +.I font +.SH DESCRIPTION +.B addftinfo +reads a troff font file +and adds some additional font-metric information +that is used by the groff system. +The font file with the information added is written on the +standard output. +The information added is guessed using +some parametric information about the font +and assumptions +about the traditional troff names for characters. +The main information added is the heights and depths of characters. +The +.I res +and +.I unitwidth +arguments should be the same as the corresponding parameters +in the DESC file; +.I font +is the name of the file describing the font; +if +.I font +ends with +.B I +the font will be assumed to be italic. +.SH OPTIONS +.B \-v +prints the version number. +.LP +All other options changes one of the parameters that is used +to derive the heights and depths. +Like the existing quantities in the font +file, each +.I value +is in +.RI inches/ res +for a font whose point size is +.IR unitwidth . +.I param +must be one of: +.TP +.B x-height +The height of lowercase letters without ascenders such as x. +.TP +.B fig-height +The height of figures (digits). +.TP +.B asc-height +The height of characters with ascenders, such as b, d or l. +.TP +.B body-height +The height of characters such as parentheses. +.TP +.B cap-height +The height of uppercase letters such as A. +.TP +.B comma-depth +The depth of a comma. +.TP +.B desc-depth +The depth of characters with descenders, such as p,q, or y. +.TP +.B body-depth +The depth of characters such as parentheses. +.LP +.B addftinfo +makes no attempt to use the specified parameters to guess +the unspecified parameters. +If a parameter is not specified the default will be used. +The defaults are chosen to have the reasonable values for +a Times font. +.SH "SEE ALSO" +.BR groff_font (@MAN5EXT@), +.BR groff (@MAN1EXT@), +.BR groff_char (@MAN7EXT@) diff --git a/contrib/groff/src/utils/addftinfo/guess.cc b/contrib/groff/src/utils/addftinfo/guess.cc new file mode 100644 index 0000000..dcfd4c9 --- /dev/null +++ b/contrib/groff/src/utils/addftinfo/guess.cc @@ -0,0 +1,490 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "guess.h" + +void guess(const char *s, const font_params ¶m, char_metric *metric) +{ + int &height = metric->height; + int &depth = metric->depth; + + metric->ic = 0; + metric->left_ic = 0; + metric->sk = 0; + height = 0; + depth = 0; + if (s[0] == '\0' || (s[1] != '\0' && s[2] != '\0')) + goto do_default; +#define HASH(c1, c2) (((unsigned char)(c1) << 8) | (unsigned char)(c2)) + switch (HASH(s[0], s[1])) { + default: + do_default: + if (metric->type & 01) + depth = param.desc_depth; + if (metric->type & 02) + height = param.asc_height; + else + height = param.x_height; + break; + case HASH('\\', '|'): + case HASH('\\', '^'): + case HASH('\\', '&'): + // these have zero height and depth + break; + case HASH('f', 0): + height = param.asc_height; + if (param.italic) + depth = param.desc_depth; + break; + case HASH('a', 0): + case HASH('c', 0): + case HASH('e', 0): + case HASH('m', 0): + case HASH('n', 0): + case HASH('o', 0): + case HASH('r', 0): + case HASH('s', 0): + case HASH('u', 0): + case HASH('v', 0): + case HASH('w', 0): + case HASH('x', 0): + case HASH('z', 0): + height = param.x_height; + break; + case HASH('i', 0): + height = param.x_height; + break; + case HASH('b', 0): + case HASH('d', 0): + case HASH('h', 0): + case HASH('k', 0): + case HASH('l', 0): + case HASH('F', 'i'): + case HASH('F', 'l'): + case HASH('f', 'f'): + case HASH('f', 'i'): + case HASH('f', 'l'): + height = param.asc_height; + break; + case HASH('t', 0): + height = param.asc_height; + break; + case HASH('g', 0): + case HASH('p', 0): + case HASH('q', 0): + case HASH('y', 0): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('j', 0): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('A', 0): + case HASH('B', 0): + case HASH('C', 0): + case HASH('D', 0): + case HASH('E', 0): + case HASH('F', 0): + case HASH('G', 0): + case HASH('H', 0): + case HASH('I', 0): + case HASH('J', 0): + case HASH('K', 0): + case HASH('L', 0): + case HASH('M', 0): + case HASH('N', 0): + case HASH('O', 0): + case HASH('P', 0): + case HASH('Q', 0): + case HASH('R', 0): + case HASH('S', 0): + case HASH('T', 0): + case HASH('U', 0): + case HASH('V', 0): + case HASH('W', 0): + case HASH('X', 0): + case HASH('Y', 0): + case HASH('Z', 0): + height = param.cap_height; + break; + case HASH('*', 'A'): + case HASH('*', 'B'): + case HASH('*', 'C'): + case HASH('*', 'D'): + case HASH('*', 'E'): + case HASH('*', 'F'): + case HASH('*', 'G'): + case HASH('*', 'H'): + case HASH('*', 'I'): + case HASH('*', 'K'): + case HASH('*', 'L'): + case HASH('*', 'M'): + case HASH('*', 'N'): + case HASH('*', 'O'): + case HASH('*', 'P'): + case HASH('*', 'Q'): + case HASH('*', 'R'): + case HASH('*', 'S'): + case HASH('*', 'T'): + case HASH('*', 'U'): + case HASH('*', 'W'): + case HASH('*', 'X'): + case HASH('*', 'Y'): + case HASH('*', 'Z'): + height = param.cap_height; + break; + case HASH('0', 0): + case HASH('1', 0): + case HASH('2', 0): + case HASH('3', 0): + case HASH('4', 0): + case HASH('5', 0): + case HASH('6', 0): + case HASH('7', 0): + case HASH('8', 0): + case HASH('9', 0): + case HASH('1', '2'): + case HASH('1', '4'): + case HASH('3', '4'): + height = param.fig_height; + break; + case HASH('(', 0): + case HASH(')', 0): + case HASH('[', 0): + case HASH(']', 0): + case HASH('{', 0): + case HASH('}', 0): + height = param.body_height; + depth = param.body_depth; + break; + case HASH('i', 's'): + height = (param.em*3)/4; + depth = param.em/4; + break; + case HASH('*', 'a'): + case HASH('*', 'e'): + case HASH('*', 'i'): + case HASH('*', 'k'): + case HASH('*', 'n'): + case HASH('*', 'o'): + case HASH('*', 'p'): + case HASH('*', 's'): + case HASH('*', 't'): + case HASH('*', 'u'): + case HASH('*', 'w'): + height = param.x_height; + break; + case HASH('*', 'd'): + case HASH('*', 'l'): + height = param.asc_height; + break; + case HASH('*', 'g'): + case HASH('*', 'h'): + case HASH('*', 'm'): + case HASH('*', 'r'): + case HASH('*', 'x'): + case HASH('*', 'y'): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('*', 'b'): + case HASH('*', 'c'): + case HASH('*', 'f'): + case HASH('*', 'q'): + case HASH('*', 'z'): + height = param.asc_height; + depth = param.desc_depth; + break; + case HASH('t', 's'): + height = param.x_height; + depth = param.desc_depth; + break; + case HASH('!', 0): + case HASH('?', 0): + case HASH('"', 0): + case HASH('#', 0): + case HASH('$', 0): + case HASH('%', 0): + case HASH('&', 0): + case HASH('*', 0): + case HASH('+', 0): + height = param.asc_height; + break; + case HASH('`', 0): + case HASH('\'', 0): + height = param.asc_height; + break; + case HASH('~', 0): + case HASH('^', 0): + case HASH('a', 'a'): + case HASH('g', 'a'): + height = param.asc_height; + break; + case HASH('r', 'u'): + case HASH('.', 0): + break; + case HASH(',', 0): + depth = param.comma_depth; + break; + case HASH('m', 'i'): + case HASH('-', 0): + case HASH('h', 'y'): + case HASH('e', 'm'): + height = param.x_height; + break; + case HASH(':', 0): + height = param.x_height; + break; + case HASH(';', 0): + height = param.x_height; + depth = param.comma_depth; + break; + case HASH('=', 0): + case HASH('e', 'q'): + height = param.x_height; + break; + case HASH('<', 0): + case HASH('>', 0): + case HASH('>', '='): + case HASH('<', '='): + case HASH('@', 0): + case HASH('/', 0): + case HASH('|', 0): + case HASH('\\', 0): + height = param.asc_height; + break; + case HASH('_', 0): + case HASH('u', 'l'): + case HASH('\\', '_'): + depth = param.em/4; + break; + case HASH('r', 'n'): + height = (param.em*3)/4; + break; + case HASH('s', 'r'): + height = (param.em*3)/4; + depth = param.em/4; + break; + case HASH('b', 'u'): + case HASH('s', 'q'): + case HASH('d', 'e'): + case HASH('d', 'g'): + case HASH('f', 'm'): + case HASH('c', 't'): + case HASH('r', 'g'): + case HASH('c', 'o'): + case HASH('p', 'l'): + case HASH('*', '*'): + case HASH('s', 'c'): + case HASH('s', 'l'): + case HASH('=', '='): + case HASH('~', '='): + case HASH('a', 'p'): + case HASH('!', '='): + case HASH('-', '>'): + case HASH('<', '-'): + case HASH('u', 'a'): + case HASH('d', 'a'): + case HASH('m', 'u'): + case HASH('d', 'i'): + case HASH('+', '-'): + case HASH('c', 'u'): + case HASH('c', 'a'): + case HASH('s', 'b'): + case HASH('s', 'p'): + case HASH('i', 'b'): + case HASH('i', 'p'): + case HASH('i', 'f'): + case HASH('p', 'd'): + case HASH('g', 'r'): + case HASH('n', 'o'): + case HASH('p', 't'): + case HASH('e', 's'): + case HASH('m', 'o'): + case HASH('b', 'r'): + case HASH('d', 'd'): + case HASH('r', 'h'): + case HASH('l', 'h'): + case HASH('o', 'r'): + case HASH('c', 'i'): + height = param.asc_height; + break; + case HASH('l', 't'): + case HASH('l', 'b'): + case HASH('r', 't'): + case HASH('r', 'b'): + case HASH('l', 'k'): + case HASH('r', 'k'): + case HASH('b', 'v'): + case HASH('l', 'f'): + case HASH('r', 'f'): + case HASH('l', 'c'): + case HASH('r', 'c'): + height = (param.em*3)/4; + depth = param.em/4; + break; +#if 0 + case HASH('%', '0'): + case HASH('-', '+'): + case HASH('-', 'D'): + case HASH('-', 'd'): + case HASH('-', 'd'): + case HASH('-', 'h'): + case HASH('.', 'i'): + case HASH('.', 'j'): + case HASH('/', 'L'): + case HASH('/', 'O'): + case HASH('/', 'l'): + case HASH('/', 'o'): + case HASH('=', '~'): + case HASH('A', 'E'): + case HASH('A', 'h'): + case HASH('A', 'N'): + case HASH('C', 's'): + case HASH('D', 'o'): + case HASH('F', 'c'): + case HASH('F', 'o'): + case HASH('I', 'J'): + case HASH('I', 'm'): + case HASH('O', 'E'): + case HASH('O', 'f'): + case HASH('O', 'K'): + case HASH('O', 'm'): + case HASH('O', 'R'): + case HASH('P', 'o'): + case HASH('R', 'e'): + case HASH('S', '1'): + case HASH('S', '2'): + case HASH('S', '3'): + case HASH('T', 'P'): + case HASH('T', 'p'): + case HASH('Y', 'e'): + case HASH('\\', '-'): + case HASH('a', '"'): + case HASH('a', '-'): + case HASH('a', '.'): + case HASH('a', '^'): + case HASH('a', 'b'): + case HASH('a', 'c'): + case HASH('a', 'd'): + case HASH('a', 'e'): + case HASH('a', 'h'): + case HASH('a', 'o'): + case HASH('a', 't'): + case HASH('a', '~'): + case HASH('b', 'a'): + case HASH('b', 'b'): + case HASH('b', 's'): + case HASH('c', '*'): + case HASH('c', '+'): + case HASH('f', '/'): + case HASH('f', 'a'): + case HASH('f', 'c'): + case HASH('f', 'o'): + case HASH('h', 'a'): + case HASH('h', 'o'): + case HASH('i', 'j'): + case HASH('l', 'A'): + case HASH('l', 'B'): + case HASH('l', 'C'): + case HASH('m', 'd'): + case HASH('n', 'c'): + case HASH('n', 'e'): + case HASH('n', 'm'): + case HASH('o', 'A'): + case HASH('o', 'a'): + case HASH('o', 'e'): + case HASH('o', 'q'): + case HASH('p', 'l'): + case HASH('p', 'p'): + case HASH('p', 's'): + case HASH('r', '!'): + case HASH('r', '?'): + case HASH('r', 'A'): + case HASH('r', 'B'): + case HASH('r', 'C'): + case HASH('r', 's'): + case HASH('s', 'h'): + case HASH('s', 's'): + case HASH('t', 'e'): + case HASH('t', 'f'): + case HASH('t', 'i'): + case HASH('t', 'm'): + case HASH('~', '~'): + case HASH('v', 'S'): + case HASH('v', 'Z'): + case HASH('v', 's'): + case HASH('v', 'z'): + case HASH('^', 'A'): + case HASH('^', 'E'): + case HASH('^', 'I'): + case HASH('^', 'O'): + case HASH('^', 'U'): + case HASH('^', 'a'): + case HASH('^', 'e'): + case HASH('^', 'i'): + case HASH('^', 'o'): + case HASH('^', 'u'): + case HASH('`', 'A'): + case HASH('`', 'E'): + case HASH('`', 'I'): + case HASH('`', 'O'): + case HASH('`', 'U'): + case HASH('`', 'a'): + case HASH('`', 'e'): + case HASH('`', 'i'): + case HASH('`', 'o'): + case HASH('`', 'u'): + case HASH('~', 'A'): + case HASH('~', 'N'): + case HASH('~', 'O'): + case HASH('~', 'a'): + case HASH('~', 'n'): + case HASH('~', 'o'): + case HASH('\'', 'A'): + case HASH('\'', 'C'): + case HASH('\'', 'E'): + case HASH('\'', 'I'): + case HASH('\'', 'O'): + case HASH('\'', 'U'): + case HASH('\'', 'a'): + case HASH('\'', 'c'): + case HASH('\'', 'e'): + case HASH('\'', 'i'): + case HASH('\'', 'o'): + case HASH('\'', 'u') + case HASH(':', 'A'): + case HASH(':', 'E'): + case HASH(':', 'I'): + case HASH(':', 'O'): + case HASH(':', 'U'): + case HASH(':', 'Y'): + case HASH(':', 'a'): + case HASH(':', 'e'): + case HASH(':', 'i'): + case HASH(':', 'o'): + case HASH(':', 'u'): + case HASH(':', 'y'): + case HASH(',', 'C'): + case HASH(',', 'c'): +#endif + } +} diff --git a/contrib/groff/src/utils/addftinfo/guess.h b/contrib/groff/src/utils/addftinfo/guess.h new file mode 100644 index 0000000..4471dda --- /dev/null +++ b/contrib/groff/src/utils/addftinfo/guess.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct font_params { + int italic; + int em; + int x_height; + int fig_height; + int cap_height; + int asc_height; + int body_height; + int comma_depth; + int desc_depth; + int body_depth; +}; + +struct char_metric { + int width; + int type; + int height; + int depth; + int ic; + int left_ic; + int sk; +}; + +void guess(const char *s, const font_params ¶m, char_metric *metric); diff --git a/contrib/groff/src/utils/afmtodit/Makefile.sub b/contrib/groff/src/utils/afmtodit/Makefile.sub new file mode 100644 index 0000000..9176924 --- /dev/null +++ b/contrib/groff/src/utils/afmtodit/Makefile.sub @@ -0,0 +1,23 @@ +MAN1=afmtodit.n +CLEANADD=afmtodit + +all: afmtodit + +afmtodit: afmtodit.pl + if test -n "$(PERLPATH)"; then \ + sed -e "s|/usr/bin/perl|$(PERLPATH)|" \ + -e "s|@VERSION@|$(version)$(revision)|" \ + $(srcdir)/afmtodit.pl >afmtodit; \ + else \ + sed -e "s|@VERSION@|$(version)$(revision)|" \ + $(srcdir)/afmtodit.pl afmtodit; \ + fi + chmod +x afmtodit + +install_data: afmtodit + -test -d $(bindir) || $(mkinstalldirs) $(bindir) + -rm -f $(bindir)/afmtodit + $(INSTALL_SCRIPT) afmtodit $(bindir)/afmtodit + +uninstall_sub: + -rm -f $(bindir)/afmtodit diff --git a/contrib/groff/src/utils/afmtodit/afmtodit.man b/contrib/groff/src/utils/afmtodit/afmtodit.man new file mode 100644 index 0000000..03a6e5c --- /dev/null +++ b/contrib/groff/src/utils/afmtodit/afmtodit.man @@ -0,0 +1,225 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH AFMTODIT @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +afmtodit \- create font files for use with groff \-Tps +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fBafmtodit 'u +.ti \niu +.B afmtodit +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-nsv +.OP \-d desc_file +.OP \-e enc_file +.OP \-i n +.OP \-a n +.I afm_file +.I map_file +.I font +.br +.ad \na +.SH DESCRIPTION +.B afmtodit +creates a font file for use with groff and +.BR grops . +.B afmtodit +is written in perl; +you must have perl version 3 installed in order to run +.BR afmtodit . +.I afm_file +is the AFM (Adobe Font Metric) file for the font. +.I map_file +is a file that says which groff character names map onto +each PostScript character name; +this file should contain a sequence of lines of the form +.IP +.I +ps_char groff_char +.LP +where +.I ps_char +is the PostScript name of the character +and +.I groff_char +is the groff name of the character (as used in the groff font file.) +The same +.I ps_char +can occur multiple times in the file; +each +.I groff_char +must occur at most once. +.I font +is the groff name of the font. +If a PostScript character is in the encoding to be used for the font +but is not mentioned in +.I map_file +then +.B afmtodit +will put it in the groff font file as an unnamed character, +which can be accessed by the +.B \eN +escape sequence in +.BR troff . +The groff font file will be output to a file called +.IR font . +.LP +If there is a downloadable font file for the font, it may be listed in +the file +.BR @FONTDIR@/devps/download ; +see +.BR grops (@MAN1EXT@). +.LP +If the +.B \-i +option is used, +.B afmtodit +will automatically generate an italic correction, +a left italic correction and a subscript correction +for each character +(the significance of these parameters is explained in +.BR groff_font (@MAN5EXT@)); +these parameters may be specified for individual characters by +adding to the +.I afm_file +lines of the form: +.IP +.BI italicCorrection\ ps_char\ n +.br +.BI leftItalicCorrection\ ps_char\ n +.br +.BI subscriptCorrection\ ps_char\ n +.LP +where +.I ps_char +is the PostScript name of the character, +and +.I n +is the desired value of the corresponding parameter in thousandths of an em. +These parameters are normally needed only for italic (or oblique) fonts. +.SH OPTIONS +.TP +.B \-v +Print version. +.TP +.B \-n +Don't output a +.B ligatures +command for this font. +Use this with constant-width fonts. +.TP +.B \-s +The font is special. +The effect of this option is to add the +.B special +command to the font file. +.TP +.BI \-d desc_file +The device description file is +.I desc_file +rather than the default +.BR DESC . +.TP +.BI \-e enc_file +The PostScript font should be reencoded to use the encoding described +in enc_file. +The format of +.I enc_file +is described in +.BR grops (@MAN1EXT@). +.TP +.BI \-a n +Use +.I n +as the slant parameter in the font file; +this is used by groff in the positioning of accents. +By default +.B afmtodit +uses the negative of the ItalicAngle specified in the afm file; +with true italic fonts it is sometimes desirable to use +a slant that is less than this. +If you find that characters from an italic font have accents +placed too far to the right over them, +then use the +.B \-a +option to give the font a smaller slant. +.TP +.BI \-i n +Generate an italic correction for each character so that +the character's width plus the character's italic correction +is equal to +.I n +thousandths of an em +plus the amount by which the right edge of the character's bounding +is to the right of the character's origin. +If this would result in a negative italic correction, use a zero +italic correction instead. +.IP +Also generate a subscript correction equal to the +product of the tangent of the slant of the font and +four fifths of the x-height of the font. +If this would result in a subscript correction greater than the italic +correction, use a subscript correction equal to the italic correction +instead. +.IP +Also generate a left italic correction for each character +equal to +.I n +thousandths of an em +plus the amount by which the left edge of the character's bounding box +is to the left of the character's origin. +The left italic correction may be negative. +.IP +This option is normally needed only with italic (or oblique) fonts. +The font files distributed with groff were created using an option of +.B \-i50 +for italic fonts. +.SH FILES +.Tp \w'\fB@FONTDIR@/devps/download'u+2n +.B @FONTDIR@/devps/DESC +Device description file. +.TP +.BI @FONTDIR@/devps/ F +Font description file for font +.IR F . +.TP +.B @FONTDIR@/devps/download +List of downloadable fonts. +.TP +.B @FONTDIR@/devps/text.enc +Encoding used for text fonts. +.TP +.B @FONTDIR@/devps/generate/textmap +Standard mapping. +.SH "SEE ALSO" +.BR groff (@MAN1EXT@), +.BR grops (@MAN1EXT@), +.BR groff_font (@MAN5EXT@), +.BR perl (1) diff --git a/contrib/groff/src/utils/afmtodit/afmtodit.pl b/contrib/groff/src/utils/afmtodit/afmtodit.pl new file mode 100644 index 0000000..661245a --- /dev/null +++ b/contrib/groff/src/utils/afmtodit/afmtodit.pl @@ -0,0 +1,331 @@ +#! /usr/bin/perl -P- +# -*- Perl -*- +# Copyright (C) 1989-2000 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +$prog = $0; +$prog =~ s@.*/@@; + +do 'getopts.pl'; +do Getopts('ve:sd:i:a:n'); + +if (opt_v) { + print "GNU afmtodit (groff) version @VERSION@\n"; + exit 0; +} + +if ($#ARGV != 2) { + die "Usage: $prog [-nsv] [-d DESC] [-e encoding] [-i n] [-a angle] afmfile mapfile font\n"; +} + +$afm = $ARGV[0]; +$map = $ARGV[1]; +$font = $ARGV[2]; +$desc = $opt_d || "DESC"; + +# read the afm file + +open(AFM, $afm) || die "$prog: can't open \`$ARGV[0]': $!\n"; + +while (<AFM>) { + chop; + @field = split(' '); + if ($field[0] eq "FontName") { + $psname = $field[1]; + } + elsif($field[0] eq "ItalicAngle") { + $italic_angle = -$field[1]; + } + elsif ($field[0] eq "KPX") { + if ($#field == 3) { + push(kern1, $field[1]); + push(kern2, $field[2]); + push(kernx, $field[3]); + } + } + elsif ($field[0] eq "italicCorrection") { + $italic_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "leftItalicCorrection") { + $left_italic_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "subscriptCorrection") { + $subscript_correction{$field[1]} = $field[2]; + } + elsif ($field[0] eq "StartCharMetrics") { + while (<AFM>) { + @field = split(' '); + last if ($field[0] eq "EndCharMetrics"); + if ($field[0] eq "C") { + $c = -1; + $wx = 0; + $n = ""; + $lly = 0; + $ury = 0; + $llx = 0; + $urx = 0; + $c = $field[1]; + $i = 2; + while ($i <= $#field) { + if ($field[$i] eq "WX") { + $w = $field[$i + 1]; + $i += 2; + } + elsif ($field[$i] eq "N") { + $n = $field[$i + 1]; + $i += 2; + } + elsif ($field[$i] eq "B") { + $llx = $field[$i + 1]; + $lly = $field[$i + 2]; + $urx = $field[$i + 3]; + $ury = $field[$i + 4]; + $i += 5; + } + elsif ($field[$i] eq "L") { + push(ligatures, $field[$i + 2]); + $i += 3; + } + else { + while ($i <= $#field && $field[$i] ne ";") { + $i++; + } + $i++; + } + } + if (!$opt_e && $c != -1) { + $encoding[$c] = $n; + $in_encoding{$n} = 1; + } + $width{$n} = $w; + $height{$n} = $ury; + $depth{$n} = -$lly; + $left_side_bearing{$n} = -$llx; + $right_side_bearing{$n} = $urx - $w; + } + } + } +} +close(AFM); + +# read the DESC file + +$sizescale = 1; + +open(DESC, $desc) || die "$prog: can't open \`$desc': $!\n"; +while (<DESC>) { + next if /^#/; + chop; + @field = split(' '); + last if $field[0] eq "charset"; + if ($field[0] eq "res") { $resolution = $field[1]; } + if ($field[0] eq "unitwidth") { $unitwidth = $field[1]; } + if ($field[0] eq "sizescale") { $sizescale = $field[1]; } +} +close(DESC); + +if ($opt_e) { + # read the encoding file + + open(ENCODING, $opt_e) || die "$prog: can't open \`$opt_e': $!\n"; + while (<ENCODING>) { + chop; + @field = split(' '); + if ($#field == 1) { + if ($field[1] >= 0 && defined $width{$field[0]}) { + $encoding[$field[1]] = $field[0]; + $in_encoding{$field[0]} = 1; + } + } + } + close(ENCODING); +} + +# read the map file + +open(MAP, $map) || die "$prog: can't open \`$map': $!\n"; +while (<MAP>) { + next if /^#/; + chop; + @field = split(' '); + if ($#field == 1 && $in_encoding{$field[0]}) { + if (defined $mapped{$field[1]}) { + warn "Both $mapped{$field[1]} and $field[0] map to $field[1]"; + } + elsif ($field[1] eq "space") { + # the PostScript character "space" is automatically mapped + # to the groff character "space"; this is for grops + warn "you are not allowed to map to the groff character `space'"; + } + elsif ($field[0] eq "space") { + warn "you are not allowed to map the PostScript character `space'"; + } + else { + $nmap{$field[0]} += 0; + $map{$field[0],$nmap{$field[0]}} = $field[1]; + $nmap{$field[0]} += 1; + $mapped{$field[1]} = $field[0]; + } + } +} +close(MAP); + +$italic_angle = $opt_a if $opt_a; + +# print it all out + +open(FONT, ">$font") || die "$prog: can't open \`$font' for output: $!\n"; +select(FONT); + +print("name $font\n"); +print("internalname $psname\n") if $psname; +print("special\n") if $opt_s; +printf("slant %g\n", $italic_angle) if $italic_angle != 0; +printf("spacewidth %d\n", do conv($width{"space"})) if defined $width{"space"}; + +if ($opt_e) { + $e = $opt_e; + $e =~ s@.*/@@; + print("encoding $e\n"); +} + +if (!$opt_n && $#ligatures >= 0) { + print("ligatures"); + foreach $lig (@ligatures) { + print(" $lig"); + } + print(" 0\n"); +} + +if ($#kern1 >= 0) { + print("kernpairs\n"); + + for ($i = 0; $i <= $#kern1; $i++) { + $c1 = $kern1[$i]; + $c2 = $kern2[$i]; + if ($in_encoding{$c1} == 1 && $nmap{$c1} != 0 + && $in_encoding{$c2} == 1 && $nmap{$c2} != 0) { + for ($j = 0; $j < $nmap{$c1}; $j++) { + for ($k = 0; $k < $nmap{$c2}; $k++) { + if ($kernx[$i] != 0) { + printf("%s %s %d\n", + $map{$c1,$j}, + $map{$c2,$k}, + do conv($kernx[$i])); + } + } + } + } + } +} + +# characters not shorter than asc_boundary are considered to have ascenders +$asc_boundary = $height{"t"} - 1; + +# likewise for descenders +$desc_boundary = $depth{"g"}; +$desc_boundary = $depth{"j"} if $depth{"j"} < $desc_boundary; +$desc_boundary = $depth{"p"} if $depth{"p"} < $desc_boundary; +$desc_boundary = $depth{"q"} if $depth{"q"} < $desc_boundary; +$desc_boundary = $depth{"y"} if $depth{"y"} < $desc_boundary; +$desc_boundary -= 1; + +if (defined $height{"x"}) { + $xheight = $height{"x"}; +} +elsif (defined $height{"alpha"}) { + $xheight = $height{"alpha"}; +} +else { + $xheight = 450; +} + +$italic_angle = $italic_angle*3.14159265358979323846/180.0; +$slant = sin($italic_angle)/cos($italic_angle); +$slant = 0 if $slant < 0; + +print("charset\n"); +for ($i = 0; $i < 256; $i++) { + $ch = $encoding[$i]; + if ($ch ne "" && $ch ne "space") { + $map{$ch,"0"} = "---" if $nmap{$ch} == 0; + $type = 0; + $h = $height{$ch}; + $h = 0 if $h < 0; + $d = $depth{$ch}; + $d = 0 if $d < 0; + $type = 1 if $d >= $desc_boundary; + $type += 2 if $h >= $asc_boundary; + printf("%s\t%d", $map{$ch,"0"}, do conv($width{$ch})); + $italic_correction = 0; + $left_math_fit = 0; + $subscript_correction = 0; + if (defined $opt_i) { + $italic_correction = $right_side_bearing{$ch} + $opt_i; + $italic_correction = 0 if $italic_correction < 0; + $subscript_correction = $slant * $xheight * .8; + $subscript_correction = $italic_correction if + $subscript_correction > $italic_correction; + $left_math_fit = $left_side_bearing{$ch} + $opt_i; + } + if (defined $italic_correction{$ch}) { + $italic_correction = $italic_correction{$ch}; + } + if (defined $left_italic_correction{$ch}) { + $left_math_fit = $left_italic_correction{$ch}; + } + if (defined $subscript_correction{$ch}) { + $subscript_correction = $subscript_correction{$ch}; + } + if ($subscript_correction != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d,%d,%d", do conv($italic_correction), + do conv($left_math_fit), + do conv($subscript_correction)); + } + elsif ($left_math_fit != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d,%d", do conv($italic_correction), + do conv($left_math_fit)); + } + elsif ($italic_correction != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + printf(",%d", do conv($italic_correction)); + } + elsif ($d != 0) { + printf(",%d,%d", do conv($h), do conv($d)); + } + else { + # always put the height in to stop groff guessing + printf(",%d", do conv($h)); + } + printf("\t%d", $type); + printf("\t0%03o\t-- %s\n", $i, $ch); + for ($j = 1; $j < $nmap{$ch}; $j++) { + printf("%s\t\"\n", $map{$ch,$j}); + } + } + if ($ch eq "space" && defined $width{"space"}) { + printf("space\t%d\t0\t0%03o\n", do conv($width{"space"}), $i); + } +} + +sub conv { + $_[0]*$unitwidth*$resolution/(72*1000*$sizescale) + ($_[0] < 0 ? -.5 : .5); +} diff --git a/contrib/groff/src/utils/hpftodit/Makefile.sub b/contrib/groff/src/utils/hpftodit/Makefile.sub new file mode 100644 index 0000000..f5ff13e --- /dev/null +++ b/contrib/groff/src/utils/hpftodit/Makefile.sub @@ -0,0 +1,6 @@ +PROG=hpftodit +MAN1=hpftodit.n +XLIBS=$(LIBGROFF) +MLIB=$(LIBM) +OBJS=hpftodit.o +CCSRCS=$(srcdir)/hpftodit.cc diff --git a/contrib/groff/src/utils/hpftodit/hpftodit.cc b/contrib/groff/src/utils/hpftodit/hpftodit.cc new file mode 100644 index 0000000..f81f5ad --- /dev/null +++ b/contrib/groff/src/utils/hpftodit/hpftodit.cc @@ -0,0 +1,827 @@ +// -*- C++ -*- +/* Copyright (C) 1994, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +TODO +put human readable font name in device file +devise new names for useful characters +use --- for unnamed characters +option to specify symbol sets to look in +make it work with TrueType fonts +put filename in error messages (or fix lib) +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <errno.h> +#include "assert.h" +#include "lib.h" +#include "posix.h" +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "nonposix.h" + +#define SIZEOF(v) (sizeof(v)/sizeof(v[0])) + +const int MULTIPLIER = 3; + +inline +int scale(int n) +{ + return n * MULTIPLIER; +} + +// tags in TFM file + +enum tag_type { + min_tag = 400, + type_tag = 400, + symbol_set_tag = 404, + msl_tag = 403, + inches_per_point_tag = 406, + design_units_per_em_tag = 408, + posture_tag = 409, + stroke_weight_tag = 411, + spacing_tag = 412, + slant_tag = 413, + appearance_width_tag = 414, + word_spacing_tag = 421, + x_height_tag = 424, + lower_ascent_tag = 427, + lower_descent_tag = 428, + width_tag = 433, + left_extent_tag = 435, + right_extent_tag = 436, + ascent_tag = 437, + descent_tag = 438, + pair_kern_tag = 439, + typeface_tag = 442, + max_tag = 443 + }; + +// types in TFM file + +enum { + ENUM_TYPE = 1, + BYTE_TYPE = 2, + USHORT_TYPE = 3, + FLOAT_TYPE = 5, + SIGNED_SHORT_TYPE = 17 + }; + + +typedef unsigned char byte; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned int uint32; + +class File { +public: + File(const char *); + void skip(int n); + byte get_byte(); + uint16 get_uint16(); + uint32 get_uint32(); + void seek(uint32 n); +private: + unsigned char *buf_; + const unsigned char *ptr_; + const unsigned char *end_; +}; + +struct entry { + char present; + uint16 type; + uint32 count; + uint32 value; + entry() : present(0) { } +}; + +struct char_info { + uint16 msl; + uint16 width; + uint16 ascent; + int16 descent; + int16 left_extent; + uint16 right_extent; + uint16 symbol_set; + unsigned char code; +}; + +const uint16 NO_SYMBOL_SET = 0; + +struct name_list { + char *name; + name_list *next; + name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { } + ~name_list() { a_delete name; } +}; + +struct symbol_set { + uint16 select; + uint16 index[256]; +}; + +#define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64)) + +uint16 text_symbol_sets[] = { + SYMBOL_SET(0, 'N'), // Latin 1 + SYMBOL_SET(6, 'J'), // Microsoft Publishing + SYMBOL_SET(2, 'N'), // Latin 2 + 0 + }; + +uint16 special_symbol_sets[] = { + SYMBOL_SET(8, 'M'), + SYMBOL_SET(5, 'M'), + SYMBOL_SET(15, 'U'), + 0 + }; + +entry tags[max_tag + 1 - min_tag]; + +char_info *char_table; +uint32 nchars; + +int msl_name_table_size = 0; +name_list **msl_name_table = 0; + +int n_symbol_sets; +symbol_set *symbol_set_table; + +static int special_flag = 0; +static int italic_flag = 0; +static int italic_sep; + +static void usage(FILE *stream); +static void usage(); +static const char *xbasename(const char *); +static void read_tags(File &); +static void check_type(); +static void check_units(File &); +static int read_map(const char *); +static void require_tag(tag_type); +static void dump_tags(File &f); +static void output_spacewidth(); +static void output_pclweight(); +static void output_pclproportional(); +static void read_and_output_pcltypeface(File &); +static void output_pclstyle(); +static void output_slant(); +static void output_ligatures(); +static void read_symbol_sets(File &); +static void read_and_output_kernpairs(File &); +static void output_charset(); +static void read_char_table(File &f); + +inline +entry &tag_info(tag_type t) +{ + return tags[t - min_tag]; +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + + int opt; + int debug_flag = 0; + + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((opt = getopt_long(argc, argv, "dsvi:", long_options, NULL)) != EOF) { + switch (opt) { + case 'd': + debug_flag = 1; + break; + case 's': + special_flag = 1; + break; + case 'i': + italic_flag = 1; + italic_sep = atoi(optarg); + break; + case 'v': + { + extern const char *Version_string; + printf("GNU hpftodit (groff) version %s\n", Version_string); + exit(0); + } + break; + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(); + break; + default: + assert(0); + } + } + if (argc - optind != 3) + usage(); + File f(argv[optind]); + if (!read_map(argv[optind + 1])) + exit(1); + current_filename = 0; + current_lineno = -1; // no line numbers + if (freopen(argv[optind + 2], "w", stdout) == 0) + fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno)); + current_filename = argv[optind]; + printf("name %s\n", xbasename(argv[optind + 2])); + if (special_flag) + printf("special\n"); + read_tags(f); + check_type(); + check_units(f); + if (debug_flag) + dump_tags(f); + read_char_table(f); + output_spacewidth(); + output_slant(); + read_and_output_pcltypeface(f); + output_pclproportional(); + output_pclweight(); + output_pclstyle(); + read_symbol_sets(f); + output_ligatures(); + read_and_output_kernpairs(f); + output_charset(); + return 0; +} + +static +void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-s] [-i n] tfm_file map_file output_font\n", + program_name); +} +static +void usage() +{ + usage(stderr); + exit(1); +} + +File::File(const char *s) +{ + // We need to read the file in binary mode because hpftodit relies + // on byte counts. + int fd = open(s, O_RDONLY | O_BINARY); + if (fd < 0) + fatal("cannot open `%1': %2", s, strerror(errno)); + current_filename = s; + struct stat sb; + if (fstat(fd, &sb) < 0) + fatal("cannot stat: %1", strerror(errno)); + if (!S_ISREG(sb.st_mode)) + fatal("not a regular file"); + buf_ = new unsigned char[sb.st_size]; + long nread = read(fd, buf_, sb.st_size); + if (nread < 0) + fatal("read error: %1", strerror(errno)); + if (nread != sb.st_size) + fatal("read unexpected number of bytes"); + ptr_ = buf_; + end_ = buf_ + sb.st_size; + // These are actually text files, so we must get rid of the `\r' + // characters. This is also enabled for Posix systems, in case the + // input came from Windows... + unsigned char *p = buf_, *q = buf_; + while (q < end_) + { + if (*q == '\r') + { + if (*++q != '\n') + *p++ = '\r'; + } +#if defined(__MSDOS__) || defined(_MSC_VER) + if (*q == '\032') // ^Z means ``software EOF'' + break; +#endif + *p++ = *q++; + } + end_ = p; +} + +void File::skip(int n) +{ + if (end_ - ptr_ < n) + fatal("unexpected end of file"); + ptr_ += n; +} + +void File::seek(uint32 n) +{ + if (end_ - buf_ < n) + fatal("unexpected end of file"); + ptr_ = buf_ + n; +} + +byte File::get_byte() +{ + if (ptr_ >= end_) + fatal("unexpected end of file"); + return *ptr_++; +} + +uint16 File::get_uint16() +{ + if (end_ - ptr_ < 2) + fatal("unexpected end of file"); + uint16 n = *ptr_++; + return n + (*ptr_++ << 8); +} + +uint32 File::get_uint32() +{ + if (end_ - ptr_ < 4) + fatal("unexpected end of file"); + uint32 n = *ptr_++; + for (int i = 0; i < 3; i++) + n += *ptr_++ << (i + 1)*8; + return n; +} + +static +void read_tags(File &f) +{ + if (f.get_byte() != 'I' || f.get_byte() != 'I') + fatal("not an Intel format TFM file"); + f.skip(6); + uint16 ntags = f.get_uint16(); + entry dummy; + for (uint16 i = 0; i < ntags; i++) { + uint16 tag = f.get_uint16(); + entry *p; + if (min_tag <= tag && tag <= max_tag) + p = tags + (tag - min_tag); + else + p = &dummy; + p->present = 1; + p->type = f.get_uint16(); + p->count = f.get_uint32(); + p->value = f.get_uint32(); + } +} + +static +void check_type() +{ + require_tag(type_tag); + if (tag_info(type_tag).value != 0) { + if (tag_info(type_tag).value == 2) + fatal("cannot handle TrueType tfm files"); + fatal("unknown type tag %1", int(tag_info(type_tag).value)); + } +} + +static +void check_units(File &f) +{ + require_tag(design_units_per_em_tag); + f.seek(tag_info(design_units_per_em_tag).value); + uint32 num = f.get_uint32(); + uint32 den = f.get_uint32(); + if (num != 8782 || den != 1) + fatal("design units per em != 8782/1"); + require_tag(inches_per_point_tag); + f.seek(tag_info(inches_per_point_tag).value); + num = f.get_uint32(); + den = f.get_uint32(); + if (num != 100 || den != 7231) + fatal("inches per point not 100/7231"); +} + +static +void require_tag(tag_type t) +{ + if (!tag_info(t).present) + fatal("tag %1 missing", int(t)); +} + +static +void output_spacewidth() +{ + require_tag(word_spacing_tag); + printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value)); +} + +static +void read_symbol_sets(File &f) +{ + uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count; + n_symbol_sets = symbol_set_dir_length/14; + symbol_set_table = new symbol_set[n_symbol_sets]; + int i; + for (i = 0; i < n_symbol_sets; i++) { + f.seek(tag_info(symbol_set_tag).value + i*14); + (void)f.get_uint32(); + uint32 off1 = f.get_uint32(); + uint32 off2 = f.get_uint32(); + (void)f.get_uint16(); // what's this for? + f.seek(off1); + int j; + uint16 kind = 0; + for (j = 0; j < off2 - off1; j++) { + unsigned char c = f.get_byte(); + if ('0' <= c && c <= '9') + kind = kind*10 + (c - '0'); + else if ('A' <= c && c <= 'Z') + kind = kind*32 + (c - 64); + } + symbol_set_table[i].select = kind; + for (j = 0; j < 256; j++) + symbol_set_table[i].index[j] = f.get_uint16(); + } + for (i = 0; i < nchars; i++) + char_table[i].symbol_set = NO_SYMBOL_SET; + + uint16 *symbol_set_selectors = (special_flag + ? special_symbol_sets + : text_symbol_sets); + for (i = 0; symbol_set_selectors[i] != 0; i++) { + int j; + for (j = 0; j < n_symbol_sets; j++) + if (symbol_set_table[j].select == symbol_set_selectors[i]) + break; + if (j < n_symbol_sets) { + for (int k = 0; k < 256; k++) { + uint16 index = symbol_set_table[j].index[k]; + if (index != 0xffff + && char_table[index].symbol_set == NO_SYMBOL_SET) { + char_table[index].symbol_set = symbol_set_table[j].select; + char_table[index].code = k; + } + } + } + } +} + +static +void read_char_table(File &f) +{ + require_tag(msl_tag); + nchars = tag_info(msl_tag).count; + char_table = new char_info[nchars]; + + f.seek(tag_info(msl_tag).value); + uint32 i; + for (i = 0; i < nchars; i++) + char_table[i].msl = f.get_uint16(); + + require_tag(width_tag); + f.seek(tag_info(width_tag).value); + for (i = 0; i < nchars; i++) + char_table[i].width = f.get_uint16(); + + require_tag(ascent_tag); + f.seek(tag_info(ascent_tag).value); + for (i = 0; i < nchars; i++) { + char_table[i].ascent = f.get_uint16(); + } + + require_tag(descent_tag); + f.seek(tag_info(descent_tag).value); + for (i = 0; i < nchars; i++) { + char_table[i].descent = f.get_uint16(); + if (char_table[i].descent > 0) + char_table[i].descent = 0; + } + + require_tag(left_extent_tag); + f.seek(tag_info(left_extent_tag).value); + for (i = 0; i < nchars; i++) + char_table[i].left_extent = int16(f.get_uint16()); + + require_tag(right_extent_tag); + f.seek(tag_info(right_extent_tag).value); + for (i = 0; i < nchars; i++) + char_table[i].right_extent = f.get_uint16(); +} + +static +void output_pclweight() +{ + require_tag(stroke_weight_tag); + int stroke_weight = tag_info(stroke_weight_tag).value; + int pcl_stroke_weight; + if (stroke_weight < 128) + pcl_stroke_weight = -3; + else if (stroke_weight == 128) + pcl_stroke_weight = 0; + else if (stroke_weight <= 145) + pcl_stroke_weight = 1; + else if (stroke_weight <= 179) + pcl_stroke_weight = 3; + else + pcl_stroke_weight = 4; + printf("pclweight %d\n", pcl_stroke_weight); +} + +static +void output_pclproportional() +{ + require_tag(spacing_tag); + printf("pclproportional %d\n", tag_info(spacing_tag).value == 0); +} + +static +void read_and_output_pcltypeface(File &f) +{ + printf("pcltypeface "); + require_tag(typeface_tag); + f.seek(tag_info(typeface_tag).value); + for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) { + unsigned char c = f.get_byte(); + if (c == '\0') + break; + putchar(c); + } + printf("\n"); +} + +static +void output_pclstyle() +{ + unsigned pcl_style = 0; + // older tfms don't have the posture tag + if (tag_info(posture_tag).present) { + if (tag_info(posture_tag).value) + pcl_style |= 1; + } + else { + require_tag(slant_tag); + if (tag_info(slant_tag).value != 0) + pcl_style |= 1; + } + require_tag(appearance_width_tag); + if (tag_info(appearance_width_tag).value < 100) // guess + pcl_style |= 4; + printf("pclstyle %d\n", pcl_style); +} + +static +void output_slant() +{ + require_tag(slant_tag); + int slant = int16(tag_info(slant_tag).value); + if (slant != 0) + printf("slant %f\n", slant/100.0); +} + +static +void output_ligatures() +{ + // don't use ligatures for fixed space font + require_tag(spacing_tag); + if (tag_info(spacing_tag).value != 0) + return; + static const char *ligature_names[] = { + "fi", "fl", "ff", "ffi", "ffl" + }; + + static const char *ligature_chars[] = { + "fi", "fl", "ff", "Fi", "Fl" + }; + + unsigned ligature_mask = 0; + int i; + for (i = 0; i < nchars; i++) { + uint16 msl = char_table[i].msl; + if (msl < msl_name_table_size + && char_table[i].symbol_set != NO_SYMBOL_SET) { + for (name_list *p = msl_name_table[msl]; p; p = p->next) + for (int j = 0; j < SIZEOF(ligature_chars); j++) + if (strcmp(p->name, ligature_chars[j]) == 0) { + ligature_mask |= 1 << j; + break; + } + } + } + if (ligature_mask) { + printf("ligatures"); + for (i = 0; i < SIZEOF(ligature_names); i++) + if (ligature_mask & (1 << i)) + printf(" %s", ligature_names[i]); + printf(" 0\n"); + } +} + +static +void read_and_output_kernpairs(File &f) +{ + if (tag_info(pair_kern_tag).present) { + printf("kernpairs\n"); + f.seek(tag_info(pair_kern_tag).value); + uint16 n_pairs = f.get_uint16(); + for (int i = 0; i < n_pairs; i++) { + uint16 i1 = f.get_uint16(); + uint16 i2 = f.get_uint16(); + int16 val = int16(f.get_uint16()); + if (char_table[i1].symbol_set != NO_SYMBOL_SET + && char_table[i2].symbol_set != NO_SYMBOL_SET + && char_table[i1].msl < msl_name_table_size + && char_table[i2].msl < msl_name_table_size) { + for (name_list *p = msl_name_table[char_table[i1].msl]; + p; + p = p->next) + for (name_list *q = msl_name_table[char_table[i2].msl]; + q; + q = q->next) + printf("%s %s %d\n", p->name, q->name, scale(val)); + } + } + } +} + +static +void output_charset() +{ + require_tag(slant_tag); + double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0; + double slant = sin(slant_angle)/cos(slant_angle); + + require_tag(x_height_tag); + require_tag(lower_ascent_tag); + require_tag(lower_descent_tag); + + printf("charset\n"); + int i; + for (i = 0; i < nchars; i++) { + uint16 msl = char_table[i].msl; + if (msl < msl_name_table_size + && msl_name_table[msl]) { + if (char_table[i].symbol_set != NO_SYMBOL_SET) { + printf("%s\t%d,%d", + msl_name_table[msl]->name, + scale(char_table[i].width), + scale(char_table[i].ascent)); + int depth = scale(- char_table[i].descent); + if (depth < 0) + depth = 0; + int italic_correction = 0; + int left_italic_correction = 0; + int subscript_correction = 0; + if (italic_flag) { + italic_correction = scale(char_table[i].right_extent + - char_table[i].width + + italic_sep); + if (italic_correction < 0) + italic_correction = 0; + subscript_correction = int((tag_info(x_height_tag).value + * slant * .8) + .5); + if (subscript_correction > italic_correction) + subscript_correction = italic_correction; + left_italic_correction = scale(italic_sep + - char_table[i].left_extent); + } + if (subscript_correction != 0) + printf(",%d,%d,%d,%d", + depth, italic_correction, left_italic_correction, + subscript_correction); + else if (left_italic_correction != 0) + printf(",%d,%d,%d", depth, italic_correction, left_italic_correction); + else if (italic_correction != 0) + printf(",%d,%d", depth, italic_correction); + else if (depth != 0) + printf(",%d", depth); + // This is fairly arbitrary. Fortunately it doesn't much matter. + unsigned type = 0; + if (char_table[i].ascent > (tag_info(lower_ascent_tag).value*9)/10) + type |= 2; + if (char_table[i].descent < (int16(tag_info(lower_descent_tag).value)*9)/10) + type |= 1; + printf("\t%d\t%d\n", + type, + char_table[i].symbol_set*256 + char_table[i].code); + for (name_list *p = msl_name_table[msl]->next; p; p = p->next) + printf("%s\t\"\n", p->name); + } + else + warning("MSL %1 not in any of the searched symbol sets", msl); + } + } +} + +static +void dump_tags(File &f) +{ + int i; + for (i = min_tag; i <= max_tag; i++) { + enum tag_type t = tag_type(i); + if (tag_info(t).present) { + fprintf(stderr, + "%d %d %d %d\n", i, tag_info(t).type, tag_info(t).count, + tag_info(t).value); + if (tag_info(t).type == FLOAT_TYPE + && tag_info(t).count == 1) { + f.seek(tag_info(t).value); + uint32 num = f.get_uint32(); + uint32 den = f.get_uint32(); + fprintf(stderr, "(%u/%u = %g)\n", num, den, (double)num/den); + } + } + } +} + +static +int read_map(const char *file) +{ + errno = 0; + FILE *fp = fopen(file, "r"); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + current_filename = file; + char buf[512]; + current_lineno = 0; + while (fgets(buf, int(sizeof(buf)), fp)) { + current_lineno++; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr == '\0' || *ptr == '#') + continue; + ptr = strtok(ptr, " \n\t"); + if (!ptr) + continue; + int n; + if (sscanf(ptr, "%d", &n) != 1) { + error("bad map file"); + fclose(fp); + return 0; + } + if (n < 0) { + error("negative code"); + fclose(fp); + return 0; + } + if (n >= msl_name_table_size) { + size_t old_size = msl_name_table_size; + name_list **old_table = msl_name_table; + msl_name_table_size = n + 256; + msl_name_table = new name_list *[msl_name_table_size]; + if (old_table) { + memcpy(msl_name_table, old_table, old_size*sizeof(name_list *)); + a_delete old_table; + } + for (size_t i = old_size; i < msl_name_table_size; i++) + msl_name_table[i] = 0; + } + ptr = strtok(0, " \n\t"); + if (!ptr) { + error("missing names"); + fclose(fp); + return 0; + } + for (; ptr; ptr = strtok(0, " \n\t")) + msl_name_table[n] = new name_list(ptr, msl_name_table[n]); + } + fclose(fp); + return 1; +} + +static +const char *xbasename(const char *s) +{ + // DIR_SEPS[] are possible directory separator characters, see + // nonposix.h. We want the rightmost separator of all possible + // ones. Example: d:/foo\\bar. + const char *b = strrchr(s, DIR_SEPS[0]), *b1; + const char *sep = &DIR_SEPS[1]; + + while (*sep) + { + b1 = strrchr(s, *sep); + if (b1 && (!b || b1 > b)) + b = b1; + sep++; + } + return b ? b + 1 : s; +} diff --git a/contrib/groff/src/utils/hpftodit/hpftodit.man b/contrib/groff/src/utils/hpftodit/hpftodit.man new file mode 100644 index 0000000..d107e8c --- /dev/null +++ b/contrib/groff/src/utils/hpftodit/hpftodit.man @@ -0,0 +1,155 @@ +.ig \"-*- nroff -*- +Copyright (C) 1994-2000 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. +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH HPFTODIT @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +hpftodit \- create font description files for use with groff \-Tlj4 +.SH SYNOPSIS +.B hpftodit +[ +.B \-sv +] +[ +.BI \-i n +] +.I tfm_file +.I map_file +.I font +.PP +It is possible to have whitespace between the +.B \-i +command line option and its parameter. +.SH DESCRIPTION +.B hpftodit +creates a font file for use with +.B +groff \-Tlj4\fR +from an HP tagged font metric file. +.I tfm_file +is the name of the tagged font metric file for the font. +.I map_file +is a file giving the groff names for characters in the font; +this file should consist of a sequence of lines of the form: +.IP +.I +n c1 c2 \fR.\|.\|. +.LP +where +.I n +is a decimal integer giving the MSL number of the character, +and +.IR c1 , +.IR c2 ,.\|.\|. +are the groff names of the character. +.I font +is the name of the groff font file. +The groff font file is written to +.IR font . +.LP +The +.B \-s +option should be given if the font is special +(a font is +.I special +if +.B troff +should search it whenever +a character is not found in the current font.) +If the font is special, +it should be listed in the +.B fonts +command in the DESC file; +if it is not special, there is no need to list it, since +.B troff +can automatically mount it when it's first used. +.LP +If the +.B \-i +option is used, +.B hpftodit +will automatically generate an italic correction, +a left italic correction and a subscript correction +for each character +(the significance of these parameters is explained in +.BR groff_font (@MAN5EXT@)). +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.B \-s +The font is special. +The effect of this option is to add the +.B special +command to the font file. +.TP +.BI \-i n +Generate an italic correction for each character so that +the character's width plus the character's italic correction +is equal to +.I n +design units +plus the amount by which the right edge of the character's bounding +is to the right of the character's origin. +If this would result in a negative italic correction, use a zero +italic correction instead. +There are 8782 design units per em for Intellifont fonts. +.IP +Also generate a subscript correction equal to the +product of the tangent of the slant of the font and +four fifths of the x-height of the font. +If this would result in a subscript correction greater than the italic +correction, use a subscript correction equal to the italic correction +instead. +.IP +Also generate a left italic correction for each character +equal to +.I n +design units +plus the amount by which the left edge of the character's bounding box +is to the left of the character's origin. +The left italic correction may be negative. +.IP +This option is normally needed only with italic (or oblique) fonts. +.SH FILES +.Tp \w'\fB@FONTDIR@/devlj4/DESC'u+2n +.B @FONTDIR@/devlj4/DESC +Device description file. +.TP +.BI @FONTDIR@/devlj4/ F +Font description file for font +.IR F . +.SH BUGS +.LP +This program was written without the benefit of complete, official +documentation on the tagged font metric format. +It is therefore likely that it will fail to work on tfm files that are +dissimilar to those for the internal fonts on the Laserjet 4, +with which it was tested: +.LP +TrueType tfm files are not supported. +.SH "SEE ALSO" +.BR groff (@MAN1EXT@), +.BR grolj4 (@MAN1EXT@), +.BR groff_font (@MAN5EXT@) diff --git a/contrib/groff/src/utils/indxbib/Makefile.sub b/contrib/groff/src/utils/indxbib/Makefile.sub new file mode 100644 index 0000000..add99eb --- /dev/null +++ b/contrib/groff/src/utils/indxbib/Makefile.sub @@ -0,0 +1,31 @@ +PROG=indxbib +MAN1=indxbib.n +XLIBS=$(LIBBIB) $(LIBGROFF) +MLIB=$(LIBM) +OBJS=\ + indxbib.o \ + dirnamemax.o \ + signal.o +CCSRCS=\ + $(srcdir)/indxbib.cc +CSRCS=\ + $(srcdir)/dirnamemax.c \ + $(srcdir)/signal.c +NAMEPREFIX=$(g) + +install_data: eign + -test -d $(datadir) || $(mkinstalldirs) $(datadir) + -test -d $(dataprogramdir) || $(mkinstalldirs) $(dataprogramdir) + -test -d $(datasubdir) || $(mkinstalldirs) $(datasubdir) + if test -f /usr/lib/eign; then \ + rm -f $(common_words_file); \ + ln -s /usr/lib/eign $(common_words_file) 2>/dev/null \ + || ln /usr/lib/eign $(common_words_file) 2>/dev/null \ + || cp /usr/lib/eign $(common_words_file); \ + else \ + rm -f $(common_words_file); \ + $(INSTALL_DATA) $(srcdir)/eign $(common_words_file); \ + fi + +uninstall_sub: + -rm -f $(common_words_file) diff --git a/contrib/groff/src/utils/indxbib/dirnamemax.c b/contrib/groff/src/utils/indxbib/dirnamemax.c new file mode 100644 index 0000000..a8cd992 --- /dev/null +++ b/contrib/groff/src/utils/indxbib/dirnamemax.c @@ -0,0 +1,49 @@ +/* dir_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */ + +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef _POSIX_VERSION + +long dir_name_max(dir) + char *dir; +{ + return pathconf(dir, _PC_NAME_MAX); +} + +#else /* not _POSIX_VERSION */ + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif /* HAVE_LIMITS_H */ + +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#else /* not HAVE_DIRENT_H */ +#ifdef HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif /* HAVE_SYS_DIR_H */ +#endif /* not HAVE_DIRENT_H */ + +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else /* !MAXNAMLEN */ +#ifdef MAXNAMELEN +#define NAME_MAX MAXNAMELEN +#else /* !MAXNAMELEN */ +#define NAME_MAX 14 +#endif /* !MAXNAMELEN */ +#endif /* !MAXNAMLEN */ +#endif /* !NAME_MAX */ + +long dir_name_max(dir) + char *dir; +{ + return NAME_MAX; +} + +#endif /* not _POSIX_VERSION */ diff --git a/contrib/groff/src/utils/indxbib/eign b/contrib/groff/src/utils/indxbib/eign new file mode 100644 index 0000000..7718c8b --- /dev/null +++ b/contrib/groff/src/utils/indxbib/eign @@ -0,0 +1,133 @@ +a +i +the +to +of +and +in +is +it +for +that +if +you +this +be +on +with +not +have +are +or +as +from +can +but +by +at +an +will +no +all +was +do +there +my +one +so +we +they +what +would +any +which +about +get +your +use +some +me +then +name +like +out +when +up +time +other +more +only +just +end +also +know +how +new +should +been +than +them +he +who +make +may +people +these +now +their +here +into +first +could +way +had +see +work +well +were +two +very +where +while +us +because +good +same +even +much +most +many +such +long +his +over +last +since +right +before +our +without +too +those +why +must +part +being +current +back +still +go +point +value +each +did +both +true +off +say +another +state +might +under +start +try diff --git a/contrib/groff/src/utils/indxbib/indxbib.cc b/contrib/groff/src/utils/indxbib/indxbib.cc new file mode 100644 index 0000000..99a6baf --- /dev/null +++ b/contrib/groff/src/utils/indxbib/indxbib.cc @@ -0,0 +1,805 @@ +// -*- C++ -*- +/* Copyright (C) 1989-1992, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "cset.h" +#include "cmap.h" + +#include "defs.h" +#include "index.h" + +#include "nonposix.h" + +extern "C" { + // Solaris 2.5.1 has these functions, + // but its stdlib.h fails to declare them. + char *mktemp(char *); + int mkstemp(char *); +} + +#define DEFAULT_HASH_TABLE_SIZE 997 +#define TEMP_INDEX_TEMPLATE "indxbibXXXXXX" + +// (2^n - MALLOC_OVERHEAD) should be a good argument for malloc(). + +#define MALLOC_OVERHEAD 16 + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +const int BLOCK_SIZE = ((1024 - MALLOC_OVERHEAD - sizeof(struct block *) + - sizeof(int)) / sizeof(int)); +struct block { + block *next; + int used; + int v[BLOCK_SIZE]; + + block(block *p = 0) : next(p), used(0) { } +}; + +struct block; + +union table_entry { + block *ptr; + int count; +}; + +struct word_list { + word_list *next; + char *str; + int len; + word_list(const char *, int, word_list *); +}; + +table_entry *hash_table; +int hash_table_size = DEFAULT_HASH_TABLE_SIZE; +// We make this the same size as hash_table so we only have to do one +// mod per key. +static word_list **common_words_table = 0; +char *key_buffer; + +FILE *indxfp; +int ntags = 0; +string filenames; +char *temp_index_file = 0; + +const char *ignore_fields = "XYZ"; +const char *common_words_file = COMMON_WORDS_FILE; +int n_ignore_words = 100; +int truncate_len = 6; +int shortest_len = 3; +int max_keys_per_item = 100; + +static void usage(FILE *stream); +static void write_hash_table(); +static void init_hash_table(); +static void read_common_words_file(); +static int store_key(char *s, int len); +static void possibly_store_key(char *s, int len); +static int do_whole_file(const char *filename); +static int do_file(const char *filename); +static void store_reference(int filename_index, int pos, int len); +static void check_integer_arg(char opt, const char *arg, int min, int *res); +static void store_filename(const char *); +static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp); +static char *get_cwd(); + +extern "C" { + void cleanup(); + long dir_name_max(const char *); + void catch_fatal_signals(); + void ignore_fatal_signals(); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + + const char *basename = 0; + typedef int (*parser_t)(const char *); + parser_t parser = do_file; + const char *directory = 0; + const char *foption = 0; + int opt; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((opt = getopt_long(argc, argv, "c:o:h:i:k:l:t:n:c:d:f:vw", + long_options, NULL)) + != EOF) + switch (opt) { + case 'c': + common_words_file = optarg; + break; + case 'd': + directory = optarg; + break; + case 'f': + foption = optarg; + break; + case 'h': + check_integer_arg('h', optarg, 1, &hash_table_size); + if (!is_prime(hash_table_size)) { + while (!is_prime(++hash_table_size)) + ; + warning("%1 not prime: using %2 instead", optarg, hash_table_size); + } + break; + case 'i': + ignore_fields = optarg; + break; + case 'k': + check_integer_arg('k', optarg, 1, &max_keys_per_item); + break; + case 'l': + check_integer_arg('l', optarg, 0, &shortest_len); + break; + case 'n': + check_integer_arg('n', optarg, 0, &n_ignore_words); + break; + case 'o': + basename = optarg; + break; + case 't': + check_integer_arg('t', optarg, 1, &truncate_len); + break; + case 'w': + parser = do_whole_file; + break; + case 'v': + { + extern const char *Version_string; + printf("GNU indxbib (groff) version %s\n", Version_string); + exit(0); + break; + } + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + default: + assert(0); + break; + } + if (optind >= argc && foption == 0) + fatal("no files and no -f option"); + if (!directory) { + char *path = get_cwd(); + store_filename(path); + a_delete path; + } + else + store_filename(directory); + init_hash_table(); + store_filename(common_words_file); + store_filename(ignore_fields); + key_buffer = new char[truncate_len]; + read_common_words_file(); + if (!basename) + basename = optind < argc ? argv[optind] : DEFAULT_INDEX_NAME; + const char *p = strrchr(basename, DIR_SEPS[0]), *p1; + const char *sep = &DIR_SEPS[1]; + while (*sep) + { + p1 = strrchr(basename, *sep); + if (p1 && (!p || p1 > p)) + p = p1; + sep++; + } + long name_max; + if (p) { + char *dir = strsave(basename); + dir[p - basename] = '\0'; + name_max = dir_name_max(dir); + a_delete dir; + } + else + name_max = dir_name_max("."); + const char *filename = p ? p + 1 : basename; + if (name_max >= 0 && strlen(filename) + sizeof(INDEX_SUFFIX) - 1 > name_max) + fatal("`%1.%2' is too long for a filename", filename, INDEX_SUFFIX); + if (p) { + p++; + temp_index_file = new char[p - basename + sizeof(TEMP_INDEX_TEMPLATE)]; + memcpy(temp_index_file, basename, p - basename); + strcpy(temp_index_file + (p - basename), TEMP_INDEX_TEMPLATE); + } + else { + temp_index_file = strsave(TEMP_INDEX_TEMPLATE); + } +#ifndef HAVE_MKSTEMP + if (!mktemp(temp_index_file) || !temp_index_file[0]) + fatal("cannot create file name for temporary file"); +#endif + catch_fatal_signals(); +#ifdef HAVE_MKSTEMP + int fd = mkstemp(temp_index_file); +#else + int fd = creat(temp_index_file, S_IRUSR|S_IRGRP|S_IROTH); +#endif + if (fd < 0) + fatal("can't create temporary index file: %1", strerror(errno)); + indxfp = fdopen(fd, FOPEN_WB); + if (indxfp == 0) + fatal("fdopen failed"); + if (fseek(indxfp, sizeof(index_header), 0) < 0) + fatal("can't seek past index header: %1", strerror(errno)); + int failed = 0; + if (foption) { + FILE *fp = stdin; + if (strcmp(foption, "-") != 0) { + errno = 0; + fp = fopen(foption, "r"); + if (!fp) + fatal("can't open `%1': %2", foption, strerror(errno)); + } + string path; + int lineno = 1; + for (;;) { + int c; + for (c = getc(fp); c != '\n' && c != EOF; c = getc(fp)) { + if (c == '\0') + error_with_file_and_line(foption, lineno, + "nul character in pathname ignored"); + else + path += c; + } + if (path.length() > 0) { + path += '\0'; + if (!(*parser)(path.contents())) + failed = 1; + path.clear(); + } + if (c == EOF) + break; + lineno++; + } + if (fp != stdin) + fclose(fp); + } + for (int i = optind; i < argc; i++) + if (!(*parser)(argv[i])) + failed = 1; + write_hash_table(); + if (fclose(indxfp) < 0) + fatal("error closing temporary index file: %1", strerror(errno)); + char *index_file = new char[strlen(basename) + sizeof(INDEX_SUFFIX)]; + strcpy(index_file, basename); + strcat(index_file, INDEX_SUFFIX); +#ifdef HAVE_RENAME + if (rename(temp_index_file, index_file) < 0) + { +#ifdef __MSDOS__ + // RENAME could fail on plain MSDOS filesystems because + // INDEX_FILE is an invalid filename, e.g. it has multiple dots. + char *fname = p ? index_file + (p - basename) : 0; + char *dot = 0; + + // Replace the dot with an underscore and try again. + if (fname + && (dot = strchr(fname, '.')) != 0 + && strcmp(dot, INDEX_SUFFIX) != 0) + *dot = '_'; + if (rename(temp_index_file, index_file) < 0) +#endif + fatal("can't rename temporary index file: %1", strerror(errno)); + } +#else /* not HAVE_RENAME */ + ignore_fatal_signals(); + if (unlink(index_file) < 0) { + if (errno != ENOENT) + fatal("can't unlink `%1': %2", index_file, strerror(errno)); + } + if (link(temp_index_file, index_file) < 0) + fatal("can't link temporary index file: %1", strerror(errno)); + if (unlink(temp_index_file) < 0) + fatal("can't unlink temporary index file: %1", strerror(errno)); +#endif /* not HAVE_RENAME */ + temp_index_file = 0; + return failed; +} + +static void usage(FILE *stream) +{ + fprintf(stream, +"usage: %s [-vw] [-c file] [-d dir] [-f file] [-h n] [-i XYZ] [-k n]\n" +" [-l n] [-n n] [-o base] [-t n] [files...]\n", + program_name); +} + +static void check_integer_arg(char opt, const char *arg, int min, int *res) +{ + char *ptr; + long n = strtol(arg, &ptr, 10); + if (n == 0 && ptr == arg) + error("argument to -%1 not an integer", opt); + else if (n < min) + error("argument to -%1 must not be less than %2", opt, min); + else { + if (n > INT_MAX) + error("argument to -%1 greater than maximum integer", opt); + else if (*ptr != '\0') + error("junk after integer argument to -%1", opt); + *res = int(n); + } +} + +static char *get_cwd() +{ + char *buf; + int size = 12; + + for (;;) { + buf = new char[size]; + if (getcwd(buf, size)) + break; + if (errno != ERANGE) + fatal("cannot get current working directory: %1", strerror(errno)); + a_delete buf; + if (size == INT_MAX) + fatal("current working directory longer than INT_MAX"); + if (size > INT_MAX/2) + size = INT_MAX; + else + size *= 2; + } + return buf; +} + +word_list::word_list(const char *s, int n, word_list *p) +: next(p), len(n) +{ + str = new char[n]; + memcpy(str, s, n); +} + +static void read_common_words_file() +{ + if (n_ignore_words <= 0) + return; + errno = 0; + FILE *fp = fopen(common_words_file, "r"); + if (!fp) + fatal("can't open `%1': %2", common_words_file, strerror(errno)); + common_words_table = new word_list * [hash_table_size]; + for (int i = 0; i < hash_table_size; i++) + common_words_table[i] = 0; + int count = 0; + int key_len = 0; + for (;;) { + int c = getc(fp); + while (c != EOF && !csalnum(c)) + c = getc(fp); + if (c == EOF) + break; + do { + if (key_len < truncate_len) + key_buffer[key_len++] = cmlower(c); + c = getc(fp); + } while (c != EOF && csalnum(c)); + if (key_len >= shortest_len) { + int h = hash(key_buffer, key_len) % hash_table_size; + common_words_table[h] = new word_list(key_buffer, key_len, + common_words_table[h]); + } + if (++count >= n_ignore_words) + break; + key_len = 0; + if (c == EOF) + break; + } + n_ignore_words = count; + fclose(fp); +} + +static int do_whole_file(const char *filename) +{ + errno = 0; + FILE *fp = fopen(filename, "r"); + if (!fp) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + int count = 0; + int key_len = 0; + int c; + while ((c = getc(fp)) != EOF) { + if (csalnum(c)) { + key_len = 1; + key_buffer[0] = c; + while ((c = getc(fp)) != EOF) { + if (!csalnum(c)) + break; + if (key_len < truncate_len) + key_buffer[key_len++] = c; + } + if (store_key(key_buffer, key_len)) { + if (++count >= max_keys_per_item) + break; + } + if (c == EOF) + break; + } + } + store_reference(filenames.length(), 0, 0); + store_filename(filename); + fclose(fp); + return 1; +} + +static int do_file(const char *filename) +{ + errno = 0; + // Need binary I/O for MS-DOS/MS-Windows, because indxbib relies on + // byte counts to be consistent with fseek. + FILE *fp = fopen(filename, FOPEN_RB); + if (fp == 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + int filename_index = filenames.length(); + store_filename(filename); + + enum { + START, // at the start of the file; also in between references + BOL, // in the middle of a reference, at the beginning of the line + PERCENT, // seen a percent at the beginning of the line + IGNORE, // ignoring a field + IGNORE_BOL, // at the beginning of a line ignoring a field + KEY, // in the middle of a key + DISCARD, // after truncate_len bytes of a key + MIDDLE // in between keys + } state = START; + + // In states START, BOL, IGNORE_BOL, space_count how many spaces at + // the beginning have been seen. In states PERCENT, IGNORE, KEY, + // MIDDLE space_count must be 0. + int space_count = 0; + int byte_count = 0; // bytes read + int key_len = 0; + int ref_start = -1; // position of start of current reference + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + // We opened the file in binary mode, so we need to skip + // every CR character before a Newline. + if (c == '\r') { + int peek = getc(fp); + if (peek = '\n') { + byte_count++; + c = peek; + } + else + ungetc(peek, fp); + } +#if defined(__MSDOS__) || defined(_MSC_VER) + else if (c == 0x1a) // ^Z means EOF in text files + break; +#endif + byte_count++; + switch (state) { + case START: + if (c == ' ' || c == '\t') { + space_count++; + break; + } + if (c == '\n') { + space_count = 0; + break; + } + ref_start = byte_count - space_count - 1; + space_count = 0; + if (c == '%') + state = PERCENT; + else if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else + state = MIDDLE; + break; + case BOL: + switch (c) { + case '%': + if (space_count > 0) { + space_count = 0; + state = MIDDLE; + } + else + state = PERCENT; + break; + case ' ': + case '\t': + space_count++; + break; + case '\n': + store_reference(filename_index, ref_start, + byte_count - 1 - space_count - ref_start); + state = START; + space_count = 0; + break; + default: + space_count = 0; + if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else + state = MIDDLE; + } + break; + case PERCENT: + if (strchr(ignore_fields, c) != 0) + state = IGNORE; + else if (c == '\n') + state = BOL; + else + state = MIDDLE; + break; + case IGNORE: + if (c == '\n') + state = IGNORE_BOL; + break; + case IGNORE_BOL: + switch (c) { + case '%': + if (space_count > 0) { + state = IGNORE; + space_count = 0; + } + else + state = PERCENT; + break; + case ' ': + case '\t': + space_count++; + break; + case '\n': + store_reference(filename_index, ref_start, + byte_count - 1 - space_count - ref_start); + state = START; + space_count = 0; + break; + default: + space_count = 0; + state = IGNORE; + } + break; + case KEY: + if (csalnum(c)) { + if (key_len < truncate_len) + key_buffer[key_len++] = c; + else + state = DISCARD; + } + else { + possibly_store_key(key_buffer, key_len); + key_len = 0; + if (c == '\n') + state = BOL; + else + state = MIDDLE; + } + break; + case DISCARD: + if (!csalnum(c)) { + possibly_store_key(key_buffer, key_len); + key_len = 0; + if (c == '\n') + state = BOL; + else + state = MIDDLE; + } + break; + case MIDDLE: + if (csalnum(c)) { + state = KEY; + key_buffer[0] = c; + key_len = 1; + } + else if (c == '\n') + state = BOL; + break; + default: + assert(0); + } + } + switch (state) { + case START: + break; + case DISCARD: + case KEY: + possibly_store_key(key_buffer, key_len); + // fall through + case BOL: + case PERCENT: + case IGNORE_BOL: + case IGNORE: + case MIDDLE: + store_reference(filename_index, ref_start, + byte_count - ref_start - space_count); + break; + default: + assert(0); + } + fclose(fp); + return 1; +} + +static void store_reference(int filename_index, int pos, int len) +{ + tag t; + t.filename_index = filename_index; + t.start = pos; + t.length = len; + fwrite_or_die(&t, sizeof(t), 1, indxfp); + ntags++; +} + +static void store_filename(const char *fn) +{ + filenames += fn; + filenames += '\0'; +} + +static void init_hash_table() +{ + hash_table = new table_entry[hash_table_size]; + for (int i = 0; i < hash_table_size; i++) + hash_table[i].ptr = 0; +} + +static void possibly_store_key(char *s, int len) +{ + static int last_tagno = -1; + static int key_count; + if (last_tagno != ntags) { + last_tagno = ntags; + key_count = 0; + } + if (key_count < max_keys_per_item) { + if (store_key(s, len)) + key_count++; + } +} + +static int store_key(char *s, int len) +{ + if (len < shortest_len) + return 0; + int is_number = 1; + for (int i = 0; i < len; i++) + if (!csdigit(s[i])) { + is_number = 0; + s[i] = cmlower(s[i]); + } + if (is_number && !(len == 4 && s[0] == '1' && s[1] == '9')) + return 0; + int h = hash(s, len) % hash_table_size; + if (common_words_table) { + for (word_list *ptr = common_words_table[h]; ptr; ptr = ptr->next) + if (len == ptr->len && memcmp(s, ptr->str, len) == 0) + return 0; + } + table_entry *pp = hash_table + h; + if (!pp->ptr) + pp->ptr = new block; + else if (pp->ptr->v[pp->ptr->used - 1] == ntags) + return 1; + else if (pp->ptr->used >= BLOCK_SIZE) + pp->ptr = new block(pp->ptr); + pp->ptr->v[(pp->ptr->used)++] = ntags; + return 1; +} + +static void write_hash_table() +{ + const int minus_one = -1; + int li = 0; + for (int i = 0; i < hash_table_size; i++) { + block *ptr = hash_table[i].ptr; + if (!ptr) + hash_table[i].count = -1; + else { + hash_table[i].count = li; + block *rev = 0; + while (ptr) { + block *tem = ptr; + ptr = ptr->next; + tem->next = rev; + rev = tem; + } + while (rev) { + fwrite_or_die(rev->v, sizeof(int), rev->used, indxfp); + li += rev->used; + block *tem = rev; + rev = rev->next; + delete tem; + } + fwrite_or_die(&minus_one, sizeof(int), 1, indxfp); + li += 1; + } + } + if (sizeof(table_entry) == sizeof(int)) + fwrite_or_die(hash_table, sizeof(int), hash_table_size, indxfp); + else { + // write it out word by word + for (int i = 0; i < hash_table_size; i++) + fwrite_or_die(&hash_table[i].count, sizeof(int), 1, indxfp); + } + fwrite_or_die(filenames.contents(), 1, filenames.length(), indxfp); + if (fseek(indxfp, 0, 0) < 0) + fatal("error seeking on index file: %1", strerror(errno)); + index_header h; + h.magic = INDEX_MAGIC; + h.version = INDEX_VERSION; + h.tags_size = ntags; + h.lists_size = li; + h.table_size = hash_table_size; + h.strings_size = filenames.length(); + h.truncate = truncate_len; + h.shortest = shortest_len; + h.common = n_ignore_words; + fwrite_or_die(&h, sizeof(h), 1, indxfp); +} + +static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp) +{ + if (fwrite(ptr, size, nitems, fp) != nitems) + fatal("fwrite failed: %1", strerror(errno)); +} + +void fatal_error_exit() +{ + cleanup(); + exit(3); +} + +extern "C" { + +void cleanup() +{ + if (temp_index_file) + unlink(temp_index_file); +} + +} diff --git a/contrib/groff/src/utils/indxbib/indxbib.man b/contrib/groff/src/utils/indxbib/indxbib.man new file mode 100644 index 0000000..ed84cca --- /dev/null +++ b/contrib/groff/src/utils/indxbib/indxbib.man @@ -0,0 +1,207 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.TH @G@INDXBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +@g@indxbib \- make inverted index for bibliographic databases +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fB@g@indxbib 'u +.ti \niu +.B @g@indxbib +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-vw +.OP \-c file +.OP \-d dir +.OP \-f file +.OP \-h n +.OP \-i string +.OP \-k n +.OP \-l n +.OP \-n n +.OP \-o file +.OP \-t n +.RI [\ filename \|.\|.\|.\ ] +.ad \na +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +.B @g@indxbib +makes an inverted index for the bibliographic databases in +.IR filename \|.\|.\|. +for use with +.BR @g@refer (@MAN1EXT@), +.BR @g@lookbib (@MAN1EXT@), +and +.BR lkbib (@MAN1EXT@). +The index will be named +.IB filename @INDEX_SUFFIX@\fR; +the index is written to a temporary file which is then renamed to this. +If no filenames are given on the command line because the +.B \-f +option has been used, and no +.B \-o +option is given, the index will be named +.BR @DEFAULT_INDEX_NAME@@INDEX_SUFFIX@ . +.LP +Bibliographic databases are divided into records by blank lines. +Within a record, each fields starts with a +.B % +character at the beginning of a line. +Fields have a one letter name which follows the +.B % +character. +.LP +The values set by the +.BR \-c , +.BR \-n , +.BR \-l +and +.B \-t +options are stored in the index; +when the index is searched, keys will be discarded and truncated in a +manner appropriate to these options; +the original keys will be used for verifying that any record +found using the index actually contains the keys. +This means that a user of an index need not know whether these +options were used in the creation of the index, +provided that not all the keys to be searched for +would have been discarded during indexing +and that the user supplies at least the part of each key +that would have remained after being truncated during indexing. +The value set by the +.B \-i +option is also stored in the index +and will be used in verifying records found using the index. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.B \-w +Index whole files. +Each file is a separate record. +.TP +.BI \-c file +Read the list of common words from +.I file +instead of +.BR @COMMON_WORDS_FILE@ . +.TP +.BI \-d dir +Use +.I dir +as the pathname of the current working directory to store in the index, +instead of the path printed by +.BR pwd (1). +Usually +.I dir +will be a symbolic link that points to the directory printed by +.BR pwd (1). +.TP +.BI \-f file +Read the files to be indexed from +.IR file . +If +.I file +is +.BR \- , +files will be read from the standard input. +The +.B \-f +option can be given at most once. +.TP +.BI \-i string +Don't index the contents of fields whose names are in +.IR string . +Initially +.I string +is +.BR XYZ . +.TP +.BI \-h n +Use the first prime greater than or equal to +.I n +for the size of the hash table. +Larger values of +.I n +will usually make searching faster, +but will make the index larger +and +.B @g@indxbib +use more memory. +Initially +.I n +is 997. +.TP +.BI \-k n +Use at most +.I n +keys per input record. +Initially +.I n +is 100. +.TP +.BI \-l n +Discard keys that are shorter than +.IR n . +Initially +.I n +is 3. +.TP +.BI \-n n +Discard the +.I n +most common words. +Initially +.I n +is 100. +.TP +.BI \-o basename +The index should be named +.IB basename @INDEX_SUFFIX@\fR. +.TP +.BI \-t n +Truncate keys to +.IR n . +Initially +.I n +is 6. +.SH FILES +.TP \w'\fBindxbib\fIXXXXXX'u+2n +.IB filename @INDEX_SUFFIX@ +Index. +.TP +.B @DEFAULT_INDEX_NAME@@INDEX_SUFFIX@ +Default index name. +.TP +.B @COMMON_WORDS_FILE@ +List of common words. +.TP +.BI indxbib XXXXXX +Temporary file. +.SH "SEE ALSO" +.BR @g@refer (@MAN1EXT@), +.BR lkbib (@MAN1EXT@), +.BR @g@lookbib (@MAN1EXT@) diff --git a/contrib/groff/src/utils/indxbib/signal.c b/contrib/groff/src/utils/indxbib/signal.c new file mode 100644 index 0000000..8078472 --- /dev/null +++ b/contrib/groff/src/utils/indxbib/signal.c @@ -0,0 +1,63 @@ +/* Copyright (C) 1992 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Unfortunately vendors seem to have problems writing a <signal.h> +that is correct for C++, so we implement all signal handling in C. */ + +#include <sys/types.h> +#include <signal.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + +extern void cleanup(); + +static RETSIGTYPE handle_fatal_signal(signum) + int signum; +{ + signal(signum, SIG_DFL); + cleanup(); + kill(getpid(), signum); +} + +void catch_fatal_signals() +{ +#ifdef SIGHUP + signal(SIGHUP, handle_fatal_signal); +#endif + signal(SIGINT, handle_fatal_signal); + signal(SIGTERM, handle_fatal_signal); +} + +#ifndef HAVE_RENAME + +void ignore_fatal_signals() +{ +#ifdef SIGHUP + signal(SIGHUP, SIG_IGN); +#endif + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); +} + +#endif /* not HAVE_RENAME */ diff --git a/contrib/groff/src/utils/lkbib/Makefile.sub b/contrib/groff/src/utils/lkbib/Makefile.sub new file mode 100644 index 0000000..8f31e10 --- /dev/null +++ b/contrib/groff/src/utils/lkbib/Makefile.sub @@ -0,0 +1,6 @@ +PROG=lkbib +MAN1=lkbib.n +XLIBS=$(LIBBIB) $(LIBGROFF) +MLIB=$(LIBM) +OBJS=lkbib.o +CCSRCS=$(srcdir)/lkbib.cc diff --git a/contrib/groff/src/utils/lkbib/lkbib.cc b/contrib/groff/src/utils/lkbib/lkbib.cc new file mode 100644 index 0000000..4d3cadc --- /dev/null +++ b/contrib/groff/src/utils/lkbib/lkbib.cc @@ -0,0 +1,137 @@ +// -*- C++ -*- +/* Copyright (C) 1989-1992, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <assert.h> + +#include "lib.h" +#include "errarg.h" +#include "error.h" + +#include "defs.h" +#include "refid.h" +#include "search.h" + +static void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-nv] [-p database] [-i XYZ] [-t N] keys ...\n", + program_name); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int search_default = 1; + search_list list; + int opt; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((opt = getopt_long(argc, argv, "nvVi:t:p:", long_options, NULL)) + != EOF) + switch (opt) { + case 'V': + verify_flag = 1; + break; + case 'n': + search_default = 0; + break; + case 'i': + linear_ignore_fields = optarg; + break; + case 't': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if (n == 0 && ptr == optarg) { + error("bad integer `%1' in `t' option", optarg); + break; + } + if (n < 1) + n = 1; + linear_truncate_len = int(n); + break; + } + case 'v': + { + extern const char *Version_string; + printf("GNU lkbib (groff) version %s\n", Version_string); + exit(0); + break; + } + case 'p': + list.add_file(optarg); + break; + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + default: + assert(0); + } + if (optind >= argc) { + usage(stderr); + exit(1); + } + char *filename = getenv("REFER"); + if (filename) + list.add_file(filename); + else if (search_default) + list.add_file(DEFAULT_INDEX, 1); + if (list.nfiles() == 0) + fatal("no databases"); + int total_len = 0; + int i; + for (i = optind; i < argc; i++) + total_len += strlen(argv[i]); + total_len += argc - optind - 1 + 1; // for spaces and '\0' + char *buffer = new char[total_len]; + char *ptr = buffer; + for (i = optind; i < argc; i++) { + if (i > optind) + *ptr++ = ' '; + strcpy(ptr, argv[i]); + ptr = strchr(ptr, '\0'); + } + search_list_iterator iter(&list, buffer); + const char *start; + int len; + int count; + for (count = 0; iter.next(&start, &len); count++) { + if (fwrite(start, 1, len, stdout) != len) + fatal("write error on stdout: %1", strerror(errno)); + // Can happen for last reference in file. + if (start[len - 1] != '\n') + putchar('\n'); + putchar('\n'); + } + return !count; +} diff --git a/contrib/groff/src/utils/lkbib/lkbib.man b/contrib/groff/src/utils/lkbib/lkbib.man new file mode 100644 index 0000000..872313d --- /dev/null +++ b/contrib/groff/src/utils/lkbib/lkbib.man @@ -0,0 +1,110 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.ds g \" empty +.ds G \" empty +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH LKBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +lkbib \- search bibliographic databases +.SH SYNOPSIS +.B lkbib +[ +.B \-v +] +[ +.BI \-i fields +] +[ +.BI \-p filename +] +[ +.BI \-t n +] +.IR key \|.\|.\|. +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +.B lkbib +searches bibliographic databases for references that contain the keys +.IR key \|.\|.\|. +and prints any references found on the standard output. +.B lkbib +will search any databases given by +.B \-p +options, and then a default database. +The default database is taken from the +.SB REFER +environment variable if it is set, +otherwise it is +.BR @DEFAULT_INDEX@ . +For each database +.I filename +to be searched, +if an index +.IB filename @INDEX_SUFFIX@ +created by +.BR @g@indxbib (@MAN1EXT@) +exists, then it will be searched instead; +each index can cover multiple databases. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.BI \-p filename +Search +.IR filename . +Multiple +.B \-p +options can be used. +.TP +.BI \-i string +When searching files for which no index exists, +ignore the contents of fields whose names are in +.IR string . +.TP +.BI \-t n +Only require the first +.I n +characters of keys to be given. +Initially +.I n +is 6. +.SH ENVIRONMENT +.TP \w'\fBREFER'u+2n +.SB REFER +Default database. +.SH FILES +.Tp \w'\fB@DEFAULT_INDEX@'u+2n +.B @DEFAULT_INDEX@ +Default database to be used if the +.SB REFER +environment variable is not set. +.IB filename @INDEX_SUFFIX@ +Index files. +.SH "SEE ALSO" +.BR @g@refer (@MAN1EXT@), +.BR @g@lookbib (@MAN1EXT@), +.BR @g@indxbib (@MAN1EXT@) diff --git a/contrib/groff/src/utils/lookbib/Makefile.sub b/contrib/groff/src/utils/lookbib/Makefile.sub new file mode 100644 index 0000000..91b1404 --- /dev/null +++ b/contrib/groff/src/utils/lookbib/Makefile.sub @@ -0,0 +1,7 @@ +PROG=lookbib +MAN1=lookbib.n +XLIBS=$(LIBBIB) $(LIBGROFF) +MLIB=$(LIBM) +OBJS=lookbib.o +CCSRCS=$(srcdir)/lookbib.cc +NAMEPREFIX=$(g) diff --git a/contrib/groff/src/utils/lookbib/lookbib.cc b/contrib/groff/src/utils/lookbib/lookbib.cc new file mode 100644 index 0000000..dc55ed9 --- /dev/null +++ b/contrib/groff/src/utils/lookbib/lookbib.cc @@ -0,0 +1,140 @@ +// -*- C++ -*- +/* Copyright (C) 1989-1992, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "errarg.h" +#include "error.h" +#include "lib.h" +#include "cset.h" + +#include "refid.h" +#include "search.h" + +extern "C" { + int isatty(int); +} + +static void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-v] [-i XYZ] [-t N] database ...\n", + program_name); +} + +int main(int argc, char **argv) +{ + program_name = argv[0]; + static char stderr_buf[BUFSIZ]; + setbuf(stderr, stderr_buf); + int opt; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((opt = getopt_long(argc, argv, "vVi:t:", long_options, NULL)) != EOF) + switch (opt) { + case 'V': + verify_flag = 1; + break; + case 'i': + linear_ignore_fields = optarg; + break; + case 't': + { + char *ptr; + long n = strtol(optarg, &ptr, 10); + if (n == 0 && ptr == optarg) { + error("bad integer `%1' in `t' option", optarg); + break; + } + if (n < 1) + n = 1; + linear_truncate_len = int(n); + break; + } + case 'v': + { + extern const char *Version_string; + printf("GNU lookbib (groff) version %s\n", Version_string); + exit(0); + break; + } + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + default: + assert(0); + } + if (optind >= argc) { + usage(stderr); + exit(1); + } + search_list list; + for (int i = optind; i < argc; i++) + list.add_file(argv[i]); + if (list.nfiles() == 0) + fatal("no databases"); + char line[1024]; + int interactive = isatty(fileno(stdin)); + for (;;) { + if (interactive) { + fputs("> ", stderr); + fflush(stderr); + } + if (!fgets(line, sizeof(line), stdin)) + break; + char *ptr = line; + while (csspace(*ptr)) + ptr++; + if (*ptr == '\0') + continue; + search_list_iterator iter(&list, line); + const char *start; + int len; + int count; + for (count = 0; iter.next(&start, &len); count++) { + if (fwrite(start, 1, len, stdout) != len) + fatal("write error on stdout: %1", strerror(errno)); + // Can happen for last reference in file. + if (start[len - 1] != '\n') + putchar('\n'); + putchar('\n'); + } + fflush(stdout); + if (interactive) { + fprintf(stderr, "%d found\n", count); + fflush(stderr); + } + } + if (interactive) + putc('\n', stderr); + return 0; +} + diff --git a/contrib/groff/src/utils/lookbib/lookbib.man b/contrib/groff/src/utils/lookbib/lookbib.man new file mode 100644 index 0000000..846798d --- /dev/null +++ b/contrib/groff/src/utils/lookbib/lookbib.man @@ -0,0 +1,78 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.TH @G@LOOKBIB @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +@g@lookbib \- search bibliographic databases +.SH SYNOPSIS +.B @g@lookbib +[ +.B \-v +] +[ +.BI \-i string +] +[ +.BI \-t n +] +.IR filename \|.\|.\|. +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +@g@lookbib prints a prompt on the standard error (unless the standard input is not a terminal), +reads from the standard input a line containing a set of keywords, +searches the bibliographic databases +.IR filename \|.\|.\|. +for references containing those keywords, +prints any references found on the standard output, +and repeats this process until the end of input. +For each database +.I filename +to be searched, +if an index +.IB filename @INDEX_SUFFIX@ +created by +.BR @g@indxbib (@MAN1EXT@) +exists, then it will be searched instead; +each index can cover multiple databases. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.BI \-i string +When searching files for which no index exists, +ignore the contents of fields whose names are in +.IR string . +.TP +.BI \-t n +Only require the first +.I n +characters of keys to be given. +Initially +.I n +is 6. +.SH FILES +.TP \w'\fIfilename\fB@INDEX_SUFFIX@'u+2n +.IB filename @INDEX_SUFFIX@ +Index files. +.SH "SEE ALSO" +.BR @g@refer (@MAN1EXT@), +.BR lkbib (@MAN1EXT@), +.BR @g@indxbib (@MAN1EXT@) diff --git a/contrib/groff/src/utils/pfbtops/Makefile.sub b/contrib/groff/src/utils/pfbtops/Makefile.sub new file mode 100644 index 0000000..f731ff5 --- /dev/null +++ b/contrib/groff/src/utils/pfbtops/Makefile.sub @@ -0,0 +1,6 @@ +PROG=pfbtops +MAN1=pfbtops.n +OBJS=pfbtops.o +CSRCS=$(srcdir)/pfbtops.c +XLIBS=$(LIBGROFF) +MLIB=$(LIBM) diff --git a/contrib/groff/src/utils/pfbtops/pfbtops.c b/contrib/groff/src/utils/pfbtops/pfbtops.c new file mode 100644 index 0000000..2159dbd --- /dev/null +++ b/contrib/groff/src/utils/pfbtops/pfbtops.c @@ -0,0 +1,131 @@ +/* This translates ps fonts in .pfb format to ASCII ps files. */ + +#include <stdio.h> +#include <getopt.h> +#include <limits.h> + +#include "nonposix.h" + +/* Binary bytes per output line. */ +#define BYTES_PER_LINE (64/2) +#define HEX_DIGITS "0123456789abcdef" + +static char *program_name; + +static void error(s) + char *s; +{ + fprintf(stderr, "%s: %s\n", program_name, s); + exit(2); +} + +static void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-v] [pfb_file]\n", program_name); +} + +int main(argc, argv) + int argc; + char **argv; +{ + int opt; + extern int optind; + 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, "v", long_options, NULL)) != EOF) { + switch (opt) { + case 'v': + { + extern char *Version_string; + printf("GNU pfbtops (groff) version %s\n", Version_string); + exit(0); + break; + } + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + } + } + + if (argc - optind > 1) { + usage(stderr); + exit(1); + } + if (argc > optind && !freopen(argv[optind], "r", stdin)) + { + perror(argv[optind]); + exit(1); + } +#ifdef SET_BINARY + SET_BINARY(fileno(stdin)); +#endif + for (;;) + { + int type, c, i; + long n; + + c = getchar(); + if (c != 0x80) + error("first byte of packet not 0x80"); + type = getchar(); + if (type == 3) + break; + if (type != 1 && type != 2) + error("bad packet type"); + n = 0; + for (i = 0; i < 4; i++) + { + c = getchar(); + if (c == EOF) + error("end of file in packet header"); + n |= (long)c << (i << 3); + } + if (n < 0) + error("negative packet length"); + if (type == 1) + { + while (--n >= 0) + { + c = getchar(); + if (c == EOF) + error("end of file in text packet"); + if (c == '\r') + c = '\n'; + putchar(c); + } + if (c != '\n') + putchar('\n'); + } + else + { + int count = 0; + while (--n >= 0) + { + c = getchar(); + if (c == EOF) + error("end of file in binary packet"); + if (count >= BYTES_PER_LINE) + { + putchar('\n'); + count = 0; + } + count++; + putchar(HEX_DIGITS[(c >> 4) & 0xf]); + putchar(HEX_DIGITS[c & 0xf]); + } + putchar('\n'); + } + } + exit(0); +} diff --git a/contrib/groff/src/utils/pfbtops/pfbtops.man b/contrib/groff/src/utils/pfbtops/pfbtops.man new file mode 100644 index 0000000..cfef3e0 --- /dev/null +++ b/contrib/groff/src/utils/pfbtops/pfbtops.man @@ -0,0 +1,44 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-1995 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. +.. +.TH PFBTOPS @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +pfbtops \- translate a PostScript font in .pfb format to ASCII +.SH SYNOPSIS +.B pfbtops +[ +.I pfb_file +] +.SH DESCRIPTION +.B pfbtops +translates a PostScript font in +.B .pfb +format to ASCII. +If +.I pfb_file +is omitted the pfb file will be read from the standard input. +The ASCII format PostScript font will be written on the standard output. +PostScript fonts for MS-DOS are normally supplied in +.B .pfb +format. +.LP +The resulting ASCII format PostScript font can be used with groff. +It must first be listed in +.BR @FONTDIR@/devps/download . +.SH "SEE ALSO" +.BR grops (@MAN1EXT@) diff --git a/contrib/groff/src/utils/tfmtodit/Makefile.sub b/contrib/groff/src/utils/tfmtodit/Makefile.sub new file mode 100644 index 0000000..057bb3e --- /dev/null +++ b/contrib/groff/src/utils/tfmtodit/Makefile.sub @@ -0,0 +1,6 @@ +PROG=tfmtodit +MAN1=tfmtodit.n +XLIBS=$(LIBGROFF) +MLIB=$(LIBM) +OBJS=tfmtodit.o +CCSRCS=$(srcdir)/tfmtodit.cc diff --git a/contrib/groff/src/utils/tfmtodit/tfmtodit.cc b/contrib/groff/src/utils/tfmtodit/tfmtodit.cc new file mode 100644 index 0000000..96768d2 --- /dev/null +++ b/contrib/groff/src/utils/tfmtodit/tfmtodit.cc @@ -0,0 +1,874 @@ +// -*- C++ -*- +/* Copyright (C) 1989-1992, 2000, 2001 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* I have tried to incorporate the changes needed for TeX 3.0 tfm files, +but I haven't tested them. */ + +/* Groff requires more font metric information than TeX. The reason +for this is that TeX has separate Math Italic fonts, whereas groff +uses normal italic fonts for math. The two additional pieces of +information required by groff correspond to the two arguments to the +math_fit() macro in the Metafont programs for the CM fonts. In the +case of a font for which math_fitting is false, these two arguments +are normally ignored by Metafont. We need to get hold of these two +parameters and put them in the groff font file. + +We do this by loading this definition after cmbase when creating cm.base. + +def ignore_math_fit(expr left_adjustment,right_adjustment) = + special "adjustment"; + numspecial left_adjustment*16/designsize; + numspecial right_adjustment*16/designsize; + enddef; + +This puts the two arguments to the math_fit macro into the gf file. +(They will appear in the gf file immediately before the character to +which they apply.) We then create a gf file using this cm.base. Then +we run tfmtodit and specify this gf file with the -g option. + +This need only be done for a font for which math_fitting is false; +When it's true, the left_correction and subscript_correction should +both be zero. */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <errno.h> +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "assert.h" +#include "cset.h" +#include "nonposix.h" + +/* Values in the tfm file should be multiplied by this. */ + +#define MULTIPLIER 1 + +struct char_info_word { + unsigned char width_index; + char height_index; + char depth_index; + char italic_index; + char tag; + unsigned char remainder; +}; + +struct lig_kern_command { + unsigned char skip_byte; + unsigned char next_char; + unsigned char op_byte; + unsigned char remainder; +}; + +class tfm { + int bc; + int ec; + int nw; + int nh; + int nd; + int ni; + int nl; + int nk; + int np; + int cs; + int ds; + char_info_word *char_info; + int *width; + int *height; + int *depth; + int *italic; + lig_kern_command *lig_kern; + int *kern; + int *param; +public: + tfm(); + ~tfm(); + int load(const char *); + int contains(int); + int get_width(int); + int get_height(int); + int get_depth(int); + int get_italic(int); + int get_param(int, int *); + int get_checksum(); + int get_design_size(); + int get_lig(unsigned char, unsigned char, unsigned char *); + friend class kern_iterator; +}; + +class kern_iterator { + tfm *t; + int c; + int i; +public: + kern_iterator(tfm *); + int next(unsigned char *c1, unsigned char *c2, int *k); +}; + + +kern_iterator::kern_iterator(tfm *p) +: t(p), c(t->bc), i(-1) +{ +} + +int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k) +{ + for (; c <= t->ec; c++) + if (t->char_info[c - t->bc].tag == 1) { + if (i < 0) { + i = t->char_info[c - t->bc].remainder; + if (t->lig_kern[i].skip_byte > 128) + i = (256*t->lig_kern[i].op_byte + + t->lig_kern[i].remainder); + } + for (;;) { + int skip = t->lig_kern[i].skip_byte; + if (skip <= 128 && t->lig_kern[i].op_byte >= 128) { + *c1 = c; + *c2 = t->lig_kern[i].next_char; + *k = t->kern[256*(t->lig_kern[i].op_byte - 128) + + t->lig_kern[i].remainder]; + if (skip == 128) { + c++; + i = -1; + } + else + i += skip + 1; + return 1; + } + if (skip >= 128) + break; + i += skip + 1; + } + i = -1; + } + return 0; +} + +tfm::tfm() +: char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0), + kern(0), param(0) +{ +} + +int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp) +{ + if (contains(c1) && char_info[c1 - bc].tag == 1) { + int i = char_info[c1 - bc].remainder; + if (lig_kern[i].skip_byte > 128) + i = 256*lig_kern[i].op_byte + lig_kern[i].remainder; + for (;;) { + int skip = lig_kern[i].skip_byte; + if (skip > 128) + break; + // We are only interested in normal ligatures, for which + // op_byte == 0. + if (lig_kern[i].op_byte == 0 + && lig_kern[i].next_char == c2) { + *cp = lig_kern[i].remainder; + return 1; + } + if (skip == 128) + break; + i += skip + 1; + } + } + return 0; +} + +int tfm::contains(int i) +{ + return i >= bc && i <= ec && char_info[i - bc].width_index != 0; +} + +int tfm::get_width(int i) +{ + return width[char_info[i - bc].width_index]; +} + +int tfm::get_height(int i) +{ + return height[char_info[i - bc].height_index]; +} + +int tfm::get_depth(int i) +{ + return depth[char_info[i - bc].depth_index]; +} + +int tfm::get_italic(int i) +{ + return italic[char_info[i - bc].italic_index]; +} + +int tfm::get_param(int i, int *p) +{ + if (i <= 0 || i > np) + return 0; + else { + *p = param[i - 1]; + return 1; + } +} + +int tfm::get_checksum() +{ + return cs; +} + +int tfm::get_design_size() +{ + return ds; +} + +tfm::~tfm() +{ + a_delete char_info; + a_delete width; + a_delete height; + a_delete depth; + a_delete italic; + a_delete lig_kern; + a_delete kern; + a_delete param; +} + +int read2(unsigned char *&s) +{ + int n; + n = *s++ << 8; + n |= *s++; + return n; +} + +int read4(unsigned char *&s) +{ + int n; + n = *s++ << 24; + n |= *s++ << 16; + n |= *s++ << 8; + n |= *s++; + return n; +} + + +int tfm::load(const char *file) +{ + errno = 0; + FILE *fp = fopen(file, FOPEN_RB); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + int c1 = getc(fp); + int c2 = getc(fp); + if (c1 == EOF || c2 == EOF) { + fclose(fp); + error("unexpected end of file on `%1'", file); + return 0; + } + int lf = (c1 << 8) + c2; + int toread = lf*4 - 2; + unsigned char *buf = new unsigned char[toread]; + if (fread(buf, 1, toread, fp) != toread) { + if (feof(fp)) + error("unexpected end of file on `%1'", file); + else + error("error on file `%1'", file); + a_delete buf; + fclose(fp); + return 0; + } + fclose(fp); + if (lf < 6) { + error("bad tfm file `%1': impossibly short", file); + a_delete buf; + return 0; + } + unsigned char *ptr = buf; + int lh = read2(ptr); + bc = read2(ptr); + ec = read2(ptr); + nw = read2(ptr); + nh = read2(ptr); + nd = read2(ptr); + ni = read2(ptr); + nl = read2(ptr); + nk = read2(ptr); + int ne = read2(ptr); + np = read2(ptr); + if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) { + error("bad tfm file `%1': lengths do not sum", file); + a_delete buf; + return 0; + } + if (lh < 2) { + error("bad tfm file `%1': header too short", file); + a_delete buf; + return 0; + } + char_info = new char_info_word[ec - bc + 1]; + width = new int[nw]; + height = new int[nh]; + depth = new int[nd]; + italic = new int[ni]; + lig_kern = new lig_kern_command[nl]; + kern = new int[nk]; + param = new int[np]; + int i; + cs = read4(ptr); + ds = read4(ptr); + ptr += (lh-2)*4; + for (i = 0; i < ec - bc + 1; i++) { + char_info[i].width_index = *ptr++; + unsigned char tem = *ptr++; + char_info[i].depth_index = tem & 0xf; + char_info[i].height_index = tem >> 4; + tem = *ptr++; + char_info[i].italic_index = tem >> 2; + char_info[i].tag = tem & 3; + char_info[i].remainder = *ptr++; + } + for (i = 0; i < nw; i++) + width[i] = read4(ptr); + for (i = 0; i < nh; i++) + height[i] = read4(ptr); + for (i = 0; i < nd; i++) + depth[i] = read4(ptr); + for (i = 0; i < ni; i++) + italic[i] = read4(ptr); + for (i = 0; i < nl; i++) { + lig_kern[i].skip_byte = *ptr++; + lig_kern[i].next_char = *ptr++; + lig_kern[i].op_byte = *ptr++; + lig_kern[i].remainder = *ptr++; + } + for (i = 0; i < nk; i++) + kern[i] = read4(ptr); + ptr += ne*4; + for (i = 0; i < np; i++) + param[i] = read4(ptr); + assert(ptr == buf + lf*4 - 2); + a_delete buf; + return 1; +} + +class gf { + int left[256]; + int right[256]; + static int sread4(int *p, FILE *fp); + static int uread3(int *p, FILE *fp); + static int uread2(int *p, FILE *fp); + static int skip(int n, FILE *fp); +public: + gf(); + int load(const char *file); + int get_left_adjustment(int i) { return left[i]; } + int get_right_adjustment(int i) { return right[i]; } +}; + +gf::gf() +{ + for (int i = 0; i < 256; i++) + left[i] = right[i] = 0; +} + +int gf::load(const char *file) +{ + enum { + paint_0 = 0, + paint1 = 64, + boc = 67, + boc1 = 68, + eoc = 69, + skip0 = 70, + skip1 = 71, + new_row_0 = 74, + xxx1 = 239, + yyy = 243, + no_op = 244, + pre = 247, + post = 248 + }; + int got_an_adjustment = 0; + int pending_adjustment = 0; + int left_adj, right_adj; + const int gf_id_byte = 131; + errno = 0; + FILE *fp = fopen(file, FOPEN_RB); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + if (getc(fp) != pre || getc(fp) != gf_id_byte) { + error("bad gf file"); + return 0; + } + int n = getc(fp); + if (n == EOF) + goto eof; + if (!skip(n, fp)) + goto eof; + for (;;) { + int op = getc(fp); + if (op == EOF) + goto eof; + if (op == post) + break; + if ((op >= paint_0 && op <= paint_0 + 63) + || (op >= new_row_0 && op <= new_row_0 + 164)) + continue; + switch (op) { + case no_op: + case eoc: + case skip0: + break; + case paint1: + case skip1: + if (!skip(1, fp)) + goto eof; + break; + case paint1 + 1: + case skip1 + 1: + if (!skip(2, fp)) + goto eof; + break; + case paint1 + 2: + case skip1 + 2: + if (!skip(3, fp)) + goto eof; + break; + case boc: + { + int code; + if (!sread4(&code, fp)) + goto eof; + if (pending_adjustment) { + pending_adjustment = 0; + left[code & 0377] = left_adj; + right[code & 0377] = right_adj; + } + if (!skip(20, fp)) + goto eof; + break; + } + case boc1: + { + int code = getc(fp); + if (code == EOF) + goto eof; + if (pending_adjustment) { + pending_adjustment = 0; + left[code] = left_adj; + right[code] = right_adj; + } + if (!skip(4, fp)) + goto eof; + break; + } + case xxx1: + { + int len = getc(fp); + if (len == EOF) + goto eof; + char buf[256]; + if (fread(buf, 1, len, fp) != len) + goto eof; + if (len == 10 /* strlen("adjustment") */ + && memcmp(buf, "adjustment", len) == 0) { + int c = getc(fp); + if (c != yyy) { + if (c != EOF) + ungetc(c, fp); + break; + } + if (!sread4(&left_adj, fp)) + goto eof; + c = getc(fp); + if (c != yyy) { + if (c != EOF) + ungetc(c, fp); + break; + } + if (!sread4(&right_adj, fp)) + goto eof; + got_an_adjustment = 1; + pending_adjustment = 1; + } + break; + } + case xxx1 + 1: + if (!uread2(&n, fp) || !skip(n, fp)) + goto eof; + break; + case xxx1 + 2: + if (!uread3(&n, fp) || !skip(n, fp)) + goto eof; + break; + case xxx1 + 3: + if (!sread4(&n, fp) || !skip(n, fp)) + goto eof; + break; + case yyy: + if (!skip(4, fp)) + goto eof; + break; + default: + fatal("unrecognized opcode `%1'", op); + break; + } + } + if (!got_an_adjustment) + warning("no adjustment specials found in gf file"); + return 1; + eof: + error("unexpected end of file"); + return 0; +} + +int gf::sread4(int *p, FILE *fp) +{ + *p = getc(fp); + if (*p >= 128) + *p -= 256; + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::uread3(int *p, FILE *fp) +{ + *p = getc(fp); + *p <<= 8; + *p |= getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::uread2(int *p, FILE *fp) +{ + *p = getc(fp); + *p <<= 8; + *p |= getc(fp); + return !ferror(fp) && !feof(fp); +} + +int gf::skip(int n, FILE *fp) +{ + while (--n >= 0) + if (getc(fp) == EOF) + return 0; + return 1; +} + + +struct char_list { + char *ch; + char_list *next; + char_list(const char *, char_list * = 0); +}; + +char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p) +{ +} + + +int read_map(const char *file, char_list **table) +{ + errno = 0; + FILE *fp = fopen(file, "r"); + if (!fp) { + error("can't open `%1': %2", file, strerror(errno)); + return 0; + } + for (int i = 0; i < 256; i++) + table[i] = 0; + char buf[512]; + int lineno = 0; + while (fgets(buf, int(sizeof(buf)), fp)) { + lineno++; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr == '\0' || *ptr == '#') + continue; + ptr = strtok(ptr, " \n\t"); + if (!ptr) + continue; + int n; + if (sscanf(ptr, "%d", &n) != 1) { + error("%1:%2: bad map file", file, lineno); + fclose(fp); + return 0; + } + if (n < 0 || n > 255) { + error("%1:%2: code out of range", file, lineno); + fclose(fp); + return 0; + } + ptr = strtok(0, " \n\t"); + if (!ptr) { + error("%1:%2: missing names", file, lineno); + fclose(fp); + return 0; + } + for (; ptr; ptr = strtok(0, " \n\t")) + table[n] = new char_list(ptr, table[n]); + } + fclose(fp); + return 1; +} + + +/* Every character that can participate in a ligature appears in the +lig_chars table. `ch' gives the full-name of the character, `name' +gives the groff name of the character, `i' gives its index in +the encoding, which is filled in later (-1 if it does not appear). */ + +struct { + const char *ch; + int i; +} lig_chars[] = { + { "f", -1 }, + { "i", -1 }, + { "l", -1 }, + { "ff", -1 }, + { "fi", -1 }, + { "fl", -1 }, + { "Fi", -1 }, + { "Fl", -1 }, +}; + +// Indices into lig_chars[]. + +enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl }; + +// Each possible ligature appears in this table. + +struct { + unsigned char c1, c2, res; + const char *ch; +} lig_table[] = { + { CH_f, CH_f, CH_ff, "ff" }, + { CH_f, CH_i, CH_fi, "fi" }, + { CH_f, CH_l, CH_fl, "fl" }, + { CH_ff, CH_i, CH_ffi, "ffi" }, + { CH_ff, CH_l, CH_ffl, "ffl" }, + }; + +static void usage(FILE *stream); + +int main(int argc, char **argv) +{ + program_name = argv[0]; + int special_flag = 0; + int skewchar = -1; + int opt; + const char *gf_file = 0; + static const struct option long_options[] = { + { "help", no_argument, 0, CHAR_MAX + 1 }, + { "version", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } + }; + while ((opt = getopt_long(argc, argv, "svg:k:", long_options, NULL)) != EOF) + switch (opt) { + case 'g': + gf_file = optarg; + break; + case 's': + special_flag = 1; + break; + case 'k': + { + char *ptr; + long n = strtol(optarg, &ptr, 0); + if ((n == 0 && ptr == optarg) + || *ptr != '\0' + || n < 0 + || n > UCHAR_MAX) + error("invalid skewchar"); + else + skewchar = (int)n; + break; + } + case 'v': + { + extern const char *Version_string; + printf("GNU tfmtodit (groff) version %s\n", Version_string); + exit(0); + break; + } + case CHAR_MAX + 1: // --help + usage(stdout); + exit(0); + break; + case '?': + usage(stderr); + exit(1); + break; + case EOF: + assert(0); + } + if (argc - optind != 3) { + usage(stderr); + exit(1); + } + gf g; + if (gf_file) { + if (!g.load(gf_file)) + return 1; + } + const char *tfm_file = argv[optind]; + const char *map_file = argv[optind + 1]; + const char *font_file = argv[optind + 2]; + tfm t; + if (!t.load(tfm_file)) + return 1; + char_list *table[256]; + if (!read_map(map_file, table)) + return 1; + errno = 0; + if (!freopen(font_file, "w", stdout)) { + error("can't open `%1' for writing: %2", font_file, strerror(errno)); + return 1; + } + printf("name %s\n", font_file); + if (special_flag) + fputs("special\n", stdout); + char *internal_name = strsave(argv[optind]); + int len = strlen(internal_name); + if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0) + internal_name[len - 4] = '\0'; + // DIR_SEPS[] are possible directory separator characters, see nonposix.h. + // We want the rightmost separator of all possible ones. + // Example: d:/foo\\bar. + const char *s = strrchr(internal_name, DIR_SEPS[0]), *s1; + const char *sep = &DIR_SEPS[1]; + while (*sep) + { + s1 = strrchr(internal_name, *sep); + if (s1 && (!s || s1 > s)) + s = s1; + sep++; + } + printf("internalname %s\n", s ? s + 1 : internal_name); + int n; + if (t.get_param(2, &n)) { + if (n > 0) + printf("spacewidth %d\n", n*MULTIPLIER); + } + if (t.get_param(1, &n) && n != 0) + printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/PI); + int xheight; + if (!t.get_param(5, &xheight)) + xheight = 0; + int i; + // Print the list of ligatures. + // First find the indices of each character that can participate in + // a ligature. + for (i = 0; i < 256; i++) + for (int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++) + for (char_list *p = table[i]; p; p = p->next) + if (strcmp(lig_chars[j].ch, p->ch) == 0) + lig_chars[j].i = i; + // For each possible ligature, if its participants all exist, + // and it appears as a ligature in the tfm file, include in + // the list of ligatures. + int started = 0; + for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) { + int i1 = lig_chars[lig_table[i].c1].i; + int i2 = lig_chars[lig_table[i].c2].i; + int r = lig_chars[lig_table[i].res].i; + if (i1 >= 0 && i2 >= 0 && r >= 0) { + unsigned char c; + if (t.get_lig(i1, i2, &c) && c == r) { + if (!started) { + started = 1; + fputs("ligatures", stdout); + } + printf(" %s", lig_table[i].ch); + } + } + } + if (started) + fputs(" 0\n", stdout); + printf("checksum %d\n", t.get_checksum()); + printf("designsize %d\n", t.get_design_size()); + // Now print out the kerning information. + int had_kern = 0; + kern_iterator iter(&t); + unsigned char c1, c2; + int k; + while (iter.next(&c1, &c2, &k)) + if (c2 != skewchar) { + k *= MULTIPLIER; + char_list *q = table[c2]; + for (char_list *p1 = table[c1]; p1; p1 = p1->next) + for (char_list *p2 = q; p2; p2 = p2->next) { + if (!had_kern) { + printf("kernpairs\n"); + had_kern = 1; + } + printf("%s %s %d\n", p1->ch, p2->ch, k); + } + } + printf("charset\n"); + char_list unnamed("---"); + for (i = 0; i < 256; i++) + if (t.contains(i)) { + char_list *p = table[i] ? table[i] : &unnamed; + int m[6]; + m[0] = t.get_width(i); + m[1] = t.get_height(i); + m[2] = t.get_depth(i); + m[3] = t.get_italic(i); + m[4] = g.get_left_adjustment(i); + m[5] = g.get_right_adjustment(i); + printf("%s\t%d", p->ch, m[0]*MULTIPLIER); + int j; + for (j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--) + if (m[j] != 0) + break; + for (k = 1; k <= j; k++) + printf(",%d", m[k]*MULTIPLIER); + int type = 0; + if (m[2] > 0) + type = 1; + if (m[1] > xheight) + type += 2; + printf("\t%d\t%04o\n", type, i); + for (p = p->next; p; p = p->next) + printf("%s\t\"\n", p->ch); + } + return 0; +} + +static void usage(FILE *stream) +{ + fprintf(stream, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n", + program_name); +} diff --git a/contrib/groff/src/utils/tfmtodit/tfmtodit.man b/contrib/groff/src/utils/tfmtodit/tfmtodit.man new file mode 100644 index 0000000..6e50aa2 --- /dev/null +++ b/contrib/groff/src/utils/tfmtodit/tfmtodit.man @@ -0,0 +1,175 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 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. +.. +.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH TFMTODIT @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +tfmtodit \- create font files for use with groff \-Tdvi +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fBtfmtodit 'u +.ti \niu +.B tfmtodit +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-sv +.OP \-g gf_file +.OP \-k skewchar +.I tfm_file +.I map_file +.I font +.br +.ad \na +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +.B tfmtodit +creates a font file for use with +.B +groff \-Tdvi\fR. +.I tfm_file +is the name of the \*(tx font metric file for the font. +.I map_file +is a file giving the groff names for characters in the font; +this file should consist of a sequence of lines of the form: +.IP +.I +n c1 c2 \fR.\|.\|. +.LP +where +.I n +is a decimal integer giving the position of the character in the font, +and +.IR c1 , +.IR c2 ,.\|.\|. +are the groff names of the character. +If a character has no groff names but exists in the tfm file, +then it will be put in the groff font file as an unnamed character. +.I font +is the name of the groff font file. +The groff font file is written to +.IR font . +.LP +The +.B \-s +option should be given if the font is special +(a font is +.I special +if +.B troff +should search it whenever +a character is not found in the current font.) +If the font is special, +it should be listed in the +.B fonts +command in the DESC file; +if it is not special, there is no need to list it, since +.B troff +can automatically mount it when it's first used. +.LP +To do a good job of math typesetting, groff requires +font metric information not present in the tfm file. +The reason for this is that \*(tx has separate math italic fonts +whereas groff uses normal italic fonts for math. +The additional information required by groff is given by the +two arguments to the +.B math_fit +macro in the Metafont programs for the Computer Modern fonts. +In a text font (a font for which +.B math_fitting +is false), Metafont normally ignores these two arguments. +Metafont can be made to put this information in the gf file +by loading the following definition after +.B cmbase +when creating +.BR cm.base : +.IP +.nf +.ft B +def ignore_math_fit(expr left_adjustment,right_adjustment) = + special "adjustment"; + numspecial left_adjustment*16/designsize; + numspecial right_adjustment*16/designsize; + enddef; +.fi +.ft R +.LP +The gf file created using this modified +.B cm.base +should be specified with the +.B \-g +option. +The +.B \-g +option should not be given for a font for which +.B math_fitting +is true. +.SH OPTIONS +.TP +.B \-v +Print the version number. +.TP +.B \-s +The font is special. +The effect of this option is to add the +.B special +command to the font file. +.TP +.BI \-k n +The skewchar of this font is at position +.IR n . +.I n +should be an integer; +it may be given in decimal, +or with a leading +.B 0 +in octal, +or with a leading +.B 0x +in hexadecimal. +The effect of this option is to ignore any kerns whose second component +is the specified character. +.TP +.BI \-g gf_file +.I gf_file +is a gf file produced by Metafont containing special and numspecial +commands giving additional font metric information. +.SH FILES +.Tp \w'\fB@FONTDIR@/devdvi/DESC'u+2n +.B @FONTDIR@/devdvi/DESC +Device description file. +.TP +.BI @FONTDIR@/devdvi/ F +Font description file for font +.IR F . +.SH "SEE ALSO" +.BR groff (@MAN1EXT@), +.BR grodvi (@MAN1EXT@), +.BR groff_font (@MAN5EXT@) |