Removed files not present in v1.19 import.

This commit is contained in:
ru 2003-05-01 13:15:22 +00:00
parent c96557721b
commit 1a17e98fb2
102 changed files with 0 additions and 78727 deletions

View File

@ -1,947 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
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 "driver.h"
#include "nonposix.h"
extern "C" const char *Version_string;
#define DEFAULT_LINEWIDTH 40
static int linewidth = DEFAULT_LINEWIDTH;
static int draw_flag = 1;
/* These values were chosen because:
(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
The width in the groff font file is the product of MULTIPLIER and the
width in the tfm file. */
#define RES 57816
#define RES_7227 (RES/7227)
#define UNITWIDTH 131072
#define SIZESCALE 100
#define MULTIPLIER 1
class dvi_font : public font {
dvi_font(const char *);
public:
int checksum;
int design_size;
~dvi_font();
void handle_unknown_font_command(const char *command, const char *arg,
const char *filename, int lineno);
static dvi_font *load_dvi_font(const char *);
};
dvi_font *dvi_font::load_dvi_font(const char *s)
{
dvi_font *f = new dvi_font(s);
if (!f->load()) {
delete f;
return 0;
}
return f;
}
dvi_font::dvi_font(const char *nm)
: font(nm), checksum(0), design_size(0)
{
}
dvi_font::~dvi_font()
{
}
void dvi_font::handle_unknown_font_command(const char *command,
const char *arg,
const char *filename, int lineno)
{
char *ptr;
if (strcmp(command, "checksum") == 0) {
if (arg == 0)
fatal_with_file_and_line(filename, lineno,
"`checksum' command requires an argument");
checksum = int(strtol(arg, &ptr, 10));
if (checksum == 0 && ptr == arg) {
fatal_with_file_and_line(filename, lineno, "bad checksum");
}
}
else if (strcmp(command, "designsize") == 0) {
if (arg == 0)
fatal_with_file_and_line(filename, lineno,
"`designsize' command requires an argument");
design_size = int(strtol(arg, &ptr, 10));
if (design_size == 0 && ptr == arg) {
fatal_with_file_and_line(filename, lineno, "bad design size");
}
}
}
#define FONTS_MAX 256
struct output_font {
dvi_font *f;
int point_size;
output_font() : f(0) { }
};
class dvi_printer : public printer {
FILE *fp;
int max_drift;
int byte_count;
int last_bop;
int page_count;
int cur_h;
int cur_v;
int end_h;
int max_h;
int max_v;
output_font output_font_table[FONTS_MAX];
font *cur_font;
int cur_point_size;
color cur_color;
int pushed;
int pushed_h;
int pushed_v;
int have_pushed;
void preamble();
void postamble();
void define_font(int);
void set_font(int);
void possibly_begin_line();
void set_color(color *);
protected:
enum {
id_byte = 2,
set1 = 128,
put1 = 133,
put_rule = 137,
bop = 139,
eop = 140,
push = 141,
pop = 142,
right1 = 143,
down1 = 157,
fnt_num_0 = 171,
fnt1 = 235,
xxx1 = 239,
fnt_def1 = 243,
pre = 247,
post = 248,
post_post = 249,
filler = 223
};
int line_thickness;
void out1(int);
void out2(int);
void out3(int);
void out4(int);
void moveto(int, int);
void out_string(const char *);
void out_signed(unsigned char, int);
void out_unsigned(unsigned char, int);
void do_special(const char *);
public:
dvi_printer();
~dvi_printer();
font *make_font(const char *);
void begin_page(int);
void end_page(int);
void set_char(int, font *, const environment *, int w, const char *name);
void special(char *arg, const environment *env, char type);
void end_of_line();
void draw(int code, int *p, int np, const environment *env);
};
class draw_dvi_printer : public dvi_printer {
int output_pen_size;
void set_line_thickness(const environment *);
void fill_next(const environment *);
public:
draw_dvi_printer();
~draw_dvi_printer();
void draw(int code, int *p, int np, const environment *env);
void end_page(int);
};
dvi_printer::dvi_printer()
: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0),
cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1)
{
if (font::res != RES)
fatal("resolution must be %1", RES);
if (font::unitwidth != UNITWIDTH)
fatal("unitwidth must be %1", UNITWIDTH);
if (font::hor != 1)
fatal("hor must be equal to 1");
if (font::vert != 1)
fatal("vert must be equal to 1");
if (font::sizescale != SIZESCALE)
fatal("sizescale must be equal to %1", SIZESCALE);
max_drift = font::res/1000; // this is fairly arbitrary
preamble();
}
dvi_printer::~dvi_printer()
{
postamble();
}
draw_dvi_printer::draw_dvi_printer()
: output_pen_size(-1)
{
}
draw_dvi_printer::~draw_dvi_printer()
{
}
void dvi_printer::out1(int n)
{
byte_count += 1;
putc(n & 0xff, fp);
}
void dvi_printer::out2(int n)
{
byte_count += 2;
putc((n >> 8) & 0xff, fp);
putc(n & 0xff, fp);
}
void dvi_printer::out3(int n)
{
byte_count += 3;
putc((n >> 16) & 0xff, fp);
putc((n >> 8) & 0xff, fp);
putc(n & 0xff, fp);
}
void dvi_printer::out4(int n)
{
byte_count += 4;
putc((n >> 24) & 0xff, fp);
putc((n >> 16) & 0xff, fp);
putc((n >> 8) & 0xff, fp);
putc(n & 0xff, fp);
}
void dvi_printer::out_string(const char *s)
{
out1(strlen(s));
while (*s != 0)
out1(*s++);
}
void dvi_printer::end_of_line()
{
if (pushed) {
out1(pop);
pushed = 0;
cur_h = pushed_h;
cur_v = pushed_v;
}
}
void dvi_printer::possibly_begin_line()
{
if (!pushed) {
have_pushed = pushed = 1;
pushed_h = cur_h;
pushed_v = cur_v;
out1(push);
}
}
int scale(int x, int z)
{
int sw;
int a, b, c, d;
int alpha, beta;
alpha = 16*z; beta = 16;
while (z >= 040000000L) {
z /= 2; beta /= 2;
}
d = x & 255;
c = (x >> 8) & 255;
b = (x >> 16) & 255;
a = (x >> 24) & 255;
sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
if (a == 255)
sw -= alpha;
else
assert(a == 0);
return sw;
}
void dvi_printer::set_color(color *col)
{
cur_color = *col;
char buf[256];
unsigned int components[4];
color_scheme cs = col->get_components(components);
switch (cs) {
case DEFAULT:
sprintf(buf, "color gray 0");
break;
case RGB:
sprintf(buf, "color rgb %.3g %.3g %.3g",
double(Red) / color::MAX_COLOR_VAL,
double(Green) / color::MAX_COLOR_VAL,
double(Blue) / color::MAX_COLOR_VAL);
break;
case CMY:
col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black);
// fall through
case CMYK:
sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g",
double(Cyan) / color::MAX_COLOR_VAL,
double(Magenta) / color::MAX_COLOR_VAL,
double(Yellow) / color::MAX_COLOR_VAL,
double(Black) / color::MAX_COLOR_VAL);
break;
case GRAY:
sprintf(buf, "color gray %.3g",
double(Gray) / color::MAX_COLOR_VAL);
break;
}
do_special(buf);
}
void dvi_printer::set_char(int index, font *f, const environment *env,
int w, const char *name)
{
if (*env->col != cur_color)
set_color(env->col);
int code = f->get_code(index);
if (env->size != cur_point_size || f != cur_font) {
cur_font = f;
cur_point_size = env->size;
int i;
for (i = 0;; i++) {
if (i >= FONTS_MAX) {
fatal("too many output fonts required");
}
if (output_font_table[i].f == 0) {
output_font_table[i].f = (dvi_font *)cur_font;
output_font_table[i].point_size = cur_point_size;
define_font(i);
}
if (output_font_table[i].f == cur_font
&& output_font_table[i].point_size == cur_point_size)
break;
}
set_font(i);
}
int distance = env->hpos - cur_h;
if (env->hpos != end_h && distance != 0) {
out_signed(right1, distance);
cur_h = env->hpos;
}
else if (distance > max_drift) {
out_signed(right1, distance - max_drift);
cur_h = env->hpos - max_drift;
}
else if (distance < -max_drift) {
out_signed(right1, distance + max_drift);
cur_h = env->hpos + max_drift;
}
if (env->vpos != cur_v) {
out_signed(down1, env->vpos - cur_v);
cur_v = env->vpos;
}
possibly_begin_line();
end_h = env->hpos + w;
cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER,
cur_point_size*RES_7227);
if (cur_h > max_h)
max_h = cur_h;
if (cur_v > max_v)
max_v = cur_v;
if (code >= 0 && code <= 127)
out1(code);
else
out_unsigned(set1, code);
}
void dvi_printer::define_font(int i)
{
out_unsigned(fnt_def1, i);
dvi_font *f = output_font_table[i].f;
out4(f->checksum);
out4(output_font_table[i].point_size*RES_7227);
out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5));
const char *nm = f->get_internal_name();
out1(0);
out_string(nm);
}
void dvi_printer::set_font(int i)
{
if (i >= 0 && i <= 63)
out1(fnt_num_0 + i);
else
out_unsigned(fnt1, i);
}
void dvi_printer::out_signed(unsigned char base, int param)
{
if (-128 <= param && param < 128) {
out1(base);
out1(param);
}
else if (-32768 <= param && param < 32768) {
out1(base+1);
out2(param);
}
else if (-(1 << 23) <= param && param < (1 << 23)) {
out1(base+2);
out3(param);
}
else {
out1(base+3);
out4(param);
}
}
void dvi_printer::out_unsigned(unsigned char base, int param)
{
if (param >= 0) {
if (param < 256) {
out1(base);
out1(param);
}
else if (param < 65536) {
out1(base+1);
out2(param);
}
else if (param < (1 << 24)) {
out1(base+2);
out3(param);
}
else {
out1(base+3);
out4(param);
}
}
else {
out1(base+3);
out4(param);
}
}
void dvi_printer::preamble()
{
out1(pre);
out1(id_byte);
out4(254000);
out4(font::res);
out4(1000);
out1(0);
}
void dvi_printer::postamble()
{
int tem = byte_count;
out1(post);
out4(last_bop);
out4(254000);
out4(font::res);
out4(1000);
out4(max_v);
out4(max_h);
out2(have_pushed); // stack depth
out2(page_count);
int i;
for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++)
define_font(i);
out1(post_post);
out4(tem);
out1(id_byte);
for (i = 0; i < 4 || byte_count % 4 != 0; i++)
out1(filler);
}
void dvi_printer::begin_page(int i)
{
page_count++;
int tem = byte_count;
out1(bop);
out4(i);
for (int j = 1; j < 10; j++)
out4(0);
out4(last_bop);
last_bop = tem;
if (cur_color != default_color)
set_color(&cur_color);
// By convention position (0,0) in a dvi file is placed at (1in, 1in).
cur_h = font::res;
cur_v = font::res;
end_h = 0;
}
void dvi_printer::end_page(int)
{
set_color(&default_color);
if (pushed)
end_of_line();
out1(eop);
cur_font = 0;
}
void draw_dvi_printer::end_page(int len)
{
dvi_printer::end_page(len);
output_pen_size = -1;
}
void dvi_printer::do_special(const char *s)
{
int len = strlen(s);
if (len == 0)
return;
possibly_begin_line();
out_unsigned(xxx1, len);
while (*s)
out1(*s++);
}
void dvi_printer::special(char *arg, const environment *env, char type)
{
if (type != 'p')
return;
moveto(env->hpos, env->vpos);
do_special(arg);
}
void dvi_printer::moveto(int h, int v)
{
if (h != cur_h) {
out_signed(right1, h - cur_h);
cur_h = h;
if (cur_h > max_h)
max_h = cur_h;
}
if (v != cur_v) {
out_signed(down1, v - cur_v);
cur_v = v;
if (cur_v > max_v)
max_v = cur_v;
}
end_h = 0;
}
void dvi_printer::draw(int code, int *p, int np, const environment *env)
{
if (code == 'l') {
int x = 0, y = 0;
int height = 0, width = 0;
int thickness;
if (line_thickness < 0)
thickness = env->size*RES_7227*linewidth/1000;
else if (line_thickness > 0)
thickness = line_thickness;
else
thickness = 1;
if (np != 2) {
error("2 arguments required for line");
}
else if (p[0] == 0) {
// vertical rule
if (p[1] > 0) {
x = env->hpos - thickness/2;
y = env->vpos + p[1] + thickness/2;
height = p[1] + thickness;
width = thickness;
}
else if (p[1] < 0) {
x = env->hpos - thickness/2;
y = env->vpos + thickness/2;
height = thickness - p[1];
width = thickness;
}
}
else if (p[1] == 0) {
if (p[0] > 0) {
x = env->hpos - thickness/2;
y = env->vpos + thickness/2;
height = thickness;
width = p[0] + thickness;
}
else if (p[0] < 0) {
x = env->hpos - p[0] - thickness/2;
y = env->vpos + thickness/2;
height = thickness;
width = thickness - p[0];
}
}
if (height != 0) {
moveto(x, y);
out1(put_rule);
out4(height);
out4(width);
}
}
else if (code == 't') {
if (np == 0) {
line_thickness = -1;
}
else {
// troff gratuitously adds an extra 0
if (np != 1 && np != 2)
error("0 or 1 argument required for thickness");
else
line_thickness = p[0];
}
}
else if (code == 'R') {
if (np != 2)
error("2 arguments required for rule");
else if (p[0] != 0 || p[1] != 0) {
int dh = p[0];
int dv = p[1];
int oh = env->hpos;
int ov = env->vpos;
if (dv > 0) {
ov += dv;
dv = -dv;
}
if (dh < 0) {
oh += dh;
dh = -dh;
}
moveto(oh, ov);
out1(put_rule);
out4(-dv);
out4(dh);
}
}
}
// XXX Will this overflow?
inline int milliinches(int n)
{
return (n*1000 + font::res/2)/font::res;
}
void draw_dvi_printer::set_line_thickness(const environment *env)
{
int desired_pen_size
= milliinches(line_thickness < 0
// Will this overflow?
? env->size*RES_7227*linewidth/1000
: line_thickness);
if (desired_pen_size != output_pen_size) {
char buf[256];
sprintf(buf, "pn %d", desired_pen_size);
do_special(buf);
output_pen_size = desired_pen_size;
}
}
void draw_dvi_printer::fill_next(const environment *env)
{
unsigned int g;
if (env->fill->is_default())
g = 0;
else {
// currently, only BW support
env->fill->get_gray(&g);
}
char buf[256];
sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL);
do_special(buf);
}
void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
{
char buf[1024];
int fill_flag = 0;
switch (code) {
case 'C':
fill_flag = 1;
// fall through
case 'c':
// troff adds an extra argument to C
if (np != 1 && !(code == 'C' && np == 2)) {
error("1 argument required for circle");
break;
}
moveto(env->hpos+p[0]/2, env->vpos);
if (fill_flag)
fill_next(env);
else
set_line_thickness(env);
int rad;
rad = milliinches(p[0]/2);
sprintf(buf, "%s 0 0 %d %d 0 6.28319",
(fill_flag ? "ia" : "ar"),
rad,
rad);
do_special(buf);
break;
case 'l':
if (np != 2) {
error("2 arguments required for line");
break;
}
moveto(env->hpos, env->vpos);
set_line_thickness(env);
do_special("pa 0 0");
sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1]));
do_special(buf);
do_special("fp");
break;
case 'E':
fill_flag = 1;
// fall through
case 'e':
if (np != 2) {
error("2 arguments required for ellipse");
break;
}
moveto(env->hpos+p[0]/2, env->vpos);
if (fill_flag)
fill_next(env);
sprintf(buf, "%s 0 0 %d %d 0 6.28319",
(fill_flag ? "ia" : "ar"),
milliinches(p[0]/2),
milliinches(p[1]/2));
do_special(buf);
break;
case 'P':
fill_flag = 1;
// fall through
case 'p':
{
if (np & 1) {
error("even number of arguments required for polygon");
break;
}
if (np == 0) {
error("no arguments for polygon");
break;
}
moveto(env->hpos, env->vpos);
if (fill_flag)
fill_next(env);
else
set_line_thickness(env);
do_special("pa 0 0");
int h = 0, v = 0;
for (int i = 0; i < np; i += 2) {
h += p[i];
v += p[i+1];
sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
do_special(buf);
}
do_special("pa 0 0");
do_special(fill_flag ? "ip" : "fp");
break;
}
case '~':
{
if (np & 1) {
error("even number of arguments required for spline");
break;
}
if (np == 0) {
error("no arguments for spline");
break;
}
moveto(env->hpos, env->vpos);
set_line_thickness(env);
do_special("pa 0 0");
int h = 0, v = 0;
for (int i = 0; i < np; i += 2) {
h += p[i];
v += p[i+1];
sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
do_special(buf);
}
do_special("sp");
break;
}
case 'a':
{
if (np != 4) {
error("4 arguments required for arc");
break;
}
set_line_thickness(env);
double c[2];
if (adjust_arc_center(p, c)) {
int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5));
moveto(env->hpos + int(c[0]), env->vpos + int(c[1]));
sprintf(buf, "ar 0 0 %d %d %f %f",
rad,
rad,
atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]),
atan2(-c[1], -c[0]));
do_special(buf);
}
else {
moveto(env->hpos, env->vpos);
do_special("pa 0 0");
sprintf(buf,
"pa %d %d",
milliinches(p[0] + p[2]),
milliinches(p[1] + p[3]));
do_special(buf);
do_special("fp");
}
break;
}
case 't':
{
if (np == 0) {
line_thickness = -1;
}
else {
// troff gratuitously adds an extra 0
if (np != 1 && np != 2) {
error("0 or 1 argument required for thickness");
break;
}
line_thickness = p[0];
}
break;
}
case 'R':
{
if (np != 2) {
error("2 arguments required for rule");
break;
}
int dh = p[0];
if (dh == 0)
break;
int dv = p[1];
if (dv == 0)
break;
int oh = env->hpos;
int ov = env->vpos;
if (dv > 0) {
ov += dv;
dv = -dv;
}
if (dh < 0) {
oh += dh;
dh = -dh;
}
moveto(oh, ov);
out1(put_rule);
out4(-dv);
out4(dh);
break;
}
default:
error("unrecognised drawing command `%1'", char(code));
break;
}
}
font *dvi_printer::make_font(const char *nm)
{
return dvi_font::load_dvi_font(nm);
}
printer *make_printer()
{
if (draw_flag)
return new draw_dvi_printer;
else
return new dvi_printer;
}
static void usage(FILE *stream);
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
int c;
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "F:vw:d", long_options, NULL)) != EOF)
switch(c) {
case 'v':
{
printf("GNU grodvi (groff) version %s\n", Version_string);
exit(0);
break;
}
case 'w':
if (sscanf(optarg, "%d", &linewidth) != 1
|| linewidth < 0 || linewidth > 1000) {
error("bad line width");
linewidth = DEFAULT_LINEWIDTH;
}
break;
case 'd':
draw_flag = 0;
break;
case 'F':
font::command_line_font_dir(optarg);
break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
#ifdef SET_BINARY
SET_BINARY(fileno(stdout));
#endif
if (optind >= argc)
do_file("-");
else {
for (int i = optind; i < argc; i++)
do_file(argv[i]);
}
delete pr;
return 0;
}
static void usage(FILE *stream)
{
fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",
program_name);
}

View File

@ -1,687 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 2002 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc
*
* html-table.h
*
* provides the methods necessary to handle indentation and tab
* positions using html tables.
*/
/*
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 "driver.h"
#include "stringclass.h"
#include "cset.h"
#include "html-table.h"
#include "ctype.h"
#include "html.h"
#if !defined(TRUE)
# define TRUE (1==1)
#endif
#if !defined(FALSE)
# define FALSE (1==0)
#endif
tabs::tabs ()
: tab(NULL)
{
}
tabs::~tabs ()
{
delete_list();
}
/*
* delete_list - frees the tab list and sets tab to NULL.
*/
void tabs::delete_list (void)
{
tab_position *p = tab;
tab_position *q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
tab = NULL;
}
void tabs::clear (void)
{
delete_list();
}
/*
* compatible - returns TRUE if the tab stops in, s, do
* not conflict with the current tab stops.
* The new tab stops are _not_ placed into
* this class.
*/
int tabs::compatible (const char *s)
{
char align;
int total=0;
tab_position *last = tab;
if (last == NULL)
return FALSE; // no tab stops defined
// move over tag name
while ((*s != (char)0) && !isspace(*s))
s++;
while (*s != (char)0 && last != NULL) {
// move over white space
while ((*s != (char)0) && isspace(*s))
s++;
// collect alignment
align = *s;
// move over alignment
s++;
// move over white space
while ((*s != (char)0) && isspace(*s))
s++;
// collect tab position
total += atoi(s);
// move over tab position
while ((*s != (char)0) && !isspace(*s))
s++;
if (last->alignment != align || last->position != total)
return FALSE;
last = last->next;
}
return TRUE;
}
/*
* init - scans the string, s, and initializes the tab stops.
*/
void tabs::init (const char *s)
{
char align;
int total=0;
tab_position *last = NULL;
clear(); // remove any tab stops
// move over tag name
while ((*s != (char)0) && !isspace(*s))
s++;
while (*s != (char)0) {
// move over white space
while ((*s != (char)0) && isspace(*s))
s++;
// collect alignment
align = *s;
// move over alignment
s++;
// move over white space
while ((*s != (char)0) && isspace(*s))
s++;
// collect tab position
total = atoi(s);
// move over tab position
while ((*s != (char)0) && !isspace(*s))
s++;
if (last == NULL) {
tab = (tab_position *)malloc(sizeof(tab_position));
last = tab;
} else {
last->next = (tab_position *)malloc(sizeof(tab_position));
last = last->next;
}
last->alignment = align;
last->position = total;
last->next = NULL;
}
}
/*
* find_tab - returns the tab number corresponding to the position, pos.
*/
int tabs::find_tab (int pos)
{
tab_position *p;
int i=0;
for (p = tab; p != NULL; p = p->next) {
i++;
if (p->position == pos)
return i;
}
return 0;
}
/*
* get_tab_pos - returns the, nth, tab position
*/
int tabs::get_tab_pos (int n)
{
tab_position *p;
n--;
for (p = tab; (p != NULL) && (n>0); p = p->next) {
n--;
if (n == 0)
return p->position;
}
return 0;
}
char tabs::get_tab_align (int n)
{
tab_position *p;
n--;
for (p = tab; (p != NULL) && (n>0); p = p->next) {
n--;
if (n == 0)
return p->alignment;
}
return 'L';
}
/*
* dump_tab - display tab positions
*/
void tabs::dump_tabs (void)
{
int i=1;
tab_position *p;
for (p = tab; p != NULL; p = p->next) {
printf("tab %d is %d\n", i, p->position);
i++;
}
}
/*
* html_table - methods
*/
html_table::html_table (simple_output *op, int linelen)
: columns(NULL), out(op), linelength(linelen), last_col(NULL), start_space(FALSE)
{
tab_stops = new tabs();
}
html_table::~html_table ()
{
if (tab_stops != NULL)
delete tab_stops;
}
/*
* remove_cols - remove a list of columns as defined by, c.
*/
void html_table::remove_cols (cols *c)
{
cols *p;
while (c != NULL) {
p = c;
c = c->next;
free(p);
}
}
/*
* set_linelength - sets the line length value in this table.
* It also adds an extra blank column to the
* table should linelen exceed the last column.
*/
void html_table::set_linelength (int linelen)
{
cols *p = NULL;
cols *c;
linelength = linelen;
for (c = columns; c != NULL; c = c->next) {
if (c->right > linelength) {
c->right = linelength;
remove_cols(c->next);
c->next = NULL;
return;
}
p = c;
}
if (p != NULL && p->right != 0)
add_column(p->no+1, p->right+1, linelen, 'L');
}
/*
* get_effective_linelength -
*/
int html_table::get_effective_linelength (void)
{
if (columns != NULL)
return linelength - columns->left;
else
return linelength;
}
/*
* add_indent - adds the indent to a table.
*/
void html_table::add_indent (int indent)
{
if (columns != NULL && columns->left > indent)
add_column(0, indent, columns->left-1, 'L');
}
/*
* emit_table_header - emits the html header for this table.
*/
void html_table::emit_table_header (int space)
{
if (columns == NULL)
return;
// dump_table();
last_col = NULL;
if (linelength > 0) {
int n = no_columns() + no_gaps();
out->nl();
out->nl();
if (space)
out->put_string("<p>");
start_space = space;
out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"").put_number(n).put_string("\" cellspacing=\"0\" cellpadding=\"0\">").nl();
out->put_string("<tr valign=\"top\" align=\"left\">").nl();
}
}
/*
* get_right - returns the right most position of this column.
*/
int html_table::get_right (cols *c)
{
if (c != NULL && c->right > 0)
return c->right;
if (c->next != NULL)
return c->left;
return linelength;
}
/*
* emit_col - moves onto column, n.
*/
void html_table::emit_col (int n)
{
cols *c = columns;
cols *b = columns;
int width = 0;
// must be a different row
if (last_col != NULL && n <= last_col->no)
emit_new_row();
while (c != NULL && c->no < n)
c = c->next;
// can we find column, n?
if (c != NULL && c->no == n) {
// shutdown previous column
if (last_col != NULL)
out->put_string("</td>").nl();
// find previous column
if (last_col == NULL)
b = columns;
else
b = last_col;
// have we a gap?
if (last_col != NULL) {
if (is_gap(b))
out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl();
b = b->next;
}
// move across to column n
while (b != c) {
width = ((get_right(b) - b->left) * 100)/get_effective_linelength();
out->put_string("<td width=\"").put_number(width).put_string("%\"></td>").nl();
// have we a gap?
if (is_gap(b))
out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl();
b = b->next;
}
width = ((get_right(b) - b->left) * 100)/get_effective_linelength();
switch (b->alignment) {
case 'C': out->put_string("<td width=\"").put_number(width).put_string("%\" align=center>").nl();
break;
case 'R': out->put_string("<td width=\"").put_number(width).put_string("%\" align=right>").nl();
break;
default:
out->put_string("<td width=\"").put_number(width).put_string("%\">").nl();
}
// remember column, b
last_col = b;
}
}
/*
* finish_row -
*/
void html_table::finish_row (void)
{
int n = 0;
cols *c;
if (last_col != NULL) {
for (c = last_col->next; c != NULL; c = c->next)
n = c->no;
if (n > 0)
emit_col(n);
out->put_string("</td>").nl();
}
}
/*
* emit_new_row - move to the next row.
*/
void html_table::emit_new_row (void)
{
finish_row();
out->put_string("<tr valign=\"top\" align=\"left\">").nl();
last_col = NULL;
}
void html_table::emit_finish_table (void)
{
finish_row();
// out->put_string("linelength = ").put_number(linelength).nl();
out->put_string("</table>");
if (start_space)
out->put_string("</p>");
out->nl();
}
/*
* add_column - adds a column. It returns FALSE if hstart..hend
* crosses into a different columns.
*/
int html_table::add_column (int coln, int hstart, int hend, char align)
{
cols *c = get_column(coln);
if (c == NULL)
return insert_column(coln, hstart, hend, align);
else
return modify_column(c, hstart, hend, align);
}
/*
* get_column - returns the column, coln.
*/
cols *html_table::get_column (int coln)
{
cols *c = columns;
while (c != NULL && coln != c->no)
c = c->next;
if (c != NULL && coln == c->no)
return c;
else
return NULL;
}
/*
* insert_column - inserts a column, coln.
* It returns TRUE if it does not bump into
* another column.
*/
int html_table::insert_column (int coln, int hstart, int hend, char align)
{
cols *c = columns;
cols *l = NULL;
cols *n = NULL;
while (c != NULL && c->no < coln) {
l = c;
c = c->next;
}
if ((l != NULL) && (hstart < l->right))
return FALSE; // new column bumps into previous one
if ((l != NULL) && (l->next != NULL) &&
(l->next->left < hend))
return FALSE; // new column bumps into next one
n = (cols *)malloc(sizeof(cols));
if (l == NULL) {
n->next = columns;
columns = n;
} else {
n->next = l->next;
l->next = n;
}
n->left = hstart;
n->right = hend;
n->no = coln;
n->alignment = align;
return TRUE;
}
/*
* modify_column - given a column, c, modify the width to
* contain hstart..hend.
* It returns TRUE if it does not clash with
* the next or previous column.
*/
int html_table::modify_column (cols *c, int hstart, int hend, char align)
{
cols *l = columns;
while (l != NULL && l->next != c)
l = l->next;
if ((l != NULL) && (hstart < l->right))
return FALSE; // new column bumps into previous one
if ((c->next != NULL) && (c->next->left < hend))
return FALSE; // new column bumps into next one
if (c->left > hstart)
c->left = hstart;
if (c->right < hend)
c->right = hend;
c->alignment = align;
return TRUE;
}
/*
* find_tab_column - finds the column number for position, pos.
* It searches through the list tab stops.
*/
int html_table::find_tab_column (int pos)
{
// remember the first column is reserved for un tabbed glyphs
return tab_stops->find_tab(pos)+1;
}
/*
* find_column - find the column number for position, pos.
* It searches through the list of columns.
*/
int html_table::find_column (int pos)
{
int p=0;
cols *c;
for (c = columns; c != NULL; c = c->next) {
if (c->left > pos)
return p;
p = c->no;
}
return p;
}
/*
* no_columns - returns the number of table columns (rather than tabs)
*/
int html_table::no_columns (void)
{
int n=0;
cols *c;
for (c = columns; c != NULL; c = c->next)
n++;
return n;
}
/*
* is_gap - returns the gap between column, c, and the next column.
*/
int html_table::is_gap (cols *c)
{
if (c == NULL || c->right == 0 || c->next == NULL)
return 0;
else
return (c->next->left - c->right)*100/get_effective_linelength();
}
/*
* no_gaps - returns the number of table gaps between the columns
*/
int html_table::no_gaps (void)
{
int n=0;
cols *c;
for (c = columns; c != NULL; c = c->next)
if (is_gap(c))
n++;
return n;
}
/*
* get_tab_pos - returns the, nth, tab position
*/
int html_table::get_tab_pos (int n)
{
return tab_stops->get_tab_pos(n);
}
char html_table::get_tab_align (int n)
{
return tab_stops->get_tab_align(n);
}
void html_table::dump_table (void)
{
if (columns != NULL) {
cols *c;
for (c = columns; c != NULL; c = c->next) {
printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment);
}
} else
tab_stops->dump_tabs();
}
/*
* html_indent - creates an indent with indentation, ind, given
* a line length of linelength.
*/
html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength)
{
table = new html_table(op, linelength);
table->add_column(1, ind+pageoffset, linelength, 'L');
table->add_indent(pageoffset);
in = ind;
pg = pageoffset;
ll = linelength;
is_used = FALSE;
}
html_indent::~html_indent (void)
{
end();
delete table;
}
void html_indent::begin (int space)
{
if (! is_used) {
table->emit_table_header(space);
table->emit_col(1);
is_used = TRUE;
}
}
void html_indent::end (void)
{
if (is_used)
table->emit_finish_table();
is_used = FALSE;
}
/*
* get_reg - collects the registers as supplied during initialization.
*/
void html_indent::get_reg (int *ind, int *pageoffset, int *linelength)
{
*ind = in;
*pageoffset = pg;
*linelength = ll;
}

View File

@ -1,964 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc
*
* html-text.cc
*
* provide a troff like state machine interface which
* generates html text.
*/
/*
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 "driver.h"
#include "stringclass.h"
#include "cset.h"
#if !defined(TRUE)
# define TRUE (1==1)
#endif
#if !defined(FALSE)
# define FALSE (1==0)
#endif
#include "html-text.h"
// #define DEBUGGING
html_text::html_text (simple_output *op) :
stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE),
current_indentation(-1), pageoffset(-1), linelength(-1),
blank_para(TRUE), start_space(FALSE)
{
}
html_text::~html_text ()
{
flush_text();
}
#if defined(DEBUGGING)
static int debugStack = FALSE;
/*
* turnDebug - flip the debugStack boolean and return the new value.
*/
static int turnDebug (void)
{
debugStack = 1-debugStack;
return debugStack;
}
/*
* dump_stack_element - display an element of the html stack, p.
*/
void html_text::dump_stack_element (tag_definition *p)
{
fprintf(stderr, " | ");
switch (p->type) {
case P_TAG: if (p->indent == NULL) {
fprintf(stderr, "<P %s>", (char *)p->arg1); break;
} else {
fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
}
case I_TAG: fprintf(stderr, "<I>"); break;
case B_TAG: fprintf(stderr, "<B>"); break;
case SUB_TAG: fprintf(stderr, "<SUB>"); break;
case SUP_TAG: fprintf(stderr, "<SUP>"); break;
case TT_TAG: fprintf(stderr, "<TT>"); break;
case PRE_TAG: if (p->indent == NULL) {
fprintf(stderr, "<PRE>"); break;
} else {
fprintf(stderr, "<PRE [TABLE]>"); break;
}
case SMALL_TAG: fprintf(stderr, "<SMALL>"); break;
case BIG_TAG: fprintf(stderr, "<BIG>"); break;
case BREAK_TAG: fprintf(stderr, "<BREAK>"); break;
case COLOR_TAG: {
if (p->col.is_default())
fprintf(stderr, "<COLOR (default)>");
else {
unsigned int r, g, b;
p->col.get_rgb(&r, &g, &b);
fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
}
break;
}
default: fprintf(stderr, "unknown tag");
}
if (p->text_emitted)
fprintf(stderr, "[t] ");
}
/*
* dump_stack - debugging function only.
*/
void html_text::dump_stack (void)
{
if (debugStack) {
tag_definition *p = stackptr;
while (p != NULL) {
dump_stack_element(p);
p = p->next;
}
}
fprintf(stderr, "\n");
fflush(stderr);
}
#else
void html_text::dump_stack (void) {}
#endif
/*
* end_tag - shuts down the tag.
*/
void html_text::end_tag (tag_definition *t)
{
switch (t->type) {
case I_TAG: out->put_string("</i>"); break;
case B_TAG: out->put_string("</b>"); break;
case P_TAG: out->put_string("</p>");
if (t->indent != NULL) {
delete t->indent;
t->indent = NULL;
}
out->nl(); out->enable_newlines(FALSE);
blank_para = TRUE; break;
case SUB_TAG: out->put_string("</sub>"); break;
case SUP_TAG: out->put_string("</sup>"); break;
case TT_TAG: out->put_string("</tt>"); break;
case PRE_TAG: out->put_string("</pre>"); out->nl(); out->enable_newlines(TRUE);
blank_para = TRUE; break;
case SMALL_TAG: out->put_string("</small>"); break;
case BIG_TAG: out->put_string("</big>"); break;
case COLOR_TAG: out->put_string("</font>"); break;
default:
error("unrecognised tag");
}
}
/*
* issue_tag - writes out an html tag with argument.
*/
void html_text::issue_tag (char *tagname, char *arg)
{
if ((arg == 0) || (strlen(arg) == 0)) {
out->put_string(tagname);
out->put_string(">");
} else {
out->put_string(tagname);
out->put_string(" ");
out->put_string(arg);
out->put_string(">");
}
}
/*
* issue_color_begin - writes out an html color tag.
*/
void html_text::issue_color_begin (color *c)
{
unsigned int r, g, b;
char buf[6+1];
out->put_string("<font color=\"#");
if (c->is_default())
sprintf(buf, "000000");
else {
c->get_rgb(&r, &g, &b);
// we have to scale 0..0xFFFF to 0..0xFF
sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
}
out->put_string(buf);
out->put_string("\">");
}
/*
* start_tag - starts a tag.
*/
void html_text::start_tag (tag_definition *t)
{
switch (t->type) {
case I_TAG: issue_tag("<i", (char *)t->arg1); break;
case B_TAG: issue_tag("<b", (char *)t->arg1); break;
case P_TAG: if (t->indent == NULL) {
out->nl();
issue_tag("\n<p", (char *)t->arg1);
} else {
out->nl();
out->simple_comment("INDENTATION");
t->indent->begin(FALSE);
start_space = FALSE;
issue_tag("<p", (char *)t->arg1);
}
out->enable_newlines(TRUE); break;
case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break;
case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break;
case TT_TAG: issue_tag("<tt", (char *)t->arg1); break;
case PRE_TAG: if (t->indent != NULL) {
out->nl();
out->simple_comment("INDENTATION");
t->indent->begin(FALSE);
start_space = FALSE;
}
out->enable_newlines(TRUE);
out->nl(); issue_tag("<pre", (char *)t->arg1);
out->enable_newlines(FALSE); break;
case SMALL_TAG: issue_tag("<small", (char *)t->arg1); break;
case BIG_TAG: issue_tag("<big", (char *)t->arg1); break;
case BREAK_TAG: break;
case COLOR_TAG: issue_color_begin(&t->col); break;
default:
error("unrecognised tag");
}
}
/*
* flush_text - flushes html tags which are outstanding on the html stack.
*/
void html_text::flush_text (void)
{
int notext=TRUE;
tag_definition *p=stackptr;
while (stackptr != 0) {
notext = (notext && (! stackptr->text_emitted));
if (! notext) {
end_tag(stackptr);
}
p = stackptr;
stackptr = stackptr->next;
free(p);
}
lastptr = NULL;
}
/*
* is_present - returns TRUE if tag is already present on the stack.
*/
int html_text::is_present (HTML_TAG t)
{
tag_definition *p=stackptr;
while (p != NULL) {
if (t == p->type)
return TRUE;
p = p->next;
}
return FALSE;
}
extern void stop();
/*
* do_push - places, tag_definition, p, onto the stack
*/
void html_text::do_push (tag_definition *p)
{
HTML_TAG t = p->type;
#if defined(DEBUGGING)
if (t == PRE_TAG)
stop();
debugStack = TRUE;
fprintf(stderr, "\nentering do_push (");
dump_stack_element(p);
fprintf(stderr, ")\n");
dump_stack();
fprintf(stderr, ")\n");
fflush(stderr);
#endif
/*
* if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
*/
if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
/*
* store, p, at the end
*/
lastptr->next = p;
lastptr = p;
p->next = NULL;
} else {
p->next = stackptr;
if (stackptr == NULL)
lastptr = p;
stackptr = p;
}
#if defined(DEBUGGING)
dump_stack();
fprintf(stderr, "exiting do_push\n");
#endif
}
/*
* push_para - adds a new entry onto the html paragraph stack.
*/
void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
{
tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
p->type = t;
p->arg1 = arg;
p->text_emitted = FALSE;
p->indent = in;
if (t == PRE_TAG && is_present(PRE_TAG))
fatal("cannot have multiple PRE_TAGs");
do_push(p);
}
void html_text::push_para (HTML_TAG t)
{
push_para(t, (void *)"", NULL);
}
void html_text::push_para (color *c)
{
tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
p->type = COLOR_TAG;
p->arg1 = NULL;
p->col = *c;
p->text_emitted = FALSE;
p->indent = NULL;
do_push(p);
}
/*
* do_italic - changes to italic
*/
void html_text::do_italic (void)
{
if (! is_present(I_TAG))
push_para(I_TAG);
}
/*
* do_bold - changes to bold.
*/
void html_text::do_bold (void)
{
if (! is_present(B_TAG))
push_para(B_TAG);
}
/*
* do_tt - changes to teletype.
*/
void html_text::do_tt (void)
{
if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
push_para(TT_TAG);
}
/*
* do_pre - changes to preformated text.
*/
void html_text::do_pre (void)
{
done_tt();
if (is_present(P_TAG)) {
html_indent *i = remove_indent(P_TAG);
(void)done_para();
if (! is_present(PRE_TAG))
push_para(PRE_TAG, NULL, i);
} else if (! is_present(PRE_TAG))
push_para(PRE_TAG, NULL, NULL);
dump_stack();
}
/*
* is_in_pre - returns TRUE if we are currently within a preformatted
* <pre> block.
*/
int html_text::is_in_pre (void)
{
return is_present(PRE_TAG);
}
/*
* do_color - initiates a new color tag.
*/
void html_text::do_color (color *c)
{
shutdown(COLOR_TAG); // shutdown a previous color tag, if present
push_para(c);
}
/*
* done_color - shutdown an outstanding color tag, if it exists.
*/
void html_text::done_color (void)
{
shutdown(COLOR_TAG);
}
/*
* shutdown - shuts down an html tag.
*/
char *html_text::shutdown (HTML_TAG t)
{
char *arg=NULL;
if (is_present(t)) {
tag_definition *p =stackptr;
tag_definition *temp =NULL;
int notext =TRUE;
dump_stack();
while ((stackptr != NULL) && (stackptr->type != t)) {
notext = (notext && (! stackptr->text_emitted));
if (! notext) {
end_tag(stackptr);
}
/*
* pop tag
*/
p = stackptr;
stackptr = stackptr->next;
if (stackptr == NULL)
lastptr = NULL;
/*
* push tag onto temp stack
*/
p->next = temp;
temp = p;
}
/*
* and examine stackptr
*/
if ((stackptr != NULL) && (stackptr->type == t)) {
if (stackptr->text_emitted) {
end_tag(stackptr);
}
if (t == P_TAG) {
arg = (char *)stackptr->arg1;
}
p = stackptr;
stackptr = stackptr->next;
if (stackptr == NULL)
lastptr = NULL;
if (p->indent != NULL)
delete p->indent;
free(p);
}
/*
* and restore unaffected tags
*/
while (temp != NULL) {
if (temp->type == COLOR_TAG)
push_para(&temp->col);
else
push_para(temp->type, temp->arg1, temp->indent);
p = temp;
temp = temp->next;
free(p);
}
}
return arg;
}
/*
* done_bold - shuts downs a bold tag.
*/
void html_text::done_bold (void)
{
shutdown(B_TAG);
}
/*
* done_italic - shuts downs an italic tag.
*/
void html_text::done_italic (void)
{
shutdown(I_TAG);
}
/*
* done_sup - shuts downs a sup tag.
*/
void html_text::done_sup (void)
{
shutdown(SUP_TAG);
}
/*
* done_sub - shuts downs a sub tag.
*/
void html_text::done_sub (void)
{
shutdown(SUB_TAG);
}
/*
* done_tt - shuts downs a tt tag.
*/
void html_text::done_tt (void)
{
shutdown(TT_TAG);
}
/*
* done_pre - shuts downs a pre tag.
*/
void html_text::done_pre (void)
{
shutdown(PRE_TAG);
}
/*
* done_small - shuts downs a small tag.
*/
void html_text::done_small (void)
{
shutdown(SMALL_TAG);
}
/*
* done_big - shuts downs a big tag.
*/
void html_text::done_big (void)
{
shutdown(BIG_TAG);
}
/*
* check_emit_text - ensures that all previous tags have been emitted (in order)
* before the text is written.
*/
void html_text::check_emit_text (tag_definition *t)
{
if ((t != NULL) && (! t->text_emitted)) {
check_emit_text(t->next);
t->text_emitted = TRUE;
start_tag(t);
}
}
/*
* do_emittext - tells the class that text was written during the current tag.
*/
void html_text::do_emittext (const char *s, int length)
{
if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
do_para("");
if (is_present(BREAK_TAG)) {
int text = remove_break();
check_emit_text(stackptr);
if (text) {
if (is_present(PRE_TAG)) {
out->nl();
} else {
out->put_string("<br>").nl();
}
}
} else {
check_emit_text(stackptr);
}
out->put_string(s, length);
space_emitted = FALSE;
blank_para = FALSE;
}
/*
* do_para - starts a new paragraph
*/
void html_text::do_para (const char *arg, html_indent *in)
{
if (! is_present(P_TAG)) {
if (is_present(PRE_TAG)) {
html_indent *i = remove_indent(PRE_TAG);
done_pre();
if (i == in || in == NULL)
in = i;
else
delete i;
}
remove_sub_sup();
push_para(P_TAG, (void *)arg, in);
space_emitted = TRUE;
}
}
void html_text::do_para (const char *arg)
{
do_para(arg, NULL);
}
void html_text::do_para (simple_output *op, const char *arg1,
int indentation, int pageoffset, int linelength)
{
html_indent *indent;
if (indentation == 0)
indent = NULL;
else
indent = new html_indent(op, indentation, pageoffset, linelength);
do_para(arg1, indent);
}
/*
* done_para - shuts down a paragraph tag.
*/
char *html_text::done_para (void)
{
space_emitted = TRUE;
return shutdown(P_TAG);
}
/*
* remove_indent - returns the indent associated with, tag.
* The indent associated with tag is set to NULL.
*/
html_indent *html_text::remove_indent (HTML_TAG tag)
{
tag_definition *p=stackptr;
while (p != NULL) {
if (tag == p->type) {
html_indent *i = p->indent;
p->indent = NULL;
return i;
}
p = p->next;
}
return NULL;
}
/*
* do_space - issues an end of paragraph
*/
void html_text::do_space (void)
{
if (is_in_pre()) {
if (blank_para)
start_space = TRUE;
else {
do_emittext("", 0);
out->nl();
}
} else {
html_indent *i = remove_indent(P_TAG);
do_para(done_para(), i);
space_emitted = TRUE;
start_space = TRUE;
}
}
/*
* do_break - issue a break tag.
*/
void html_text::do_break (void)
{
if (! is_present(PRE_TAG)) {
if (emitted_text()) {
if (! is_present(BREAK_TAG)) {
push_para(BREAK_TAG);
}
}
}
space_emitted = TRUE;
}
/*
* do_newline - issue a newline providing that we are inside a <pre> tag.
*/
void html_text::do_newline (void)
{
if (is_present(PRE_TAG)) {
do_emittext("\n", 1);
space_emitted = TRUE;
}
}
/*
* emitted_text - returns FALSE if white space has just been written.
*/
int html_text::emitted_text (void)
{
return !space_emitted;
}
/*
* ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph.
*/
int html_text::ever_emitted_text (void)
{
return !blank_para;
}
/*
* starts_with_space - returns TRUE if we have start this paragraph with a .sp
*/
int html_text::starts_with_space (void)
{
return start_space;
}
/*
* emit_space - writes a space providing that text was written beforehand.
*/
void html_text::emit_space (void)
{
if (space_emitted) {
if (is_present(PRE_TAG)) {
do_emittext(" ", 1);
}
} else {
out->space_or_newline();
space_emitted = TRUE;
}
}
/*
* remove_def - removes a definition, t, from the stack.
*/
void html_text::remove_def (tag_definition *t)
{
tag_definition *p = stackptr;
tag_definition *l = 0;
tag_definition *q = 0;
while ((p != 0) && (p != t)) {
l = p;
p = p->next;
}
if ((p != 0) && (p == t)) {
if (p == stackptr) {
stackptr = stackptr->next;
if (stackptr == NULL)
lastptr = NULL;
q = stackptr;
} else if (l == 0) {
error("stack list pointers are wrong");
} else {
l->next = p->next;
q = p->next;
if (l->next == NULL)
lastptr = l;
}
free(p);
}
}
/*
* remove_tag - removes a tag from the stack.
*/
void html_text::remove_tag (HTML_TAG tag)
{
tag_definition *p = stackptr;
while ((p != 0) && (p->type != tag)) {
p = p->next;
}
if ((p != 0) && (p->type == tag))
remove_def(p);
}
/*
* remove_sub_sup - removes a sub or sup tag, should either exist on the stack.
*/
void html_text::remove_sub_sup (void)
{
if (is_present(SUB_TAG)) {
remove_tag(SUB_TAG);
}
if (is_present(SUP_TAG)) {
remove_tag(SUP_TAG);
}
if (is_present(PRE_TAG)) {
remove_tag(PRE_TAG);
}
}
/*
* remove_break - break tags are not balanced thus remove it once it has been emitted.
* It returns TRUE if text was emitted before the <br> was issued.
*/
int html_text::remove_break (void)
{
tag_definition *p = stackptr;
tag_definition *l = 0;
tag_definition *q = 0;
while ((p != 0) && (p->type != BREAK_TAG)) {
l = p;
p = p->next;
}
if ((p != 0) && (p->type == BREAK_TAG)) {
if (p == stackptr) {
stackptr = stackptr->next;
if (stackptr == NULL)
lastptr = NULL;
q = stackptr;
} else if (l == 0)
error("stack list pointers are wrong");
else {
l->next = p->next;
q = p->next;
if (l->next == NULL)
lastptr = l;
}
free(p);
}
/*
* now determine whether text was issued before <br>
*/
while (q != 0) {
if (q->text_emitted)
return TRUE;
else
q = q->next;
}
return FALSE;
}
/*
* remove_para_align - removes a paragraph which has a text
* argument. If the paragraph has no text
* argument then it is left alone.
*/
void html_text::remove_para_align (void)
{
if (is_present(P_TAG)) {
tag_definition *p=stackptr;
while (p != NULL) {
if (p->type == P_TAG && p->arg1 != NULL) {
html_indent *i = remove_indent(P_TAG);
done_para();
do_para("", i);
return;
}
p = p->next;
}
}
}
/*
* do_small - potentially inserts a <small> tag into the html stream.
* However we check for a <big> tag, if present then we terminate it.
* Otherwise a <small> tag is inserted.
*/
void html_text::do_small (void)
{
if (is_present(BIG_TAG))
done_big();
else
push_para(SMALL_TAG);
}
/*
* do_big - is the mirror image of do_small.
*/
void html_text::do_big (void)
{
if (is_present(SMALL_TAG))
done_small();
else
push_para(BIG_TAG);
}
/*
* do_sup - save a superscript tag on the stack of tags.
*/
void html_text::do_sup (void)
{
push_para(SUP_TAG);
}
/*
* do_sub - save a subscript tag on the stack of tags.
*/
void html_text::do_sub (void)
{
push_para(SUB_TAG);
}

View File

@ -1,356 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote output.cc
* but it owes a huge amount of ideas and raw code from
* James Clark (jjc@jclark.com) grops/ps.cc.
*
* output.cc
*
* provide the simple low level output routines needed by html.cc
*/
/*
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 "driver.h"
#include "stringclass.h"
#include "cset.h"
#include <time.h>
#include "html.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#undef DEBUGGING
// #define DEBUGGING
#if !defined(TRUE)
# define TRUE (1==1)
#endif
#if !defined(FALSE)
# define FALSE (1==0)
#endif
#if defined(DEBUGGING)
# define FPUTC(X,Y) do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
# define FPUTS(X,Y) do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
# define PUTC(X,Y) do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
#else
# define FPUTC(X,Y) do { fputc((X),(Y)); } while (0)
# define FPUTS(X,Y) do { fputs((X),(Y)); } while (0)
# define PUTC(X,Y) do { putc((X),(Y)); } while (0)
#endif
/*
* word - initialise a word and set next to NULL
*/
word::word (const char *w, int n)
: next(0)
{
s = (char *)malloc(n+1);
strncpy(s, w, n);
s[n] = (char)0;
}
/*
* destroy word and the string copy.
*/
word::~word ()
{
free(s);
}
/*
* word_list - create an empty word list.
*/
word_list::word_list ()
: length(0), head(0), tail(0)
{
}
/*
* flush - flush a word list to a FILE, f, and return the
* length of the buffered string.
*/
int word_list::flush (FILE *f)
{
word *t;
int len=length;
while (head != 0) {
t = head;
head = head->next;
FPUTS(t->s, f);
delete t;
}
head = 0;
tail = 0;
length = 0;
#if defined(DEBUGGING)
fflush(f); // just for testing
#endif
return( len );
}
/*
* add_word - adds a word to the outstanding word list.
*/
void word_list::add_word (const char *s, int n)
{
if (head == 0) {
head = new word(s, n);
tail = head;
} else {
tail->next = new word(s, n);
tail = tail->next;
}
length += n;
}
/*
* get_length - returns the number of characters buffered
*/
int word_list::get_length (void)
{
return( length );
}
/*
* the classes and methods for simple_output manipulation
*/
simple_output::simple_output(FILE *f, int n)
: fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0)
{
}
simple_output &simple_output::set_file(FILE *f)
{
if (fp)
fflush(fp);
fp = f;
return *this;
}
simple_output &simple_output::copy_file(FILE *infp)
{
int c;
while ((c = getc(infp)) != EOF)
PUTC(c, fp);
return *this;
}
simple_output &simple_output::end_line()
{
flush_last_word();
if (col != 0) {
PUTC('\n', fp);
col = 0;
}
return *this;
}
simple_output &simple_output::special(const char *s)
{
return *this;
}
simple_output &simple_output::simple_comment(const char *s)
{
flush_last_word();
if (col != 0)
PUTC('\n', fp);
FPUTS("<!-- ", fp);
FPUTS(s, fp);
FPUTS(" -->\n", fp);
col = 0;
return *this;
}
simple_output &simple_output::begin_comment(const char *s)
{
flush_last_word();
if (col != 0)
PUTC('\n', fp);
col = 0;
put_string("<!--");
space_or_newline();
last_word.add_word(s, strlen(s));
return *this;
}
simple_output &simple_output::end_comment()
{
flush_last_word();
space_or_newline();
put_string("-->").nl();
return *this;
}
/*
* check_newline - checks to see whether we are able to issue
* a newline and that one is needed.
*/
simple_output &simple_output::check_newline(int n)
{
if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
FPUTC('\n', fp);
col = last_word.flush(fp);
}
return *this;
}
/*
* space_or_newline - will emit a newline or a space later on
* depending upon the current column.
*/
simple_output &simple_output::space_or_newline (void)
{
if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
FPUTC('\n', fp);
if (last_word.get_length() > 0) {
col = last_word.flush(fp);
} else {
col = 0;
}
} else {
if (last_word.get_length() != 0) {
if (col > 0) {
FPUTC(' ', fp);
col++;
}
col += last_word.flush(fp);
}
}
return *this;
}
/*
* nl - writes a newline providing that we
* are not in the first column.
*/
simple_output &simple_output::nl (void)
{
space_or_newline();
col += last_word.flush(fp);
if (col != 0) {
FPUTC('\n', fp);
col = 0;
}
return *this ;
}
simple_output &simple_output::set_fixed_point(int n)
{
assert(n >= 0 && n <= 10);
fixed_point = n;
return *this;
}
simple_output &simple_output::put_raw_char(char c)
{
col += last_word.flush(fp);
PUTC(c, fp);
col++;
return *this;
}
simple_output &simple_output::put_string(const char *s, int n)
{
last_word.add_word(s, n);
return *this;
}
simple_output &simple_output::put_string(const char *s)
{
last_word.add_word(s, strlen(s));
return *this;
}
simple_output &simple_output::put_string(const string &s)
{
last_word.add_word(s.contents(), s.length());
return *this;
}
simple_output &simple_output::put_number(int n)
{
char buf[1 + INT_DIGITS + 1];
sprintf(buf, "%d", n);
put_string(buf);
return *this;
}
simple_output &simple_output::put_float(double d)
{
char buf[128];
sprintf(buf, "%.4f", d);
put_string(buf);
return *this;
}
simple_output &simple_output::enable_newlines (int auto_newlines)
{
check_newline(0);
newlines = auto_newlines;
check_newline(0);
return *this;
}
/*
* flush_last_word - flushes the last word and adjusts the
* col position. It will insert a newline
* before the last word if allowed and if
* necessary.
*/
void simple_output::flush_last_word (void)
{
int len=last_word.get_length();
if (len > 0) {
if (newlines) {
if (col + len + 1 > max_line_length) {
FPUTS("\n", fp);
col = 0;
} else {
FPUTS(" ", fp);
col++;
}
len += last_word.flush(fp);
} else {
FPUTS(" ", fp);
col++;
col += last_word.flush(fp);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,740 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Francisco Andrés Verdú <pandres@dragonet.es> with many ideas
taken from the other groff drivers.
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
- Add X command to include bitmaps
*/
#define _GNU_SOURCE
#include "driver.h"
#include "lbp.h"
#include "charset.h"
#include "paper.h"
#include "nonposix.h"
extern "C" const char *Version_string;
static int user_papersize = -1; // papersize
static int orientation = -1; // orientation
static double user_paperlength = 0; // Custom Paper size
static double user_paperwidth = 0;
static int ncopies = 1; // Number of copies
#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em
static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR;
static int set_papersize(const char *paperformat);
class lbp_font : public font {
public:
~lbp_font();
void handle_unknown_font_command(const char *command, const char *arg,
const char *filename, int lineno);
static lbp_font *load_lbp_font(const char *);
char *lbpname;
char is_scalable;
private:
lbp_font(const char *);
};
class lbp_printer : public printer {
public:
lbp_printer(int, double, double);
~lbp_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
void begin_page(int);
void end_page(int page_length);
font *make_font(const char *);
void end_of_line();
private:
void set_line_thickness(int size,const environment *env);
void vdmstart();
void vdmflush(); // the name vdmend was already used in lbp.h
void setfillmode(int mode);
void polygon( int hpos,int vpos,int np,int *p);
char *font_name(const lbp_font *f, const int siz);
int fill_pattern;
int fill_mode;
int cur_hpos;
int cur_vpos;
lbp_font *cur_font;
int cur_size;
unsigned short cur_symbol_set;
int line_thickness;
int req_linethickness; // requested line thickness
int papersize;
int paperlength; // custom paper size
int paperwidth;
};
// Compatibility section.
//
// Here we define some functions not present in some of the targets
// platforms
#ifndef HAVE_STRSEP
// Solaris 8 doesn't have the strsep function
static char *strsep(char **pcadena, const char *delim)
{
char *p;
p = strtok(*pcadena, delim);
*pcadena = strtok(NULL, delim);
return p;
}
#endif
lbp_font::lbp_font(const char *nm)
: font(nm)
{
}
lbp_font::~lbp_font()
{
}
lbp_font *lbp_font::load_lbp_font(const char *s)
{
lbp_font *f = new lbp_font(s);
f->lbpname = NULL;
f->is_scalable = 1; // Default is that fonts are scalable
if (!f->load()) {
delete f;
return 0;
}
return f;
}
void lbp_font::handle_unknown_font_command(const char *command,
const char *arg,
const char *filename, int lineno)
{
if (strcmp(command, "lbpname") == 0) {
if (arg == 0)
fatal_with_file_and_line(filename, lineno,
"`%1' command requires an argument",
command);
this->lbpname = new char[strlen(arg) + 1];
strcpy(this->lbpname, arg);
// we recognize bitmapped fonts by the first character of its name
if (arg[0] == 'N')
this->is_scalable = 0;
// fprintf(stderr, "Loading font \"%s\" \n", arg);
}
// fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n",
// command, arg, filename, lineno);
}
static void wp54charset()
{
unsigned int i;
lbpputs("\033[714;100;29;0;32;120.}");
for (i = 0; i < sizeof(symset); i++)
lbpputc(symset[i]);
lbpputs("\033[100;0 D");
return;
}
lbp_printer::lbp_printer(int ps, double pw, double pl)
: fill_pattern(1),
fill_mode(0),
cur_hpos(-1),
cur_font(0),
cur_size(0),
cur_symbol_set(0),
req_linethickness(-1)
{
#ifdef SET_BINARY
SET_BINARY(fileno(stdout));
#endif
lbpinit(stdout);
lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
wp54charset(); // Define the new symbol set
lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
// Paper size handling
if (orientation < 0)
orientation = 0; // Default orientation is portrait
papersize = 14; // Default paper size is A4
if (font::papersize) {
papersize = set_papersize(font::papersize);
paperlength = font::paperlength;
paperwidth = font::paperwidth;
}
if (ps >= 0) {
papersize = ps;
paperlength = int(pl * font::res + 0.5);
paperwidth = int(pw * font::res + 0.5);
}
if (papersize < 80) // standard paper
lbpprintf("\033[%dp", (papersize | orientation));
else // Custom paper
lbpprintf("\033[%d;%d;%dp", (papersize | orientation),
paperlength, paperwidth);
// Number of copies
lbpprintf("\033[%dv\n", ncopies);
lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
lbpmoveabs(0, 0);
lbpputs("\033[0t\033[2t");
lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
// Secondary symbol set IBMR1
cur_symbol_set = 0;
}
lbp_printer::~lbp_printer()
{
lbpputs("\033P1y\033\\");
lbpputs("\033c\033<");
}
void lbp_printer::begin_page(int)
{
}
void lbp_printer::end_page(int)
{
if (vdminited())
vdmflush();
lbpputc('\f');
cur_hpos = -1;
}
void lbp_printer::end_of_line()
{
cur_hpos = -1; // force absolute motion
}
char *lbp_printer::font_name(const lbp_font *f, const int siz)
{
static char bfont_name[255]; // The resulting font name
char type, // Italic, Roman, Bold
ori, // Normal or Rotated
*nam; // The font name without other data.
int cpi; // The font size in characters per inch
// (bitmapped fonts are monospaced).
/* Bitmap font selection is ugly in this printer, so don't expect
this function to be elegant. */
bfont_name[0] = 0x00;
if (orientation) // Landscape
ori = 'R';
else // Portrait
ori = 'N';
type = f->lbpname[strlen(f->lbpname) - 1];
nam = new char[strlen(f->lbpname) - 2];
strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2);
nam[strlen(f->lbpname) - 2] = 0x00;
// fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori);
/* Since these fonts are available only at certain sizes,
10 and 17 cpi for courier, 12 and 17 cpi for elite,
we adjust the resulting size. */
cpi = 17;
// Fortunately there are only two bitmapped fonts shipped with the printer.
if (!strcasecmp(nam, "courier")) {
// Courier font
if (siz >= 12)
cpi = 10;
else cpi = 17;
}
if (!strcasecmp(nam, "elite")) {
if (siz >= 10)
cpi = 12;
else cpi = 17;
}
// Now that we have all the data, let's generate the font name.
if ((type != 'B') && (type != 'I')) // Roman font
sprintf(bfont_name, "%c%s%d", ori, nam, cpi);
else
sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type);
return bfont_name;
}
void lbp_printer::set_char(int index, font *f, const environment *env,
int w, const char *name)
{
int code = f->get_code(index);
unsigned char ch = code & 0xff;
unsigned short symbol_set = code >> 8;
if (f != cur_font) {
lbp_font *psf = (lbp_font *)f;
// fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size);
if (psf->is_scalable) {
// Scalable font selection is different from bitmaped
lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname,
(int)((env->size * font::res) / 72));
}
else
// bitmapped font
lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size));
lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
cur_font = psf;
cur_symbol_set = 0;
// Update the line thickness if needed
if ((req_linethickness < 0 ) && (env->size != cur_size))
set_line_thickness(req_linethickness,env);
cur_size = env->size;
}
if (symbol_set != cur_symbol_set) {
if (cur_symbol_set == 3)
// if current symbol set is Symbol we must restore the font
lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname,
(int)((env->size * font::res) / 72));
switch (symbol_set) {
case 0:
lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
break;
case 1:
lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
break;
case 2:
lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
break;
case 3:
lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",
(int)((env->size * font::res) / 72));
lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
break;
case 4:
lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
break;
}
cur_symbol_set = symbol_set;
}
if (env->size != cur_size) {
if (!cur_font->is_scalable)
lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size));
else
lbpprintf("\033[%d C", (int)((env->size * font::res) / 72));
cur_size = env->size;
// Update the line thickness if needed
if (req_linethickness < 0 )
set_line_thickness(req_linethickness,env);
}
if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) {
// lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos);
lbpmoveabs(env->hpos - 64, env->vpos - 64);
cur_vpos = env->vpos;
cur_hpos = env->hpos;
}
if ((ch & 0x7F) < 32)
lbpputs("\033[1.v");
lbpputc(ch);
cur_hpos += w;
}
void lbp_printer::vdmstart()
{
FILE *f;
static int changed_origin = 0;
errno = 0;
f = tmpfile();
// f = fopen("/tmp/gtmp","w+");
if (f == NULL)
perror("Opening temporary file");
vdminit(f);
if (!changed_origin) { // we should change the origin only one time
changed_origin = 1;
vdmorigin(-63, 0);
}
vdmlinewidth(line_thickness);
}
void
lbp_printer::vdmflush()
{
char buffer[1024];
int bytes_read = 1;
vdmend();
fflush(lbpoutput);
/* let's copy the vdm code to the output */
rewind(vdmoutput);
do {
bytes_read = fread(buffer, 1, sizeof(buffer), vdmoutput);
bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput);
} while (bytes_read == sizeof(buffer));
fclose(vdmoutput); // This will also delete the file,
// since it is created by tmpfile()
vdmoutput = NULL;
}
inline void lbp_printer::setfillmode(int mode)
{
if (mode != fill_mode) {
if (mode != 1)
vdmsetfillmode(mode, 1, 0);
else
vdmsetfillmode(mode, 1, 1); // To get black we must use white
// inverted
fill_mode = mode;
}
}
inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p)
{
int *points, i;
points = new int[np + 2];
points[0] = hpos;
points[1] = vpos;
// fprintf(stderr, "Poligon (%d,%d) ", points[0], points[1]);
for (i = 0; i < np; i++)
points[i + 2] = p[i];
// for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]);
// fprintf(stderr, "\n");
vdmpolygon((np /2) + 1, points);
}
inline void lbp_printer::set_line_thickness(int size,const environment *env)
{
if (size == 0)
line_thickness = 1;
else {
if (size < 0)
// line_thickness =
// (env->size * (font::res/72)) * (linewidth_factor/1000)
// we ought to check for overflow
line_thickness =
env->size * linewidth_factor * font::res / 72000;
else // size > 0
line_thickness = size;
} // else from if (size == 0)
if (line_thickness < 1)
line_thickness = 1;
if (vdminited())
vdmlinewidth(line_thickness);
req_linethickness = size; // an size requested
/* fprintf(stderr, "thickness: %d == %d, size %d, %d \n",
size, line_thickness, env->size,req_linethickness); */
return;
}; // lbp_printer::set_line_thickness
void lbp_printer::draw(int code, int *p, int np, const environment *env)
{
if ((req_linethickness < 0 ) && (env->size != cur_size))
set_line_thickness(req_linethickness,env);
switch (code) {
case 't':
if (np == 0)
line_thickness = 1;
else { // troff gratuitously adds an extra 0
if (np != 1 && np != 2) {
error("0 or 1 argument required for thickness");
break;
};
set_line_thickness(p[0],env);
};
break;
case 'l': // Line
if (np != 2) {
error("2 arguments required for line");
break;
}
if (!vdminited())
vdmstart();
vdmline(env->hpos, env->vpos, p[0], p[1]);
/* fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n",
env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],
env->vpos -64 + p[1], env->size, line_thickness);*/
break;
case 'R': // Rule
if (np != 2) {
error("2 arguments required for Rule");
break;
}
if (vdminited()) {
setfillmode(fill_pattern); // Solid Rule
vdmrectangle(env->hpos, env->vpos, p[0], p[1]);
}
else {
lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]);
cur_vpos = p[1];
cur_hpos = p[0];
}
// fprintf(stderr, "\nrule: thickness %d == %d\n",
// env->size, line_thickness);
break;
case 'P': // Filled Polygon
if (!vdminited())
vdmstart();
setfillmode(fill_pattern);
polygon(env->hpos, env->vpos, np, p);
break;
case 'p': // Empty Polygon
if (!vdminited())
vdmstart();
setfillmode(0);
polygon(env->hpos, env->vpos, np, p);
break;
case 'C': // Filled Circle
if (!vdminited())
vdmstart();
// fprintf(stderr, "Circle (%d,%d) Fill %d\n",
// env->hpos, env->vpos, fill_pattern);
setfillmode(fill_pattern);
vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
break;
case 'c': // Empty Circle
if (!vdminited())
vdmstart();
setfillmode(0);
vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
break;
case 'E': // Filled Ellipse
if (!vdminited())
vdmstart();
setfillmode(fill_pattern);
vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
break;
case 'e': // Empty Ellipse
if (!vdminited())
vdmstart();
setfillmode(0);
vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
break;
case 'a': // Arc
if (!vdminited())
vdmstart();
setfillmode(0);
// VDM draws arcs clockwise and pic counterclockwise
// We must compensate for that, exchanging the starting and
// ending points
vdmvarc(env->hpos + p[0], env->vpos+p[1],
int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))),
p[2], p[3],
(-p[0]), (-p[1]), 1, 2);
break;
case '~': // Spline
if (!vdminited())
vdmstart();
setfillmode(0);
vdmspline(np/2, env->hpos, env->vpos, p);
break;
case 'f':
if (np != 1 && np != 2) {
error("1 argument required for fill");
break;
}
// fprintf(stderr, "Fill %d\n", p[0]);
if ((p[0] == 1) || (p[0] >= 1000)) { // Black
fill_pattern = 1;
break;
}
if (p[0] == 0) { // White
fill_pattern = 0;
break;
}
if ((p[0] > 1) && (p[0] < 1000))
{
if (p[0] >= 990) fill_pattern = -23;
else if (p[0] >= 700) fill_pattern = -28;
else if (p[0] >= 500) fill_pattern = -27;
else if (p[0] >= 400) fill_pattern = -26;
else if (p[0] >= 300) fill_pattern = -25;
else if (p[0] >= 200) fill_pattern = -22;
else if (p[0] >= 100) fill_pattern = -24;
else fill_pattern = -21;
}
break;
case 'F':
// not implemented yet
break;
default:
error("unrecognised drawing command `%1'", char(code));
break;
}
return;
}
font *lbp_printer::make_font(const char *nm)
{
return lbp_font::load_lbp_font(nm);
}
printer *make_printer()
{
return new lbp_printer(user_papersize, user_paperwidth, user_paperlength);
}
static struct {
const char *name;
int code;
} lbp_papersizes[] =
{{ "A4", 14 },
{ "letter", 30 },
{ "legal", 32 },
{ "executive", 40 },
};
static int set_papersize(const char *paperformat)
{
unsigned int i;
// First test for a standard (i.e. supported directly by the printer)
// paper size
for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++)
{
if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0)
return lbp_papersizes[i].code;
}
// Otherwise, we assume a custom paper size
return 82;
}
static void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno)
{
// orientation command
if (strcasecmp(command, "orientation") == 0) {
// We give priority to command line options
if (orientation > 0)
return;
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`orientation' command requires an argument");
else {
if (strcasecmp(arg, "portrait") == 0)
orientation = 0;
else {
if (strcasecmp(arg, "landscape") == 0)
orientation = 1;
else
error_with_file_and_line(filename, lineno,
"invalid argument to `orientation' command");
}
}
}
}
static struct option long_options[] = {
{ "orientation", required_argument, NULL, 'o' },
{ "version", no_argument, NULL, 'v' },
{ "copies", required_argument, NULL, 'c' },
{ "landscape", no_argument, NULL, 'l' },
{ "papersize", required_argument, NULL, 'p' },
{ "linewidth", required_argument, NULL, 'w' },
{ "fontdir", required_argument, NULL, 'F' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, 0, 0 }
};
static void usage(FILE *stream)
{
fprintf(stream,
"usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or]\n"
" [-w width] [files ...]\n"
"\n"
" -o --orientation=[portrait|landscape]\n"
" -v --version\n"
" -c --copies=numcopies\n"
" -l --landscape\n"
" -p --papersize=paper_size\n"
" -w --linewidth=width\n"
" -F --fontdir=dir\n"
" -h --help\n",
program_name);
}
int main(int argc, char **argv)
{
if (program_name == NULL)
program_name = strsave(argv[0]);
font::set_unknown_desc_command_handler(handle_unknown_desc_command);
// command line parsing
int c = 0;
int option_index = 0;
while (c >= 0) {
c = getopt_long (argc, argv, "F:p:lvo:c:hw:",
long_options, &option_index);
switch (c) {
case 'F':
font::command_line_font_dir(optarg);
break;
case 'p':
{
const char *s;
if (!font::scan_papersize(optarg, &s,
&user_paperlength, &user_paperwidth))
error("invalid paper size `%1' ignored", optarg);
else
user_papersize = set_papersize(s);
break;
}
case 'l':
orientation = 1;
break;
case 'v':
printf("GNU grolbp (groff) version %s\n", Version_string);
exit(0);
break;
case 'o':
if (strcasecmp(optarg, "portrait") == 0)
orientation = 0;
else {
if (strcasecmp(optarg, "landscape") == 0)
orientation = 1;
else
error("unknown orientation '%1'", optarg);
};
break;
case 'c':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if ((n <= 0) && (ptr == optarg))
error("argument for -c must be a positive integer");
else if (n <= 0 || n > 32767)
error("out of range argument for -c");
else
ncopies = unsigned(n);
break;
}
case 'w':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if (n == 0 && ptr == optarg)
error("argument for -w must be a non-negative integer");
else if (n < 0 || n > INT_MAX)
error("out of range argument for -w");
else
linewidth_factor = int(n);
break;
}
case 'h':
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
}
}
if (optind >= argc)
do_file("-");
while (optind < argc)
do_file(argv[optind++]);
lbpputs("\033c\033<");
delete pr;
return 0;
}

View File

@ -1,708 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1994, 2000, 2001, 2002 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
option to use beziers for circle/ellipse/arc
option to use lines for spline (for LJ3)
left/top offset registration
output bin selection option
paper source option
output non-integer parameters using fixed point numbers
X command to insert contents of file
X command to specify inline escape sequence (how to specify unprintable chars?)
X command to include bitmap graphics
*/
#include "driver.h"
#include "nonposix.h"
extern "C" const char *Version_string;
static struct {
const char *name;
int code;
// at 300dpi
int x_offset_portrait;
int x_offset_landscape;
} paper_table[] = {
{ "letter", 2, 75, 60 },
{ "legal", 3, 75, 60 },
{ "executive", 1, 75, 60 },
{ "a4", 26, 71, 59 },
{ "com10", 81, 75, 60 },
{ "monarch", 80, 75, 60 },
{ "c5", 91, 71, 59 },
{ "b5", 100, 71, 59 },
{ "dl", 90, 71, 59 },
};
static int user_paper_size = -1;
static int landscape_flag = 0;
static int duplex_flag = 0;
// An upper limit on the paper size in centipoints,
// used for setting HPGL picture frame.
#define MAX_PAPER_WIDTH (12*720)
#define MAX_PAPER_HEIGHT (17*720)
// Dotted lines that are thinner than this don't work right.
#define MIN_DOT_PEN_WIDTH .351
#ifndef DEFAULT_LINE_WIDTH_FACTOR
// in ems/1000
#define DEFAULT_LINE_WIDTH_FACTOR 40
#endif
const int DEFAULT_HPGL_UNITS = 1016;
int line_width_factor = DEFAULT_LINE_WIDTH_FACTOR;
unsigned ncopies = 0; // 0 means don't send ncopies command
static int lookup_paper_size(const char *);
class lj4_font : public font {
public:
~lj4_font();
void handle_unknown_font_command(const char *command, const char *arg,
const char *filename, int lineno);
static lj4_font *load_lj4_font(const char *);
int weight;
int style;
int proportional;
int typeface;
private:
lj4_font(const char *);
};
lj4_font::lj4_font(const char *nm)
: font(nm), weight(0), style(0), proportional(0), typeface(0)
{
}
lj4_font::~lj4_font()
{
}
lj4_font *lj4_font::load_lj4_font(const char *s)
{
lj4_font *f = new lj4_font(s);
if (!f->load()) {
delete f;
return 0;
}
return f;
}
static struct {
const char *s;
int lj4_font::*ptr;
int min;
int max;
} command_table[] = {
{ "pclweight", &lj4_font::weight, -7, 7 },
{ "pclstyle", &lj4_font::style, 0, 32767 },
{ "pclproportional", &lj4_font::proportional, 0, 1 },
{ "pcltypeface", &lj4_font::typeface, 0, 65535 },
};
void lj4_font::handle_unknown_font_command(const char *command,
const char *arg,
const char *filename, int lineno)
{
for (unsigned int i = 0;
i < sizeof(command_table)/sizeof(command_table[0]); i++) {
if (strcmp(command, command_table[i].s) == 0) {
if (arg == 0)
fatal_with_file_and_line(filename, lineno,
"`%1' command requires an argument",
command);
char *ptr;
long n = strtol(arg, &ptr, 10);
if (n == 0 && ptr == arg)
fatal_with_file_and_line(filename, lineno,
"`%1' command requires numeric argument",
command);
if (n < command_table[i].min) {
error_with_file_and_line(filename, lineno,
"argument for `%1' command must not be less than %2",
command, command_table[i].min);
n = command_table[i].min;
}
else if (n > command_table[i].max) {
error_with_file_and_line(filename, lineno,
"argument for `%1' command must not be greater than %2",
command, command_table[i].max);
n = command_table[i].max;
}
this->*command_table[i].ptr = int(n);
break;
}
}
}
class lj4_printer : public printer {
public:
lj4_printer(int);
~lj4_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
void begin_page(int);
void end_page(int page_length);
font *make_font(const char *);
void end_of_line();
private:
void set_line_thickness(int size, int dot = 0);
void hpgl_init();
void hpgl_start();
void hpgl_end();
int moveto(int hpos, int vpos);
int moveto1(int hpos, int vpos);
int cur_hpos;
int cur_vpos;
lj4_font *cur_font;
int cur_size;
unsigned short cur_symbol_set;
int x_offset;
int line_thickness;
double pen_width;
double hpgl_scale;
int hpgl_inited;
int paper_size;
};
inline
int lj4_printer::moveto(int hpos, int vpos)
{
if (cur_hpos != hpos || cur_vpos != vpos || cur_hpos < 0)
return moveto1(hpos, vpos);
else
return 1;
}
inline
void lj4_printer::hpgl_start()
{
fputs("\033%1B", stdout);
}
inline
void lj4_printer::hpgl_end()
{
fputs(";\033%0A", stdout);
}
lj4_printer::lj4_printer(int ps)
: cur_hpos(-1),
cur_font(0),
cur_size(0),
cur_symbol_set(0),
line_thickness(-1),
pen_width(-1.0),
hpgl_inited(0)
{
if (7200 % font::res != 0)
fatal("invalid resolution %1: resolution must be a factor of 7200",
font::res);
fputs("\033E", stdout); // reset
if (font::res != 300)
printf("\033&u%dD", font::res); // unit of measure
if (ncopies > 0)
printf("\033&l%uX", ncopies);
paper_size = 0; // default to letter
if (font::papersize) {
int n = lookup_paper_size(font::papersize);
if (n < 0)
error("unknown paper size `%1'", font::papersize);
else
paper_size = n;
}
if (ps >= 0)
paper_size = ps;
printf("\033&l%dA" // paper size
"\033&l%dO" // orientation
"\033&l0E", // no top margin
paper_table[paper_size].code,
landscape_flag != 0);
if (landscape_flag)
x_offset = paper_table[paper_size].x_offset_landscape;
else
x_offset = paper_table[paper_size].x_offset_portrait;
x_offset = (x_offset * font::res) / 300;
if (duplex_flag)
printf("\033&l%dS", duplex_flag);
}
lj4_printer::~lj4_printer()
{
fputs("\033E", stdout);
}
void lj4_printer::begin_page(int)
{
}
void lj4_printer::end_page(int)
{
putchar('\f');
cur_hpos = -1;
}
void lj4_printer::end_of_line()
{
cur_hpos = -1; // force absolute motion
}
inline
int is_unprintable(unsigned char c)
{
return c < 32 && (c == 0 || (7 <= c && c <= 15) || c == 27);
}
void lj4_printer::set_char(int index, font *f, const environment *env,
int w, const char *name)
{
int code = f->get_code(index);
unsigned char ch = code & 0xff;
unsigned short symbol_set = code >> 8;
if (symbol_set != cur_symbol_set) {
printf("\033(%d%c", symbol_set/32, (symbol_set & 31) + 64);
cur_symbol_set = symbol_set;
}
if (f != cur_font) {
lj4_font *psf = (lj4_font *)f;
// FIXME only output those that are needed
printf("\033(s%dp%ds%db%dT",
psf->proportional,
psf->style,
psf->weight,
psf->typeface);
if (!psf->proportional || !cur_font || !cur_font->proportional)
cur_size = 0;
cur_font = psf;
}
if (env->size != cur_size) {
if (cur_font->proportional) {
static const char *quarters[] = { "", ".25", ".5", ".75" };
printf("\033(s%d%sV", env->size/4, quarters[env->size & 3]);
}
else {
double pitch = double(font::res)/w;
// PCL uses the next largest pitch, so round it down.
pitch = floor(pitch*100.0)/100.0;
printf("\033(s%.2fH", pitch);
}
cur_size = env->size;
}
if (!moveto(env->hpos, env->vpos))
return;
if (is_unprintable(ch))
fputs("\033&p1X", stdout);
putchar(ch);
cur_hpos += w;
}
int lj4_printer::moveto1(int hpos, int vpos)
{
if (hpos < x_offset || vpos < 0)
return 0;
fputs("\033*p", stdout);
if (cur_hpos < 0)
printf("%dx%dY", hpos - x_offset, vpos);
else {
if (cur_hpos != hpos)
printf("%s%d%c", hpos > cur_hpos ? "+" : "",
hpos - cur_hpos, vpos == cur_vpos ? 'X' : 'x');
if (cur_vpos != vpos)
printf("%s%dY", vpos > cur_vpos ? "+" : "", vpos - cur_vpos);
}
cur_hpos = hpos;
cur_vpos = vpos;
return 1;
}
void lj4_printer::draw(int code, int *p, int np, const environment *env)
{
switch (code) {
case 'R':
{
if (np != 2) {
error("2 arguments required for rule");
break;
}
int hpos = env->hpos;
int vpos = env->vpos;
int hsize = p[0];
int vsize = p[1];
if (hsize < 0) {
hpos += hsize;
hsize = -hsize;
}
if (vsize < 0) {
vpos += vsize;
vsize = -vsize;
}
if (!moveto(hpos, vpos))
return;
printf("\033*c%da%db0P", hsize, vsize);
break;
}
case 'l':
if (np != 2) {
error("2 arguments required for line");
break;
}
hpgl_init();
if (!moveto(env->hpos, env->vpos))
return;
hpgl_start();
set_line_thickness(env->size, p[0] == 0 && p[1] == 0);
printf("PD%d,%d", p[0], p[1]);
hpgl_end();
break;
case 'p':
case 'P':
{
if (np & 1) {
error("even number of arguments required for polygon");
break;
}
if (np == 0) {
error("no arguments for polygon");
break;
}
hpgl_init();
if (!moveto(env->hpos, env->vpos))
return;
hpgl_start();
if (code == 'p')
set_line_thickness(env->size);
printf("PMPD%d", p[0]);
for (int i = 1; i < np; i++)
printf(",%d", p[i]);
printf("PM2%cP", code == 'p' ? 'E' : 'F');
hpgl_end();
break;
}
case '~':
{
if (np & 1) {
error("even number of arguments required for spline");
break;
}
if (np == 0) {
error("no arguments for spline");
break;
}
hpgl_init();
if (!moveto(env->hpos, env->vpos))
return;
hpgl_start();
set_line_thickness(env->size);
printf("PD%d,%d", p[0]/2, p[1]/2);
const int tnum = 2;
const int tden = 3;
if (np > 2) {
fputs("BR", stdout);
for (int i = 0; i < np - 2; i += 2) {
if (i != 0)
putchar(',');
printf("%d,%d,%d,%d,%d,%d",
(p[i]*tnum)/(2*tden),
(p[i + 1]*tnum)/(2*tden),
p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden),
p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden),
(p[i] - p[i]/2) + p[i + 2]/2,
(p[i + 1] - p[i + 1]/2) + p[i + 3]/2);
}
}
printf("PR%d,%d", p[np - 2] - p[np - 2]/2, p[np - 1] - p[np - 1]/2);
hpgl_end();
break;
}
case 'c':
case 'C':
// troff adds an extra argument to C
if (np != 1 && !(code == 'C' && np == 2)) {
error("1 argument required for circle");
break;
}
hpgl_init();
if (!moveto(env->hpos + p[0]/2, env->vpos))
return;
hpgl_start();
if (code == 'c') {
set_line_thickness(env->size);
printf("CI%d", p[0]/2);
}
else
printf("WG%d,0,360", p[0]/2);
hpgl_end();
break;
case 'e':
case 'E':
if (np != 2) {
error("2 arguments required for ellipse");
break;
}
hpgl_init();
if (!moveto(env->hpos + p[0]/2, env->vpos))
return;
hpgl_start();
printf("SC0,%.4f,0,-%.4f,2", hpgl_scale * double(p[0])/p[1], hpgl_scale);
if (code == 'e') {
set_line_thickness(env->size);
printf("CI%d", p[1]/2);
}
else
printf("WG%d,0,360", p[1]/2);
printf("SC0,%.4f,0,-%.4f,2", hpgl_scale, hpgl_scale);
hpgl_end();
break;
case 'a':
{
if (np != 4) {
error("4 arguments required for arc");
break;
}
hpgl_init();
if (!moveto(env->hpos, env->vpos))
return;
hpgl_start();
set_line_thickness(env->size);
double c[2];
if (adjust_arc_center(p, c)) {
double sweep = ((atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0])
- atan2(-c[1], -c[0]))
* 180.0/PI);
if (sweep > 0.0)
sweep -= 360.0;
printf("PDAR%d,%d,%f", int(c[0]), int(c[1]), sweep);
}
else
printf("PD%d,%d", p[0] + p[2], p[1] + p[3]);
hpgl_end();
}
break;
case 'f':
if (np != 1 && np != 2) {
error("1 argument required for fill");
break;
}
hpgl_init();
hpgl_start();
if (p[0] >= 0 && p[0] <= 1000)
printf("FT10,%d", p[0]/10);
hpgl_end();
break;
case 'F':
// not implemented yet
break;
case 't':
{
if (np == 0) {
line_thickness = -1;
}
else {
// troff gratuitously adds an extra 0
if (np != 1 && np != 2) {
error("0 or 1 argument required for thickness");
break;
}
line_thickness = p[0];
}
break;
}
default:
error("unrecognised drawing command `%1'", char(code));
break;
}
}
void lj4_printer::hpgl_init()
{
if (hpgl_inited)
return;
hpgl_inited = 1;
hpgl_scale = double(DEFAULT_HPGL_UNITS)/font::res;
printf("\033&f0S" // push position
"\033*p0x0Y" // move to 0,0
"\033*c%dx%dy0T" // establish picture frame
"\033%%1B" // switch to HPGL
"SP1SC0,%.4f,0,-%.4f,2IR0,100,0,100" // set up scaling
"LA1,4,2,4" // round line ends and joins
"PR" // relative plotting
"TR0" // opaque
";\033%%1A" // back to PCL
"\033&f1S", // pop position
MAX_PAPER_WIDTH, MAX_PAPER_HEIGHT,
hpgl_scale, hpgl_scale);
}
void lj4_printer::set_line_thickness(int size, int dot)
{
double pw;
if (line_thickness < 0)
pw = (size * (line_width_factor * 25.4))/(font::sizescale * 72000.0);
else
pw = line_thickness*25.4/font::res;
if (dot && pw < MIN_DOT_PEN_WIDTH)
pw = MIN_DOT_PEN_WIDTH;
if (pw != pen_width) {
printf("PW%f", pw);
pen_width = pw;
}
}
font *lj4_printer::make_font(const char *nm)
{
return lj4_font::load_lj4_font(nm);
}
printer *make_printer()
{
return new lj4_printer(user_paper_size);
}
static
int lookup_paper_size(const char *s)
{
for (unsigned int i = 0;
i < sizeof(paper_table)/sizeof(paper_table[0]); i++) {
// FIXME Perhaps allow unique prefix.
if (strcasecmp(s, paper_table[i].name) == 0)
return i;
}
return -1;
}
static void usage(FILE *stream);
extern "C" int optopt, optind;
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
int c;
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, ":F:p:d:lvw:c:", long_options, NULL))
!= EOF)
switch(c) {
case 'l':
landscape_flag = 1;
break;
case ':':
if (optopt == 'd') {
fprintf(stderr, "duplex assumed to be long-side\n");
duplex_flag = 1;
} else
fprintf(stderr, "option -%c requires an operand\n", optopt);
fflush(stderr);
break;
case 'd':
if (!isdigit(*optarg)) // this ugly hack prevents -d without
optind--; // args from messing up the arg list
duplex_flag = atoi(optarg);
if (duplex_flag != 1 && duplex_flag != 2) {
fprintf(stderr, "odd value for duplex; assumed to be long-side\n");
duplex_flag = 1;
}
break;
case 'p':
{
int n = lookup_paper_size(optarg);
if (n < 0)
error("unknown paper size `%1'", optarg);
else
user_paper_size = n;
break;
}
case 'v':
{
printf("GNU grolj4 (groff) version %s\n", Version_string);
exit(0);
break;
}
case 'F':
font::command_line_font_dir(optarg);
break;
case 'c':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if (n == 0 && ptr == optarg)
error("argument for -c must be a positive integer");
else if (n <= 0 || n > 32767)
error("out of range argument for -c");
else
ncopies = unsigned(n);
break;
}
case 'w':
{
char *ptr;
long n = strtol(optarg, &ptr, 10);
if (n == 0 && ptr == optarg)
error("argument for -w must be a non-negative integer");
else if (n < 0 || n > INT_MAX)
error("out of range argument for -w");
else
line_width_factor = int(n);
break;
}
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
#ifdef SET_BINARY
SET_BINARY(fileno(stdout));
#endif
if (optind >= argc)
do_file("-");
else {
for (int i = optind; i < argc; i++)
do_file(argv[i]);
}
delete pr;
return 0;
}
static void usage(FILE *stream)
{
fprintf(stream,
"usage: %s [-lv] [-d [n]] [-c n] [-p paper_size]\n"
" [-w n] [-F dir] [files ...]\n",
program_name);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,776 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989-2000, 2001, 2002 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 "driver.h"
#include "device.h"
extern "C" const char *Version_string;
#define putstring(s) fputs(s, stdout)
#ifndef SHRT_MIN
#define SHRT_MIN (-32768)
#endif
#ifndef SHRT_MAX
#define SHRT_MAX 32767
#endif
#define TAB_WIDTH 8
static int horizontal_tab_flag = 0;
static int form_feed_flag = 0;
static int bold_flag = 1;
static int underline_flag = 1;
static int overstrike_flag = 1;
static int draw_flag = 1;
static int italic_flag = 0;
static int reverse_flag = 0;
static int old_drawing_scheme = 0;
enum {
UNDERLINE_MODE = 0x01,
BOLD_MODE = 0x02,
VDRAW_MODE = 0x04,
HDRAW_MODE = 0x08,
CU_MODE = 0x10,
COLOR_CHANGE = 0x20
};
// Mode to use for bold-underlining.
static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
#ifndef IS_EBCDIC_HOST
#define CSI "\033["
#else
#define CSI "\047["
#endif
// SGR handling (ISO 6429)
#define SGR_BOLD CSI "1m"
#define SGR_NO_BOLD CSI "22m"
#define SGR_ITALIC CSI "3m"
#define SGR_NO_ITALIC CSI "23m"
#define SGR_UNDERLINE CSI "4m"
#define SGR_NO_UNDERLINE CSI "24m"
#define SGR_REVERSE CSI "7m"
#define SGR_NO_REVERSE CSI "27m"
// many terminals can't handle `CSI 39 m' and `CSI 49 m' to reset
// the foreground and bachground color, respectively; thus we use
// `CSI 0 m' exclusively
#define SGR_DEFAULT CSI "0m"
#define TTY_MAX_COLORS 8
#define DEFAULT_COLOR_IDX TTY_MAX_COLORS
class tty_font : public font {
tty_font(const char *);
unsigned char mode;
public:
~tty_font();
unsigned char get_mode() { return mode; }
#if 0
void handle_x_command(int argc, const char **argv);
#endif
static tty_font *load_tty_font(const char *);
};
tty_font *tty_font::load_tty_font(const char *s)
{
tty_font *f = new tty_font(s);
if (!f->load()) {
delete f;
return 0;
}
const char *num = f->get_internal_name();
long n;
if (num != 0 && (n = strtol(num, 0, 0)) != 0)
f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE));
if (!underline_flag)
f->mode &= ~UNDERLINE_MODE;
if (!bold_flag)
f->mode &= ~BOLD_MODE;
if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode;
return f;
}
tty_font::tty_font(const char *nm)
: font(nm), mode(0)
{
}
tty_font::~tty_font()
{
}
#if 0
void tty_font::handle_x_command(int argc, const char **argv)
{
if (argc >= 1 && strcmp(argv[0], "bold") == 0)
mode |= BOLD_MODE;
else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
mode |= UNDERLINE_MODE;
}
#endif
class glyph {
static glyph *free_list;
public:
glyph *next;
short hpos;
unsigned int code;
unsigned char mode;
unsigned char back_color_idx;
unsigned char fore_color_idx;
void *operator new(size_t);
void operator delete(void *);
inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
inline int order() {
return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); }
};
glyph *glyph::free_list = 0;
void *glyph::operator new(size_t)
{
if (!free_list) {
const int BLOCK = 1024;
free_list = (glyph *)new char[sizeof(glyph) * BLOCK];
for (int i = 0; i < BLOCK - 1; i++)
free_list[i].next = free_list + i + 1;
free_list[BLOCK - 1].next = 0;
}
glyph *p = free_list;
free_list = free_list->next;
p->next = 0;
return p;
}
void glyph::operator delete(void *p)
{
if (p) {
((glyph *)p)->next = free_list;
free_list = (glyph *)p;
}
}
class tty_printer : public printer {
int is_utf8;
glyph **lines;
int nlines;
int cached_v;
int cached_vpos;
unsigned char curr_fore_idx;
unsigned char curr_back_idx;
int is_underline;
int is_bold;
int cu_flag;
color tty_colors[TTY_MAX_COLORS];
void make_underline();
void make_bold(unsigned int);
unsigned char color_to_idx(color *col);
void add_char(unsigned int, int, int, color *, color *, unsigned char);
public:
tty_printer(const char *device);
~tty_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
void special(char *arg, const environment *env, char type);
void change_color(const environment *env);
void change_fill_color(const environment *env);
void put_char(unsigned int);
void put_color(unsigned char, int);
void begin_page(int) { }
void end_page(int page_length);
font *make_font(const char *);
};
tty_printer::tty_printer(const char *device) : cached_v(0)
{
is_utf8 = !strcmp(device, "utf8");
tty_colors[0].set_rgb(0, // black
0,
0);
tty_colors[1].set_rgb(color::MAX_COLOR_VAL, // red
0,
0);
tty_colors[2].set_rgb(0, // green
color::MAX_COLOR_VAL,
0);
tty_colors[3].set_rgb(color::MAX_COLOR_VAL, // yellow
color::MAX_COLOR_VAL,
0);
tty_colors[4].set_rgb(0, // blue
0,
color::MAX_COLOR_VAL);
tty_colors[5].set_rgb(color::MAX_COLOR_VAL, // magenta
0,
color::MAX_COLOR_VAL);
tty_colors[6].set_rgb(0, // cyan
color::MAX_COLOR_VAL,
color::MAX_COLOR_VAL);
tty_colors[7].set_rgb(color::MAX_COLOR_VAL, // white
color::MAX_COLOR_VAL,
color::MAX_COLOR_VAL);
nlines = 66;
lines = new glyph *[nlines];
for (int i = 0; i < nlines; i++)
lines[i] = 0;
cu_flag = 0;
}
tty_printer::~tty_printer()
{
a_delete lines;
}
void tty_printer::make_underline()
{
if (old_drawing_scheme) {
putchar('_');
putchar('\b');
}
else {
if (!is_underline) {
if (italic_flag)
putstring(SGR_ITALIC);
else if (reverse_flag)
putstring(SGR_REVERSE);
else
putstring(SGR_UNDERLINE);
}
is_underline = 1;
}
}
void tty_printer::make_bold(unsigned int c)
{
if (old_drawing_scheme) {
put_char(c);
putchar('\b');
}
else {
if (!is_bold)
putstring(SGR_BOLD);
is_bold = 1;
}
}
unsigned char tty_printer::color_to_idx(color *col)
{
if (col->is_default())
return DEFAULT_COLOR_IDX;
for (int i = 0; i < TTY_MAX_COLORS; i++)
if (*col == tty_colors[i])
return (unsigned char)i;
unsigned r, g, b;
col->get_rgb(&r, &g, &b);
error("Unknown color (%1, %2, %3) mapped to default", r, g, b);
return DEFAULT_COLOR_IDX;
}
void tty_printer::set_char(int i, font *f, const environment *env,
int w, const char *name)
{
if (w != font::hor)
fatal("width of character not equal to horizontal resolution");
add_char(f->get_code(i),
env->hpos, env->vpos,
env->col, env->fill,
((tty_font *)f)->get_mode());
}
void tty_printer::add_char(unsigned int c,
int h, int v,
color *fore, color *back,
unsigned char mode)
{
#if 0
// This is too expensive.
if (h % font::hor != 0)
fatal("horizontal position not a multiple of horizontal resolution");
#endif
int hpos = h / font::hor;
if (hpos < SHRT_MIN || hpos > SHRT_MAX) {
error("character with ridiculous horizontal position discarded");
return;
}
int vpos;
if (v == cached_v && cached_v != 0)
vpos = cached_vpos;
else {
if (v % font::vert != 0)
fatal("vertical position not a multiple of vertical resolution");
vpos = v / font::vert;
if (vpos > nlines) {
glyph **old_lines = lines;
lines = new glyph *[vpos + 1];
memcpy(lines, old_lines, nlines * sizeof(glyph *));
for (int i = nlines; i <= vpos; i++)
lines[i] = 0;
a_delete old_lines;
nlines = vpos + 1;
}
// Note that the first output line corresponds to groff
// position font::vert.
if (vpos <= 0) {
error("character above first line discarded");
return;
}
cached_v = v;
cached_vpos = vpos;
}
glyph *g = new glyph;
g->hpos = hpos;
g->code = c;
g->fore_color_idx = color_to_idx(fore);
g->back_color_idx = color_to_idx(back);
g->mode = mode;
// The list will be reversed later. After reversal, it must be in
// increasing order of hpos, with COLOR_CHANGE and CU specials before
// HDRAW characters before VDRAW characters before normal characters
// at each hpos, and otherwise in order of occurrence.
glyph **pp;
for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
if ((*pp)->hpos < hpos
|| ((*pp)->hpos == hpos && (*pp)->order() >= g->order()))
break;
g->next = *pp;
*pp = g;
}
void tty_printer::special(char *arg, const environment *env, char type)
{
if (type == 'u') {
add_char(*arg - '0', env->hpos, env->vpos, env->col, env->fill, CU_MODE);
return;
}
if (type != 'p')
return;
char *p;
for (p = arg; *p == ' ' || *p == '\n'; p++)
;
char *tag = p;
for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
;
if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) {
error("X command without `tty:' tag ignored");
return;
}
p++;
for (; *p == ' ' || *p == '\n'; p++)
;
char *command = p;
for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
;
if (*command == '\0') {
error("empty X command ignored");
return;
}
if (strncmp(command, "sgr", p - command) == 0) {
for (; *p == ' ' || *p == '\n'; p++)
;
int n;
if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0)
old_drawing_scheme = 1;
else
old_drawing_scheme = 0;
}
}
void tty_printer::change_color(const environment *env)
{
add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
}
void tty_printer::change_fill_color(const environment *env)
{
add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
}
void tty_printer::draw(int code, int *p, int np, const environment *env)
{
if (code != 'l' || !draw_flag)
return;
if (np != 2) {
error("2 arguments required for line");
return;
}
if (p[0] == 0) {
// vertical line
int v = env->vpos;
int len = p[1];
if (len < 0) {
v += len;
len = -len;
}
while (len >= 0) {
add_char('|', env->hpos, v, env->col, env->fill, VDRAW_MODE);
len -= font::vert;
v += font::vert;
}
}
if (p[1] == 0) {
// horizontal line
int h = env->hpos;
int len = p[0];
if (len < 0) {
h += len;
len = -len;
}
while (len >= 0) {
add_char('-', h, env->vpos, env->col, env->fill, HDRAW_MODE);
len -= font::hor;
h += font::hor;
}
}
}
void tty_printer::put_char(unsigned int wc)
{
if (is_utf8 && wc >= 0x80) {
char buf[6 + 1];
int count;
char *p = buf;
if (wc < 0x800)
count = 1, *p = (unsigned char)((wc >> 6) | 0xc0);
else if (wc < 0x10000)
count = 2, *p = (unsigned char)((wc >> 12) | 0xe0);
else if (wc < 0x200000)
count = 3, *p = (unsigned char)((wc >> 18) | 0xf0);
else if (wc < 0x4000000)
count = 4, *p = (unsigned char)((wc >> 24) | 0xf8);
else if (wc <= 0x7fffffff)
count = 5, *p = (unsigned char)((wc >> 30) | 0xfC);
else
return;
do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80);
while (count > 0);
*++p = '\0';
putstring(buf);
}
else
putchar(wc);
}
void tty_printer::put_color(unsigned char color_index, int back)
{
if (color_index == DEFAULT_COLOR_IDX) {
putstring(SGR_DEFAULT);
// set bold and underline again
if (is_bold)
putstring(SGR_BOLD);
if (is_underline) {
if (italic_flag)
putstring(SGR_ITALIC);
else if (reverse_flag)
putstring(SGR_REVERSE);
else
putstring(SGR_UNDERLINE);
}
// set other color again
back = !back;
color_index = back ? curr_back_idx : curr_fore_idx;
}
putstring(CSI);
if (back)
putchar('4');
else
putchar('3');
putchar(color_index + '0');
putchar('m');
}
void tty_printer::end_page(int page_length)
{
if (page_length % font::vert != 0)
error("vertical position at end of page not multiple of vertical resolution");
int lines_per_page = page_length / font::vert;
int last_line;
for (last_line = nlines; last_line > 0; last_line--)
if (lines[last_line - 1])
break;
#if 0
if (last_line > lines_per_page) {
error("characters past last line discarded");
do {
--last_line;
while (lines[last_line]) {
glyph *tem = lines[last_line];
lines[last_line] = tem->next;
delete tem;
}
} while (last_line > lines_per_page);
}
#endif
for (int i = 0; i < last_line; i++) {
glyph *p = lines[i];
lines[i] = 0;
glyph *g = 0;
while (p) {
glyph *tem = p->next;
p->next = g;
g = p;
p = tem;
}
int hpos = 0;
glyph *nextp;
curr_fore_idx = DEFAULT_COLOR_IDX;
curr_back_idx = DEFAULT_COLOR_IDX;
is_underline = 0;
is_bold = 0;
for (p = g; p; delete p, p = nextp) {
nextp = p->next;
if (p->mode & CU_MODE) {
cu_flag = p->code;
continue;
}
if (nextp && p->hpos == nextp->hpos) {
if (p->draw_mode() == HDRAW_MODE &&
nextp->draw_mode() == VDRAW_MODE) {
nextp->code = '+';
continue;
}
if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
nextp->code = p->code;
continue;
}
if (!overstrike_flag)
continue;
}
if (hpos > p->hpos) {
do {
putchar('\b');
hpos--;
} while (hpos > p->hpos);
}
else {
if (horizontal_tab_flag) {
for (;;) {
int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
if (next_tab_pos > p->hpos)
break;
if (cu_flag)
make_underline();
else if (!old_drawing_scheme && is_underline) {
if (italic_flag)
putstring(SGR_NO_ITALIC);
else if (reverse_flag)
putstring(SGR_NO_REVERSE);
else
putstring(SGR_NO_UNDERLINE);
is_underline = 0;
}
putchar('\t');
hpos = next_tab_pos;
}
}
for (; hpos < p->hpos; hpos++) {
if (cu_flag)
make_underline();
else if (!old_drawing_scheme && is_underline) {
if (italic_flag)
putstring(SGR_NO_ITALIC);
else if (reverse_flag)
putstring(SGR_NO_REVERSE);
else
putstring(SGR_NO_UNDERLINE);
is_underline = 0;
}
putchar(' ');
}
}
assert(hpos == p->hpos);
if (p->mode & COLOR_CHANGE) {
if (!old_drawing_scheme) {
if (p->fore_color_idx != curr_fore_idx) {
put_color(p->fore_color_idx, 0);
curr_fore_idx = p->fore_color_idx;
}
if (p->back_color_idx != curr_back_idx) {
put_color(p->back_color_idx, 1);
curr_back_idx = p->back_color_idx;
}
}
continue;
}
if (p->mode & UNDERLINE_MODE)
make_underline();
else if (!old_drawing_scheme && is_underline) {
if (italic_flag)
putstring(SGR_NO_ITALIC);
else if (reverse_flag)
putstring(SGR_NO_REVERSE);
else
putstring(SGR_NO_UNDERLINE);
is_underline = 0;
}
if (p->mode & BOLD_MODE)
make_bold(p->code);
else if (!old_drawing_scheme && is_bold) {
putstring(SGR_NO_BOLD);
is_bold = 0;
}
if (!old_drawing_scheme) {
if (p->fore_color_idx != curr_fore_idx) {
put_color(p->fore_color_idx, 0);
curr_fore_idx = p->fore_color_idx;
}
if (p->back_color_idx != curr_back_idx) {
put_color(p->back_color_idx, 1);
curr_back_idx = p->back_color_idx;
}
}
put_char(p->code);
hpos++;
}
if (!old_drawing_scheme
&& (is_bold || is_underline
|| curr_fore_idx != DEFAULT_COLOR_IDX
|| curr_back_idx != DEFAULT_COLOR_IDX))
putstring(SGR_DEFAULT);
putchar('\n');
}
if (form_feed_flag) {
if (last_line < lines_per_page)
putchar('\f');
}
else {
for (; last_line < lines_per_page; last_line++)
putchar('\n');
}
}
font *tty_printer::make_font(const char *nm)
{
return tty_font::load_tty_font(nm);
}
printer *make_printer()
{
return new tty_printer(device);
}
static void usage(FILE *stream);
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
if (getenv("GROFF_NO_SGR"))
old_drawing_scheme = 1;
setbuf(stderr, stderr_buf);
int c;
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
while ((c = getopt_long(argc, argv, "bBcdfF:hioruUv", long_options, NULL))
!= EOF)
switch(c) {
case 'v':
printf("GNU grotty (groff) version %s\n", Version_string);
exit(0);
break;
case 'i':
// Use italic font instead of underlining.
italic_flag = 1;
break;
case 'b':
// Do not embolden by overstriking.
bold_flag = 0;
break;
case 'c':
// Use old scheme for emboldening and underline.
old_drawing_scheme = 1;
break;
case 'u':
// Do not underline.
underline_flag = 0;
break;
case 'o':
// Do not overstrike (other than emboldening and underlining).
overstrike_flag = 0;
break;
case 'r':
// Use reverse mode instead of underlining.
reverse_flag = 1;
break;
case 'B':
// Do bold-underlining as bold.
bold_underline_mode = BOLD_MODE;
break;
case 'U':
// Do bold-underlining as underlining.
bold_underline_mode = UNDERLINE_MODE;
break;
case 'h':
// Use horizontal tabs.
horizontal_tab_flag = 1;
break;
case 'f':
form_feed_flag = 1;
break;
case 'F':
font::command_line_font_dir(optarg);
break;
case 'd':
// Ignore \D commands.
draw_flag = 0;
break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
if (old_drawing_scheme) {
italic_flag = 0;
reverse_flag = 0;
}
else {
bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
bold_flag = 1;
underline_flag = 1;
}
if (optind >= argc)
do_file("-");
else {
for (int i = optind; i < argc; i++)
do_file(argv[i]);
}
delete pr;
return 0;
}
static void usage(FILE *stream)
{
fprintf(stream, "usage: %s [-bBcdfhioruUv] [-F dir] [files ...]\n",
program_name);
}

View File

@ -1,38 +0,0 @@
/* 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. */
unsigned hash(const char *s, int len)
{
#if 0
unsigned h = 0, g;
while (*s != '\0') {
h <<= 4;
h += *s++;
if ((g = h & 0xf0000000) != 0) {
h ^= g >> 24;
h ^= g;
}
}
#endif
unsigned h = 0;
while (--len >= 0)
h = *s++ + 65587*h;
return h;
}

View File

@ -1,640 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 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 "lib.h"
#include <stdlib.h>
#include <errno.h>
#include "posix.h"
#include "cset.h"
#include "cmap.h"
#include "errarg.h"
#include "error.h"
#include "refid.h"
#include "search.h"
#include "index.h"
#include "defs.h"
#include "nonposix.h"
// Interface to mmap.
extern "C" {
void *mapread(int fd, int len);
int unmap(void *, int len);
}
#if 0
const
#endif
int minus_one = -1;
int verify_flag = 0;
struct word_list;
class index_search_item : public search_item {
search_item *out_of_date_files;
index_header header;
char *buffer;
void *map_addr;
int map_len;
tag *tags;
int *table;
int *lists;
char *pool;
char *key_buffer;
char *filename_buffer;
int filename_buflen;
char **common_words_table;
int common_words_table_size;
const char *ignore_fields;
time_t mtime;
const char *do_verify();
const int *search1(const char **pp, const char *end);
const int *search(const char *ptr, int length, int **temp_listp);
const char *munge_filename(const char *);
void read_common_words_file();
void add_out_of_date_file(int fd, const char *filename, int fid);
public:
index_search_item(const char *, int);
~index_search_item();
int load(int fd);
search_item_iterator *make_search_item_iterator(const char *);
int verify();
void check_files();
int next_filename_id() const;
friend class index_search_item_iterator;
};
class index_search_item_iterator : public search_item_iterator {
index_search_item *indx;
search_item_iterator *out_of_date_files_iter;
search_item *next_out_of_date_file;
const int *found_list;
int *temp_list;
char *buf;
int buflen;
linear_searcher searcher;
char *query;
int get_tag(int tagno, const linear_searcher &, const char **, int *,
reference_id *);
public:
index_search_item_iterator(index_search_item *, const char *);
~index_search_item_iterator();
int next(const linear_searcher &, const char **, int *, reference_id *);
};
index_search_item::index_search_item(const char *filename, int fid)
: search_item(filename, fid), out_of_date_files(0), buffer(0), map_addr(0),
map_len(0), key_buffer(0), filename_buffer(0), filename_buflen(0),
common_words_table(0)
{
}
index_search_item::~index_search_item()
{
if (buffer)
free(buffer);
if (map_addr) {
if (unmap(map_addr, map_len) < 0)
error("unmap: %1", strerror(errno));
}
while (out_of_date_files) {
search_item *tem = out_of_date_files;
out_of_date_files = out_of_date_files->next;
delete tem;
}
a_delete filename_buffer;
a_delete key_buffer;
if (common_words_table) {
for (int i = 0; i < common_words_table_size; i++)
a_delete common_words_table[i];
a_delete common_words_table;
}
}
class file_closer {
int *fdp;
public:
file_closer(int &fd) : fdp(&fd) { }
~file_closer() { close(*fdp); }
};
// Tell the compiler that a variable is intentionally unused.
inline void unused(void *) { }
int index_search_item::load(int fd)
{
file_closer fd_closer(fd); // close fd on return
unused(&fd_closer);
struct stat sb;
if (fstat(fd, &sb) < 0) {
error("can't fstat `%1': %2", name, strerror(errno));
return 0;
}
if (!S_ISREG(sb.st_mode)) {
error("`%1' is not a regular file", name);
return 0;
}
mtime = sb.st_mtime;
int size = int(sb.st_size);
char *addr;
map_addr = mapread(fd, size);
if (map_addr) {
addr = (char *)map_addr;
map_len = size;
}
else {
addr = buffer = (char *)malloc(size);
if (buffer == 0) {
error("can't allocate buffer for `%1'", name);
return 0;
}
char *ptr = buffer;
int bytes_to_read = size;
while (bytes_to_read > 0) {
int nread = read(fd, ptr, bytes_to_read);
if (nread == 0) {
error("unexpected EOF on `%1'", name);
return 0;
}
if (nread < 0) {
error("read error on `%1': %2", name, strerror(errno));
return 0;
}
bytes_to_read -= nread;
ptr += nread;
}
}
header = *(index_header *)addr;
if (header.magic != INDEX_MAGIC) {
error("`%1' is not an index file: wrong magic number", name);
return 0;
}
if (header.version != INDEX_VERSION) {
error("version number in `%1' is wrong: was %2, should be %3",
name, header.version, INDEX_VERSION);
return 0;
}
int sz = (header.tags_size * sizeof(tag)
+ header.lists_size * sizeof(int)
+ header.table_size * sizeof(int)
+ header.strings_size
+ sizeof(header));
if (sz != size) {
error("size of `%1' is wrong: was %2, should be %3",
name, size, sz);
return 0;
}
tags = (tag *)(addr + sizeof(header));
lists = (int *)(tags + header.tags_size);
table = (int *)(lists + header.lists_size);
pool = (char *)(table + header.table_size);
ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1;
key_buffer = new char[header.truncate];
read_common_words_file();
return 1;
}
const char *index_search_item::do_verify()
{
if (tags == 0)
return "not loaded";
if (lists[header.lists_size - 1] >= 0)
return "last list element not negative";
int i;
for (i = 0; i < header.table_size; i++) {
int li = table[i];
if (li >= header.lists_size)
return "bad list index";
if (li >= 0) {
for (int *ptr = lists + li; *ptr >= 0; ptr++) {
if (*ptr >= header.tags_size)
return "bad tag index";
if (*ptr >= ptr[1] && ptr[1] >= 0)
return "list not ordered";
}
}
}
for (i = 0; i < header.tags_size; i++) {
if (tags[i].filename_index >= header.strings_size)
return "bad index in tags";
if (tags[i].length < 0)
return "bad length in tags";
if (tags[i].start < 0)
return "bad start in tags";
}
if (pool[header.strings_size - 1] != '\0')
return "last character in pool not nul";
return 0;
}
int index_search_item::verify()
{
const char *reason = do_verify();
if (!reason)
return 1;
error("`%1' is bad: %2", name, reason);
return 0;
}
int index_search_item::next_filename_id() const
{
return filename_id + header.strings_size + 1;
}
search_item_iterator *index_search_item::make_search_item_iterator(
const char *query)
{
return new index_search_item_iterator(this, query);
}
search_item *make_index_search_item(const char *filename, int fid)
{
char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)];
strcpy(index_filename, filename);
strcat(index_filename, INDEX_SUFFIX);
int fd = open(index_filename, O_RDONLY | O_BINARY);
if (fd < 0)
return 0;
index_search_item *item = new index_search_item(index_filename, fid);
a_delete index_filename;
if (!item->load(fd)) {
close(fd);
delete item;
return 0;
}
else if (verify_flag && !item->verify()) {
delete item;
return 0;
}
else {
item->check_files();
return item;
}
}
index_search_item_iterator::index_search_item_iterator(index_search_item *ind,
const char *q)
: indx(ind), out_of_date_files_iter(0), next_out_of_date_file(0), temp_list(0),
buf(0), buflen(0),
searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate),
query(strsave(q))
{
found_list = indx->search(q, strlen(q), &temp_list);
if (!found_list) {
found_list = &minus_one;
warning("all keys would have been discarded in constructing index `%1'",
indx->name);
}
}
index_search_item_iterator::~index_search_item_iterator()
{
a_delete temp_list;
a_delete buf;
a_delete query;
delete out_of_date_files_iter;
}
int index_search_item_iterator::next(const linear_searcher &,
const char **pp, int *lenp,
reference_id *ridp)
{
if (found_list) {
for (;;) {
int tagno = *found_list;
if (tagno == -1)
break;
found_list++;
if (get_tag(tagno, searcher, pp, lenp, ridp))
return 1;
}
found_list = 0;
next_out_of_date_file = indx->out_of_date_files;
}
while (next_out_of_date_file) {
if (out_of_date_files_iter == 0)
out_of_date_files_iter
= next_out_of_date_file->make_search_item_iterator(query);
if (out_of_date_files_iter->next(searcher, pp, lenp, ridp))
return 1;
delete out_of_date_files_iter;
out_of_date_files_iter = 0;
next_out_of_date_file = next_out_of_date_file->next;
}
return 0;
}
int index_search_item_iterator::get_tag(int tagno,
const linear_searcher &searcher,
const char **pp, int *lenp,
reference_id *ridp)
{
if (tagno < 0 || tagno >= indx->header.tags_size) {
error("bad tag number");
return 0;
}
tag *tp = indx->tags + tagno;
const char *filename = indx->munge_filename(indx->pool + tp->filename_index);
int fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
error("can't open `%1': %2", filename, strerror(errno));
return 0;
}
struct stat sb;
if (fstat(fd, &sb) < 0) {
error("can't fstat: %1", strerror(errno));
close(fd);
return 0;
}
time_t mtime = sb.st_mtime;
if (mtime > indx->mtime) {
indx->add_out_of_date_file(fd, filename,
indx->filename_id + tp->filename_index);
return 0;
}
int res = 0;
FILE *fp = fdopen(fd, FOPEN_RB);
if (!fp) {
error("fdopen failed");
close(fd);
return 0;
}
if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0)
error("can't seek on `%1': %2", filename, strerror(errno));
else {
int length = tp->length;
int err = 0;
if (length == 0) {
struct stat sb;
if (fstat(fileno(fp), &sb) < 0) {
error("can't stat `%1': %2", filename, strerror(errno));
err = 1;
}
else if (!S_ISREG(sb.st_mode)) {
error("`%1' is not a regular file", filename);
err = 1;
}
else
length = int(sb.st_size);
}
if (!err) {
if (length + 2 > buflen) {
a_delete buf;
buflen = length + 2;
buf = new char[buflen];
}
if (fread(buf + 1, 1, length, fp) != (size_t)length)
error("fread on `%1' failed: %2", filename, strerror(errno));
else {
buf[0] = '\n';
// Remove the CR characters from CRLF pairs.
int sidx = 1, didx = 1;
for ( ; sidx < length + 1; sidx++, didx++)
{
if (buf[sidx] == '\r')
{
if (buf[++sidx] != '\n')
buf[didx++] = '\r';
else
length--;
}
if (sidx != didx)
buf[didx] = buf[sidx];
}
buf[length + 1] = '\n';
res = searcher.search(buf + 1, buf + 2 + length, pp, lenp);
if (res && ridp)
*ridp = reference_id(indx->filename_id + tp->filename_index,
tp->start);
}
}
}
fclose(fp);
return res;
}
const char *index_search_item::munge_filename(const char *filename)
{
if (IS_ABSOLUTE(filename))
return filename;
const char *cwd = pool;
int need_slash = (cwd[0] != 0
&& strchr(DIR_SEPS, strchr(cwd, '\0')[-1]) == 0);
int len = strlen(cwd) + strlen(filename) + need_slash + 1;
if (len > filename_buflen) {
a_delete filename_buffer;
filename_buflen = len;
filename_buffer = new char[len];
}
strcpy(filename_buffer, cwd);
if (need_slash)
strcat(filename_buffer, "/");
strcat(filename_buffer, filename);
return filename_buffer;
}
const int *index_search_item::search1(const char **pp, const char *end)
{
while (*pp < end && !csalnum(**pp))
*pp += 1;
if (*pp >= end)
return 0;
const char *start = *pp;
while (*pp < end && csalnum(**pp))
*pp += 1;
int len = *pp - start;
if (len < header.shortest)
return 0;
if (len > header.truncate)
len = header.truncate;
int is_number = 1;
for (int i = 0; i < len; i++)
if (csdigit(start[i]))
key_buffer[i] = start[i];
else {
key_buffer[i] = cmlower(start[i]);
is_number = 0;
}
if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9'))
return 0;
unsigned hc = hash(key_buffer, len);
if (common_words_table) {
for (int h = hc % common_words_table_size;
common_words_table[h];
--h) {
if (strlen(common_words_table[h]) == (size_t)len
&& memcmp(common_words_table[h], key_buffer, len) == 0)
return 0;
if (h == 0)
h = common_words_table_size;
}
}
int li = table[int(hc % header.table_size)];
return li < 0 ? &minus_one : lists + li;
}
static void merge(int *result, const int *s1, const int *s2)
{
for (; *s1 >= 0; s1++) {
while (*s2 >= 0 && *s2 < *s1)
s2++;
if (*s2 == *s1)
*result++ = *s2;
}
*result++ = -1;
}
const int *index_search_item::search(const char *ptr, int length,
int **temp_listp)
{
const char *end = ptr + length;
if (*temp_listp) {
a_delete *temp_listp;
*temp_listp = 0;
}
const int *first_list = 0;
while (ptr < end && (first_list = search1(&ptr, end)) == 0)
;
if (!first_list)
return 0;
if (*first_list < 0)
return first_list;
const int *second_list = 0;
while (ptr < end && (second_list = search1(&ptr, end)) == 0)
;
if (!second_list)
return first_list;
if (*second_list < 0)
return second_list;
const int *p;
for (p = first_list; *p >= 0; p++)
;
int len = p - first_list;
for (p = second_list; *p >= 0; p++)
;
if (p - second_list < len)
len = p - second_list;
int *matches = new int[len + 1];
merge(matches, first_list, second_list);
while (ptr < end) {
const int *list = search1(&ptr, end);
if (list != 0) {
if (*list < 0) {
a_delete matches;
return list;
}
merge(matches, matches, list);
if (*matches < 0) {
a_delete matches;
return &minus_one;
}
}
}
*temp_listp = matches;
return matches;
}
void index_search_item::read_common_words_file()
{
if (header.common <= 0)
return;
const char *common_words_file = munge_filename(strchr(pool, '\0') + 1);
errno = 0;
FILE *fp = fopen(common_words_file, "r");
if (!fp) {
error("can't open `%1': %2", common_words_file, strerror(errno));
return;
}
common_words_table_size = 2*header.common + 1;
while (!is_prime(common_words_table_size))
common_words_table_size++;
common_words_table = new char *[common_words_table_size];
for (int i = 0; i < common_words_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 < header.truncate)
key_buffer[key_len++] = cmlower(c);
c = getc(fp);
} while (c != EOF && csalnum(c));
if (key_len >= header.shortest) {
int h = hash(key_buffer, key_len) % common_words_table_size;
while (common_words_table[h]) {
if (h == 0)
h = common_words_table_size;
--h;
}
common_words_table[h] = new char[key_len + 1];
memcpy(common_words_table[h], key_buffer, key_len);
common_words_table[h][key_len] = '\0';
}
if (++count >= header.common)
break;
key_len = 0;
if (c == EOF)
break;
}
fclose(fp);
}
void index_search_item::add_out_of_date_file(int fd, const char *filename,
int fid)
{
search_item **pp;
for (pp = &out_of_date_files; *pp; pp = &(*pp)->next)
if ((*pp)->is_named(filename))
return;
*pp = make_linear_search_item(fd, filename, fid);
warning("`%1' modified since `%2' created", filename, name);
}
void index_search_item::check_files()
{
const char *pool_end = pool + header.strings_size;
for (const char *ptr = strchr(ignore_fields, '\0') + 1;
ptr < pool_end;
ptr = strchr(ptr, '\0') + 1) {
const char *path = munge_filename(ptr);
struct stat sb;
if (stat(path, &sb) < 0)
error("can't stat `%1': %2", path, strerror(errno));
else if (sb.st_mtime > mtime) {
int fd = open(path, O_RDONLY | O_BINARY);
if (fd < 0)
error("can't open `%1': %2", path, strerror(errno));
else
add_out_of_date_file(fd, path, filename_id + (ptr - pool));
}
}
}

View File

@ -1,503 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 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 "lib.h"
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "posix.h"
#include "errarg.h"
#include "error.h"
#include "cset.h"
#include "cmap.h"
#include "nonposix.h"
#include "refid.h"
#include "search.h"
class file_buffer {
char *buffer;
char *bufend;
public:
file_buffer();
~file_buffer();
int load(int fd, const char *filename);
const char *get_start() const;
const char *get_end() const;
};
typedef unsigned char uchar;
static uchar map[256];
static uchar inv_map[256][3];
struct map_init {
map_init();
};
static map_init the_map_init;
map_init::map_init()
{
int i;
for (i = 0; i < 256; i++)
map[i] = csalnum(i) ? cmlower(i) : '\0';
for (i = 0; i < 256; i++) {
if (cslower(i)) {
inv_map[i][0] = i;
inv_map[i][1] = cmupper(i);
inv_map[i][2] = '\0';
}
else if (csdigit(i)) {
inv_map[i][0] = i;
inv_map[i][1] = 0;
}
else
inv_map[i][0] = '\0';
}
}
class bmpattern {
char *pat;
int len;
int delta[256];
public:
bmpattern(const char *pattern, int pattern_length);
~bmpattern();
const char *search(const char *p, const char *end) const;
int length() const;
};
bmpattern::bmpattern(const char *pattern, int pattern_length)
: len(pattern_length)
{
pat = new char[len];
int i;
for (i = 0; i < len; i++)
pat[i] = map[uchar(pattern[i])];
for (i = 0; i < 256; i++)
delta[i] = len;
for (i = 0; i < len; i++)
for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++)
delta[*inv] = len - i - 1;
}
const char *bmpattern::search(const char *buf, const char *end) const
{
int buflen = end - buf;
if (len > buflen)
return 0;
const char *strend;
if (buflen > len*4)
strend = end - len*4;
else
strend = buf;
const char *k = buf + len - 1;
const int *del = delta;
const char *pattern = pat;
for (;;) {
while (k < strend) {
int t = del[uchar(*k)];
if (!t)
break;
k += t;
k += del[uchar(*k)];
k += del[uchar(*k)];
}
while (k < end && del[uchar(*k)] != 0)
k++;
if (k == end)
break;
int j = len - 1;
const char *s = k;
for (;;) {
if (j == 0)
return s;
if (map[uchar(*--s)] != uchar(pattern[--j]))
break;
}
k++;
}
return 0;
}
bmpattern::~bmpattern()
{
a_delete pat;
}
inline int bmpattern::length() const
{
return len;
}
static const char *find_end(const char *bufend, const char *p);
const char *linear_searcher::search_and_check(const bmpattern *key,
const char *buf, const char *bufend, const char **start) const
{
assert(buf[-1] == '\n');
assert(bufend[-1] == '\n');
const char *ptr = buf;
for (;;) {
const char *found = key->search(ptr, bufend);
if (!found)
break;
if (check_match(buf, bufend, found, key->length(), &ptr, start))
return found;
}
return 0;
}
static const char *skip_field(const char *end, const char *p)
{
for (;;)
if (*p++ == '\n') {
if (p == end || *p == '%')
break;
const char *q;
for (q = p; *q == ' ' || *q == '\t'; q++)
;
if (*q == '\n')
break;
p = q + 1;
}
return p;
}
static const char *find_end(const char *bufend, const char *p)
{
for (;;)
if (*p++ == '\n') {
if (p == bufend)
break;
const char *q;
for (q = p; *q == ' ' || *q == '\t'; q++)
;
if (*q == '\n')
break;
p = q + 1;
}
return p;
}
int linear_searcher::check_match(const char *buf, const char *bufend,
const char *match, int matchlen,
const char **cont, const char **start) const
{
*cont = match + 1;
// The user is required to supply only the first truncate_len characters
// of the key. If truncate_len <= 0, he must supply all the key.
if ((truncate_len <= 0 || matchlen < truncate_len)
&& map[uchar(match[matchlen])] != '\0')
return 0;
// The character before the match must not be an alphanumeric
// character (unless the alphanumeric character follows one or two
// percent characters at the beginning of the line), nor must it be
// a percent character at the beginning of a line, nor a percent
// character following a percent character at the beginning of a
// line.
switch (match - buf) {
case 0:
break;
case 1:
if (match[-1] == '%' || map[uchar(match[-1])] != '\0')
return 0;
break;
case 2:
if (map[uchar(match[-1])] != '\0' && match[-2] != '%')
return 0;
if (match[-1] == '%'
&& (match[-2] == '\n' || match[-2] == '%'))
return 0;
break;
default:
if (map[uchar(match[-1])] != '\0'
&& !(match[-2] == '%'
&& (match[-3] == '\n'
|| (match[-3] == '%' && match[-4] == '\n'))))
return 0;
if (match[-1] == '%'
&& (match[-2] == '\n'
|| (match[-2] == '%' && match[-3] == '\n')))
return 0;
}
const char *p = match;
int had_percent = 0;
for (;;) {
if (*p == '\n') {
if (!had_percent && p[1] == '%') {
if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) {
*cont = skip_field(bufend, match + matchlen);
return 0;
}
if (!start)
break;
had_percent = 1;
}
if (p <= buf) {
if (start)
*start = p + 1;
return 1;
}
const char *q;
for (q = p - 1; *q == ' ' || *q == '\t'; q--)
;
if (*q == '\n') {
if (start)
*start = p + 1;
break;
}
p = q;
}
p--;
}
return 1;
}
file_buffer::file_buffer()
: buffer(0), bufend(0)
{
}
file_buffer::~file_buffer()
{
a_delete buffer;
}
const char *file_buffer::get_start() const
{
return buffer ? buffer + 4 : 0;
}
const char *file_buffer::get_end() const
{
return bufend;
}
int file_buffer::load(int fd, const char *filename)
{
struct stat sb;
if (fstat(fd, &sb) < 0)
error("can't fstat `%1': %2", filename, strerror(errno));
else if (!S_ISREG(sb.st_mode))
error("`%1' is not a regular file", filename);
else {
// We need one character extra at the beginning for an additional newline
// used as a sentinel. We get 4 instead so that the read buffer will be
// word-aligned. This seems to make the read slightly faster. We also
// need one character at the end also for an additional newline used as a
// sentinel.
int size = int(sb.st_size);
buffer = new char[size + 4 + 1];
int nread = read(fd, buffer + 4, size);
if (nread < 0)
error("error reading `%1': %2", filename, strerror(errno));
else if (nread != size)
error("size of `%1' decreased", filename);
else {
char c;
nread = read(fd, &c, 1);
if (nread != 0)
error("size of `%1' increased", filename);
else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0)
error("database `%1' is a binary file", filename);
else {
close(fd);
buffer[3] = '\n';
int sidx = 4, didx = 4;
for ( ; sidx < size + 4; sidx++, didx++)
{
if (buffer[sidx] == '\r')
{
if (buffer[++sidx] != '\n')
buffer[didx++] = '\r';
else
size--;
}
if (sidx != didx)
buffer[didx] = buffer[sidx];
}
bufend = buffer + 4 + size;
if (bufend[-1] != '\n')
*bufend++ = '\n';
return 1;
}
}
a_delete buffer;
buffer = 0;
}
close(fd);
return 0;
}
linear_searcher::linear_searcher(const char *query, int query_len,
const char *ign, int trunc)
: ignore_fields(ign), truncate_len(trunc), keys(0), nkeys(0)
{
const char *query_end = query + query_len;
int nk = 0;
const char *p;
for (p = query; p < query_end; p++)
if (map[uchar(*p)] != '\0'
&& (p[1] == '\0' || map[uchar(p[1])] == '\0'))
nk++;
if (nk == 0)
return;
keys = new bmpattern*[nk];
p = query;
for (;;) {
while (p < query_end && map[uchar(*p)] == '\0')
p++;
if (p == query_end)
break;
const char *start = p;
while (p < query_end && map[uchar(*p)] != '\0')
p++;
keys[nkeys++] = new bmpattern(start, p - start);
}
assert(nkeys <= nk);
if (nkeys == 0) {
a_delete keys;
keys = 0;
}
}
linear_searcher::~linear_searcher()
{
for (int i = 0; i < nkeys; i++)
delete keys[i];
a_delete keys;
}
int linear_searcher::search(const char *buffer, const char *bufend,
const char **startp, int *lengthp) const
{
assert(bufend - buffer > 0);
assert(buffer[-1] == '\n');
assert(bufend[-1] == '\n');
if (nkeys == 0)
return 0;
for (;;) {
const char *refstart;
const char *found = search_and_check(keys[0], buffer, bufend, &refstart);
if (!found)
break;
const char *refend = find_end(bufend, found + keys[0]->length());
int i;
for (i = 1; i < nkeys; i++)
if (!search_and_check(keys[i], refstart, refend))
break;
if (i >= nkeys) {
*startp = refstart;
*lengthp = refend - refstart;
return 1;
}
buffer = refend;
}
return 0;
}
class linear_search_item : public search_item {
file_buffer fbuf;
public:
linear_search_item(const char *filename, int fid);
~linear_search_item();
int load(int fd);
search_item_iterator *make_search_item_iterator(const char *);
friend class linear_search_item_iterator;
};
class linear_search_item_iterator : public search_item_iterator {
linear_search_item *lsi;
int pos;
public:
linear_search_item_iterator(linear_search_item *, const char *query);
~linear_search_item_iterator();
int next(const linear_searcher &, const char **ptr, int *lenp,
reference_id *ridp);
};
search_item *make_linear_search_item(int fd, const char *filename, int fid)
{
linear_search_item *item = new linear_search_item(filename, fid);
if (!item->load(fd)) {
delete item;
return 0;
}
else
return item;
}
linear_search_item::linear_search_item(const char *filename, int fid)
: search_item(filename, fid)
{
}
linear_search_item::~linear_search_item()
{
}
int linear_search_item::load(int fd)
{
return fbuf.load(fd, name);
}
search_item_iterator *linear_search_item::make_search_item_iterator(
const char *query)
{
return new linear_search_item_iterator(this, query);
}
linear_search_item_iterator::linear_search_item_iterator(
linear_search_item *p, const char *)
: lsi(p), pos(0)
{
}
linear_search_item_iterator::~linear_search_item_iterator()
{
}
int linear_search_item_iterator::next(const linear_searcher &searcher,
const char **startp, int *lengthp,
reference_id *ridp)
{
const char *bufstart = lsi->fbuf.get_start();
const char *bufend = lsi->fbuf.get_end();
const char *ptr = bufstart + pos;
if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) {
pos = *startp + *lengthp - bufstart;
if (ridp)
*ridp = reference_id(lsi->filename_id, *startp - bufstart);
return 1;
}
else
return 0;
}

View File

@ -1,133 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 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 "lib.h"
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "posix.h"
#include "errarg.h"
#include "error.h"
#include "nonposix.h"
#include "refid.h"
#include "search.h"
int linear_truncate_len = 6;
const char *linear_ignore_fields = "XYZ";
search_list::search_list()
: list(0), niterators(0), next_fid(1)
{
}
search_list::~search_list()
{
assert(niterators == 0);
while (list) {
search_item *tem = list->next;
delete list;
list = tem;
}
}
void search_list::add_file(const char *filename, int silent)
{
search_item *p = make_index_search_item(filename, next_fid);
if (!p) {
int fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
if (!silent)
error("can't open `%1': %2", filename, strerror(errno));
}
else
p = make_linear_search_item(fd, filename, next_fid);
}
if (p) {
search_item **pp;
for (pp = &list; *pp; pp = &(*pp)->next)
;
*pp = p;
next_fid = p->next_filename_id();
}
}
int search_list::nfiles() const
{
int n = 0;
for (search_item *ptr = list; ptr; ptr = ptr->next)
n++;
return n;
}
search_list_iterator::search_list_iterator(search_list *p, const char *q)
: list(p), ptr(p->list), iter(0), query(strsave(q)),
searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len)
{
list->niterators += 1;
}
search_list_iterator::~search_list_iterator()
{
list->niterators -= 1;
a_delete query;
delete iter;
}
int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp)
{
while (ptr) {
if (iter == 0)
iter = ptr->make_search_item_iterator(query);
if (iter->next(searcher, pp, lenp, ridp))
return 1;
delete iter;
iter = 0;
ptr = ptr->next;
}
return 0;
}
search_item::search_item(const char *nm, int fid)
: name(strsave(nm)), filename_id(fid), next(0)
{
}
search_item::~search_item()
{
a_delete name;
}
int search_item::is_named(const char *nm) const
{
return strcmp(name, nm) == 0;
}
int search_item::next_filename_id() const
{
return filename_id + 1;
}
search_item_iterator::~search_item_iterator()
{
}

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +0,0 @@
// -*- C++ -*-
// <groff_src_dir>/src/libs/libdriver/printer.cc
/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
Last update: 12 Apr 2002
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 "driver.h"
printer *pr = 0;
font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
: p(f), next(fp)
{
}
printer::printer()
: font_list(0), font_table(0), nfonts(0)
{
}
printer::~printer()
{
a_delete font_table;
while (font_list) {
font_pointer_list *tem = font_list;
font_list = font_list->next;
delete tem->p;
delete tem;
}
if (ferror(stdout) || fflush(stdout) < 0)
fatal("output error");
}
void printer::load_font(int n, const char *nm)
{
assert(n >= 0);
if (n >= nfonts) {
if (nfonts == 0) {
nfonts = 10;
if (nfonts <= n)
nfonts = n + 1;
font_table = new font *[nfonts];
for (int i = 0; i < nfonts; i++)
font_table[i] = 0;
}
else {
font **old_font_table = font_table;
int old_nfonts = nfonts;
nfonts *= 2;
if (n >= nfonts)
nfonts = n + 1;
font_table = new font *[nfonts];
int i;
for (i = 0; i < old_nfonts; i++)
font_table[i] = old_font_table[i];
for (i = old_nfonts; i < nfonts; i++)
font_table[i] = 0;
a_delete old_font_table;
}
}
font *f = find_font(nm);
font_table[n] = f;
}
font *printer::find_font(const char *nm)
{
for (font_pointer_list *p = font_list; p; p = p->next)
if (strcmp(p->p->get_name(), nm) == 0)
return p->p;
font *f = make_font(nm);
if (!f)
fatal("sorry, I can't continue");
font_list = new font_pointer_list(f, font_list);
return f;
}
font *printer::make_font(const char *nm)
{
return font::load_font(nm);
}
void printer::end_of_line()
{
}
void printer::special(char *, const environment *, char)
{
}
void printer::draw(int, int *, int, const environment *)
{
}
void printer::change_color(const environment *)
{
}
void printer::change_fill_color(const environment *)
{
}
void printer::set_ascii_char(unsigned char c, const environment *env,
int *widthp)
{
char buf[2];
int w;
font *f;
buf[0] = c;
buf[1] = '\0';
int i = set_char_and_width(buf, env, &w, &f);
set_char(i, f, env, w, 0);
if (widthp) {
*widthp = w;
}
}
void printer::set_special_char(const char *nm, const environment *env,
int *widthp)
{
font *f;
int w;
int i = set_char_and_width(nm, env, &w, &f);
if (i != -1) {
set_char(i, f, env, w, nm);
if (widthp)
*widthp = w;
}
}
int printer::set_char_and_width(const char *nm, const environment *env,
int *widthp, font **f)
{
int i = font::name_to_index(nm);
int fn = env->fontno;
if (fn < 0 || fn >= nfonts) {
error("bad font position `%1'", fn);
return(-1);
}
*f = font_table[fn];
if (*f == 0) {
error("no font mounted at `%1'", fn);
return(-1);
}
if (!(*f)->contains(i)) {
if (nm[0] != '\0' && nm[1] == '\0')
error("font `%1' does not contain ascii character `%2'",
(*f)->get_name(),
nm[0]);
else
error("font `%1' does not contain special character `%2'",
(*f)->get_name(),
nm);
return(-1);
}
int w = (*f)->get_width(i, env->size);
if (widthp)
*widthp = w;
return( i );
}
void printer::set_numbered_char(int num, const environment *env, int *widthp)
{
int i = font::number_to_index(num);
int fn = env->fontno;
if (fn < 0 || fn >= nfonts) {
error("bad font position `%1'", fn);
return;
}
font *f = font_table[fn];
if (f == 0) {
error("no font mounted at `%1'", fn);
return;
}
if (!f->contains(i)) {
error("font `%1' does not contain numbered character %2",
f->get_name(),
num);
return;
}
int w = f->get_width(i, env->size);
if (widthp)
*widthp = w;
set_char(i, f, env, w, 0);
}
font *printer::get_font_from_index(int fontno)
{
if ((fontno >= 0) && (fontno < nfonts))
return(font_table[fontno]);
else
return(0);
}

View File

@ -1,34 +0,0 @@
/* 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 <stdio.h>
#include <stdlib.h>
#include "assert.h"
extern const char *program_name;
void assertion_failed(int lineno, const char *filename)
{
if (program_name != 0)
fprintf(stderr, "%s: ", program_name);
fprintf(stderr, "Failed assertion at line %d, file `%s'.\n",
lineno, filename);
fflush(stderr);
abort();
}

View File

@ -1,37 +0,0 @@
/* 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 <string.h>
extern char *strsave(const char *);
extern const char *current_filename;
extern int current_lineno;
void change_filename(const char *f)
{
if (current_filename != 0 && strcmp(current_filename, f) == 0)
return;
current_filename = strsave(f);
}
void change_lineno(int ln)
{
current_lineno = ln;
}

View File

@ -1,56 +0,0 @@
// -*- 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 <ctype.h>
#include "cmap.h"
cmap cmlower(CMAP_BUILTIN);
cmap cmupper(CMAP_BUILTIN);
#ifdef isascii
#define ISASCII(c) isascii(c)
#else
#define ISASCII(c) (1)
#endif
cmap::cmap()
{
unsigned char *p = v;
for (int i = 0; i <= UCHAR_MAX; i++)
p[i] = i;
}
cmap::cmap(cmap_builtin)
{
// these are initialised by cmap_init::cmap_init()
}
int cmap_init::initialised = 0;
cmap_init::cmap_init()
{
if (initialised)
return;
initialised = 1;
for (int i = 0; i <= UCHAR_MAX; i++) {
cmupper.v[i] = ISASCII(i) && islower(i) ? toupper(i) : i;
cmlower.v[i] = ISASCII(i) && isupper(i) ? tolower(i) : i;
}
}

View File

@ -1,363 +0,0 @@
// -*- C++ -*-
/* <groff_src_dir>/src/libs/libgroff/color.cc
Last update: 10 Apr 2002
Copyright (C) 2001, 2002 Free Software Foundation, Inc.
Written by Gaius Mulley <gaius@glam.ac.uk>
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 "color.h"
#include "cset.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <assert.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include "errarg.h"
#include "error.h"
static inline unsigned int
min(const unsigned int a, const unsigned int b)
{
if (a < b)
return a;
else
return b;
}
color::color(const color * const c)
{
scheme = c->scheme;
components[0] = c->components[0];
components[1] = c->components[1];
components[2] = c->components[2];
components[3] = c->components[3];
}
int color::operator==(const color & c) const
{
if (scheme != c.scheme)
return 0;
switch (scheme) {
case DEFAULT:
break;
case RGB:
if (Red != c.Red || Green != c.Green || Blue != c.Blue)
return 0;
break;
case CMYK:
if (Cyan != c.Cyan || Magenta != c.Magenta
|| Yellow != c.Yellow || Black != c.Black)
return 0;
break;
case GRAY:
if (Gray != c.Gray)
return 0;
break;
case CMY:
if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
return 0;
break;
}
return 1;
}
int color::operator!=(const color & c) const
{
return !(*this == c);
}
color_scheme color::get_components(unsigned int *c) const
{
#if 0
if (sizeof (c) < sizeof (unsigned int) * 4)
fatal("argument is not big enough to store 4 color components");
#endif
c[0] = components[0];
c[1] = components[1];
c[2] = components[2];
c[3] = components[3];
return scheme;
}
void color::set_default()
{
scheme = DEFAULT;
}
// (0, 0, 0) is black
void color::set_rgb(const unsigned int r, const unsigned int g,
const unsigned int b)
{
scheme = RGB;
Red = min(MAX_COLOR_VAL, r);
Green = min(MAX_COLOR_VAL, g);
Blue = min(MAX_COLOR_VAL, b);
}
// (0, 0, 0) is white
void color::set_cmy(const unsigned int c, const unsigned int m,
const unsigned int y)
{
scheme = CMY;
Cyan = min(MAX_COLOR_VAL, c);
Magenta = min(MAX_COLOR_VAL, m);
Yellow = min(MAX_COLOR_VAL, y);
}
// (0, 0, 0, 0) is white
void color::set_cmyk(const unsigned int c, const unsigned int m,
const unsigned int y, const unsigned int k)
{
scheme = CMYK;
Cyan = min(MAX_COLOR_VAL, c);
Magenta = min(MAX_COLOR_VAL, m);
Yellow = min(MAX_COLOR_VAL, y);
Black = min(MAX_COLOR_VAL, k);
}
// (0) is black
void color::set_gray(const unsigned int g)
{
scheme = GRAY;
Gray = min(MAX_COLOR_VAL, g);
}
/*
* atoh - computes the decimal value of a hexadecimal number string.
* `length' characters of `s' are read. Returns 1 if successful.
*/
static int atoh(unsigned int *result,
const char * const s, const size_t length)
{
size_t i = 0;
unsigned int val = 0;
while ((i < length) && csxdigit(s[i])) {
if (csdigit(s[i]))
val = val*0x10 + (s[i]-'0');
else if (csupper(s[i]))
val = val*0x10 + (s[i]-'A') + 10;
else
val = val*0x10 + (s[i]-'a') + 10;
i++;
}
if (i != length)
return 0;
*result = val;
return 1;
}
/*
* read_encoding - set color from a hexadecimal color string.
*
* Use color scheme `cs' to parse `n' color components from string `s'.
* Returns 1 if successful.
*/
int color::read_encoding(const color_scheme cs, const char * const s,
const size_t n)
{
size_t hex_length = 2;
scheme = cs;
char *p = (char *) s;
p++;
if (*p == '#') {
hex_length = 4;
p++;
}
for (size_t i = 0; i < n; i++) {
if (!atoh(&(components[i]), p, hex_length))
return 0;
if (hex_length == 2)
components[i] *= 0x101; // scale up -- 0xff should become 0xffff
p += hex_length;
}
return 1;
}
int color::read_rgb(const char * const s)
{
return read_encoding(RGB, s, 3);
}
int color::read_cmy(const char * const s)
{
return read_encoding(CMY, s, 3);
}
int color::read_cmyk(const char * const s)
{
return read_encoding(CMYK, s, 4);
}
int color::read_gray(const char * const s)
{
return read_encoding(GRAY, s, 1);
}
void
color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const
{
switch (scheme) {
case RGB:
*r = Red;
*g = Green;
*b = Blue;
break;
case CMY:
*r = MAX_COLOR_VAL - Cyan;
*g = MAX_COLOR_VAL - Magenta;
*b = MAX_COLOR_VAL - Yellow;
break;
case CMYK:
*r = MAX_COLOR_VAL
- min(MAX_COLOR_VAL,
Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
*g = MAX_COLOR_VAL
- min(MAX_COLOR_VAL,
Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
*b = MAX_COLOR_VAL
- min(MAX_COLOR_VAL,
Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
break;
case GRAY:
*r = *g = *b = Gray;
break;
default:
assert(0);
break;
}
}
void
color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const
{
switch (scheme) {
case RGB:
*c = MAX_COLOR_VAL - Red;
*m = MAX_COLOR_VAL - Green;
*y = MAX_COLOR_VAL - Blue;
break;
case CMY:
*c = Cyan;
*m = Magenta;
*y = Yellow;
break;
case CMYK:
*c = min(MAX_COLOR_VAL,
Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
*m = min(MAX_COLOR_VAL,
Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
*y = min(MAX_COLOR_VAL,
Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
break;
case GRAY:
*c = *m = *y = MAX_COLOR_VAL - Gray;
break;
default:
assert(0);
break;
}
}
void color::get_cmyk(unsigned int *c, unsigned int *m,
unsigned int *y, unsigned int *k) const
{
switch (scheme) {
case RGB:
*k = min(MAX_COLOR_VAL - Red,
min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
if (MAX_COLOR_VAL == *k) {
*c = MAX_COLOR_VAL;
*m = MAX_COLOR_VAL;
*y = MAX_COLOR_VAL;
}
else {
*c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
/ (MAX_COLOR_VAL - *k);
*m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
/ (MAX_COLOR_VAL - *k);
*y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
/ (MAX_COLOR_VAL - *k);
}
break;
case CMY:
*k = min(Cyan, min(Magenta, Yellow));
if (MAX_COLOR_VAL == *k) {
*c = MAX_COLOR_VAL;
*m = MAX_COLOR_VAL;
*y = MAX_COLOR_VAL;
}
else {
*c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
*m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
*y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
}
break;
case CMYK:
*c = Cyan;
*m = Magenta;
*y = Yellow;
*k = Black;
break;
case GRAY:
*c = *m = *y = 0;
*k = MAX_COLOR_VAL - Gray;
break;
default:
assert(0);
break;
}
}
// we use `0.222r + 0.707g + 0.071b' (this is the ITU standard)
// as an approximation for gray
void color::get_gray(unsigned int *g) const
{
switch (scheme) {
case RGB:
*g = (222*Red + 707*Green + 71*Blue) / 1000;
break;
case CMY:
*g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
break;
case CMYK:
*g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
* (MAX_COLOR_VAL - Black);
break;
case GRAY:
*g = Gray;
break;
default:
assert(0);
break;
}
}
color default_color;

View File

@ -1,102 +0,0 @@
// -*- 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 <ctype.h>
#include "cset.h"
cset csalpha(CSET_BUILTIN);
cset csupper(CSET_BUILTIN);
cset cslower(CSET_BUILTIN);
cset csdigit(CSET_BUILTIN);
cset csxdigit(CSET_BUILTIN);
cset csspace(CSET_BUILTIN);
cset cspunct(CSET_BUILTIN);
cset csalnum(CSET_BUILTIN);
cset csprint(CSET_BUILTIN);
cset csgraph(CSET_BUILTIN);
cset cscntrl(CSET_BUILTIN);
#ifdef isascii
#define ISASCII(c) isascii(c)
#else
#define ISASCII(c) (1)
#endif
void cset::clear()
{
char *p = v;
for (int i = 0; i <= UCHAR_MAX; i++)
p[i] = 0;
}
cset::cset()
{
clear();
}
cset::cset(const char *s)
{
clear();
while (*s)
v[(unsigned char)*s++] = 1;
}
cset::cset(const unsigned char *s)
{
clear();
while (*s)
v[*s++] = 1;
}
cset::cset(cset_builtin)
{
// these are initialised by cset_init::cset_init()
}
cset &cset::operator|=(const cset &cs)
{
for (int i = 0; i <= UCHAR_MAX; i++)
if (cs.v[i])
v[i] = 1;
return *this;
}
int cset_init::initialised = 0;
cset_init::cset_init()
{
if (initialised)
return;
initialised = 1;
for (int i = 0; i <= UCHAR_MAX; i++) {
csalpha.v[i] = ISASCII(i) && isalpha(i);
csupper.v[i] = ISASCII(i) && isupper(i);
cslower.v[i] = ISASCII(i) && islower(i);
csdigit.v[i] = ISASCII(i) && isdigit(i);
csxdigit.v[i] = ISASCII(i) && isxdigit(i);
csspace.v[i] = ISASCII(i) && isspace(i);
cspunct.v[i] = ISASCII(i) && ispunct(i);
csalnum.v[i] = ISASCII(i) && isalnum(i);
csprint.v[i] = ISASCII(i) && isprint(i);
csgraph.v[i] = ISASCII(i) && isgraph(i);
cscntrl.v[i] = ISASCII(i) && iscntrl(i);
}
}

View File

@ -1,36 +0,0 @@
// -*- 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 <stdlib.h>
#include "device.h"
#include "defs.h"
const char *device = DEVICE;
struct device_init {
device_init();
} _device_init;
device_init::device_init()
{
char *tem = getenv("GROFF_TYPESETTER");
if (tem)
device = tem;
}

View File

@ -1,128 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002
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 "assert.h"
#include "errarg.h"
errarg::errarg(const char *p) : type(STRING)
{
s = p ? p : "(null)";
}
errarg::errarg() : type(EMPTY)
{
}
errarg::errarg(int nn) : type(INTEGER)
{
n = nn;
}
errarg::errarg(unsigned int uu) : type(UNSIGNED_INTEGER)
{
u = uu;
}
errarg::errarg(char cc) : type(CHAR)
{
c = cc;
}
errarg::errarg(unsigned char cc) : type(CHAR)
{
c = cc;
}
errarg::errarg(double dd) : type(DOUBLE)
{
d = dd;
}
int errarg::empty() const
{
return type == EMPTY;
}
extern "C" {
const char *i_to_a(int);
const char *ui_to_a(unsigned int);
}
void errarg::print() const
{
switch (type) {
case INTEGER:
fputs(i_to_a(n), stderr);
break;
case UNSIGNED_INTEGER:
fputs(ui_to_a(u), stderr);
break;
case CHAR:
putc(c, stderr);
break;
case STRING:
fputs(s, stderr);
break;
case DOUBLE:
fprintf(stderr, "%g", d);
break;
case EMPTY:
break;
}
}
errarg empty_errarg;
void errprint(const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
assert(format != 0);
char c;
while ((c = *format++) != '\0') {
if (c == '%') {
c = *format++;
switch(c) {
case '%':
fputc('%', stderr);
break;
case '1':
assert(!arg1.empty());
arg1.print();
break;
case '2':
assert(!arg2.empty());
arg2.print();
break;
case '3':
assert(!arg3.empty());
arg3.print();
break;
default:
assert(0);
}
}
else
putc(c, stderr);
}
}

View File

@ -1,137 +0,0 @@
// -*- 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "errarg.h"
#include "error.h"
extern void fatal_error_exit();
enum error_type { WARNING, ERROR, FATAL };
static void do_error_with_file_and_line(const char *filename, int lineno,
error_type type,
const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
int need_space = 0;
if (program_name) {
fprintf(stderr, "%s:", program_name);
need_space = 1;
}
if (lineno >= 0 && filename != 0) {
if (strcmp(filename, "-") == 0)
filename = "<standard input>";
fprintf(stderr, "%s:%d:", filename, lineno);
need_space = 1;
}
switch (type) {
case FATAL:
fputs("fatal error:", stderr);
need_space = 1;
break;
case ERROR:
break;
case WARNING:
fputs("warning:", stderr);
need_space = 1;
break;
}
if (need_space)
fputc(' ', stderr);
errprint(format, arg1, arg2, arg3);
fputc('\n', stderr);
fflush(stderr);
if (type == FATAL)
fatal_error_exit();
}
static void do_error(error_type type,
const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error_with_file_and_line(current_filename, current_lineno,
type, format, arg1, arg2, arg3);
}
void error(const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error(ERROR, format, arg1, arg2, arg3);
}
void warning(const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error(WARNING, format, arg1, arg2, arg3);
}
void fatal(const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error(FATAL, format, arg1, arg2, arg3);
}
void error_with_file_and_line(const char *filename,
int lineno,
const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error_with_file_and_line(filename, lineno,
ERROR, format, arg1, arg2, arg3);
}
void warning_with_file_and_line(const char *filename,
int lineno,
const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error_with_file_and_line(filename, lineno,
WARNING, format, arg1, arg2, arg3);
}
void fatal_with_file_and_line(const char *filename,
int lineno,
const char *format,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
do_error_with_file_and_line(filename, lineno,
FATAL, format, arg1, arg2, arg3);
}

View File

@ -1,27 +0,0 @@
/* 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 <stdlib.h>
#define FATAL_ERROR_EXIT_CODE 3
void fatal_error_exit()
{
exit(FATAL_ERROR_EXIT_CODE);
}

View File

@ -1 +0,0 @@
const char *current_filename = 0;

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
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 "lib.h"
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include "font.h"
#include "searchpath.h"
#include "device.h"
#include "defs.h"
const char *const FONT_ENV_VAR = "GROFF_FONT_PATH";
static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0);
int font::res = 0;
int font::hor = 1;
int font::vert = 1;
int font::unitwidth = 0;
int font::paperwidth = 0;
int font::paperlength = 0;
const char *font::papersize = 0;
int font::biggestfont = 0;
int font::spare2 = 0;
int font::sizescale = 1;
int font::tcommand = 0;
int font::pass_filenames = 0;
int font::use_charnames_in_special = 0;
const char **font::font_name_table = 0;
int *font::sizes = 0;
const char *font::family = 0;
const char **font::style_table = 0;
FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0;
void font::command_line_font_dir(const char *dir)
{
font_path.command_line_dir(dir);
}
FILE *font::open_file(const char *name, char **pathp)
{
char *filename = new char[strlen(name) + strlen(device) + 5];
sprintf(filename, "dev%s/%s", device, name);
FILE *fp = font_path.open_file(filename, pathp);
a_delete filename;
return fp;
}

View File

@ -1,286 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by Gaius Mulley <gaius@glam.ac.uk>
using adjust_arc_center() from printer.cc, written by James Clark.
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 <math.h>
#undef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#undef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
// This utility function adjusts the specified center of the
// arc so that it is equidistant between the specified start
// and end points. (p[0], p[1]) is a vector from the current
// point to the center; (p[2], p[3]) is a vector from the
// center to the end point. If the center can be adjusted,
// a vector from the current point to the adjusted center is
// stored in c[0], c[1] and 1 is returned. Otherwise 0 is
// returned.
#if 1
int adjust_arc_center(const int *p, double *c)
{
// We move the center along a line parallel to the line between
// the specified start point and end point so that the center
// is equidistant between the start and end point.
// It can be proved (using Lagrange multipliers) that this will
// give the point nearest to the specified center that is equidistant
// between the start and end point.
double x = p[0] + p[2]; // (x, y) is the end point
double y = p[1] + p[3];
double n = x*x + y*y;
if (n != 0) {
c[0]= double(p[0]);
c[1] = double(p[1]);
double k = .5 - (c[0]*x + c[1]*y)/n;
c[0] += k*x;
c[1] += k*y;
return 1;
}
else
return 0;
}
#else
int printer::adjust_arc_center(const int *p, double *c)
{
int x = p[0] + p[2]; // (x, y) is the end point
int y = p[1] + p[3];
// Start at the current point; go in the direction of the specified
// center point until we reach a point that is equidistant between
// the specified starting point and the specified end point. Place
// the center of the arc there.
double n = p[0]*double(x) + p[1]*double(y);
if (n > 0) {
double k = (double(x)*x + double(y)*y)/(2.0*n);
// (cx, cy) is our chosen center
c[0] = k*p[0];
c[1] = k*p[1];
return 1;
}
else {
// We would never reach such a point. So instead start at the
// specified end point of the arc. Go towards the specified
// center point until we reach a point that is equidistant between
// the specified start point and specified end point. Place
// the center of the arc there.
n = p[2]*double(x) + p[3]*double(y);
if (n > 0) {
double k = 1 - (double(x)*x + double(y)*y)/(2.0*n);
// (c[0], c[1]) is our chosen center
c[0] = p[0] + k*p[2];
c[1] = p[1] + k*p[3];
return 1;
}
else
return 0;
}
}
#endif
/*
* check_output_arc_limits - works out the smallest box that will encompass
* an arc defined by an origin (x, y) and two
* vectors (p0, p1) and (p2, p3).
* (x1, y1) -> start of arc
* (x1, y1) + (xv1, yv1) -> center of circle
* (x1, y1) + (xv1, yv1) + (xv2, yv2) -> end of arc
*
* Works out in which quadrant the arc starts and
* stops, and from this it determines the x, y
* max/min limits. The arc is drawn clockwise.
*
* [I'm sure there is a better way to do this, but
* I don't know how. Please can someone let me
* know or "improve" this function.]
*/
void check_output_arc_limits(int x1, int y1,
int xv1, int yv1,
int xv2, int yv2,
double c0, double c1,
int *minx, int *maxx,
int *miny, int *maxy)
{
int radius = (int)sqrt(c0*c0 + c1*c1);
int x2 = x1 + xv1 + xv2; // end of arc is (x2, y2)
int y2 = y1 + yv1 + yv2;
// firstly lets use the `circle' limitation
*minx = x1 + xv1 - radius;
*maxx = x1 + xv1 + radius;
*miny = y1 + yv1 - radius;
*maxy = y1 + yv1 + radius;
/* now to see which min/max can be reduced and increased for the limits of
* the arc
*
* Q2 | Q1
* -----+-----
* Q3 | Q4
*
*
* NB. (x1+xv1, y1+yv1) is at the origin
*
* below we ask a nested question
* (i) from which quadrant does the first vector start?
* (ii) into which quadrant does the second vector go?
* from the 16 possible answers we determine the limits of the arc
*/
if (xv1 > 0 && yv1 > 0) {
// first vector in Q3
if (xv2 >= 0 && yv2 >= 0 ) {
// second in Q1
*maxx = x2;
*miny = y1;
}
else if (xv2 < 0 && yv2 >= 0) {
// second in Q2
*maxx = x2;
*miny = y1;
}
else if (xv2 >= 0 && yv2 < 0) {
// second in Q4
*miny = MIN(y1, y2);
}
else if (xv2 < 0 && yv2 < 0) {
// second in Q3
if (x1 >= x2) {
*minx = x2;
*maxx = x1;
*miny = MIN(y1, y2);
*maxy = MAX(y1, y2);
}
else {
// xv2, yv2 could all be zero?
}
}
}
else if (xv1 > 0 && yv1 < 0) {
// first vector in Q2
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
*maxx = MAX(x1, x2);
*minx = MIN(x1, x2);
*miny = y1;
}
else if (xv2 < 0 && yv2 >= 0) {
// second in Q2
if (x1 < x2) {
*maxx = x2;
*minx = x1;
*miny = MIN(y1, y2);
*maxy = MAX(y1, y2);
}
else {
// otherwise almost full circle anyway
}
}
else if (xv2 >= 0 && yv2 < 0) {
// second in Q4
*miny = y2;
*minx = x1;
}
else if (xv2 < 0 && yv2 < 0) {
// second in Q3
*minx = MIN(x1, x2);
}
}
else if (xv1 <= 0 && yv1 <= 0) {
// first vector in Q1
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
if (x1 < x2) {
*minx = x1;
*maxx = x2;
*miny = MIN(y1, y2);
*maxy = MAX(y1, y2);
}
else {
// nearly full circle
}
}
else if (xv2 < 0 && yv2 >= 0) {
// second in Q2
*maxy = MAX(y1, y2);
}
else if (xv2 >= 0 && yv2 < 0) {
// second in Q4
*miny = MIN(y1, y2);
*maxy = MAX(y1, y2);
*minx = MIN(x1, x2);
}
else if (xv2 < 0 && yv2 < 0) {
// second in Q3
*minx = x2;
*maxy = y1;
}
}
else if (xv1 <= 0 && yv1 > 0) {
// first vector in Q4
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
*maxx = MAX(x1, x2);
}
else if (xv2 < 0 && yv2 >= 0) {
// second in Q2
*maxy = MAX(y1, y2);
*maxx = MAX(x1, x2);
}
else if (xv2 >= 0 && yv2 < 0) {
// second in Q4
if (x1 >= x2) {
*miny = MIN(y1, y2);
*maxy = MAX(y1, y2);
*minx = MIN(x1, x2);
*maxx = MAX(x2, x2);
}
else {
// nearly full circle
}
}
else if (xv2 < 0 && yv2 < 0) {
// second in Q3
*maxy = MAX(y1, y2);
*minx = MIN(x1, x2);
*maxx = MAX(x1, x2);
}
}
// this should *never* happen but if it does it means a case above is wrong
// this code is only present for safety sake
if (*maxx < *minx) {
fprintf(stderr, "assert failed *minx > *maxx\n");
fflush(stderr);
*maxx = *minx;
}
if (*maxy < *miny) {
fprintf(stderr, "assert failed *miny > *maxy\n");
fflush(stderr);
*maxy = *miny;
}
}

View File

@ -1,59 +0,0 @@
/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Gaius Mulley (gaius@glam.ac.uk)
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 "lib.h"
#include <stddef.h>
#include <stdlib.h>
#include "nonposix.h"
#include "stringclass.h"
#include "html-strings.h"
/*
* This file contains a very simple set of routines which might
* be shared by preprocessors. It allows a preprocessor to indicate
* when an inline image should be created.
* This string is intercepted by pre-grohtml and substituted for
* the image name and suppression escapes.
*
* pre-html runs troff twice, once with -Thtml and once with -Tps.
* troff -Thtml device driver emits a <src='image'.png> tag
* and the postscript device driver works out the min/max limits
* of the graphic region. These region limits are read by pre-html
* and an image is generated via troff -Tps -> gs -> png
*/
/*
* html_begin_suppress - emit a start of image tag which will be seen
* by pre-html.
*/
void html_begin_suppress()
{
put_string(HTML_IMAGE_INLINE_BEGIN, stdout);
}
/*
* html_end_suppress - emit an end of image tag which will be seen
* by pre-html.
*/
void html_end_suppress()
{
put_string(HTML_IMAGE_INLINE_END, stdout);
}

View File

@ -1,60 +0,0 @@
/* Copyright (C) 2000, 2002 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 "lib.h"
// Table of invalid input characters.
char invalid_char_table[256]= {
#ifndef IS_EBCDIC_HOST
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#else
1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
};

View File

@ -1,62 +0,0 @@
// -*- 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 <string.h>
#include <ctype.h>
#include "cset.h"
#include "stringclass.h"
extern void change_filename(const char *);
extern void change_lineno(int);
int interpret_lf_args(const char *p)
{
while (*p == ' ')
p++;
if (!csdigit(*p))
return 0;
int ln = 0;
do {
ln *= 10;
ln += *p++ - '0';
} while (csdigit(*p));
if (*p != ' ' && *p != '\n' && *p != '\0')
return 0;
while (*p == ' ')
p++;
if (*p == '\0' || *p == '\n') {
change_lineno(ln);
return 1;
}
const char *q;
for (q = p;
*q != '\0' && *q != ' ' && *q != '\n' && *q != '\\';
q++)
;
string tem(p, q - p);
while (*q == ' ')
q++;
if (*q != '\n' && *q != '\0')
return 0;
tem += '\0';
change_filename(tem.contents());
change_lineno(ln);
return 1;
}

View File

@ -1 +0,0 @@
int current_lineno = 0;

View File

@ -1,30 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 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. */
#include "lib.h"
#include "searchpath.h"
#include "macropath.h"
#include "defs.h"
#define MACROPATH_ENVVAR "GROFF_TMAC_PATH"
search_path macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 1);
search_path safer_macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 0);
search_path config_macro_path(MACROPATH_ENVVAR, MACROPATH, 0, 0);

View File

@ -1,69 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1992, 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. */
/* file_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */
#include "lib.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#ifdef _POSIX_VERSION
size_t file_name_max(const char *fname)
{
return pathconf(fname, _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 */
size_t file_name_max(const char *)
{
return NAME_MAX;
}
#endif /* not _POSIX_VERSION */

View File

@ -1,34 +0,0 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
Written by Werner Lemberg (wl@gnu.org)
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. */
/* This file is heavily based on the file mkstemp.c which is part of the
fileutils package. */
extern int gen_tempname(char *, int = 0);
/* Generate a unique temporary directory name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the filename unique.
Then open the directory and return a fd. */
int mksdir(char *tmpl)
{
return gen_tempname(tmpl, 1);
}

View File

@ -1,34 +0,0 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
Written by Werner Lemberg (wl@gnu.org)
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. */
/* This file is heavily based on the file mkstemp.c which is part of the
fileutils package. */
extern int gen_tempname(char *, int);
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the filename unique.
Then open the file and return a fd. */
int mkstemp(char *tmpl)
{
return gen_tempname(tmpl, 0);
}

View File

@ -1,117 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
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 "lib.h"
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include "errarg.h"
#include "error.h"
#include "font.h"
#include "ptable.h"
declare_ptable(int)
implement_ptable(int)
class character_indexer {
public:
character_indexer();
~character_indexer();
int ascii_char_index(unsigned char);
int named_char_index(const char *);
int numbered_char_index(int);
private:
enum { NSMALL = 256 };
int next_index;
int ascii_index[256];
int small_number_index[NSMALL];
PTABLE(int) table;
};
character_indexer::character_indexer()
: next_index(0)
{
int i;
for (i = 0; i < 256; i++)
ascii_index[i] = -1;
for (i = 0; i < NSMALL; i++)
small_number_index[i] = -1;
}
character_indexer::~character_indexer()
{
}
int character_indexer::ascii_char_index(unsigned char c)
{
if (ascii_index[c] < 0)
ascii_index[c] = next_index++;
return ascii_index[c];
}
int character_indexer::numbered_char_index(int n)
{
if (n >= 0 && n < NSMALL) {
if (small_number_index[n] < 0)
small_number_index[n] = next_index++;
return small_number_index[n];
}
// Not the most efficient possible implementation.
char buf[INT_DIGITS + 3];
buf[0] = ' ';
strcpy(buf + 1, i_to_a(n));
return named_char_index(buf);
}
int character_indexer::named_char_index(const char *s)
{
int *np = table.lookup(s);
if (!np) {
np = new int;
*np = next_index++;
table.define(s, np);
}
return *np;
}
static character_indexer indexer;
int font::number_to_index(int n)
{
return indexer.numbered_char_index(n);
}
int font::name_to_index(const char *s)
{
assert(s != 0 && s[0] != '\0' && s[0] != ' ');
if (s[1] == '\0')
return indexer.ascii_char_index(s[0]);
/* char128 and \200 are synonyms */
if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
char *res;
long n = strtol(s + 4, &res, 10);
if (res != s + 4 && *res == '\0' && n >= 0 && n < 256)
return indexer.ascii_char_index((unsigned char)n);
}
return indexer.named_char_index(s);
}

View File

@ -1,69 +0,0 @@
/* Copyright (C) 1989, 1990, 1991, 1992, 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 "lib.h"
#include <stddef.h>
#include <stdlib.h>
#include "posix.h"
#include "nonposix.h"
extern const char *program_name;
static void ewrite(const char *s)
{
write(2, s, strlen(s));
}
void *operator new(size_t size)
{
// Avoid relying on the behaviour of malloc(0).
if (size == 0)
size++;
#ifdef COOKIE_BUG
char *p = (char *)malloc(unsigned(size + 8));
#else /* not COOKIE_BUG */
char *p = (char *)malloc(unsigned(size));
#endif /* not COOKIE_BUG */
if (p == 0) {
if (program_name) {
ewrite(program_name);
ewrite(": ");
}
ewrite("out of memory\n");
_exit(-1);
}
#ifdef COOKIE_BUG
((unsigned *)p)[1] = 0;
return p + 8;
#else /* not COOKIE_BUG */
return p;
#endif /* not COOKIE_BUG */
}
#ifdef COOKIE_BUG
void operator delete(void *p)
{
if (p)
free((void *)((char *)p - 8));
}
#endif /* COOKIE_BUG */

View File

@ -1,84 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 2002
Free Software Foundation, Inc.
Written by Werner Lemberg (wl@gnu.org)
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 "lib.h"
#include "paper.h"
paper papersizes[NUM_PAPERSIZES];
// length and width in mm
static void add_iso_paper(char series, int offset,
int start_length, int start_width)
{
int length = start_length;
int width = start_width;
for (int i = 0; i < 8; i++)
{
char *p = new char[3];
p[0] = series;
p[1] = '0' + i;
p[2] = '\0';
papersizes[offset + i].name = p;
// convert mm to inch
papersizes[offset + i].length = (double)length / 25.4;
papersizes[offset + i].width = (double)width / 25.4;
// after division by two, values must be rounded down to the next
// integer (as specified by ISO)
int tmp = width;
width = length;
length = tmp / 2;
}
}
// length and width in inch
static void add_american_paper(const char *name, int index,
double length, double width )
{
char *p = new char[strlen(name) + 1];
strcpy(p, name);
papersizes[index].name = p;
papersizes[index].length = length;
papersizes[index].width = width;
}
int papersize_init::initialised = 0;
papersize_init::papersize_init()
{
if (initialised)
return;
initialised = 1;
add_iso_paper('a', 0, 1189, 841);
add_iso_paper('b', 8, 1414, 1000);
add_iso_paper('c', 16, 1297, 917);
add_iso_paper('d', 24, 1090, 771);
add_american_paper("letter", 32, 11, 8.5);
add_american_paper("legal", 33, 14, 8.5);
add_american_paper("tabloid", 34, 17, 11);
add_american_paper("ledger", 35, 11, 17);
add_american_paper("statement", 36, 8.5, 5.5);
add_american_paper("executive", 37, 10, 7.5);
// the next three entries are for grolj4
add_american_paper("com10", 38, 9.5, 4.125);
add_american_paper("monarch", 39, 7.5, 3.875);
// this is an ISO format, but it easier to use add_american_paper
add_american_paper("dl", 40, 220/25.4, 110/25.4);
}

View File

@ -1,26 +0,0 @@
#include <math.h>
int is_prime(unsigned n)
{
if (n <= 3)
return 1;
if (!(n & 1))
return 0;
if (n % 3 == 0)
return 0;
unsigned lim = unsigned(sqrt((double)n));
unsigned d = 5;
for (;;) {
if (d > lim)
break;
if (n % d == 0)
return 0;
d += 2;
if (d > lim)
break;
if (n % d == 0)
return 0;
d += 4;
}
return 1;
}

View File

@ -1 +0,0 @@
const char *program_name = 0;

View File

@ -1,52 +0,0 @@
/* 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 "ptable.h"
#include "errarg.h"
#include "error.h"
unsigned long hash_string(const char *s)
{
assert(s != 0);
unsigned long h = 0, g;
while (*s != 0) {
h <<= 4;
h += *s++;
if ((g = h & 0xf0000000) != 0) {
h ^= g >> 24;
h ^= g;
}
}
return h;
}
static const unsigned table_sizes[] = {
101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009,
80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009,
16000057, 32000011, 64000031, 128000003, 0
};
unsigned next_ptable_size(unsigned n)
{
const unsigned *p;
for (p = table_sizes; *p <= n; p++)
if (*p == 0)
fatal("cannot expand table");
return *p;
}

View File

@ -1,132 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 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 "lib.h"
#include <stdlib.h>
#include <assert.h>
#include "searchpath.h"
#include "nonposix.h"
search_path::search_path(const char *envvar, const char *standard,
int add_home, int add_current)
{
char *home = 0;
if (add_home)
home = getenv("HOME");
char *e = 0;
if (envvar)
e = getenv(envvar);
dirs = new char[((e && *e) ? strlen(e) + 1 : 0)
+ (add_current ? 1 + 1 : 0)
+ ((home && *home) ? strlen(home) + 1 : 0)
+ ((standard && *standard) ? strlen(standard) : 0)
+ 1];
*dirs = '\0';
if (e && *e) {
strcat(dirs, e);
strcat(dirs, PATH_SEP);
}
if (add_current) {
strcat(dirs, ".");
strcat(dirs, PATH_SEP);
}
if (home && *home) {
strcat(dirs, home);
strcat(dirs, PATH_SEP);
}
if (standard && *standard)
strcat(dirs, standard);
init_len = strlen(dirs);
}
search_path::~search_path()
{
// dirs is always allocated
a_delete dirs;
}
void search_path::command_line_dir(const char *s)
{
char *old = dirs;
unsigned old_len = strlen(old);
unsigned slen = strlen(s);
dirs = new char[old_len + 1 + slen + 1];
memcpy(dirs, old, old_len - init_len);
char *p = dirs;
p += old_len - init_len;
if (init_len == 0)
*p++ = PATH_SEP[0];
memcpy(p, s, slen);
p += slen;
if (init_len > 0) {
*p++ = PATH_SEP[0];
memcpy(p, old + old_len - init_len, init_len);
p += init_len;
}
*p++ = '\0';
a_delete old;
}
FILE *search_path::open_file(const char *name, char **pathp)
{
assert(name != 0);
if (IS_ABSOLUTE(name) || *dirs == '\0') {
FILE *fp = fopen(name, "r");
if (fp) {
if (pathp)
*pathp = strsave(name);
return fp;
}
else
return 0;
}
unsigned namelen = strlen(name);
char *p = dirs;
for (;;) {
char *end = strchr(p, PATH_SEP[0]);
if (!end)
end = strchr(p, '\0');
int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0;
char *path = new char[(end - p) + need_slash + namelen + 1];
memcpy(path, p, end - p);
if (need_slash)
path[end - p] = '/';
strcpy(path + (end - p) + need_slash, name);
#if 0
fprintf(stderr, "trying `%s'\n", path);
#endif
FILE *fp = fopen(path, "r");
if (fp) {
if (pathp)
*pathp = path;
else
a_delete path;
return fp;
}
a_delete path;
if (*end == '\0')
break;
p = end + 1;
}
return 0;
}

View File

@ -1,341 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
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 "lib.h"
#include "stringclass.h"
static char *salloc(int len, int *sizep);
static void sfree(char *ptr, int size);
static char *sfree_alloc(char *ptr, int size, int len, int *sizep);
static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep);
static char *salloc(int len, int *sizep)
{
if (len == 0) {
*sizep = 0;
return 0;
}
else
return new char[*sizep = len*2];
}
static void sfree(char *ptr, int)
{
a_delete ptr;
}
static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep)
{
if (oldsz >= len) {
*sizep = oldsz;
return ptr;
}
a_delete ptr;
if (len == 0) {
*sizep = 0;
return 0;
}
else
return new char[*sizep = len*2];
}
static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep)
{
if (oldsz >= newlen) {
*sizep = oldsz;
return ptr;
}
if (newlen == 0) {
a_delete ptr;
*sizep = 0;
return 0;
}
else {
char *p = new char[*sizep = newlen*2];
if (oldlen < newlen && oldlen != 0)
memcpy(p, ptr, oldlen);
a_delete ptr;
return p;
}
}
string::string() : ptr(0), len(0), sz(0)
{
}
string::string(const char *p, int n) : len(n)
{
assert(n >= 0);
ptr = salloc(n, &sz);
if (n != 0)
memcpy(ptr, p, n);
}
string::string(const char *p)
{
if (p == 0) {
len = 0;
ptr = 0;
sz = 0;
}
else {
len = strlen(p);
ptr = salloc(len, &sz);
memcpy(ptr, p, len);
}
}
string::string(char c) : len(1)
{
ptr = salloc(1, &sz);
*ptr = c;
}
string::string(const string &s) : len(s.len)
{
ptr = salloc(len, &sz);
if (len != 0)
memcpy(ptr, s.ptr, len);
}
string::~string()
{
sfree(ptr, sz);
}
string &string::operator=(const string &s)
{
ptr = sfree_alloc(ptr, sz, s.len, &sz);
len = s.len;
if (len != 0)
memcpy(ptr, s.ptr, len);
return *this;
}
string &string::operator=(const char *p)
{
if (p == 0) {
sfree(ptr, len);
len = 0;
ptr = 0;
sz = 0;
}
else {
int slen = strlen(p);
ptr = sfree_alloc(ptr, sz, slen, &sz);
len = slen;
memcpy(ptr, p, len);
}
return *this;
}
string &string::operator=(char c)
{
ptr = sfree_alloc(ptr, sz, 1, &sz);
len = 1;
*ptr = c;
return *this;
}
void string::move(string &s)
{
sfree(ptr, sz);
ptr = s.ptr;
len = s.len;
sz = s.sz;
s.ptr = 0;
s.len = 0;
s.sz = 0;
}
void string::grow1()
{
ptr = srealloc(ptr, sz, len, len + 1, &sz);
}
string &string::operator+=(const char *p)
{
if (p != 0) {
int n = strlen(p);
int newlen = len + n;
if (newlen > sz)
ptr = srealloc(ptr, sz, len, newlen, &sz);
memcpy(ptr + len, p, n);
len = newlen;
}
return *this;
}
string &string::operator+=(const string &s)
{
if (s.len != 0) {
int newlen = len + s.len;
if (newlen > sz)
ptr = srealloc(ptr, sz, len, newlen, &sz);
memcpy(ptr + len, s.ptr, s.len);
len = newlen;
}
return *this;
}
void string::append(const char *p, int n)
{
if (n > 0) {
int newlen = len + n;
if (newlen > sz)
ptr = srealloc(ptr, sz, len, newlen, &sz);
memcpy(ptr + len, p, n);
len = newlen;
}
}
string::string(const char *s1, int n1, const char *s2, int n2)
{
assert(n1 >= 0 && n2 >= 0);
len = n1 + n2;
if (len == 0) {
sz = 0;
ptr = 0;
}
else {
ptr = salloc(len, &sz);
if (n1 == 0)
memcpy(ptr, s2, n2);
else {
memcpy(ptr, s1, n1);
if (n2 != 0)
memcpy(ptr + n1, s2, n2);
}
}
}
int operator<=(const string &s1, const string &s2)
{
return (s1.len <= s2.len
? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
: s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
}
int operator<(const string &s1, const string &s2)
{
return (s1.len < s2.len
? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0
: s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0);
}
int operator>=(const string &s1, const string &s2)
{
return (s1.len >= s2.len
? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
: s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
}
int operator>(const string &s1, const string &s2)
{
return (s1.len > s2.len
? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0
: s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0);
}
void string::set_length(int i)
{
assert(i >= 0);
if (i > sz)
ptr = srealloc(ptr, sz, len, i, &sz);
len = i;
}
void string::clear()
{
len = 0;
}
int string::search(char c) const
{
char *p = ptr ? (char *)memchr(ptr, c, len) : NULL;
return p ? p - ptr : -1;
}
// we silently strip nuls
char *string::extract() const
{
char *p = ptr;
int n = len;
int nnuls = 0;
int i;
for (i = 0; i < n; i++)
if (p[i] == '\0')
nnuls++;
char *q = new char[n + 1 - nnuls];
char *r = q;
for (i = 0; i < n; i++)
if (p[i] != '\0')
*r++ = p[i];
*r = '\0';
return q;
}
void string::remove_spaces()
{
int l = len - 1;
while (l >= 0 && ptr[l] == ' ')
l--;
char *p = ptr;
if (l > 0)
while (*p == ' ') {
p++;
l--;
}
if (len - 1 != l) {
if (l >= 0) {
len = l + 1;
char *tmp = new char[len];
memcpy(tmp, p, len);
a_delete ptr;
ptr = tmp;
}
else {
len = 0;
if (ptr) {
a_delete ptr;
ptr = 0;
}
}
}
}
void put_string(const string &s, FILE *fp)
{
int len = s.length();
const char *ptr = s.contents();
for (int i = 0; i < len; i++)
putc(ptr[i], fp);
}
string as_string(int i)
{
static char buf[INT_DIGITS + 2];
sprintf(buf, "%d", i);
return string(buf);
}

View File

@ -1,31 +0,0 @@
// -*- 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 <string.h>
char *strsave(const char *s)
{
if (s == 0)
return 0;
char *p = new char[strlen(s) + 1];
strcpy(p, s);
return p;
}

View File

@ -1,172 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 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 "lib.h"
#include <errno.h>
#include <stdlib.h>
#include "posix.h"
#include "errarg.h"
#include "error.h"
#include "nonposix.h"
// If this is set, create temporary files there
#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR"
// otherwise if this is set, create temporary files there
#define TMPDIR_ENVVAR "TMPDIR"
// otherwise if P_tmpdir is defined, create temporary files there
#ifdef P_tmpdir
# define DEFAULT_TMPDIR P_tmpdir
#else
// otherwise create temporary files here.
# define DEFAULT_TMPDIR "/tmp"
#endif
// Use this as the prefix for temporary filenames.
#define TMPFILE_PREFIX_SHORT ""
#define TMPFILE_PREFIX_LONG "groff"
char *tmpfile_prefix;
size_t tmpfile_prefix_len;
int use_short_postfix = 0;
struct temp_init {
temp_init();
~temp_init();
} _temp_init;
temp_init::temp_init()
{
const char *tem = getenv(GROFF_TMPDIR_ENVVAR);
if (!tem) {
tem = getenv(TMPDIR_ENVVAR);
if (!tem)
tem = DEFAULT_TMPDIR;
}
size_t tem_len = strlen(tem);
const char *tem_end = tem + tem_len - 1;
int need_slash = strchr(DIR_SEPS, *tem_end) == NULL ? 1 : 0;
char *tem2 = new char[tem_len + need_slash + 1];
strcpy(tem2, tem);
if (need_slash)
strcat(tem2, "/");
const char *tem3 = TMPFILE_PREFIX_LONG;
if (file_name_max(tem2) <= 14) {
tem3 = TMPFILE_PREFIX_SHORT;
use_short_postfix = 1;
}
tmpfile_prefix_len = tem_len + need_slash + strlen(tem3);
tmpfile_prefix = new char[tmpfile_prefix_len + 1];
strcpy(tmpfile_prefix, tem2);
strcat(tmpfile_prefix, tem3);
a_delete tem2;
}
temp_init::~temp_init()
{
a_delete tmpfile_prefix;
}
/*
* Generate a temporary name template with a postfix
* immediately after the TMPFILE_PREFIX.
* It uses the groff preferences for a temporary directory.
* Note that no file name is either created or opened,
* only the *template* is returned.
*/
char *xtmptemplate(const char *postfix_long, const char *postfix_short)
{
const char *postfix = use_short_postfix ? postfix_short : postfix_long;
int postlen = 0;
if (postfix)
postlen = strlen(postfix);
char *templ = new char[tmpfile_prefix_len + postlen + 6 + 1];
strcpy(templ, tmpfile_prefix);
if (postlen > 0)
strcat(templ, postfix);
strcat(templ, "XXXXXX");
return templ;
}
// The trick with unlinking the temporary file while it is still in
// use is not portable, it will fail on MS-DOS and most MS-Windows
// filesystems. So it cannot be used on non-Posix systems.
// Instead, we maintain a list of files to be deleted on exit.
// This should be portable to all platforms.
struct xtmpfile_list {
char *fname;
xtmpfile_list *next;
xtmpfile_list(char *fn) : fname(fn), next(0) {}
};
xtmpfile_list *xtmpfiles_to_delete = 0;
struct xtmpfile_list_init {
~xtmpfile_list_init();
} _xtmpfile_list_init;
xtmpfile_list_init::~xtmpfile_list_init()
{
xtmpfile_list *x = xtmpfiles_to_delete;
while (x != 0) {
if (unlink(x->fname) < 0)
error("cannot unlink `%1': %2", x->fname, strerror(errno));
xtmpfile_list *tmp = x;
x = x->next;
a_delete tmp->fname;
delete tmp;
}
}
static void add_tmp_file(const char *name)
{
char *s = new char[strlen(name)+1];
strcpy(s, name);
xtmpfile_list *x = new xtmpfile_list(s);
x->next = xtmpfiles_to_delete;
xtmpfiles_to_delete = x;
}
// Open a temporary file and with fatal error on failure.
FILE *xtmpfile(char **namep,
const char *postfix_long, const char *postfix_short,
int do_unlink)
{
char *templ = xtmptemplate(postfix_long, postfix_short);
errno = 0;
int fd = mkstemp(templ);
if (fd < 0)
fatal("cannot create temporary file: %1", strerror(errno));
errno = 0;
FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O
if (!fp)
fatal("fdopen: %1", strerror(errno));
if (do_unlink)
add_tmp_file(templ);
if (namep)
*namep = templ;
else
a_delete templ;
return fp;
}

View File

@ -1,116 +0,0 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
Written by Werner Lemberg (wl@gnu.org)
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. */
/* This file is heavily based on the function __gen_tempname() in the
file tempname.c which is part of the fileutils package. */
#include "lib.h"
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "posix.h"
#include "nonposix.h"
#ifndef TMP_MAX
# define TMP_MAX 238328
#endif
#if HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#ifdef NEED_DECLARATION_GETTIMEOFDAY
extern "C" {
int gettimeofday(struct timeval *, void *);
}
#endif
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
/* Use the widest available unsigned type if uint64_t is not
available. The algorithm below extracts a number less than 62**6
(approximately 2**35.725) from uint64_t, so ancient hosts where
uintmax_t is only 32 bits lose about 3.725 bits of randomness,
which is better than not having mkstemp at all. */
#if !defined UINT64_MAX && !defined uint64_t
# define uint64_t uintmax_t
#endif
/* These are the characters used in temporary filenames. */
static const char letters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int gen_tempname(char *tmpl, int dir)
{
static uint64_t value;
size_t len = strlen(tmpl);
if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX"))
return -1; /* EINVAL */
/* This is where the Xs start. */
char *XXXXXX = &tmpl[len - 6];
/* Get some more or less random data. */
#if HAVE_GETTIMEOFDAY
timeval tv;
gettimeofday(&tv, NULL);
uint64_t random_time_bits = ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec;
#else
uint64_t random_time_bits = time(NULL);
#endif
value += random_time_bits ^ getpid();
for (int count = 0; count < TMP_MAX; value += 7777, ++count) {
uint64_t v = value;
/* Fill in the random bits. */
XXXXXX[0] = letters[v % 62];
v /= 62;
XXXXXX[1] = letters[v % 62];
v /= 62;
XXXXXX[2] = letters[v % 62];
v /= 62;
XXXXXX[3] = letters[v % 62];
v /= 62;
XXXXXX[4] = letters[v % 62];
v /= 62;
XXXXXX[5] = letters[v % 62];
int fd = dir ? mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR)
: open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd >= 0)
return fd;
else if (errno != EEXIST)
return -1;
}
/* We got out of the loop because we ran out of combinations to try. */
return -1; /* EEXIST */
}

View File

@ -1,611 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h"
#include "pbox.h"
const char *current_roman_font;
char *gfont = 0;
char *grfont = 0;
char *gbfont = 0;
int gsize = 0;
int script_size_reduction = -1; // negative means reduce by a percentage
int positive_space = -1;
int negative_space = -1;
int minimum_size = 5;
int fat_offset = 4;
int body_height = 85;
int body_depth = 35;
int over_hang = 0;
int accent_width = 31;
int delimiter_factor = 900;
int delimiter_shortfall = 50;
int null_delimiter_space = 12;
int script_space = 5;
int thin_space = 17;
int medium_space = 22;
int thick_space = 28;
int num1 = 70;
int num2 = 40;
// we don't use num3, because we don't have \atop
int denom1 = 70;
int denom2 = 36;
int axis_height = 26; // in 100ths of an em
int sup1 = 42;
int sup2 = 37;
int sup3 = 28;
int default_rule_thickness = 4;
int sub1 = 20;
int sub2 = 23;
int sup_drop = 38;
int sub_drop = 5;
int x_height = 45;
int big_op_spacing1 = 11;
int big_op_spacing2 = 17;
int big_op_spacing3 = 20;
int big_op_spacing4 = 60;
int big_op_spacing5 = 10;
// These are for piles and matrices.
int baseline_sep = 140; // = num1 + denom1
int shift_down = 26; // = axis_height
int column_sep = 100; // = em space
int matrix_side_sep = 17; // = thin space
int nroff = 0; // should we grok ndefine or tdefine?
struct {
const char *name;
int *ptr;
} param_table[] = {
{ "fat_offset", &fat_offset },
{ "over_hang", &over_hang },
{ "accent_width", &accent_width },
{ "delimiter_factor", &delimiter_factor },
{ "delimiter_shortfall", &delimiter_shortfall },
{ "null_delimiter_space", &null_delimiter_space },
{ "script_space", &script_space },
{ "thin_space", &thin_space },
{ "medium_space", &medium_space },
{ "thick_space", &thick_space },
{ "num1", &num1 },
{ "num2", &num2 },
{ "denom1", &denom1 },
{ "denom2", &denom2 },
{ "axis_height", &axis_height },
{ "sup1", &sup1 },
{ "sup2", &sup2 },
{ "sup3", &sup3 },
{ "default_rule_thickness", &default_rule_thickness },
{ "sub1", &sub1 },
{ "sub2", &sub2 },
{ "sup_drop", &sup_drop },
{ "sub_drop", &sub_drop },
{ "x_height", &x_height },
{ "big_op_spacing1", &big_op_spacing1 },
{ "big_op_spacing2", &big_op_spacing2 },
{ "big_op_spacing3", &big_op_spacing3 },
{ "big_op_spacing4", &big_op_spacing4 },
{ "big_op_spacing5", &big_op_spacing5 },
{ "minimum_size", &minimum_size },
{ "baseline_sep", &baseline_sep },
{ "shift_down", &shift_down },
{ "column_sep", &column_sep },
{ "matrix_side_sep", &matrix_side_sep },
{ "draw_lines", &draw_flag },
{ "body_height", &body_height },
{ "body_depth", &body_depth },
{ "nroff", &nroff },
{ 0, 0 }
};
void set_param(const char *name, int value)
{
for (int i = 0; param_table[i].name != 0; i++)
if (strcmp(param_table[i].name, name) == 0) {
*param_table[i].ptr = value;
return;
}
error("unrecognised parameter `%1'", name);
}
int script_style(int style)
{
return style > SCRIPT_STYLE ? style - 2 : style;
}
int cramped_style(int style)
{
return (style & 1) ? style - 1 : style;
}
void set_space(int n)
{
if (n < 0)
negative_space = -n;
else
positive_space = n;
}
// Return 0 if the specified size is bad.
// The caller is responsible for giving the error message.
int set_gsize(const char *s)
{
const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
char *end;
long n = strtol(p, &end, 10);
if (n <= 0 || *end != '\0' || n > INT_MAX)
return 0;
if (p > s) {
if (!gsize)
gsize = 10;
if (*s == '+') {
if (gsize > INT_MAX - n)
return 0;
gsize += int(n);
}
else {
if (gsize - n <= 0)
return 0;
gsize -= int(n);
}
}
else
gsize = int(n);
return 1;
}
void set_script_reduction(int n)
{
script_size_reduction = n;
}
const char *get_gfont()
{
return gfont ? gfont : "I";
}
const char *get_grfont()
{
return grfont ? grfont : "R";
}
const char *get_gbfont()
{
return gbfont ? gbfont : "B";
}
void set_gfont(const char *s)
{
a_delete gfont;
gfont = strsave(s);
}
void set_grfont(const char *s)
{
a_delete grfont;
grfont = strsave(s);
}
void set_gbfont(const char *s)
{
a_delete gbfont;
gbfont = strsave(s);
}
// this must be precisely 2 characters in length
#define COMPATIBLE_REG "0C"
void start_string()
{
printf(".nr " COMPATIBLE_REG " \\n(.C\n");
printf(".cp 0\n");
printf(".ds " LINE_STRING "\n");
}
void output_string()
{
printf("\\*(" LINE_STRING "\n");
}
void restore_compatibility()
{
printf(".cp \\n(" COMPATIBLE_REG "\n");
}
void do_text(const char *s)
{
printf(".eo\n");
printf(".as " LINE_STRING " \"%s\n", s);
printf(".ec\n");
}
void set_minimum_size(int n)
{
minimum_size = n;
}
void set_script_size()
{
if (minimum_size < 0)
minimum_size = 0;
if (script_size_reduction >= 0)
printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
else
printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size);
}
int box::next_uid = 0;
box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
{
}
box::~box()
{
}
void box::top_level()
{
// debug_print();
// putc('\n', stderr);
box *b = this;
printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
printf(".ft\n");
printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
printf(".ft %s\n", get_gfont());
printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
if (gsize > 0) {
char buf[INT_DIGITS + 1];
sprintf(buf, "%d", gsize);
b = new size_box(strsave(buf), b);
}
current_roman_font = get_grfont();
// This catches tabs used within \Z (which aren't allowed).
b->check_tabs(0);
int r = b->compute_metrics(DISPLAY_STYLE);
printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
printf(".ft \\n[" SAVED_FONT_REG "]\n");
printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
if (r == FOUND_MARK) {
printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
}
else if (r == FOUND_LINEUP)
printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
else
assert(r == FOUND_NOTHING);
// The problem here is that the argument to \f is read in copy mode,
// so we cannot use \E there; so we hide it in a string instead.
// Another problem is that if we use \R directly, then the space will
// prevent it working in a macro argument.
printf(".ds " SAVE_FONT_STRING " "
"\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
"\\fP"
"\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
"\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.ps]'"
"\\s0"
"\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.ps]'"
"\n"
".ds " RESTORE_FONT_STRING " "
"\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
"\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
"\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
"\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
"\n");
printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
printf("\\f[%s]", get_gfont());
printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
current_roman_font = get_grfont();
b->output();
printf("\\E*[" RESTORE_FONT_STRING "]\n");
if (r == FOUND_LINEUP)
printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
b->uid);
b->extra_space();
if (!inline_flag)
printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
DEPTH_FORMAT "]u-%dM>?0)\n",
b->uid, body_height, b->uid, body_depth);
delete b;
next_uid = 0;
}
// gpic defines this register so as to make geqn not produce `\x's
#define EQN_NO_EXTRA_SPACE_REG "0x"
void box::extra_space()
{
printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
if (positive_space >= 0 || negative_space >= 0) {
if (positive_space > 0)
printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
if (negative_space > 0)
printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
positive_space = negative_space = -1;
}
else {
printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
" \\x'-(\\n[" HEIGHT_FORMAT
"]u-%dM)'\n",
uid, body_height, uid, body_height);
printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
" \\x'\\n[" DEPTH_FORMAT
"]u-%dM'\n",
uid, body_depth, uid, body_depth);
}
}
int box::compute_metrics(int)
{
printf(".nr " WIDTH_FORMAT " 0\n", uid);
printf(".nr " HEIGHT_FORMAT " 0\n", uid);
printf(".nr " DEPTH_FORMAT " 0\n", uid);
return FOUND_NOTHING;
}
void box::compute_subscript_kern()
{
printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
}
void box::compute_skew()
{
printf(".nr " SKEW_FORMAT " 0\n", uid);
}
void box::output()
{
}
void box::check_tabs(int)
{
}
int box::is_char()
{
return 0;
}
int box::left_is_italic()
{
return 0;
}
int box::right_is_italic()
{
return 0;
}
void box::hint(unsigned)
{
}
void box::handle_char_type(int, int)
{
}
box_list::box_list(box *pp)
{
p = new box*[10];
for (int i = 0; i < 10; i++)
p[i] = 0;
maxlen = 10;
len = 1;
p[0] = pp;
}
void box_list::append(box *pp)
{
if (len + 1 > maxlen) {
box **oldp = p;
maxlen *= 2;
p = new box*[maxlen];
memcpy(p, oldp, sizeof(box*)*len);
a_delete oldp;
}
p[len++] = pp;
}
box_list::~box_list()
{
for (int i = 0; i < len; i++)
delete p[i];
a_delete p;
}
void box_list::list_check_tabs(int level)
{
for (int i = 0; i < len; i++)
p[i]->check_tabs(level);
}
pointer_box::pointer_box(box *pp) : p(pp)
{
spacing_type = p->spacing_type;
}
pointer_box::~pointer_box()
{
delete p;
}
int pointer_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return r;
}
void pointer_box::compute_subscript_kern()
{
p->compute_subscript_kern();
printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
}
void pointer_box::compute_skew()
{
p->compute_skew();
printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
uid, p->uid);
}
void pointer_box::check_tabs(int level)
{
p->check_tabs(level);
}
int simple_box::compute_metrics(int)
{
printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
output();
printf(DELIMITER_CHAR "\n");
printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
return FOUND_NOTHING;
}
void simple_box::compute_subscript_kern()
{
// do nothing, we already computed it in do_metrics
}
void simple_box::compute_skew()
{
// do nothing, we already computed it in do_metrics
}
int box::is_simple()
{
return 0;
}
int simple_box::is_simple()
{
return 1;
}
quoted_text_box::quoted_text_box(char *s) : text(s)
{
}
quoted_text_box::~quoted_text_box()
{
a_delete text;
}
void quoted_text_box::output()
{
if (text)
fputs(text, stdout);
}
tab_box::tab_box() : disabled(0)
{
}
// We treat a tab_box as having width 0 for width computations.
void tab_box::output()
{
if (!disabled)
printf("\\t");
}
void tab_box::check_tabs(int level)
{
if (level > 0) {
error("tabs allowed only at outermost level");
disabled = 1;
}
}
space_box::space_box()
{
spacing_type = SUPPRESS_TYPE;
}
void space_box::output()
{
printf("\\h'%dM'", thick_space);
}
half_space_box::half_space_box()
{
spacing_type = SUPPRESS_TYPE;
}
void half_space_box::output()
{
printf("\\h'%dM'", thin_space);
}
void box_list::list_debug_print(const char *sep)
{
p[0]->debug_print();
for (int i = 1; i < len; i++) {
fprintf(stderr, "%s", sep);
p[i]->debug_print();
}
}
void quoted_text_box::debug_print()
{
fprintf(stderr, "\"%s\"", (text ? text : ""));
}
void half_space_box::debug_print()
{
fprintf(stderr, "^");
}
void space_box::debug_print()
{
fprintf(stderr, "~");
}
void tab_box::debug_print()
{
fprintf(stderr, "<tab>");
}

View File

@ -1,381 +0,0 @@
// -*- 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 "eqn.h"
#include "pbox.h"
enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
// Small must be none-zero and must exist in each device.
// Small will be put in the roman font, others are assumed to be
// on the special font (so no font change will be necessary.)
struct delimiter {
const char *name;
int flags;
const char *small;
const char *chain_format;
const char *ext;
const char *top;
const char *mid;
const char *bot;
} delim_table[] = {
{
"(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
"\\[parenleftex]",
"\\[parenlefttp]",
0,
"\\[parenleftbt]",
},
{
")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
"\\[parenrightex]",
"\\[parenrighttp]",
0,
"\\[parenrightbt]",
},
{
"[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
"\\[bracketleftex]",
"\\[bracketlefttp]",
0,
"\\[bracketleftbt]",
},
{
"]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
"\\[bracketrightex]",
"\\[bracketrighttp]",
0,
"\\[bracketrightbt]",
},
{
"{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
"\\[braceleftex]",
"\\[bracelefttp]",
"\\[braceleftmid]",
"\\[braceleftbt]",
},
{
"}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
"\\[bracerightex]",
"\\[bracerighttp]",
"\\[bracerightmid]",
"\\[bracerightbt]",
},
{
"|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
"\\[barex]",
},
{
"floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
"\\[bracketleftex]",
0,
0,
"\\[bracketleftbt]",
},
{
"floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
"\\[bracketrightex]",
0,
0,
"\\[bracketrightbt]",
},
{
"ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
"\\[bracketleftex]",
"\\[bracketlefttp]",
},
{
"ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
"\\[bracketrightex]",
"\\[bracketrighttp]",
},
{
"||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
"\\[bardblex]",
},
{
"<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
},
{
">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
},
{
"uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
"\\[arrowvertex]",
"\\[arrowverttp]",
},
{
"downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
"\\[arrowvertex]",
0,
0,
"\\[arrowvertbt]",
},
{
"updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
"\\[arrowvertex]",
"\\[arrowverttp]",
0,
"\\[arrowvertbt]",
},
};
const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
class delim_box : public box {
private:
char *left;
char *right;
box *p;
public:
delim_box(char *, box *, char *);
~delim_box();
int compute_metrics(int);
void output();
void check_tabs(int);
void debug_print();
};
box *make_delim_box(char *l, box *pp, char *r)
{
if (l != 0 && *l == '\0') {
a_delete l;
l = 0;
}
if (r != 0 && *r == '\0') {
a_delete r;
r = 0;
}
return new delim_box(l, pp, r);
}
delim_box::delim_box(char *l, box *pp, char *r)
: left(l), right(r), p(pp)
{
}
delim_box::~delim_box()
{
a_delete left;
a_delete right;
delete p;
}
static void build_extensible(const char *ext, const char *top, const char *mid,
const char *bot)
{
assert(ext != 0);
printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
ext);
printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
if (top) {
printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
top);
printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
}
if (mid) {
printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
mid);
printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
}
if (bot) {
printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
bot);
printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
}
printf(".nr " TOTAL_HEIGHT_REG " 0");
if (top)
printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
if (bot)
printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
if (mid)
printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
printf("\n");
// determine how many extensible characters we need
printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
if (mid)
printf("/2");
printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
if (mid)
printf("*2");
printf(")\n");
printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
"\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
axis_height);
if (top)
printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
"\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
"\\v'\\n[" TOP_DEPTH_REG "]u'\n",
top);
// this macro appends $2 copies of $3 to string $1
printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
"." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
".\\}\n"
"..\n");
printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
"\\v'\\n[" EXT_HEIGHT_REG "]u'"
"\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
"\\v'\\n[" EXT_DEPTH_REG "]u'\n",
ext);
if (mid) {
printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
"\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
"\\v'\\n[" MID_DEPTH_REG "]u'\n",
mid);
printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
" \\n[" TEMP_REG "] "
"\\v'\\n[" EXT_HEIGHT_REG "]u'"
"\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
"\\v'\\n[" EXT_DEPTH_REG "]u'\n",
ext);
}
if (bot)
printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
"\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
"\\v'\\n[" BOT_DEPTH_REG "]u'\n",
bot);
printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
}
static void define_extensible_string(char *delim, int uid,
left_or_right_t left_or_right)
{
printf(".ds " DELIM_STRING "\n");
delimiter *d = delim_table;
int delim_len = strlen(delim);
int i;
for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
if (strncmp(delim, d->name, delim_len) == 0
&& (left_or_right & d->flags) != 0)
break;
if (i >= DELIM_TABLE_SIZE) {
error("there is no `%1' delimiter", delim);
printf(".nr " DELIM_WIDTH_REG " 0\n");
return;
}
printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
"\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
"\\{",
current_roman_font, d->small, axis_height,
current_roman_font, d->small);
char buf[256];
sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
printf(".nr " INDEX_REG " 0\n"
".de " TEMP_MACRO "\n"
".ie c%s \\{\\\n"
".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
"\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
"\\{.nr " INDEX_REG " +1\n"
"." TEMP_MACRO "\n"
".\\}\\}\n"
".el .nr " INDEX_REG " 0-1\n"
"..\n"
"." TEMP_MACRO "\n",
buf, buf, axis_height, buf);
if (d->ext) {
printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
build_extensible(d->ext, d->top, d->mid, d->bot);
printf(".\\}\\}\n");
}
printf(".\\}\n");
printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
uid, uid, axis_height);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
uid, uid, axis_height);
}
int delim_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
p->uid, axis_height, p->uid, axis_height);
printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
">?(\\n[" DELTA_REG "]*2-%dM)\n",
delimiter_factor, delimiter_shortfall);
if (left) {
define_extensible_string(left, uid, LEFT_DELIM);
printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
uid);
if (r)
printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
}
if (right) {
define_extensible_string(right, uid, RIGHT_DELIM);
printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
uid);
}
return r;
}
void delim_box::output()
{
if (left)
printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
p->output();
if (right)
printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
}
void delim_box::check_tabs(int level)
{
p->check_tabs(level);
}
void delim_box::debug_print()
{
fprintf(stderr, "left \"%s\" { ", left ? left : "");
p->debug_print();
fprintf(stderr, " }");
if (right)
fprintf(stderr, " right \"%s\"", right);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h"
#include "pbox.h"
class limit_box : public box {
private:
box *p;
box *from;
box *to;
public:
limit_box(box *, box *, box *);
~limit_box();
int compute_metrics(int);
void output();
void debug_print();
void check_tabs(int);
};
box *make_limit_box(box *pp, box *qq, box *rr)
{
return new limit_box(pp, qq, rr);
}
limit_box::limit_box(box *pp, box *qq, box *rr)
: p(pp), from(qq), to(rr)
{
spacing_type = p->spacing_type;
}
limit_box::~limit_box()
{
delete p;
delete from;
delete to;
}
int limit_box::compute_metrics(int style)
{
printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
set_script_size();
printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
int res = 0;
int mark_uid = -1;
if (from != 0) {
res = from->compute_metrics(cramped_style(script_style(style)));
if (res)
mark_uid = from->uid;
}
if (to != 0) {
int r = to->compute_metrics(script_style(style));
if (res && r)
error("multiple marks and lineups");
else {
mark_uid = to->uid;
res = r;
}
}
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
int r = p->compute_metrics(style);
p->compute_subscript_kern();
if (res && r)
error("multiple marks and lineups");
else {
mark_uid = p->uid;
res = r;
}
printf(".nr " LEFT_WIDTH_FORMAT " "
"0\\n[" WIDTH_FORMAT "]",
uid, p->uid);
if (from != 0)
printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
p->uid, from->uid);
if (to != 0)
printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
p->uid, to->uid);
printf("/2\n");
printf(".nr " WIDTH_FORMAT " "
"0\\n[" WIDTH_FORMAT "]",
uid, p->uid);
if (from != 0)
printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
p->uid, from->uid);
if (to != 0)
printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
p->uid, to->uid);
printf("/2+\\n[" LEFT_WIDTH_FORMAT "]\n", uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
if (to != 0)
printf(">?\\n[" WIDTH_FORMAT "]", to->uid);
if (from != 0)
printf(">?\\n[" WIDTH_FORMAT "]", from->uid);
printf("\n");
if (res)
printf(".nr " MARK_REG " +(\\n[" LEFT_WIDTH_FORMAT "]"
"-(\\n[" WIDTH_FORMAT "]/2))\n",
uid, mark_uid);
if (to != 0) {
printf(".nr " SUP_RAISE_FORMAT " %dM+\\n[" DEPTH_FORMAT
"]>?%dM+\\n[" HEIGHT_FORMAT "]\n",
uid, big_op_spacing1, to->uid, big_op_spacing3, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
HEIGHT_FORMAT "]+%dM\n",
uid, uid, to->uid, big_op_spacing5);
}
else
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
if (from != 0) {
printf(".nr " SUB_LOWER_FORMAT " %dM+\\n[" HEIGHT_FORMAT
"]>?%dM+\\n[" DEPTH_FORMAT "]\n",
uid, big_op_spacing2, from->uid, big_op_spacing4, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
DEPTH_FORMAT "]+%dM\n",
uid, uid, from->uid, big_op_spacing5);
}
else
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return res;
}
void limit_box::output()
{
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
if (to != 0) {
printf("\\Z" DELIMITER_CHAR);
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
"+(-\\n[" WIDTH_FORMAT "]u+\\n[" SUB_KERN_FORMAT "]u/2u)'",
uid, to->uid, p->uid);
to->output();
printf(DELIMITER_CHAR);
}
if (from != 0) {
printf("\\Z" DELIMITER_CHAR);
printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
"+(-\\n[" SUB_KERN_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
uid, p->uid, from->uid);
from->output();
printf(DELIMITER_CHAR);
}
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
"-(\\n[" WIDTH_FORMAT "]u/2u)'",
uid, p->uid);
p->output();
printf(DELIMITER_CHAR);
printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
}
void limit_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " }");
if (from) {
fprintf(stderr, " from { ");
from->debug_print();
fprintf(stderr, " }");
}
if (to) {
fprintf(stderr, " to { ");
to->debug_print();
fprintf(stderr, " }");
}
}
void limit_box::check_tabs(int level)
{
if (to)
to->check_tabs(level + 1);
if (from)
from->check_tabs(level + 1);
p->check_tabs(level + 1);
}

View File

@ -1,237 +0,0 @@
// -*- 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 "eqn.h"
#include "pbox.h"
list_box *box::to_list_box()
{
return 0;
}
list_box *list_box::to_list_box()
{
return this;
}
void list_box::append(box *pp)
{
list_box *q = pp->to_list_box();
if (q == 0)
list.append(pp);
else {
for (int i = 0; i < q->list.len; i++) {
list.append(q->list.p[i]);
q->list.p[i] = 0;
}
q->list.len = 0;
delete q;
}
}
list_box::list_box(box *pp) : list(pp), sty(-1)
{
list_box *q = pp->to_list_box();
if (q != 0) {
// flatten it
list.p[0] = q->list.p[0];
for (int i = 1; i < q->list.len; i++) {
list.append(q->list.p[i]);
q->list.p[i] = 0;
}
q->list.len = 0;
delete q;
}
}
static int compute_spacing(int is_script, int left, int right)
{
if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
return 0;
if (left == PUNCTUATION_TYPE)
return is_script ? 0 : thin_space;
if (left == OPENING_TYPE || right == CLOSING_TYPE)
return 0;
if (right == BINARY_TYPE || left == BINARY_TYPE)
return is_script ? 0 : medium_space;
if (right == RELATION_TYPE) {
if (left == RELATION_TYPE)
return 0;
else
return is_script ? 0 : thick_space;
}
if (left == RELATION_TYPE)
return is_script ? 0 : thick_space;
if (right == OPERATOR_TYPE)
return thin_space;
if (left == INNER_TYPE || right == INNER_TYPE)
return is_script ? 0 : thin_space;
if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
return thin_space;
return 0;
}
int list_box::compute_metrics(int style)
{
sty = style;
int i;
for (i = 0; i < list.len; i++) {
int t = list.p[i]->spacing_type;
// 5
if (t == BINARY_TYPE) {
int prevt;
if (i == 0
|| (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
|| prevt == OPERATOR_TYPE
|| prevt == RELATION_TYPE
|| prevt == OPENING_TYPE
|| prevt == PUNCTUATION_TYPE)
list.p[i]->spacing_type = ORDINARY_TYPE;
}
// 7
else if ((t == RELATION_TYPE || t == CLOSING_TYPE
|| t == PUNCTUATION_TYPE)
&& i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
list.p[i-1]->spacing_type = ORDINARY_TYPE;
}
for (i = 0; i < list.len; i++) {
unsigned flags = 0;
if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
flags |= HINT_PREV_IS_ITALIC;
if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
flags |= HINT_NEXT_IS_ITALIC;
if (flags)
list.p[i]->hint(flags);
}
is_script = (style <= SCRIPT_STYLE);
int total_spacing = 0;
for (i = 1; i < list.len; i++)
total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
list.p[i]->spacing_type);
int res = 0;
for (i = 0; i < list.len; i++)
if (!list.p[i]->is_simple()) {
int r = list.p[i]->compute_metrics(style);
if (r) {
if (res)
error("multiple marks and lineups");
else {
compute_sublist_width(i);
printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
res = r;
}
}
}
printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
for (i = 0; i < list.len; i++)
if (!list.p[i]->is_simple())
printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
printf("\n");
printf(".nr " HEIGHT_FORMAT " 0", uid);
for (i = 0; i < list.len; i++)
if (!list.p[i]->is_simple())
printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
printf("\n");
printf(".nr " DEPTH_FORMAT " 0", uid);
for (i = 0; i < list.len; i++)
if (!list.p[i]->is_simple())
printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
printf("\n");
int have_simple = 0;
for (i = 0; i < list.len && !have_simple; i++)
have_simple = list.p[i]->is_simple();
if (have_simple) {
printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
for (i = 0; i < list.len; i++)
if (list.p[i]->is_simple())
list.p[i]->output();
printf(DELIMITER_CHAR "\n");
printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
uid, uid);
printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
uid, uid);
}
return res;
}
void list_box::compute_sublist_width(int n)
{
int total_spacing = 0;
int i;
for (i = 1; i < n + 1 && i < list.len; i++)
total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
list.p[i]->spacing_type);
printf(".nr " TEMP_REG " %dM", total_spacing);
for (i = 0; i < n; i++)
if (!list.p[i]->is_simple())
printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
int have_simple = 0;
for (i = 0; i < n && !have_simple; i++)
have_simple = list.p[i]->is_simple();
if (have_simple) {
printf("+\\w" DELIMITER_CHAR);
for (i = 0; i < n; i++)
if (list.p[i]->is_simple())
list.p[i]->output();
printf(DELIMITER_CHAR);
}
printf("\n");
}
void list_box::compute_subscript_kern()
{
// We can only call compute_subscript_kern if we have called
// compute_metrics first.
if (list.p[list.len-1]->is_simple())
list.p[list.len-1]->compute_metrics(sty);
list.p[list.len-1]->compute_subscript_kern();
printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
uid, list.p[list.len-1]->uid);
}
void list_box::output()
{
for (int i = 0; i < list.len; i++) {
if (i > 0) {
int n = compute_spacing(is_script,
list.p[i-1]->spacing_type,
list.p[i]->spacing_type);
if (n > 0)
printf("\\h'%dM'", n);
}
list.p[i]->output();
}
}
void list_box::handle_char_type(int st, int ft)
{
for (int i = 0; i < list.len; i++)
list.p[i]->handle_char_type(st, ft);
}
void list_box::debug_print()
{
list.list_debug_print(" ");
}
void list_box::check_tabs(int level)
{
list.list_check_tabs(level);
}

View File

@ -1,395 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
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 "eqn.h"
#include "stringclass.h"
#include "device.h"
#include "searchpath.h"
#include "macropath.h"
#include "htmlhint.h"
#include "pbox.h"
#include "ctype.h"
#define STARTUP_FILE "eqnrc"
extern int yyparse();
extern "C" const char *Version_string;
static char *delim_search (char *, int);
static int inline_equation (FILE *, string &, string &);
char start_delim = '\0';
char end_delim = '\0';
int non_empty_flag;
int inline_flag;
int draw_flag = 0;
int one_size_reduction_flag = 0;
int compatible_flag = 0;
int no_newline_in_delim_flag = 0;
int html = 0;
int read_line(FILE *fp, string *p)
{
p->clear();
int c = -1;
while ((c = getc(fp)) != EOF) {
if (!invalid_input_char(c))
*p += char(c);
else
error("invalid input character code `%1'", c);
if (c == '\n')
break;
}
current_lineno++;
return p->length() > 0;
}
void do_file(FILE *fp, const char *filename)
{
string linebuf;
string str;
printf(".lf 1 %s\n", filename);
current_filename = filename;
current_lineno = 0;
while (read_line(fp, &linebuf)) {
if (linebuf.length() >= 4
&& linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
&& (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
put_string(linebuf, stdout);
linebuf += '\0';
if (interpret_lf_args(linebuf.contents() + 3))
current_lineno--;
}
else if (linebuf.length() >= 4
&& linebuf[0] == '.'
&& linebuf[1] == 'E'
&& linebuf[2] == 'Q'
&& (linebuf[3] == ' ' || linebuf[3] == '\n'
|| compatible_flag)) {
put_string(linebuf, stdout);
int start_lineno = current_lineno + 1;
str.clear();
for (;;) {
if (!read_line(fp, &linebuf))
fatal("end of file before .EN");
if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
if (linebuf[2] == 'N'
&& (linebuf.length() == 3 || linebuf[3] == ' '
|| linebuf[3] == '\n' || compatible_flag))
break;
else if (linebuf[2] == 'Q' && linebuf.length() > 3
&& (linebuf[3] == ' ' || linebuf[3] == '\n'
|| compatible_flag))
fatal("nested .EQ");
}
str += linebuf;
}
str += '\0';
start_string();
init_lex(str.contents(), current_filename, start_lineno);
non_empty_flag = 0;
inline_flag = 0;
yyparse();
restore_compatibility();
if (non_empty_flag) {
printf(".lf %d\n", current_lineno - 1);
output_string();
}
printf(".lf %d\n", current_lineno);
put_string(linebuf, stdout);
}
else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
&& inline_equation(fp, linebuf, str))
;
else
put_string(linebuf, stdout);
}
current_filename = 0;
current_lineno = 0;
}
// Handle an inline equation. Return 1 if it was an inline equation,
// otherwise.
static int inline_equation(FILE *fp, string &linebuf, string &str)
{
linebuf += '\0';
char *ptr = &linebuf[0];
char *start = delim_search(ptr, start_delim);
if (!start) {
// It wasn't a delimiter after all.
linebuf.set_length(linebuf.length() - 1); // strip the '\0'
return 0;
}
start_string();
inline_flag = 1;
for (;;) {
if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
error("missing `%1'", end_delim);
char *nl = strchr(start + 1, '\n');
if (nl != 0)
*nl = '\0';
do_text(ptr);
break;
}
int start_lineno = current_lineno;
*start = '\0';
do_text(ptr);
ptr = start + 1;
str.clear();
for (;;) {
char *end = strchr(ptr, end_delim);
if (end != 0) {
*end = '\0';
str += ptr;
ptr = end + 1;
break;
}
str += ptr;
if (!read_line(fp, &linebuf))
fatal("unterminated `%1' at line %2, looking for `%3'",
start_delim, start_lineno, end_delim);
linebuf += '\0';
ptr = &linebuf[0];
}
str += '\0';
if (html) {
printf(".as1 %s ", LINE_STRING);
html_begin_suppress();
printf("\n");
}
init_lex(str.contents(), current_filename, start_lineno);
yyparse();
if (html) {
printf(".as1 %s ", LINE_STRING);
html_end_suppress();
printf("\n");
}
start = delim_search(ptr, start_delim);
if (start == 0) {
char *nl = strchr(ptr, '\n');
if (nl != 0)
*nl = '\0';
do_text(ptr);
break;
}
}
restore_compatibility();
printf(".lf %d\n", current_lineno);
output_string();
printf(".lf %d\n", current_lineno + 1);
return 1;
}
/* Search for delim. Skip over number register and string names etc. */
static char *delim_search(char *ptr, int delim)
{
while (*ptr) {
if (*ptr == delim)
return ptr;
if (*ptr++ == '\\') {
switch (*ptr) {
case 'n':
case '*':
case 'f':
case 'g':
case 'k':
switch (*++ptr) {
case '\0':
case '\\':
break;
case '(':
if (*++ptr != '\\' && *ptr != '\0'
&& *++ptr != '\\' && *ptr != '\0')
ptr++;
break;
case '[':
while (*++ptr != '\0')
if (*ptr == ']') {
ptr++;
break;
}
break;
default:
ptr++;
break;
}
break;
case '\\':
case '\0':
break;
default:
ptr++;
break;
}
}
}
return 0;
}
void usage(FILE *stream)
{
fprintf(stream,
"usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
program_name);
}
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
int opt;
int load_startup_file = 1;
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, "DCRvd:f:p:s:m:T:M:rN", long_options,
NULL))
!= EOF)
switch (opt) {
case 'C':
compatible_flag = 1;
break;
case 'R': // don't load eqnrc
load_startup_file = 0;
break;
case 'M':
config_macro_path.command_line_dir(optarg);
break;
case 'v':
{
printf("GNU eqn (groff) version %s\n", Version_string);
exit(0);
break;
}
case 'd':
if (optarg[0] == '\0' || optarg[1] == '\0')
error("-d requires two character argument");
else if (invalid_input_char(optarg[0]))
error("bad delimiter `%1'", optarg[0]);
else if (invalid_input_char(optarg[1]))
error("bad delimiter `%1'", optarg[1]);
else {
start_delim = optarg[0];
end_delim = optarg[1];
}
break;
case 'f':
set_gfont(optarg);
break;
case 'T':
device = optarg;
if (strcmp(device, "ps:html") == 0) {
device = "ps";
html = 1;
}
break;
case 's':
if (!set_gsize(optarg))
error("invalid size `%1'", optarg);
break;
case 'p':
{
int n;
if (sscanf(optarg, "%d", &n) == 1)
set_script_reduction(n);
else
error("bad size `%1'", optarg);
}
break;
case 'm':
{
int n;
if (sscanf(optarg, "%d", &n) == 1)
set_minimum_size(n);
else
error("bad size `%1'", optarg);
}
break;
case 'r':
one_size_reduction_flag = 1;
break;
case 'D':
warning("-D option is obsolete: use `set draw_lines 1' instead");
draw_flag = 1;
break;
case 'N':
no_newline_in_delim_flag = 1;
break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
init_table(device);
init_char_table();
printf(".if !'\\*(.T'%s' "
".if !'\\*(.T'html' " // the html device uses `-Tps' to render
// equations as images
".tm warning: %s should have been given a `-T\\*(.T' option\n",
device, program_name);
printf(".if '\\*(.T'html' "
".if !'%s'ps' "
".tm warning: %s should have been given a `-Tps' option\n",
device, program_name);
printf(".if '\\*(.T'html' "
".if !'%s'ps' "
".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n",
device);
if (load_startup_file) {
char *path;
FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
if (fp) {
do_file(fp, path);
fclose(fp);
a_delete path;
}
}
if (optind >= argc)
do_file(stdin, "-");
else
for (int i = optind; i < argc; i++)
if (strcmp(argv[i], "-") == 0)
do_file(stdin, "-");
else {
errno = 0;
FILE *fp = fopen(argv[i], "r");
if (!fp)
fatal("can't open `%1': %2", argv[i], strerror(errno));
else {
do_file(fp, argv[i]);
fclose(fp);
}
}
if (ferror(stdout) || fflush(stdout) < 0)
fatal("output error");
return 0;
}

View File

@ -1,121 +0,0 @@
// -*- 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 "eqn.h"
#include "pbox.h"
class mark_box : public pointer_box {
public:
mark_box(box *);
int compute_metrics(int);
void output();
void debug_print();
};
// we push down marks so that they don't interfere with spacing
box *make_mark_box(box *p)
{
list_box *b = p->to_list_box();
if (b != 0) {
b->list.p[0] = make_mark_box(b->list.p[0]);
return b;
}
else
return new mark_box(p);
}
mark_box::mark_box(box *pp) : pointer_box(pp)
{
}
void mark_box::output()
{
p->output();
}
int mark_box::compute_metrics(int style)
{
int res = p->compute_metrics(style);
if (res)
error("multiple marks and lineups");
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " MARK_REG " 0\n");
return FOUND_MARK;
}
void mark_box::debug_print()
{
fprintf(stderr, "mark { ");
p->debug_print();
fprintf(stderr, " }");
}
class lineup_box : public pointer_box {
public:
lineup_box(box *);
void output();
int compute_metrics(int style);
void debug_print();
};
// we push down lineups so that they don't interfere with spacing
box *make_lineup_box(box *p)
{
list_box *b = p->to_list_box();
if (b != 0) {
b->list.p[0] = make_lineup_box(b->list.p[0]);
return b;
}
else
return new lineup_box(p);
}
lineup_box::lineup_box(box *pp) : pointer_box(pp)
{
}
void lineup_box::output()
{
p->output();
}
int lineup_box::compute_metrics(int style)
{
int res = p->compute_metrics(style);
if (res)
error("multiple marks and lineups");
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " MARK_REG " 0\n");
return FOUND_LINEUP;
}
void lineup_box::debug_print()
{
fprintf(stderr, "lineup { ");
p->debug_print();
fprintf(stderr, " }");
}

View File

@ -1,601 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h"
#include "pbox.h"
class accent_box : public pointer_box {
private:
box *ab;
public:
accent_box(box *, box *);
~accent_box();
int compute_metrics(int);
void output();
void debug_print();
void check_tabs(int);
};
box *make_accent_box(box *p, box *q)
{
return new accent_box(p, q);
}
accent_box::accent_box(box *pp, box *qq) : pointer_box(pp), ab(qq)
{
}
accent_box::~accent_box()
{
delete ab;
}
#if 0
int accent_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
p->compute_skew();
ab->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
uid, p->uid, x_height);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
SUP_RAISE_FORMAT "]\n",
uid, ab->uid, uid);
return r;
}
void accent_box::output()
{
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
SKEW_FORMAT "]u'",
p->uid, ab->uid, p->uid);
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
ab->output();
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid);
printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
SKEW_FORMAT "]u)'",
p->uid, ab->uid, p->uid);
p->output();
}
#endif
/* This version copes with the possibility of an accent's being wider
than its accentee. LEFT_WIDTH_FORMAT gives the distance from the
left edge of the resulting box to the middle of the accentee's box.*/
int accent_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
p->compute_skew();
ab->compute_metrics(style);
printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n",
uid, p->uid, ab->uid, p->uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])"
"+\\n[" LEFT_WIDTH_FORMAT "]\n",
uid, p->uid, ab->uid, p->uid, uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
uid, p->uid, x_height);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
SUP_RAISE_FORMAT "]\n",
uid, ab->uid, uid);
if (r)
printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
"-(\\n[" WIDTH_FORMAT "]/2)'\n",
uid, p->uid);
return r;
}
void accent_box::output()
{
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u"
"-(\\n[" WIDTH_FORMAT "]u/2u)'",
uid, p->uid, ab->uid);
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
ab->output();
printf(DELIMITER_CHAR);
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
uid, p->uid);
p->output();
printf(DELIMITER_CHAR);
printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
}
void accent_box::check_tabs(int level)
{
ab->check_tabs(level + 1);
p->check_tabs(level + 1);
}
void accent_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " } accent { ");
ab->debug_print();
fprintf(stderr, " }");
}
class overline_char_box : public simple_box {
public:
overline_char_box();
void output();
void debug_print();
};
overline_char_box::overline_char_box()
{
}
void overline_char_box::output()
{
printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height);
printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
accent_width);
printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height);
}
void overline_char_box::debug_print()
{
fprintf(stderr, "<overline char>");
}
class overline_box : public pointer_box {
public:
overline_box(box *);
int compute_metrics(int);
void output();
void debug_print();
};
box *make_overline_box(box *p)
{
if (p->is_char())
return new accent_box(p, new overline_char_box);
else
return new overline_box(p);
}
overline_box::overline_box(box *pp) : pointer_box(pp)
{
}
int overline_box::compute_metrics(int style)
{
int r = p->compute_metrics(cramped_style(style));
// 9
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n",
uid, p->uid, default_rule_thickness*5);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return r;
}
void overline_box::output()
{
// 9
printf("\\Z" DELIMITER_CHAR);
printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'",
p->uid, 7*default_rule_thickness);
if (draw_flag)
printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
else
printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
printf(DELIMITER_CHAR);
p->output();
}
void overline_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " } bar");
}
class uaccent_box : public pointer_box {
box *ab;
public:
uaccent_box(box *, box *);
~uaccent_box();
int compute_metrics(int);
void output();
void compute_subscript_kern();
void check_tabs(int);
void debug_print();
};
box *make_uaccent_box(box *p, box *q)
{
return new uaccent_box(p, q);
}
uaccent_box::uaccent_box(box *pp, box *qq)
: pointer_box(pp), ab(qq)
{
}
uaccent_box::~uaccent_box()
{
delete ab;
}
int uaccent_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
ab->compute_metrics(style);
printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
">?(\\n[" WIDTH_FORMAT "]/2)\n",
uid, p->uid, ab->uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
">?(\\n[" WIDTH_FORMAT "]/2)"
"+\\n[" LEFT_WIDTH_FORMAT "]\n",
uid, p->uid, ab->uid, uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
"+\\n[" DEPTH_FORMAT "]\n",
uid, p->uid, ab->uid);
if (r)
printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
"-(\\n[" WIDTH_FORMAT "]/2)'\n",
uid, p->uid);
return r;
}
void uaccent_box::output()
{
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
uid, ab->uid);
printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid);
ab->output();
printf(DELIMITER_CHAR);
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
uid, p->uid);
p->output();
printf(DELIMITER_CHAR);
printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
}
void uaccent_box::check_tabs(int level)
{
ab->check_tabs(level + 1);
p->check_tabs(level + 1);
}
void uaccent_box::compute_subscript_kern()
{
box::compute_subscript_kern(); // want 0 subscript kern
}
void uaccent_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " } uaccent { ");
ab->debug_print();
fprintf(stderr, " }");
}
class underline_char_box : public simple_box {
public:
underline_char_box();
void output();
void debug_print();
};
underline_char_box::underline_char_box()
{
}
void underline_char_box::output()
{
printf("\\v'%dM/2u'", 7*default_rule_thickness);
printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
accent_width);
printf("\\v'-%dM/2u'", 7*default_rule_thickness);
}
void underline_char_box::debug_print()
{
fprintf(stderr, "<underline char>");
}
class underline_box : public pointer_box {
public:
underline_box(box *);
int compute_metrics(int);
void output();
void compute_subscript_kern();
void debug_print();
};
box *make_underline_box(box *p)
{
if (p->is_char())
return new uaccent_box(p, new underline_char_box);
else
return new underline_box(p);
}
underline_box::underline_box(box *pp) : pointer_box(pp)
{
}
int underline_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
// 10
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
uid, p->uid, default_rule_thickness*5);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
return r;
}
void underline_box::output()
{
// 10
printf("\\Z" DELIMITER_CHAR);
printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'",
p->uid, 7*default_rule_thickness);
if (draw_flag)
printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
else
printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
printf(DELIMITER_CHAR);
p->output();
}
// we want an underline box to have 0 subscript kern
void underline_box::compute_subscript_kern()
{
box::compute_subscript_kern();
}
void underline_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " } under");
}
size_box::size_box(char *s, box *pp) : pointer_box(pp), size(s)
{
}
int size_box::compute_metrics(int style)
{
printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
printf(".ps %s\n", size);
printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
int r = p->compute_metrics(style);
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return r;
}
void size_box::output()
{
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
p->output();
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
}
size_box::~size_box()
{
a_delete size;
}
void size_box::debug_print()
{
fprintf(stderr, "size %s { ", size);
p->debug_print();
fprintf(stderr, " }");
}
font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s)
{
}
font_box::~font_box()
{
a_delete f;
}
int font_box::compute_metrics(int style)
{
const char *old_roman_font = current_roman_font;
current_roman_font = f;
printf(".nr " FONT_FORMAT " \\n[.f]\n", uid);
printf(".ft %s\n", f);
int r = p->compute_metrics(style);
current_roman_font = old_roman_font;
printf(".ft \\n[" FONT_FORMAT "]\n", uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return r;
}
void font_box::output()
{
printf("\\f[%s]", f);
const char *old_roman_font = current_roman_font;
current_roman_font = f;
p->output();
current_roman_font = old_roman_font;
printf("\\f[\\n[" FONT_FORMAT "]]", uid);
}
void font_box::debug_print()
{
fprintf(stderr, "font %s { ", f);
p->debug_print();
fprintf(stderr, " }");
}
fat_box::fat_box(box *pp) : pointer_box(pp)
{
}
int fat_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
uid, p->uid, fat_offset);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
return r;
}
void fat_box::output()
{
p->output();
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid);
printf("\\h'%dM'", fat_offset);
p->output();
}
void fat_box::debug_print()
{
fprintf(stderr, "fat { ");
p->debug_print();
fprintf(stderr, " }");
}
vmotion_box::vmotion_box(int i, box *pp) : pointer_box(pp), n(i)
{
}
int vmotion_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
if (n > 0) {
printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n",
uid, n, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
}
else {
printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n",
uid, -n, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n",
uid, p->uid);
}
return r;
}
void vmotion_box::output()
{
printf("\\v'%dM'", -n);
p->output();
printf("\\v'%dM'", n);
}
void vmotion_box::debug_print()
{
if (n >= 0)
fprintf(stderr, "up %d { ", n);
else
fprintf(stderr, "down %d { ", -n);
p->debug_print();
fprintf(stderr, " }");
}
hmotion_box::hmotion_box(int i, box *pp) : pointer_box(pp), n(i)
{
}
int hmotion_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
uid, p->uid, n);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
if (r)
printf(".nr " MARK_REG " +%dM\n", n);
return r;
}
void hmotion_box::output()
{
printf("\\h'%dM'", n);
p->output();
}
void hmotion_box::debug_print()
{
if (n >= 0)
fprintf(stderr, "fwd %d { ", n);
else
fprintf(stderr, "back %d { ", -n);
p->debug_print();
fprintf(stderr, " }");
}
vcenter_box::vcenter_box(box *pp) : pointer_box(pp)
{
}
int vcenter_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
HEIGHT_FORMAT "]/2+%dM\n",
uid, p->uid, p->uid, axis_height);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
return r;
}
void vcenter_box::output()
{
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
p->output();
printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
}
void vcenter_box::debug_print()
{
fprintf(stderr, "vcenter { ");
p->debug_print();
fprintf(stderr, " }");
}

View File

@ -1,197 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
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 "eqn.h"
#include "pbox.h"
class over_box : public box {
private:
int reduce_size;
box *num;
box *den;
public:
over_box(int small, box *, box *);
~over_box();
void debug_print();
int compute_metrics(int);
void output();
void check_tabs(int);
};
box *make_over_box(box *pp, box *qq)
{
return new over_box(0, pp, qq);
}
box *make_small_over_box(box *pp, box *qq)
{
return new over_box(1, pp, qq);
}
over_box::over_box(int is_small, box *pp, box *qq)
: reduce_size(is_small), num(pp), den(qq)
{
spacing_type = INNER_TYPE;
}
over_box::~over_box()
{
delete num;
delete den;
}
int over_box::compute_metrics(int style)
{
if (reduce_size) {
style = script_style(style);
printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
set_script_size();
printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
}
int mark_uid = 0;
int res = num->compute_metrics(style);
if (res)
mark_uid = num->uid;
int r = den->compute_metrics(cramped_style(style));
if (r && res)
error("multiple marks and lineups");
else {
mark_uid = den->uid;
res = r;
}
if (reduce_size)
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]",
uid, num->uid, den->uid);
// allow for \(ru being wider than both the numerator and denominator
if (!draw_flag)
fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout);
printf(")+%dM\n", null_delimiter_space*2 + over_hang*2);
// 15b
printf(".nr " SUP_RAISE_FORMAT " %dM\n",
uid, (reduce_size ? num2 : num1));
printf(".nr " SUB_LOWER_FORMAT " %dM\n",
uid, (reduce_size ? denom2 : denom1));
// 15d
printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT
"]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n",
uid, num->uid, uid, axis_height, default_rule_thickness,
default_rule_thickness*(reduce_size ? 1 : 3));
printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT
"]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n",
uid, den->uid, uid, axis_height, default_rule_thickness,
default_rule_thickness*(reduce_size ? 1 : 3));
printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
HEIGHT_FORMAT "]\n",
uid, uid, num->uid);
printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
DEPTH_FORMAT "]\n",
uid, uid, den->uid);
if (res)
printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n["
WIDTH_FORMAT "]/2)\n", uid, mark_uid);
return res;
}
#define USE_Z
void over_box::output()
{
if (reduce_size)
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
#ifdef USE_Z
printf("\\Z" DELIMITER_CHAR);
#endif
// move up to the numerator baseline
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
// move across so that it's centered
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
uid, num->uid);
// print the numerator
num->output();
#ifdef USE_Z
printf(DELIMITER_CHAR);
#else
// back again
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", num->uid);
printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
uid, num->uid);
// down again
printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
#endif
#ifdef USE_Z
printf("\\Z" DELIMITER_CHAR);
#endif
// move down to the denominator baseline
printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
// move across so that it's centered
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
uid, den->uid);
// print the the denominator
den->output();
#ifdef USE_Z
printf(DELIMITER_CHAR);
#else
// back again
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", den->uid);
printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
uid, den->uid);
// up again
printf("\\v'-\\n[" SUB_LOWER_FORMAT "]u'", uid);
#endif
if (reduce_size)
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
// draw the line
printf("\\h'%dM'", null_delimiter_space);
printf("\\v'-%dM'", axis_height);
fputs(draw_flag ? "\\D'l" : "\\l'", stdout);
printf("\\n[" WIDTH_FORMAT "]u-%dM",
uid, 2*null_delimiter_space);
fputs(draw_flag ? " 0'" : "\\&\\(ru'", stdout);
printf("\\v'%dM'", axis_height);
printf("\\h'%dM'", null_delimiter_space);
}
void over_box::debug_print()
{
fprintf(stderr, "{ ");
num->debug_print();
if (reduce_size)
fprintf(stderr, " } smallover { ");
else
fprintf(stderr, " } over { ");
den->debug_print();
fprintf(stderr, " }");
}
void over_box::check_tabs(int level)
{
num->check_tabs(level + 1);
den->check_tabs(level + 1);
}

View File

@ -1,293 +0,0 @@
// -*- 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. */
// piles and matrices
#include "eqn.h"
#include "pbox.h"
// SUP_RAISE_FORMAT gives the first baseline
// BASELINE_SEP_FORMAT gives the separation between baselines
int pile_box::compute_metrics(int style)
{
int i;
for (i = 0; i < col.len; i++)
col.p[i]->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0", uid);
for (i = 0; i < col.len; i++)
printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid);
printf("\n");
printf(".nr " BASELINE_SEP_FORMAT " %dM",
uid, baseline_sep+col.space);
for (i = 1; i < col.len; i++)
printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5);
// round it so that it's a multiple of the vertical resolution
printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
"+%dM\n",
uid, uid, col.len-1, axis_height - shift_down);
printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
HEIGHT_FORMAT "]\n",
uid, uid, col.p[0]->uid);
printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n["
DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n",
uid, uid, col.len-1, col.p[col.len-1]->uid, uid);
return FOUND_NOTHING;
}
void pile_box::output()
{
int i;
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
for (i = 0; i < col.len; i++) {
switch (col.align) {
case LEFT_ALIGN:
break;
case CENTER_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
uid, col.p[i]->uid);
break;
case RIGHT_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
uid, col.p[i]->uid);
break;
default:
assert(0);
}
col.p[i]->output();
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid);
switch (col.align) {
case LEFT_ALIGN:
break;
case CENTER_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
col.p[i]->uid, uid);
break;
case RIGHT_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
col.p[i]->uid, uid);
break;
default:
assert(0);
}
if (i != col.len - 1)
printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
}
printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid);
printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
}
pile_box::pile_box(box *pp) : col(pp)
{
}
void pile_box::check_tabs(int level)
{
col.list_check_tabs(level);
}
void pile_box::debug_print()
{
col.debug_print("pile");
}
int matrix_box::compute_metrics(int style)
{
int i, j;
int maxlen = 0;
int space = 0;
for (i = 0; i < len; i++) {
for (j = 0; j < p[i]->len; j++)
p[i]->p[j]->compute_metrics(style);
if (p[i]->len > maxlen)
maxlen = p[i]->len;
if (p[i]->space > space)
space = p[i]->space;
}
for (i = 0; i < len; i++) {
printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i);
for (j = 0; j < p[i]->len; j++)
printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid);
printf("\n");
}
printf(".nr " WIDTH_FORMAT " %dM",
uid, column_sep*(len-1)+2*matrix_side_sep);
for (i = 0; i < len; i++)
printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i);
printf("\n");
printf(".nr " BASELINE_SEP_FORMAT " %dM",
uid, baseline_sep+space);
for (i = 0; i < len; i++)
for (j = 1; j < p[i]->len; j++)
printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5);
// round it so that it's a multiple of the vertical resolution
printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
"+%dM\n",
uid, uid, maxlen-1, axis_height - shift_down);
printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0",
uid, uid);
for (i = 0; i < len; i++)
printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid);
printf(")>?0\n");
printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n["
SUP_RAISE_FORMAT "]+(0",
uid, uid, maxlen-1, uid);
for (i = 0; i < len; i++)
if (p[i]->len == maxlen)
printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[maxlen-1]->uid);
printf(")>?0\n");
return FOUND_NOTHING;
}
void matrix_box::output()
{
printf("\\h'%dM'", matrix_side_sep);
for (int i = 0; i < len; i++) {
int j;
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
for (j = 0; j < p[i]->len; j++) {
switch (p[i]->align) {
case LEFT_ALIGN:
break;
case CENTER_ALIGN:
printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
uid, i, p[i]->p[j]->uid);
break;
case RIGHT_ALIGN:
printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
uid, i, p[i]->p[j]->uid);
break;
default:
assert(0);
}
p[i]->p[j]->output();
printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid);
switch (p[i]->align) {
case LEFT_ALIGN:
break;
case CENTER_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'",
p[i]->p[j]->uid, uid, i);
break;
case RIGHT_ALIGN:
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'",
p[i]->p[j]->uid, uid, i);
break;
default:
assert(0);
}
if (j != p[i]->len - 1)
printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
}
printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid);
printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i);
if (i != len - 1)
printf("\\h'%dM'", column_sep);
}
printf("\\h'%dM'", matrix_side_sep);
}
matrix_box::matrix_box(column *pp)
{
p = new column*[10];
for (int i = 0; i < 10; i++)
p[i] = 0;
maxlen = 10;
len = 1;
p[0] = pp;
}
matrix_box::~matrix_box()
{
for (int i = 0; i < len; i++)
delete p[i];
a_delete p;
}
void matrix_box::append(column *pp)
{
if (len + 1 > maxlen) {
column **oldp = p;
maxlen *= 2;
p = new column*[maxlen];
memcpy(p, oldp, sizeof(column*)*len);
a_delete oldp;
}
p[len++] = pp;
}
void matrix_box::check_tabs(int level)
{
for (int i = 0; i < len; i++)
p[i]->list_check_tabs(level);
}
void matrix_box::debug_print()
{
fprintf(stderr, "matrix { ");
p[0]->debug_print("col");
for (int i = 1; i < len; i++) {
fprintf(stderr, " ");
p[i]->debug_print("col");
}
fprintf(stderr, " }");
}
column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0)
{
}
void column::set_alignment(alignment a)
{
align = a;
}
void column::set_space(int n)
{
space = n;
}
void column::debug_print(const char *s)
{
char c = '\0'; // shut up -Wall
switch (align) {
case LEFT_ALIGN:
c = 'l';
break;
case RIGHT_ALIGN:
c = 'r';
break;
case CENTER_ALIGN:
c = 'c';
break;
default:
assert(0);
}
fprintf(stderr, "%c%s %d { ", c, s, space);
list_debug_print(" above ");
fprintf(stderr, " }");
}

View File

@ -1,221 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h"
#include "pbox.h"
class script_box : public pointer_box {
private:
box *sub;
box *sup;
public:
script_box(box *, box *, box *);
~script_box();
int compute_metrics(int);
void output();
void debug_print();
int left_is_italic();
void hint(unsigned);
void check_tabs(int);
};
/* The idea is that the script should attach to the rightmost box
of a list. For example, given `2x sup 3', the superscript should
attach to `x' rather than `2x'. */
box *make_script_box(box *nuc, box *sub, box *sup)
{
list_box *b = nuc->to_list_box();
if (b != 0) {
b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
sub,
sup);
return b;
}
else
return new script_box(nuc, sub, sup);
}
script_box::script_box(box *pp, box *qq, box *rr)
: pointer_box(pp), sub(qq), sup(rr)
{
}
script_box::~script_box()
{
delete sub;
delete sup;
}
int script_box::left_is_italic()
{
return p->left_is_italic();
}
int script_box::compute_metrics(int style)
{
int res = p->compute_metrics(style);
p->compute_subscript_kern();
printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
set_script_size();
printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
if (sub != 0)
sub->compute_metrics(cramped_style(script_style(style)));
if (sup != 0)
sup->compute_metrics(script_style(style));
// 18a
if (p->is_char()) {
printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
}
else {
printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
uid, p->uid, sup_drop);
printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
uid, p->uid, sub_drop);
}
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
if (sup == 0) {
assert(sub != 0);
// 18b
printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
HEIGHT_FORMAT "]-(%dM*4/5))\n",
uid, uid, sub1, sub->uid, x_height);
}
else {
// sup != 0
// 18c
int p;
if (style == DISPLAY_STYLE)
p = sup1;
else if (style & 1) // not cramped
p = sup2;
else
p = sup3;
printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
"]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
uid, uid, p, sup->uid, x_height);
// 18d
if (sub != 0) {
printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
uid, uid, sub2);
// 18e
printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
SUB_LOWER_FORMAT "]+(4*%dM)\n",
sup->uid, uid, sub->uid, uid, default_rule_thickness);
printf(".if \\n[" TEMP_REG "] \\{");
printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
"]+\\n[" DEPTH_FORMAT "]>?0\n",
x_height, uid, sup->uid);
printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
printf(".\\}\n");
}
}
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
if (sub != 0 && sup != 0)
printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
WIDTH_FORMAT "])+%dM)>?0\n",
sub->uid, p->uid, sup->uid, script_space);
else if (sub != 0)
printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
sub->uid, p->uid, script_space);
else if (sup != 0)
printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
else
printf("\n");
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
uid, p->uid);
if (sup != 0)
printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
uid, sup->uid);
if (sub != 0)
printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
uid, sub->uid);
printf("\n");
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
uid, p->uid);
if (sub != 0)
printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
uid, sub->uid);
if (sup != 0)
printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
uid, sup->uid);
printf("\n");
return res;
}
void script_box::output()
{
p->output();
if (sup != 0) {
printf("\\Z" DELIMITER_CHAR);
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
sup->output();
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
printf(DELIMITER_CHAR);
}
if (sub != 0) {
printf("\\Z" DELIMITER_CHAR);
printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
sub->output();
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
printf(DELIMITER_CHAR);
}
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
uid, p->uid);
}
void script_box::hint(unsigned flags)
{
p->hint(flags & ~HINT_NEXT_IS_ITALIC);
}
void script_box::debug_print()
{
fprintf(stderr, "{ ");
p->debug_print();
fprintf(stderr, " }");
if (sub) {
fprintf(stderr, " sub { ");
sub->debug_print();
fprintf(stderr, " }");
}
if (sup) {
fprintf(stderr, " sup { ");
sup->debug_print();
fprintf(stderr, " }");
}
}
void script_box::check_tabs(int level)
{
if (sup)
sup->check_tabs(level + 1);
if (sub)
sub->check_tabs(level + 1);
p->check_tabs(level);
}

View File

@ -1,115 +0,0 @@
// -*- 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 "eqn.h"
#include "pbox.h"
#define STRING_FORMAT PREFIX "str%d"
#define SPECIAL_STRING "0s"
#define SPECIAL_WIDTH_REG "0w"
#define SPECIAL_HEIGHT_REG "0h"
#define SPECIAL_DEPTH_REG "0d"
#define SPECIAL_SUB_KERN_REG "0skern"
#define SPECIAL_SKEW_REG "0skew"
/*
For example:
.de Cl
.ds 0s \Z'\\*[0s]'\v'\\n(0du'\D'l \\n(0wu -\\n(0hu-\\n(0du'\v'\\n(0hu'
..
.EQ
define cancel 'special Cl'
.EN
*/
class special_box : public pointer_box {
char *macro_name;
public:
special_box(char *, box *);
~special_box();
int compute_metrics(int);
void compute_subscript_kern();
void compute_skew();
void output();
void debug_print();
};
box *make_special_box(char *s, box *p)
{
return new special_box(s, p);
}
special_box::special_box(char *s, box *pp) : pointer_box(pp), macro_name(s)
{
}
special_box::~special_box()
{
a_delete macro_name;
}
int special_box::compute_metrics(int style)
{
int r = p->compute_metrics(style);
p->compute_subscript_kern();
p->compute_skew();
printf(".ds " SPECIAL_STRING " \"");
p->output();
printf("\n");
printf(".nr " SPECIAL_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", p->uid);
printf(".nr " SPECIAL_HEIGHT_REG " \\n[" HEIGHT_FORMAT "]\n", p->uid);
printf(".nr " SPECIAL_DEPTH_REG " \\n[" DEPTH_FORMAT "]\n", p->uid);
printf(".nr " SPECIAL_SUB_KERN_REG " \\n[" SUB_KERN_FORMAT "]\n", p->uid);
printf(".nr " SPECIAL_SKEW_REG " 0\\n[" SKEW_FORMAT "]\n", p->uid);
printf(".%s\n", macro_name);
printf(".rn " SPECIAL_STRING " " STRING_FORMAT "\n", uid);
printf(".nr " WIDTH_FORMAT " 0\\n[" SPECIAL_WIDTH_REG "]\n", uid);
printf(".nr " HEIGHT_FORMAT " 0>?\\n[" SPECIAL_HEIGHT_REG "]\n", uid);
printf(".nr " DEPTH_FORMAT " 0>?\\n[" SPECIAL_DEPTH_REG "]\n", uid);
printf(".nr " SUB_KERN_FORMAT " 0>?\\n[" SPECIAL_SUB_KERN_REG "]\n", uid);
printf(".nr " SKEW_FORMAT " 0\\n[" SPECIAL_SKEW_REG "]\n", uid);
// User will have to change MARK_REG if appropriate.
return r;
}
void special_box::compute_subscript_kern()
{
// Already computed in compute_metrics(), so do nothing.
}
void special_box::compute_skew()
{
// Already computed in compute_metrics(), so do nothing.
}
void special_box::output()
{
printf("\\*[" STRING_FORMAT "]", uid);
}
void special_box::debug_print()
{
fprintf(stderr, "special %s { ", macro_name);
p->debug_print();
fprintf(stderr, " }");
}

View File

@ -1,179 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h"
#include "pbox.h"
class sqrt_box : public pointer_box {
public:
sqrt_box(box *);
int compute_metrics(int style);
void output();
void debug_print();
void check_tabs(int);
};
box *make_sqrt_box(box *pp)
{
return new sqrt_box(pp);
}
sqrt_box::sqrt_box(box *pp) : pointer_box(pp)
{
}
#define SQRT_CHAR "\\(sr"
#define RADICAL_EXTENSION_CHAR "\\[radicalex]"
#define SQRT_CHAIN "\\[sr\\\\n[" INDEX_REG "]]"
#define BAR_CHAIN "\\[radicalex\\\\n[" INDEX_REG "]]"
int sqrt_box::compute_metrics(int style)
{
// 11
int r = p->compute_metrics(cramped_style(style));
printf(".nr " TEMP_REG " \\n[" HEIGHT_FORMAT "]+\\n[" DEPTH_FORMAT
"]+%dM+(%dM/4)\n",
p->uid, p->uid, default_rule_thickness,
(style > SCRIPT_STYLE ? x_height : default_rule_thickness));
printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
printf(".ds " SQRT_STRING_FORMAT " " SQRT_CHAR "\n", uid);
printf(".ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n");
printf(".nr " SQRT_WIDTH_FORMAT
" 0\\w" DELIMITER_CHAR SQRT_CHAR DELIMITER_CHAR "\n",
uid);
printf(".if \\n[rst]-\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{",
default_rule_thickness);
printf(".nr " INDEX_REG " 0\n"
".de " TEMP_MACRO "\n"
".ie c" SQRT_CHAIN " \\{"
".ds " SQRT_STRING_FORMAT " " SQRT_CHAIN "\n"
".ie c" BAR_CHAIN " .ds " BAR_STRING " " BAR_CHAIN "\n"
".el .ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n"
".nr " SQRT_WIDTH_FORMAT
" 0\\w" DELIMITER_CHAR SQRT_CHAIN DELIMITER_CHAR "\n"
".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{"
".nr " INDEX_REG " +1\n"
"." TEMP_MACRO "\n"
".\\}\\}\n"
".el .nr " INDEX_REG " 0-1\n"
"..\n"
"." TEMP_MACRO "\n",
uid, uid, default_rule_thickness);
printf(".if \\n[" INDEX_REG "]<0 \\{");
// Determine the maximum point size
printf(".ps 1000\n");
printf(".nr " MAX_SIZE_REG " \\n[.ps]\n");
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
// We define a macro that will increase the current point size
// until we get a radical sign that's tall enough or we reach
// the maximum point size.
printf(".de " TEMP_MACRO "\n"
".nr " SQRT_WIDTH_FORMAT
" 0\\w" DELIMITER_CHAR "\\*[" SQRT_STRING_FORMAT "]" DELIMITER_CHAR "\n"
".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "]"
"&(\\\\n[.ps]<\\n[" MAX_SIZE_REG "]) \\{"
".ps +1\n"
"." TEMP_MACRO "\n"
".\\}\n"
"..\n"
"." TEMP_MACRO "\n",
uid, uid, default_rule_thickness);
printf(".\\}\\}\n");
printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
// set TEMP_REG to the amount by which the radical sign is too big
printf(".nr " TEMP_REG " \\n[rst]-\\n[rsb]-%dM-\\n[" TEMP_REG "]\n",
default_rule_thickness);
// If TEMP_REG is negative, the bottom of the radical sign should
// be -TEMP_REG above the bottom of p. If it's positive, the bottom
// of the radical sign should be TEMP_REG/2 below the bottom of p.
// This calculates the amount by which the baseline of the radical
// should be raised.
printf(".nr " SUP_RAISE_FORMAT " (-\\n[" TEMP_REG "]>?(-\\n[" TEMP_REG "]/2))"
"-\\n[rsb]-\\n[" DEPTH_FORMAT "]\n", uid, p->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n",
uid, p->uid, uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
">?(-\\n[" SUP_RAISE_FORMAT "]-\\n[rsb])\n",
uid, p->uid, uid);
// Do this last, so we don't lose height and depth information on
// the radical sign.
// Remember that the width of the bar might be greater than the width of p.
printf(".nr " TEMP_REG " "
"\\n[" WIDTH_FORMAT "]"
">?\\w" DELIMITER_CHAR "\\*[" BAR_STRING "]" DELIMITER_CHAR "\n",
p->uid);
printf(".as " SQRT_STRING_FORMAT " "
"\\l'\\n[" TEMP_REG "]u\\&\\*[" BAR_STRING "]'\n",
uid);
printf(".nr " WIDTH_FORMAT " \\n[" TEMP_REG "]"
"+\\n[" SQRT_WIDTH_FORMAT "]\n",
uid, uid);
if (r)
printf(".nr " MARK_REG " +\\n[" SQRT_WIDTH_FORMAT "]\n", uid);
// the top of the bar might be higher than the top of the radical sign
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n",
uid, p->uid, uid);
// put a bit of extra space above the bar
printf(".nr " HEIGHT_FORMAT " +%dM\n", uid, default_rule_thickness);
printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
return r;
}
void sqrt_box::output()
{
printf("\\Z" DELIMITER_CHAR);
printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
printf("\\*[" SQRT_STRING_FORMAT "]", uid);
printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
printf(DELIMITER_CHAR);
printf("\\Z" DELIMITER_CHAR);
printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u"
"+\\n[" SQRT_WIDTH_FORMAT "]u/2u'",
uid, p->uid, uid);
p->output();
printf(DELIMITER_CHAR);
printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
}
void sqrt_box::debug_print()
{
fprintf(stderr, "sqrt { ");
p->debug_print();
fprintf(stderr, " }");
}
void sqrt_box::check_tabs(int level)
{
p->check_tabs(level + 1);
}

View File

@ -1,528 +0,0 @@
// -*- 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 "eqn.h"
#include "pbox.h"
#include "ptable.h"
class char_box : public simple_box {
unsigned char c;
char next_is_italic;
char prev_is_italic;
public:
char_box(unsigned char);
void debug_print();
void output();
int is_char();
int left_is_italic();
int right_is_italic();
void hint(unsigned);
void handle_char_type(int, int);
};
class special_char_box : public simple_box {
char *s;
public:
special_char_box(const char *);
~special_char_box();
void output();
void debug_print();
int is_char();
void handle_char_type(int, int);
};
const char *spacing_type_table[] = {
"ordinary",
"operator",
"binary",
"relation",
"opening",
"closing",
"punctuation",
"inner",
"suppress",
0,
};
const int DIGIT_TYPE = 0;
const int LETTER_TYPE = 1;
const char *font_type_table[] = {
"digit",
"letter",
0,
};
struct char_info {
int spacing_type;
int font_type;
char_info();
};
char_info::char_info()
: spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
{
}
static char_info char_table[256];
declare_ptable(char_info)
implement_ptable(char_info)
PTABLE(char_info) special_char_table;
static int get_special_char_spacing_type(const char *ch)
{
char_info *p = special_char_table.lookup(ch);
return p ? p->spacing_type : ORDINARY_TYPE;
}
static int get_special_char_font_type(const char *ch)
{
char_info *p = special_char_table.lookup(ch);
return p ? p->font_type : DIGIT_TYPE;
}
static void set_special_char_type(const char *ch, int st, int ft)
{
char_info *p = special_char_table.lookup(ch);
if (!p) {
p = new char_info;
special_char_table.define(ch, p);
}
if (st >= 0)
p->spacing_type = st;
if (ft >= 0)
p->font_type = ft;
}
void init_char_table()
{
set_special_char_type("pl", 2, -1); // binary
set_special_char_type("mi", 2, -1);
set_special_char_type("eq", 3, -1); // relation
set_special_char_type("<=", 3, -1);
set_special_char_type(">=", 3, -1);
char_table['}'].spacing_type = 5; // closing
char_table[')'].spacing_type = 5;
char_table[']'].spacing_type = 5;
char_table['{'].spacing_type = 4; // opening
char_table['('].spacing_type = 4;
char_table['['].spacing_type = 4;
char_table[','].spacing_type = 6; // punctuation
char_table[';'].spacing_type = 6;
char_table[':'].spacing_type = 6;
char_table['.'].spacing_type = 6;
char_table['>'].spacing_type = 3;
char_table['<'].spacing_type = 3;
char_table['*'].spacing_type = 2; // binary
for (int i = 0; i < 256; i++)
if (csalpha(i))
char_table[i].font_type = LETTER_TYPE;
}
static int lookup_spacing_type(const char *type)
{
for (int i = 0; spacing_type_table[i] != 0; i++)
if (strcmp(spacing_type_table[i], type) == 0)
return i;
return -1;
}
static int lookup_font_type(const char *type)
{
for (int i = 0; font_type_table[i] != 0; i++)
if (strcmp(font_type_table[i], type) == 0)
return i;
return -1;
}
void box::set_spacing_type(char *type)
{
int t = lookup_spacing_type(type);
if (t < 0)
error("unrecognised type `%1'", type);
else
spacing_type = t;
a_delete type;
}
char_box::char_box(unsigned char cc)
: c(cc), next_is_italic(0), prev_is_italic(0)
{
spacing_type = char_table[c].spacing_type;
}
void char_box::hint(unsigned flags)
{
if (flags & HINT_PREV_IS_ITALIC)
prev_is_italic = 1;
if (flags & HINT_NEXT_IS_ITALIC)
next_is_italic = 1;
}
void char_box::output()
{
int font_type = char_table[c].font_type;
if (font_type != LETTER_TYPE)
printf("\\f[%s]", current_roman_font);
if (!prev_is_italic)
fputs("\\,", stdout);
if (c == '\\')
fputs("\\e", stdout);
else
putchar(c);
if (!next_is_italic)
fputs("\\/", stdout);
else
fputs("\\&", stdout); // suppress ligaturing and kerning
if (font_type != LETTER_TYPE)
fputs("\\fP", stdout);
}
int char_box::left_is_italic()
{
int font_type = char_table[c].font_type;
return font_type == LETTER_TYPE;
}
int char_box::right_is_italic()
{
int font_type = char_table[c].font_type;
return font_type == LETTER_TYPE;
}
int char_box::is_char()
{
return 1;
}
void char_box::debug_print()
{
if (c == '\\') {
putc('\\', stderr);
putc('\\', stderr);
}
else
putc(c, stderr);
}
special_char_box::special_char_box(const char *t)
{
s = strsave(t);
spacing_type = get_special_char_spacing_type(s);
}
special_char_box::~special_char_box()
{
a_delete s;
}
void special_char_box::output()
{
int font_type = get_special_char_font_type(s);
if (font_type != LETTER_TYPE)
printf("\\f[%s]", current_roman_font);
printf("\\,\\[%s]\\/", s);
if (font_type != LETTER_TYPE)
printf("\\fP");
}
int special_char_box::is_char()
{
return 1;
}
void special_char_box::debug_print()
{
fprintf(stderr, "\\[%s]", s);
}
void char_box::handle_char_type(int st, int ft)
{
if (st >= 0)
char_table[c].spacing_type = st;
if (ft >= 0)
char_table[c].font_type = ft;
}
void special_char_box::handle_char_type(int st, int ft)
{
set_special_char_type(s, st, ft);
}
void set_char_type(const char *type, char *ch)
{
assert(ch != 0);
int st = lookup_spacing_type(type);
int ft = lookup_font_type(type);
if (st < 0 && ft < 0) {
error("bad character type `%1'", type);
a_delete ch;
return;
}
box *b = split_text(ch);
b->handle_char_type(st, ft);
delete b;
}
/* We give primes special treatment so that in ``x' sub 2'', the ``2''
will be tucked under the prime */
class prime_box : public pointer_box {
box *pb;
public:
prime_box(box *);
~prime_box();
int compute_metrics(int style);
void output();
void compute_subscript_kern();
void debug_print();
void handle_char_type(int, int);
};
box *make_prime_box(box *pp)
{
return new prime_box(pp);
}
prime_box::prime_box(box *pp) : pointer_box(pp)
{
pb = new special_char_box("fm");
}
prime_box::~prime_box()
{
delete pb;
}
int prime_box::compute_metrics(int style)
{
int res = p->compute_metrics(style);
pb->compute_metrics(style);
printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]"
"+\\n[" WIDTH_FORMAT "]\n",
uid, p->uid, pb->uid);
printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
">?\\n[" HEIGHT_FORMAT "]\n",
uid, p->uid, pb->uid);
printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
">?\\n[" DEPTH_FORMAT "]\n",
uid, p->uid, pb->uid);
return res;
}
void prime_box::compute_subscript_kern()
{
p->compute_subscript_kern();
printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]"
"+\\n[" SUB_KERN_FORMAT "]>?0\n",
uid, pb->uid, p->uid);
}
void prime_box::output()
{
p->output();
pb->output();
}
void prime_box::handle_char_type(int st, int ft)
{
p->handle_char_type(st, ft);
pb->handle_char_type(st, ft);
}
void prime_box::debug_print()
{
p->debug_print();
putc('\'', stderr);
}
box *split_text(char *text)
{
list_box *lb = 0;
box *fb = 0;
char *s = text;
while (*s != '\0') {
char c = *s++;
box *b = 0;
switch (c) {
case '+':
b = new special_char_box("pl");
break;
case '-':
b = new special_char_box("mi");
break;
case '=':
b = new special_char_box("eq");
break;
case '\'':
b = new special_char_box("fm");
break;
case '<':
if (*s == '=') {
b = new special_char_box("<=");
s++;
break;
}
goto normal_char;
case '>':
if (*s == '=') {
b = new special_char_box(">=");
s++;
break;
}
goto normal_char;
case '\\':
if (*s == '\0') {
lex_error("bad escape");
break;
}
c = *s++;
switch (c) {
case '(':
{
char buf[3];
if (*s != '\0') {
buf[0] = *s++;
if (*s != '\0') {
buf[1] = *s++;
buf[2] = '\0';
b = new special_char_box(buf);
}
else {
lex_error("bad escape");
}
}
else {
lex_error("bad escape");
}
}
break;
case '[':
{
char *ch = s;
while (*s != ']' && *s != '\0')
s++;
if (*s == '\0')
lex_error("bad escape");
else {
*s++ = '\0';
b = new special_char_box(ch);
}
}
break;
case 'f':
case 'g':
case 'k':
case 'n':
case '*':
{
char *escape_start = s - 2;
switch (*s) {
case '(':
if (*++s != '\0')
++s;
break;
case '[':
for (++s; *s != '\0' && *s != ']'; s++)
;
break;
}
if (*s == '\0')
lex_error("bad escape");
else {
++s;
char *buf = new char[s - escape_start + 1];
memcpy(buf, escape_start, s - escape_start);
buf[s - escape_start] = '\0';
b = new quoted_text_box(buf);
}
}
break;
case '-':
case '_':
{
char buf[2];
buf[0] = c;
buf[1] = '\0';
b = new special_char_box(buf);
}
break;
case '`':
b = new special_char_box("ga");
break;
case '\'':
b = new special_char_box("aa");
break;
case 'e':
case '\\':
b = new char_box('\\');
break;
case '^':
case '|':
case '0':
{
char buf[3];
buf[0] = '\\';
buf[1] = c;
buf[2] = '\0';
b = new quoted_text_box(strsave(buf));
break;
}
default:
lex_error("unquoted escape");
b = new quoted_text_box(strsave(s - 2));
s = strchr(s, '\0');
break;
}
break;
default:
normal_char:
b = new char_box(c);
break;
}
while (*s == '\'') {
if (b == 0)
b = new quoted_text_box(0);
b = new prime_box(b);
s++;
}
if (b != 0) {
if (lb != 0)
lb->append(b);
else if (fb != 0) {
lb = new list_box(fb);
lb->append(b);
}
else
fb = b;
}
}
delete text;
if (lb != 0)
return lb;
else if (fb != 0)
return fb;
else
return new quoted_text_box(0);
}

View File

@ -1,339 +0,0 @@
/* Last non-groff version: hdb.c 1.8 (Berkeley) 84/10/20
*
* Copyright -C- 1982 Barry S. Roitblat
*
* This file contains database routines for the hard copy programs of the
* gremlin picture editor.
*/
#include "gprint.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "errarg.h"
#include "error.h"
#define MAXSTRING 128
#define MAXSTRING_S "127"
/* imports from main.cc */
extern int linenum; /* current line number in input file */
extern char gremlinfile[]; /* name of file currently reading */
extern int SUNFILE; /* TRUE if SUN gremlin file */
extern void savebounds(float x, float y);
/* imports from hpoint.cc */
extern POINT *PTInit();
extern POINT *PTMakePoint(float x, float y, POINT ** pplist);
int DBGetType(register char *s);
/*
* This routine returns a pointer to an initialized database element which
* would be the only element in an empty list.
*/
ELT *
DBInit()
{
return ((ELT *) NULL);
} /* end DBInit */
/*
* This routine creates a new element with the specified attributes and
* links it into database.
*/
ELT *
DBCreateElt(int type,
POINT * pointlist,
int brush,
int size,
char *text,
ELT **db)
{
register ELT *temp;
temp = (ELT *) malloc(sizeof(ELT));
temp->nextelt = *db;
temp->type = type;
temp->ptlist = pointlist;
temp->brushf = brush;
temp->size = size;
temp->textpt = text;
*db = temp;
return (temp);
} /* end CreateElt */
/*
* This routine reads the specified file into a database and returns a
* pointer to that database.
*/
ELT *
DBRead(register FILE *file)
{
register int i;
register int done; /* flag for input exhausted */
register float nx; /* x holder so x is not set before orienting */
int type; /* element type */
ELT *elist; /* pointer to the file's elements */
POINT *plist; /* pointer for reading in points */
char string[MAXSTRING], *txt;
float x, y; /* x and y are read in point coords */
int len, brush, size;
int lastpoint;
SUNFILE = FALSE;
elist = DBInit();
(void) fscanf(file, "%" MAXSTRING_S "s%*[^\n]\n", string);
if (strcmp(string, "gremlinfile")) {
if (strcmp(string, "sungremlinfile")) {
error("`%1' is not a gremlin file", gremlinfile);
return (elist);
}
SUNFILE = TRUE;
}
(void) fscanf(file, "%d%f%f\n", &size, &x, &y);
/* ignore orientation and file positioning point */
done = FALSE;
while (!done) {
/* if (fscanf(file,"%" MAXSTRING_S "s\n", string) == EOF) */
/* I changed the scanf format because the element */
/* can have two words (e.g. CURVE SPLINE) */
if (fscanf(file, "\n%" MAXSTRING_S "[^\n]%*[^\n]\n", string) == EOF) {
error("`%1', error in file format", gremlinfile);
return (elist);
}
type = DBGetType(string); /* interpret element type */
if (type < 0) { /* no more data */
done = TRUE;
(void) fclose(file);
} else {
#ifdef UW_FASTSCAN
(void) xscanf(file, &x, &y); /* always one point */
#else
(void) fscanf(file, "%f%f\n", &x, &y); /* always one point */
#endif /* UW_FASTSCAN */
plist = PTInit(); /* NULL point list */
/*
* Files created on the SUN have point lists terminated by a line
* containing only an asterik ('*'). Files created on the AED have
* point lists terminated by the coordinate pair (-1.00 -1.00).
*/
if (TEXT(type)) { /* read only first point for TEXT elements */
nx = xorn(x, y);
y = yorn(x, y);
(void) PTMakePoint(nx, y, &plist);
savebounds(nx, y);
#ifdef UW_FASTSCAN
while (xscanf(file, &x, &y));
#else
lastpoint = FALSE;
do {
fgets(string, MAXSTRING, file);
if (string[0] == '*') { /* SUN gremlin file */
lastpoint = TRUE;
} else {
(void) sscanf(string, "%f%f", &x, &y);
if ((x == -1.00 && y == -1.00) && (!SUNFILE))
lastpoint = TRUE;
}
} while (!lastpoint);
#endif /* UW_FASTSCAN */
} else { /* not TEXT element */
#ifdef UW_FASTSCAN
do {
nx = xorn(x, y);
y = yorn(x, y);
(void) PTMakePoint(nx, y, &plist);
savebounds(nx, y);
} while (xscanf(file, &x, &y));
#else
lastpoint = FALSE;
while (!lastpoint) {
nx = xorn(x, y);
y = yorn(x, y);
(void) PTMakePoint(nx, y, &plist);
savebounds(nx, y);
fgets(string, MAXSTRING, file);
if (string[0] == '*') { /* SUN gremlin file */
lastpoint = TRUE;
} else {
(void) sscanf(string, "%f%f", &x, &y);
if ((x == -1.00 && y == -1.00) && (!SUNFILE))
lastpoint = TRUE;
}
}
#endif /* UW_FASTSCAN */
}
(void) fscanf(file, "%d%d\n", &brush, &size);
(void) fscanf(file, "%d", &len); /* text length */
(void) getc(file); /* eat blank */
txt = (char *) malloc((unsigned) len + 1);
for (i = 0; i < len; ++i) { /* read text */
txt[i] = getc(file);
}
txt[len] = '\0';
(void) DBCreateElt(type, plist, brush, size, txt, &elist);
} /* end else */
} /* end while not done */ ;
return (elist);
} /* end DBRead */
/*
* Interpret element type in string s.
* Old file format consisted of integer element types.
* New file format has literal names for element types.
*/
int
DBGetType(register char *s)
{
if (isdigit(s[0]) || (s[0] == '-')) /* old element format or EOF */
return (atoi(s));
switch (s[0]) {
case 'P':
return (POLYGON);
case 'V':
return (VECTOR);
case 'A':
return (ARC);
case 'C':
if (s[1] == 'U') {
if (s[5] == '\n')
return (CURVE);
switch (s[7]) {
case 'S':
return(BSPLINE);
case 'E':
fprintf(stderr,
"Warning: Bezier Curves will be printed as B-Splines\n");
return(BSPLINE);
default:
return(CURVE);
}
}
switch (s[4]) {
case 'L':
return (CENTLEFT);
case 'C':
return (CENTCENT);
case 'R':
return (CENTRIGHT);
default:
fatal("unknown element type");
}
case 'B':
switch (s[3]) {
case 'L':
return (BOTLEFT);
case 'C':
return (BOTCENT);
case 'R':
return (BOTRIGHT);
default:
fatal("unknown element type");
}
case 'T':
switch (s[3]) {
case 'L':
return (TOPLEFT);
case 'C':
return (TOPCENT);
case 'R':
return (TOPRIGHT);
default:
fatal("unknown element type");
}
default:
fatal("unknown element type");
}
return 0; /* never reached */
}
#ifdef UW_FASTSCAN
/*
* Optimization hack added by solomon@crys.wisc.edu, 12/2/86.
* A huge fraction of the time was spent reading floating point numbers from
* the input file, but the numbers always have the format 'ddd.dd'. Thus
* the following special-purpose version of fscanf.
*
* xscanf(f,xp,yp) does roughly what fscanf(f,"%f%f",xp,yp) does except:
* -the next piece of input must be of the form
* <space>* <digit>*'.'<digit>* <space>* <digit>*'.'<digit>*
* -xscanf eats the character following the second number
* -xscanf returns 0 for "end-of-data" indication, 1 otherwise, where
* end-of-data is signalled by a '*' [in which case the rest of the
* line is gobbled], or by '-1.00 -1.00' [but only if !SUNFILE].
*/
int
xscanf(FILE *f,
float *xp,
float *yp)
{
register int c, i, j, m, frac;
int iscale = 1, jscale = 1; /* x = i/scale, y=j/jscale */
while ((c = getc(f)) == ' ');
if (c == '*') {
while ((c = getc(f)) != '\n');
return 0;
}
i = m = frac = 0;
while (isdigit(c) || c == '.' || c == '-') {
if (c == '-') {
m++;
c = getc(f);
continue;
}
if (c == '.')
frac = 1;
else {
if (frac)
iscale *= 10;
i = 10 * i + c - '0';
}
c = getc(f);
}
if (m)
i = -i;
*xp = (double) i / (double) iscale;
while ((c = getc(f)) == ' ');
j = m = frac = 0;
while (isdigit(c) || c == '.' || c == '-') {
if (c == '-') {
m++;
c = getc(f);
continue;
}
if (c == '.')
frac = 1;
else {
if (frac)
jscale *= 10;
j = 10 * j + c - '0';
}
c = getc(f);
}
if (m)
j = -j;
*yp = (double) j / (double) jscale;
return (SUNFILE || i != -iscale || j != -jscale);
}
#endif /* UW_FASTSCAN */
/* EOF */

File diff suppressed because it is too large Load Diff

View File

@ -1,49 +0,0 @@
/* Last non-groff version: hpoint.c 1.1 84/10/08 */
/*
* This file contains routines for manipulating the point data structures
* for the gremlin picture editor.
*/
#include <stdlib.h>
#include "gprint.h"
/*
* Return pointer to empty point list.
*/
POINT *
PTInit()
{
return ((POINT *) NULL);
}
/*
* This routine creates a new point with coordinates x and y and links it
* into the pointlist.
*/
POINT *
PTMakePoint(float x,
float y,
POINT **pplist)
{
register POINT *point;
if (Nullpoint(point = *pplist)) { /* empty list */
*pplist = (POINT *) malloc(sizeof(POINT));
point = *pplist;
} else {
while (!Nullpoint(point->nextpt))
point = point->nextpt;
point->nextpt = (POINT *) malloc(sizeof(POINT));
point = point->nextpt;
}
point->x = x;
point->y = y;
point->nextpt = PTInit();
return (point);
} /* end PTMakePoint */
/* EOF */

View File

@ -1,906 +0,0 @@
/* Last non-groff version: main.cc 1.23 (Berkeley) 85/08/05
*
* Adapted to GNU troff by Daniel Senderowicz 99/12/29.
*
* Further refinements by Werner Lemberg 00/02/20.
*
*
* This file contains the main and file system dependent routines for
* processing gremlin files into troff input. The program watches input go
* by to standard output, only interpreting things between .GS and .GE
* lines. Default values (font, size, scale, thickness) may be overridden
* with a `default' command and are further overridden by commands in the
* input.
*
* Inside the GS and GE, commands are accepted to reconfigure the picture.
* At most one command may reside on each line, and each command is followed
* by a parameter separated by white space. The commands are as follows,
* and may be abbreviated down to one character (with exception of `scale'
* and `stipple' down to "sc" and "st") and may be upper or lower case.
*
* default - Make all settings in the current
* .GS/.GE the global defaults. Height,
* width and file are NOT saved.
* 1, 2, 3, 4 - Set size 1, 2, 3, or 4 (followed by an
* integer point size).
* roman, italics, bold, special - Set gremlin's fonts to any other troff
* font (one or two characters).
* stipple, l - Use a stipple font for polygons. Arg
* is troff font name. No Default. Can
* use only one stipple font per picture.
* (See below for stipple font index.)
* scale, x - Scale is IN ADDITION to the global
* scale factor from the default.
* pointscale - Turn on scaling point sizes to match
* `scale' commands. (Optional operand
* `off' to turn it off.)
* narrow, medium, thick - Set widths of lines.
* file - Set the file name to read the gremlin
* picture from. If the file isn't in
* the current directory, the gremlin
* library is tried.
* width, height - These two commands override any
* scaling factor that is in effect, and
* forces the picture to fit into either
* the height or width specified,
* whichever makes the picture smaller.
* The operand for these two commands is
* a floating-point number in units of
* inches.
* l<nn> (integer <nn>) - Set association between stipple <nn>
* and a stipple `character'. <nn> must
* be in the range 0 to NSTIPPLES (16)
* inclusive. The integer operand is an
* index in the stipple font selected.
* Valid cf (cifplot) indices are 1-32
* (although 24 is not defined), valid ug
* (unigrafix) indices are 1-14, and
* valid gs (gray scale) indices are
* 0-16. Nonetheless, any number between
* 0 and 255 is accepted since new
* stipple fonts may be added. An
* integer operand is required.
*
* Troff number registers used: g1 through g9. g1 is the width of the
* picture, and g2 is the height. g3, and g4, save information, g8 and g9
* are used for text processing and g5-g7 are reserved.
*/
#include "lib.h"
#include <ctype.h>
#include <stdlib.h>
#include "gprint.h"
#include "device.h"
#include "font.h"
#include "searchpath.h"
#include "macropath.h"
#include "errarg.h"
#include "error.h"
#include "defs.h"
extern "C" const char *Version_string;
/* database imports */
extern void HGPrintElt(ELT *element, int baseline);
extern ELT *DBInit();
extern ELT *DBRead(register FILE *file);
extern POINT *PTInit();
extern POINT *PTMakePoint(float x, float y, POINT **pplist);
#define SUN_SCALEFACTOR 0.70
/* #define DEFSTIPPLE "gs" */
#define DEFSTIPPLE "cf"
#define MAXINLINE 100 /* input line length */
#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */
#define BIG 999999999999.0 /* unweildly large floating number */
static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99";
int res; /* the printer's resolution goes here */
int dotshifter; /* for the length of dotted curves */
double linethickness; /* brush styles */
int linmod;
int lastx; /* point registers for printing elements */
int lasty;
int lastyline; /* A line's vertical position is NOT the */
/* same after that line is over, so for a */
/* line of drawing commands, vertical */
/* spacing is kept in lastyline */
/* These are the default fonts, sizes, line styles, */
/* and thicknesses. They can be modified from a */
/* `default' command and are reset each time the */
/* start of a picture (.GS) is found. */
char *deffont[] =
{"R", "I", "B", "S"};
int defsize[] =
{10, 16, 24, 36};
/* #define BASE_THICKNESS 1.0 */
#define BASE_THICKNESS 0.15
double defthick[STYLES] =
{1 * BASE_THICKNESS,
1 * BASE_THICKNESS,
5 * BASE_THICKNESS,
1 * BASE_THICKNESS,
1 * BASE_THICKNESS,
3 * BASE_THICKNESS};
/* int cf_stipple_index[NSTIPPLES + 1] = */
/* {0, 1, 3, 12, 14, 16, 19, 21, 23}; */
/* a logarithmic scale looks better than a linear one for the gray shades */
/* */
/* int other_stipple_index[NSTIPPLES + 1] = */
/* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; */
int cf_stipple_index[NSTIPPLES + 1] =
{0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */
int other_stipple_index[NSTIPPLES + 1] =
{0, 62, 125, 187, 250, 312, 375, 437, 500,
562, 625, 687, 750, 812, 875, 937, 1000};
/* int *defstipple_index = other_stipple_index; */
int *defstipple_index = cf_stipple_index;
int style[STYLES] =
{DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID};
double scale = 1.0; /* no scaling, default */
int defpoint = 0; /* flag for pointsize scaling */
char *defstipple = (char *) 0;
enum {
OUTLINE, FILL, BOTH
} polyfill;
/* flag to controll filling of polygons */
double adj1 = 0.0;
double adj2 = 0.0;
double adj3 = 0.0;
double adj4 = 0.0;
double thick[STYLES]; /* thicknesses set by defaults, then by */
/* commands */
char *tfont[FONTS]; /* fonts originally set to deffont values, */
/* then */
int tsize[SIZES]; /* optionally changed by commands inside */
/* grn */
int stipple_index[NSTIPPLES + 1]; /* stipple font file indices */
char *stipple;
double xscale; /* scaling factor from individual pictures */
double troffscale; /* scaling factor at output time */
double width; /* user-request maximum width for picture */
/* (in inches) */
double height; /* user-request height */
int pointscale; /* flag for pointsize scaling */
int setdefault; /* flag for a .GS/.GE to remember all */
/* settings */
int sflag; /* -s flag: sort order (do polyfill first) */
double toppoint; /* remember the picture */
double bottompoint; /* bounds in these variables */
double leftpoint;
double rightpoint;
int ytop; /* these are integer versions of the above */
int ybottom; /* so not to convert each time they're used */
int xleft;
int xright;
int linenum = 0; /* line number of input file */
char inputline[MAXINLINE]; /* spot to filter through the file */
char *c1 = inputline; /* c1, c2, and c3 will be used to */
char *c2 = inputline + 1; /* hunt for lines that begin with */
char *c3 = inputline + 2; /* ".GS" by looking individually */
char *c4 = inputline + 3; /* needed for compatibility mode */
char GScommand[MAXINLINE]; /* put user's ".GS" command line here */
char gremlinfile[MAXINLINE]; /* filename to use for a picture */
int SUNFILE = FALSE; /* TRUE if SUN gremlin file */
int compatibility_flag = FALSE; /* TRUE if in compatibility mode */
void getres();
char *doinput(FILE *fp);
void conv(register FILE *fp, int baseline);
void savestate();
int has_polygon(register ELT *elist);
void interpret(char *line);
void
usage(FILE *stream)
{
fprintf(stream,
"usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n",
program_name);
}
/*----------------------------------------------------------------------------*
| Routine: main (argument_count, argument_pointer)
|
| Results: Parses the command line, accumulating input file names, then
| reads the inputs, passing it directly to output until a `.GS'
| line is read. Main then passes control to `conv' to do the
| gremlin file conversions.
*----------------------------------------------------------------------------*/
int
main(int argc,
char **argv)
{
program_name = argv[0];
register FILE *fp;
register int k;
register char c;
register int gfil = 0;
char *file[50];
char *operand(int *argcp, char ***argvp);
while (--argc) {
if (**++argv != '-')
file[gfil++] = *argv;
else
switch (c = (*argv)[1]) {
case 0:
file[gfil++] = NULL;
break;
case 'C': /* compatibility mode */
compatibility_flag = TRUE;
break;
case 'F': /* font path to find DESC */
font::command_line_font_dir(operand(&argc, &argv));
break;
case 'T': /* final output typesetter name */
device = operand(&argc, &argv);
break;
case 'M': /* set library directory */
macro_path.command_line_dir(operand(&argc, &argv));
break;
case 's': /* preserve order of elements */
sflag = 1;
break;
case '-':
if (strcmp(*argv,"--version")==0) {
case 'v':
printf("GNU grn (groff) version %s\n", Version_string);
exit(0);
break;
}
if (strcmp(*argv,"--help")==0) {
case '?':
usage(stdout);
exit(0);
break;
}
// fallthrough
default:
error("unknown switch: %1", c);
usage(stderr);
exit(1);
}
}
getres(); /* set the resolution for an output device */
if (gfil == 0) { /* no filename, use standard input */
file[0] = NULL;
gfil++;
}
for (k = 0; k < gfil; k++) {
if (file[k] != NULL) {
if ((fp = fopen(file[k], "r")) == NULL)
fatal("can't open %1", file[k]);
} else
fp = stdin;
while (doinput(fp) != NULL) {
if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
if (compatibility_flag ||
*c4 == '\n' || *c4 == ' ' || *c4 == '\0')
conv(fp, linenum);
else
fputs(inputline, stdout);
} else
fputs(inputline, stdout);
}
}
}
/*----------------------------------------------------------------------------*
| Routine: char * operand (& argc, & argv)
|
| Results: Returns address of the operand given with a command-line
| option. It uses either `-Xoperand' or `-X operand', whichever
| is present. The program is terminated if no option is
| present.
|
| Side Efct: argc and argv are updated as necessary.
*----------------------------------------------------------------------------*/
char *
operand(int *argcp,
char ***argvp)
{
if ((**argvp)[2])
return (**argvp + 2); /* operand immediately follows */
if ((--*argcp) <= 0) { /* no operand */
error("command-line option operand missing.");
exit(8);
}
return (*(++(*argvp))); /* operand is next word */
}
/*----------------------------------------------------------------------------*
| Routine: getres ()
|
| Results: Sets `res' to the resolution of the output device.
*----------------------------------------------------------------------------*/
void
getres()
{
int linepiece;
if (!font::load_desc())
fatal("sorry, I can't continue");
res = font::res;
/* Correct the brush thicknesses based on res */
/* if (res >= 256) {
defthick[0] = res >> 8;
defthick[1] = res >> 8;
defthick[2] = res >> 4;
defthick[3] = res >> 8;
defthick[4] = res >> 8;
defthick[5] = res >> 6;
} */
linepiece = res >> 9;
for (dotshifter = 0; linepiece; dotshifter++)
linepiece = linepiece >> 1;
}
/*----------------------------------------------------------------------------*
| Routine: char * doinput (file_pointer)
|
| Results: A line of input is read into `inputline'.
|
| Side Efct: "linenum" is incremented.
|
| Bugs: Lines longer than MAXINLINE are NOT checked, except for
| updating `linenum'.
*----------------------------------------------------------------------------*/
char *
doinput(FILE *fp)
{
char *k;
if ((k = fgets(inputline, MAXINLINE, fp)) == NULL)
return k;
if (strchr(inputline, '\n')) /* ++ only if it's a complete line */
linenum++;
return (char *) !NULL;
}
/*----------------------------------------------------------------------------*
| Routine: initpic ( )
|
| Results: Sets all parameters to the normal defaults, possibly
| overridden by a setdefault command. Initialize the picture
| variables, and output the startup commands to troff to begin
| the picture.
*----------------------------------------------------------------------------*/
void
initpic()
{
register int i;
for (i = 0; i < STYLES; i++) { /* line thickness defaults */
thick[i] = defthick[i];
}
for (i = 0; i < FONTS; i++) { /* font name defaults */
tfont[i] = deffont[i];
}
for (i = 0; i < SIZES; i++) { /* font size defaults */
tsize[i] = defsize[i];
}
for (i = 0; i <= NSTIPPLES; i++) { /* stipple font file default indices */
stipple_index[i] = defstipple_index[i];
}
stipple = defstipple;
gremlinfile[0] = 0; /* filename is `null' */
setdefault = 0; /* this is not the default settings (yet) */
toppoint = BIG; /* set the picture bounds out */
bottompoint = -BIG; /* of range so they'll be set */
leftpoint = BIG; /* by `savebounds' on input */
rightpoint = -BIG;
pointscale = defpoint; /* flag for scaling point sizes default */
xscale = scale; /* default scale of individual pictures */
width = 0.0; /* size specifications input by user */
height = 0.0;
linethickness = DEFTHICK; /* brush styles */
linmod = DEFSTYLE;
}
/*----------------------------------------------------------------------------*
| Routine: conv (file_pointer, starting_line)
|
| Results: At this point, we just passed a `.GS' line in the input
| file. conv reads the input and calls `interpret' to process
| commands, gathering up information until a `.GE' line is
| found. It then calls `HGPrint' to do the translation of the
| gremlin file to troff commands.
*----------------------------------------------------------------------------*/
void
conv(register FILE *fp,
int baseline)
{
register FILE *gfp = NULL; /* input file pointer */
register int done = 0; /* flag to remember if finished */
register ELT *e; /* current element pointer */
ELT *PICTURE; /* whole picture data base pointer */
double temp; /* temporary calculating area */
/* POINT ptr; */ /* coordinates of a point to pass to `mov' */
/* routine */
int flyback; /* flag `want to end up at the top of the */
/* picture?' */
int compat; /* test character after .GE or .GF */
initpic(); /* set defaults, ranges, etc. */
strcpy(GScommand, inputline); /* save `.GS' line for later */
do {
done = (doinput(fp) == NULL); /* test for EOF */
flyback = (*c3 == 'F'); /* and .GE or .GF */
compat = (compatibility_flag ||
*c4 == '\n' || *c4 == ' ' || *c4 == '\0');
done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) &&
compat);
if (done) {
if (setdefault)
savestate();
if (!gremlinfile[0]) {
if (!setdefault)
error("at line %1: no picture filename.\n", baseline);
return;
}
char *path;
gfp = macro_path.open_file(gremlinfile, &path);
if (!gfp)
return;
PICTURE = DBRead(gfp); /* read picture file */
fclose(gfp);
a_delete path;
if (DBNullelt(PICTURE))
return; /* If a request is made to make the */
/* picture fit into a specific area, */
/* set the scale to do that. */
if (stipple == (char *) NULL) /* if user forgot stipple */
if (has_polygon(PICTURE)) /* and picture has a polygon */
stipple = DEFSTIPPLE; /* then set the default */
if ((temp = bottompoint - toppoint) < 0.1)
temp = 0.1;
temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG;
if ((troffscale = rightpoint - leftpoint) < 0.1)
troffscale = 0.1;
troffscale = (width != 0.0) ?
width / (troffscale * SCREENtoINCH) : BIG;
if (temp == BIG && troffscale == BIG)
troffscale = xscale;
else {
if (temp < troffscale)
troffscale = temp;
} /* here, troffscale is the */
/* picture's scaling factor */
if (pointscale) {
register int i; /* do pointscaling here, when */
/* scale is known, before output */
for (i = 0; i < SIZES; i++)
tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5);
}
/* change to device units */
troffscale *= SCREENtoINCH * res; /* from screen units */
ytop = (int) (toppoint * troffscale); /* calculate integer */
ybottom = (int) (bottompoint * troffscale); /* versions of the */
xleft = (int) (leftpoint * troffscale); /* picture limits */
xright = (int) (rightpoint * troffscale);
/* save stuff in number registers, */
/* register g1 = picture width and */
/* register g2 = picture height, */
/* set vertical spacing, no fill, */
/* and break (to make sure picture */
/* starts on left), and put out the */
/* user's `.GS' line. */
printf(".br\n"
".nr g1 %du\n"
".nr g2 %du\n"
"%s"
".nr g3 \\n(.f\n"
".nr g4 \\n(.s\n"
"\\0\n"
".sp -1\n",
xright - xleft, ybottom - ytop, GScommand);
if (stipple) /* stipple requested for this picture */
printf(".st %s\n", stipple);
lastx = xleft; /* note where we are (upper left */
lastyline = lasty = ytop; /* corner of the picture) */
/* Just dump everything in the order it appears.
*
* If -s command-line option, traverse picture twice: First time,
* print only the interiors of filled polygons (as borderless
* polygons). Second time, print the outline as series of line
* segments. This way, postprocessors that overwrite rather than
* merge picture elements (such as Postscript) can still have text and
* graphics on a shaded background.
*/
/* if (sflag) */
if (!sflag) { /* changing the default for filled polygons */
e = PICTURE;
polyfill = FILL;
while (!DBNullelt(e)) {
printf(".mk\n");
if (e->type == POLYGON)
HGPrintElt(e, baseline);
printf(".rt\n");
lastx = xleft;
lastyline = lasty = ytop;
e = DBNextElt(e);
}
}
e = PICTURE;
/* polyfill = !sflag ? BOTH : OUTLINE; */
polyfill = sflag ? BOTH : OUTLINE; /* changing the default */
while (!DBNullelt(e)) {
printf(".mk\n");
HGPrintElt(e, baseline);
printf(".rt\n");
lastx = xleft;
lastyline = lasty = ytop;
e = DBNextElt(e);
}
/* decide where to end picture */
/* I changed everything here. I always use the combination .mk and */
/* .rt so once finished I just space down the heigth of the picture */
/* that is \n(g2u */
if (flyback) { /* end picture at upper left */
/* ptr.x = leftpoint;
ptr.y = toppoint; */
} else { /* end picture at lower left */
/* ptr.x = leftpoint;
ptr.y = bottompoint; */
printf(".sp \\n(g2u\n");
}
/* tmove(&ptr); */ /* restore default line parameters */
/* restore everything to the way it was before the .GS, then put */
/* out the `.GE' line from user */
/* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
/* groff doesn't understand the \Ds command */
printf("\\D't %du'\n", DEFTHICK);
if (flyback) /* make sure we end up at top of */
printf(".sp -1\n"); /* picture if `flying back' */
if (stipple) /* restore stipple to previous */
printf(".st\n");
printf(".br\n"
".ft \\n(g3\n"
".ps \\n(g4\n"
"%s", inputline);
} else
interpret(inputline); /* take commands from the input file */
} while (!done);
}
/*----------------------------------------------------------------------------*
| Routine: savestate ( )
|
| Results: all the current scaling / font size / font name / thickness
| / pointscale settings are saved to be the defaults. Scaled
| point sizes are NOT saved. The scaling is done each time a
| new picture is started.
|
| Side Efct: scale, and def* are modified.
*----------------------------------------------------------------------------*/
void
savestate()
{
register int i;
for (i = 0; i < STYLES; i++) /* line thickness defaults */
defthick[i] = thick[i];
for (i = 0; i < FONTS; i++) /* font name defaults */
deffont[i] = tfont[i];
for (i = 0; i < SIZES; i++) /* font size defaults */
defsize[i] = tsize[i];
for (i = 0; i <= NSTIPPLES; i++) /* stipple font file default indices */
defstipple_index[i] = stipple_index[i];
defstipple = stipple; /* if stipple has been set, it's remembered */
scale *= xscale; /* default scale of individual pictures */
defpoint = pointscale; /* flag for scaling pointsizes from x factors */
}
/*----------------------------------------------------------------------------*
| Routine: savebounds (x_coordinate, y_coordinate)
|
| Results: Keeps track of the maximum and minimum extent of a picture
| in the global variables: left-, right-, top- and
| bottompoint. `savebounds' assumes that the points have been
| oriented to the correct direction. No scaling has taken
| place, though.
*----------------------------------------------------------------------------*/
void
savebounds(float x,
float y)
{
if (x < leftpoint)
leftpoint = x;
if (x > rightpoint)
rightpoint = x;
if (y < toppoint)
toppoint = y;
if (y > bottompoint)
bottompoint = y;
}
/*----------------------------------------------------------------------------*
| Routine: interpret (character_string)
|
| Results: Commands are taken from the input string and performed.
| Commands are separated by the endofline, and are of the
| format:
| string1 string2
|
| where string1 is the command and string2 is the argument.
|
| Side Efct: Font and size strings, plus the gremlin file name and the
| width and height variables are set by this routine.
*----------------------------------------------------------------------------*/
void
interpret(char *line)
{
char str1[MAXINLINE];
char str2[MAXINLINE];
register char *chr;
register int i;
double par;
str2[0] = '\0';
sscanf(line, "%80s%80s", &str1[0], &str2[0]);
for (chr = &str1[0]; *chr; chr++) /* convert command to */
if (isupper(*chr))
*chr = tolower(*chr); /* lower case */
switch (str1[0]) {
case '1':
case '2': /* font sizes */
case '3':
case '4':
i = atoi(str2);
if (i > 0 && i < 1000)
tsize[str1[0] - '1'] = i;
else
error("bad font size value at line %1", linenum);
break;
case 'r': /* roman */
if (str2[0] < '0')
goto nofont;
tfont[0] = (char *) malloc(strlen(str2) + 1);
strcpy(tfont[0], str2);
break;
case 'i': /* italics */
if (str2[0] < '0')
goto nofont;
tfont[1] = (char *) malloc(strlen(str2) + 1);
strcpy(tfont[1], str2);
break;
case 'b': /* bold */
if (str2[0] < '0')
goto nofont;
tfont[2] = (char *) malloc(strlen(str2) + 1);
strcpy(tfont[2], str2);
break;
case 's': /* special */
if (str1[1] == 'c')
goto scalecommand; /* or scale */
if (str2[0] < '0') {
nofont:
error("no fontname specified in line %1", linenum);
break;
}
if (str1[1] == 't')
goto stipplecommand; /* or stipple */
tfont[3] = (char *) malloc(strlen(str2) + 1);
strcpy(tfont[3], str2);
break;
case 'l': /* l */
if (isdigit(str1[1])) { /* set stipple index */
int index = atoi(str1 + 1), val;
if (index < 0 || index > NSTIPPLES) {
error("bad stipple number %1 at line %2", index, linenum);
break;
}
if (!defstipple_index)
defstipple_index = other_stipple_index;
val = atoi(str2);
if (val >= 0 && val < 256)
stipple_index[index] = val;
else
error("bad stipple index value at line %1", linenum);
break;
}
stipplecommand: /* set stipple name */
stipple = (char *) malloc(strlen(str2) + 1);
strcpy(stipple, str2);
/* if its a `known' font (currently only `cf'), set indicies */
if (strcmp(stipple, "cf") == 0)
defstipple_index = cf_stipple_index;
else
defstipple_index = other_stipple_index;
for (i = 0; i <= NSTIPPLES; i++)
stipple_index[i] = defstipple_index[i];
break;
case 'a': /* text adjust */
par = atof(str2);
switch (str1[1]) {
case '1':
adj1 = par;
break;
case '2':
adj2 = par;
break;
case '3':
adj3 = par;
break;
case '4':
adj4 = par;
break;
default:
error("bad adjust command at line %1", linenum);
break;
}
break;
case 't': /* thick */
thick[2] = defthick[0] * atof(str2);
break;
case 'm': /* medium */
thick[5] = defthick[0] * atof(str2);
break;
case 'n': /* narrow */
thick[0] = thick[1] = thick[3] = thick[4] =
defthick[0] * atof(str2);
break;
case 'x': /* x */
scalecommand: /* scale */
par = atof(str2);
if (par > 0.0)
xscale *= par;
else
error("invalid scale value on line %1", linenum);
break;
case 'f': /* file */
strcpy(gremlinfile, str2);
break;
case 'w': /* width */
width = atof(str2);
if (width < 0.0)
width = -width;
break;
case 'h': /* height */
height = atof(str2);
if (height < 0.0)
height = -height;
break;
case 'd': /* defaults */
setdefault = 1;
break;
case 'p': /* pointscale */
if (strcmp("off", str2))
pointscale = 1;
else
pointscale = 0;
break;
default:
error("unknown command `%1' on line %2", str1, linenum);
exit(8);
break;
};
}
/*
* return TRUE if picture contains a polygon
* otherwise FALSE
*/
int
has_polygon(register ELT *elist)
{
while (!DBNullelt(elist)) {
if (elist->type == POLYGON)
return (1);
elist = DBNextElt(elist);
}
return (0);
}
/* EOF */

File diff suppressed because it is too large Load Diff

View File

@ -1,333 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Written by Gaius Mulley (gaius@glam.ac.uk).
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 "lib.h"
#include <signal.h>
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include "errarg.h"
#include "error.h"
#include "stringclass.h"
#include "posix.h"
#include "nonposix.h"
#include <errno.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "pushback.h"
#include "pre-html.h"
#if !defined(TRUE)
# define TRUE (1==1)
#endif
#if !defined(FALSE)
# define FALSE (1==0)
#endif
# define ERROR(X) (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \
(fflush(stderr)) && localexit(1))
#define MAXPUSHBACKSTACK 4096 /* maximum number of character that can be pushed back */
/*
* constructor for pushBackBuffer
*/
pushBackBuffer::pushBackBuffer (char *filename)
{
charStack = (char *)malloc(MAXPUSHBACKSTACK);
if (charStack == 0) {
sys_fatal("malloc");
}
stackPtr = 0; /* index to push back stack */
debug = 0;
verbose = 0;
eofFound = FALSE;
lineNo = 1;
if (strcmp(filename, "") != 0) {
stdIn = dup(0);
close(0);
if (open(filename, O_RDONLY) != 0) {
sys_fatal("when trying to open file");
} else {
fileName = filename;
}
}
}
pushBackBuffer::~pushBackBuffer ()
{
int old;
if (charStack != 0) {
free(charStack);
}
close(0);
/* restore stdin in file descriptor 0 */
old = dup(stdIn);
close(stdIn);
}
/*
* localexit - wraps exit with a return code to aid the ERROR macro.
*/
int localexit (int i)
{
exit(i);
return( 1 );
}
/*
* getPB - returns a character, possibly a pushed back character.
*/
char pushBackBuffer::getPB (void)
{
if (stackPtr>0) {
stackPtr--;
return( charStack[stackPtr] );
} else {
char ch;
if (read(0, &ch, 1) == 1) {
if (verbose) {
printf("%c", ch);
}
if (ch == '\n') {
lineNo++;
}
return( ch );
} else {
eofFound = TRUE;
return( eof );
}
}
}
/*
* putPB - pushes a character onto the push back stack.
* The same character is returned.
*/
char pushBackBuffer::putPB (char ch)
{
if (stackPtr<MAXPUSHBACKSTACK) {
charStack[stackPtr] = ch ;
stackPtr++;
} else {
ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
}
return( ch );
}
/*
* isWhite - returns TRUE if a white character is found. This character is NOT consumed.
*/
static int isWhite (char ch)
{
return( (ch==' ') || (ch == '\t') || (ch == '\n') );
}
/*
* skipToNewline - skips characters until a newline is seen.
*/
void pushBackBuffer::skipToNewline (void)
{
char ch;
while ((putPB(getPB()) != '\n') && (! eofFound)) {
ch = getPB();
}
}
/*
* skipUntilToken - skips until a token is seen
*/
void pushBackBuffer::skipUntilToken (void)
{
char ch;
while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
ch = getPB();
if (ch == '#') {
skipToNewline();
}
}
}
/*
* isString - returns TRUE if the string, s, matches the pushed back string.
* if TRUE is returned then this string is consumed, otherwise it is
* left alone.
*/
int pushBackBuffer::isString (char *s)
{
int length=strlen(s);
int i=0;
while ((i<length) && (putPB(getPB())==s[i])) {
if (getPB() != s[i]) {
ERROR("assert failed");
}
i++;
}
if (i==length) {
return( TRUE );
} else {
i--;
while (i>=0) {
if (putPB(s[i]) != s[i]) {
ERROR("assert failed");
}
i--;
}
}
return( FALSE );
}
/*
* isDigit - returns TRUE if the character, ch, is a digit.
*/
static int isDigit (char ch)
{
return( ((ch>='0') && (ch<='9')) );
}
/*
* isHexDigit - returns TRUE if the character, ch, is a hex digit.
*/
#if 0
static int isHexDigit (char ch)
{
return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
}
#endif
/*
* readInt - returns an integer from the input stream.
*/
int pushBackBuffer::readInt (void)
{
int c =0;
int i =0;
int s =1;
char ch=getPB();
while (isWhite(ch)) {
ch=getPB();
}
// now read integer
if (ch == '-') {
s = -1;
ch = getPB();
}
while (isDigit(ch)) {
i *= 10;
if ((ch>='0') && (ch<='9')) {
i += (int)(ch-'0');
}
ch = getPB();
c++;
}
if (ch != putPB(ch)) {
ERROR("assert failed");
}
return( i*s );
}
/*
* convertToFloat - converts integers, a and b into a.b
*/
static float convertToFloat (int a, int b)
{
int c=10;
float f;
while (b>c) {
c *= 10;
}
f = ((float)a) + (((float)b)/((float)c));
return( f );
}
/*
* readNumber - returns a float representing the word just read.
*/
float pushBackBuffer::readNumber (void)
{
int i;
char ch;
i = readInt();
if ((ch = getPB()) == '.') {
return convertToFloat(i, readInt());
}
putPB(ch);
return (float)i;
}
/*
* readString - reads a string terminated by white space
* and returns a malloced area of memory containing
* a copy of the characters.
*/
char *pushBackBuffer::readString (void)
{
char buffer[MAXPUSHBACKSTACK];
char *string = 0;
int i=0;
char ch=getPB();
while (isWhite(ch)) {
ch=getPB();
}
while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) {
buffer[i] = ch;
i++;
ch = getPB();
}
if (i < MAXPUSHBACKSTACK) {
buffer[i] = (char)0;
string = (char *)malloc(strlen(buffer)+1);
strcpy(string, buffer);
}
return( string );
}

View File

@ -1,496 +0,0 @@
// -*- 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 "pic.h"
#include "common.h"
// output a dashed circle as a series of arcs
void common_output::dashed_circle(const position &cent, double rad,
const line_type &lt)
{
assert(lt.type == line_type::dashed);
line_type slt = lt;
slt.type = line_type::solid;
double dash_angle = lt.dash_width/rad;
int ndashes;
double gap_angle;
if (dash_angle >= M_PI/4.0) {
if (dash_angle < M_PI/2.0) {
gap_angle = M_PI/2.0 - dash_angle;
ndashes = 4;
}
else if (dash_angle < M_PI) {
gap_angle = M_PI - dash_angle;
ndashes = 2;
}
else {
circle(cent, rad, slt, -1.0);
return;
}
}
else {
ndashes = 4*int(ceil(M_PI/(4.0*dash_angle)));
gap_angle = (M_PI*2.0)/ndashes - dash_angle;
}
for (int i = 0; i < ndashes; i++) {
double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0;
solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt);
}
}
// output a dotted circle as a series of dots
void common_output::dotted_circle(const position &cent, double rad,
const line_type &lt)
{
assert(lt.type == line_type::dotted);
double gap_angle = lt.dash_width/rad;
int ndots;
if (gap_angle >= M_PI/2.0) {
// always have at least 2 dots
gap_angle = M_PI;
ndots = 2;
}
else {
ndots = 4*int(M_PI/(2.0*gap_angle));
gap_angle = (M_PI*2.0)/ndots;
}
double ang = 0.0;
for (int i = 0; i < ndots; i++, ang += gap_angle)
dot(cent + position(cos(ang), sin(ang))*rad, lt);
}
// return non-zero iff we can compute a center
int compute_arc_center(const position &start, const position &cent,
const position &end, position *result)
{
// This finds the point along the vector from start to cent that
// is equidistant between start and end.
distance c = cent - start;
distance e = end - start;
double n = c*e;
if (n == 0.0)
return 0;
*result = start + c*((e*e)/(2.0*n));
return 1;
}
// output a dashed arc as a series of arcs
void common_output::dashed_arc(const position &start, const position &cent,
const position &end, const line_type &lt)
{
assert(lt.type == line_type::dashed);
position c;
if (!compute_arc_center(start, cent, end, &c)) {
line(start, &end, 1, lt);
return;
}
distance start_offset = start - c;
distance end_offset = end - c;
double start_angle = atan2(start_offset.y, start_offset.x);
double end_angle = atan2(end_offset.y, end_offset.x);
double rad = hypot(c - start);
double dash_angle = lt.dash_width/rad;
double total_angle = end_angle - start_angle;
while (total_angle < 0)
total_angle += M_PI + M_PI;
if (total_angle <= dash_angle*2.0) {
solid_arc(cent, rad, start_angle, end_angle, lt);
return;
}
int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5);
double dash_and_gap_angle = (total_angle - dash_angle)/ndashes;
for (int i = 0; i <= ndashes; i++)
solid_arc(cent, rad, start_angle + i*dash_and_gap_angle,
start_angle + i*dash_and_gap_angle + dash_angle, lt);
}
// output a dotted arc as a series of dots
void common_output::dotted_arc(const position &start, const position &cent,
const position &end, const line_type &lt)
{
assert(lt.type == line_type::dotted);
position c;
if (!compute_arc_center(start, cent, end, &c)) {
line(start, &end, 1, lt);
return;
}
distance start_offset = start - c;
distance end_offset = end - c;
double start_angle = atan2(start_offset.y, start_offset.x);
double total_angle = atan2(end_offset.y, end_offset.x) - start_angle;
while (total_angle < 0)
total_angle += M_PI + M_PI;
double rad = hypot(c - start);
int ndots = int(total_angle/(lt.dash_width/rad) + .5);
if (ndots == 0)
dot(start, lt);
else {
for (int i = 0; i <= ndots; i++) {
double a = start_angle + (total_angle*i)/ndots;
dot(cent + position(cos(a), sin(a))*rad, lt);
}
}
}
void common_output::solid_arc(const position &cent, double rad,
double start_angle, double end_angle,
const line_type &lt)
{
line_type slt = lt;
slt.type = line_type::solid;
arc(cent + position(cos(start_angle), sin(start_angle))*rad,
cent,
cent + position(cos(end_angle), sin(end_angle))*rad,
slt);
}
void common_output::rounded_box(const position &cent, const distance &dim,
double rad, const line_type &lt, double fill)
{
if (fill >= 0.0)
filled_rounded_box(cent, dim, rad, fill);
switch (lt.type) {
case line_type::invisible:
break;
case line_type::dashed:
dashed_rounded_box(cent, dim, rad, lt);
break;
case line_type::dotted:
dotted_rounded_box(cent, dim, rad, lt);
break;
case line_type::solid:
solid_rounded_box(cent, dim, rad, lt);
break;
default:
assert(0);
}
}
void common_output::dashed_rounded_box(const position &cent,
const distance &dim, double rad,
const line_type &lt)
{
line_type slt = lt;
slt.type = line_type::solid;
double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5);
double hor_gap_width = (n_hor_dashes != 0
? hor_length/n_hor_dashes - lt.dash_width
: 0.0);
double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5);
double vert_gap_width = (n_vert_dashes != 0
? vert_length/n_vert_dashes - lt.dash_width
: 0.0);
// Note that each corner arc has to be split into two for dashing,
// because one part is dashed using vert_gap_width, and the other
// using hor_gap_width.
double offset = lt.dash_width/2.0;
dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
-M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset);
dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
cent + position(dim.x/2.0, dim.y/2.0 - rad),
slt, lt.dash_width, vert_gap_width, &offset);
dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
offset = lt.dash_width/2.0;
dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset);
dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
cent + position(-dim.x/2.0 + rad, dim.y/2.0),
slt, lt.dash_width, hor_gap_width, &offset);
dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset);
offset = lt.dash_width/2.0;
dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset);
dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
slt, lt.dash_width, vert_gap_width, &offset);
dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset);
offset = lt.dash_width/2.0;
dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset);
dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
cent + position(dim.x/2.0 - rad, -dim.y/2.0),
slt, lt.dash_width, hor_gap_width, &offset);
dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset);
}
// Used by dashed_rounded_box.
void common_output::dash_arc(const position &cent, double rad,
double start_angle, double end_angle,
const line_type &lt,
double dash_width, double gap_width,
double *offsetp)
{
double length = (end_angle - start_angle)*rad;
double pos = 0.0;
for (;;) {
if (*offsetp >= dash_width) {
double rem = dash_width + gap_width - *offsetp;
if (pos + rem > length) {
*offsetp += length - pos;
break;
}
else {
pos += rem;
*offsetp = 0.0;
}
}
else {
double rem = dash_width - *offsetp;
if (pos + rem > length) {
solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt);
*offsetp += length - pos;
break;
}
else {
solid_arc(cent, rad, start_angle + pos/rad,
start_angle + (pos + rem)/rad, lt);
pos += rem;
*offsetp = dash_width;
}
}
}
}
// Used by dashed_rounded_box.
void common_output::dash_line(const position &start, const position &end,
const line_type &lt,
double dash_width, double gap_width,
double *offsetp)
{
distance dist = end - start;
double length = hypot(dist);
if (length == 0.0)
return;
double pos = 0.0;
for (;;) {
if (*offsetp >= dash_width) {
double rem = dash_width + gap_width - *offsetp;
if (pos + rem > length) {
*offsetp += length - pos;
break;
}
else {
pos += rem;
*offsetp = 0.0;
}
}
else {
double rem = dash_width - *offsetp;
if (pos + rem > length) {
line(start + dist*(pos/length), &end, 1, lt);
*offsetp += length - pos;
break;
}
else {
position p(start + dist*((pos + rem)/length));
line(start + dist*(pos/length), &p, 1, lt);
pos += rem;
*offsetp = dash_width;
}
}
}
}
void common_output::dotted_rounded_box(const position &cent,
const distance &dim, double rad,
const line_type &lt)
{
line_type slt = lt;
slt.type = line_type::solid;
double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad;
int n_hor_dots = int(hor_length/lt.dash_width + .5);
double hor_gap_width = (n_hor_dots != 0
? hor_length/n_hor_dots
: lt.dash_width);
double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad;
int n_vert_dots = int(vert_length/lt.dash_width + .5);
double vert_gap_width = (n_vert_dots != 0
? vert_length/n_vert_dots
: lt.dash_width);
double epsilon = lt.dash_width/(rad*100.0);
double offset = 0.0;
dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
-M_PI/4.0, 0, slt, vert_gap_width, &offset);
dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad),
cent + position(dim.x/2.0, dim.y/2.0 - rad),
slt, vert_gap_width, &offset);
dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
offset = 0.0;
dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad,
M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset);
dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0),
cent + position(-dim.x/2.0 + rad, dim.y/2.0),
slt, hor_gap_width, &offset);
dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset);
offset = 0.0;
dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad,
3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset);
dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad),
cent + position(-dim.x/2.0, -dim.y/2.0 + rad),
slt, vert_gap_width, &offset);
dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset);
offset = 0.0;
dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad,
5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset);
dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0),
cent + position(dim.x/2.0 - rad, -dim.y/2.0),
slt, hor_gap_width, &offset);
dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad,
3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset);
}
// Used by dotted_rounded_box.
void common_output::dot_arc(const position &cent, double rad,
double start_angle, double end_angle,
const line_type &lt, double gap_width,
double *offsetp)
{
double length = (end_angle - start_angle)*rad;
double pos = 0.0;
for (;;) {
if (*offsetp == 0.0) {
double ang = start_angle + pos/rad;
dot(cent + position(cos(ang), sin(ang))*rad, lt);
}
double rem = gap_width - *offsetp;
if (pos + rem > length) {
*offsetp += length - pos;
break;
}
else {
pos += rem;
*offsetp = 0.0;
}
}
}
// Used by dotted_rounded_box.
void common_output::dot_line(const position &start, const position &end,
const line_type &lt, double gap_width,
double *offsetp)
{
distance dist = end - start;
double length = hypot(dist);
if (length == 0.0)
return;
double pos = 0.0;
for (;;) {
if (*offsetp == 0.0)
dot(start + dist*(pos/length), lt);
double rem = gap_width - *offsetp;
if (pos + rem > length) {
*offsetp += length - pos;
break;
}
else {
pos += rem;
*offsetp = 0.0;
}
}
}
void common_output::solid_rounded_box(const position &cent,
const distance &dim, double rad,
const line_type &lt)
{
position tem = cent - dim/2.0;
arc(tem + position(0.0, rad),
tem + position(rad, rad),
tem + position(rad, 0.0),
lt);
tem = cent + position(-dim.x/2.0, dim.y/2.0);
arc(tem + position(rad, 0.0),
tem + position(rad, -rad),
tem + position(0.0, -rad),
lt);
tem = cent + dim/2.0;
arc(tem + position(0.0, -rad),
tem + position(-rad, -rad),
tem + position(-rad, 0.0),
lt);
tem = cent + position(dim.x/2.0, -dim.y/2.0);
arc(tem + position(-rad, 0.0),
tem + position(-rad, rad),
tem + position(0.0, rad),
lt);
position end;
end = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt);
end = cent + position(dim.x/2.0 - rad, dim.y/2.0);
line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt);
end = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt);
end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt);
}
void common_output::filled_rounded_box(const position &cent,
const distance &dim, double rad,
double fill)
{
line_type ilt;
ilt.type = line_type::invisible;
circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill);
circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill);
circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill);
circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill);
position vec[4];
vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad);
vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad);
vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
polygon(vec, 4, ilt, fill);
vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0);
vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0);
vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0);
polygon(vec, 4, ilt, fill);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,635 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989-1992, 2000, 2001, 2002 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 "pic.h"
extern int yyparse();
extern "C" const char *Version_string;
output *out;
int flyback_flag;
int zero_length_line_flag = 0;
// Non-zero means we're using a groff driver.
int driver_extension_flag = 1;
int compatible_flag = 0;
int safer_flag = 1;
int command_char = '.'; // the character that introduces lines
// that should be passed through tranparently
static int lf_flag = 1; // non-zero if we should attempt to understand
// lines beginning with `.lf'
// Non-zero means a parse error was encountered.
static int had_parse_error = 0;
void do_file(const char *filename);
class top_input : public input {
FILE *fp;
int bol;
int eof;
int push_back[3];
int start_lineno;
public:
top_input(FILE *);
int get();
int peek();
int get_location(const char **, int *);
};
top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
{
push_back[0] = push_back[1] = push_back[2] = EOF;
start_lineno = current_lineno;
}
int top_input::get()
{
if (eof)
return EOF;
if (push_back[2] != EOF) {
int c = push_back[2];
push_back[2] = EOF;
return c;
}
else if (push_back[1] != EOF) {
int c = push_back[1];
push_back[1] = EOF;
return c;
}
else if (push_back[0] != EOF) {
int c = push_back[0];
push_back[0] = EOF;
return c;
}
int c = getc(fp);
while (invalid_input_char(c)) {
error("invalid input character code %1", int(c));
c = getc(fp);
bol = 0;
}
if (bol && c == '.') {
c = getc(fp);
if (c == 'P') {
c = getc(fp);
if (c == 'F' || c == 'E') {
int d = getc(fp);
if (d != EOF)
ungetc(d, fp);
if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
eof = 1;
flyback_flag = c == 'F';
return EOF;
}
push_back[0] = c;
push_back[1] = 'P';
return '.';
}
if (c == 'S') {
c = getc(fp);
if (c != EOF)
ungetc(c, fp);
if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
error("nested .PS");
eof = 1;
return EOF;
}
push_back[0] = 'S';
push_back[1] = 'P';
return '.';
}
if (c != EOF)
ungetc(c, fp);
push_back[0] = 'P';
return '.';
}
else {
if (c != EOF)
ungetc(c, fp);
return '.';
}
}
if (c == '\n') {
bol = 1;
current_lineno++;
return '\n';
}
bol = 0;
if (c == EOF) {
eof = 1;
error("end of file before .PE or .PF");
error_with_file_and_line(current_filename, start_lineno - 1,
".PS was here");
}
return c;
}
int top_input::peek()
{
if (eof)
return EOF;
if (push_back[2] != EOF)
return push_back[2];
if (push_back[1] != EOF)
return push_back[1];
if (push_back[0] != EOF)
return push_back[0];
int c = getc(fp);
while (invalid_input_char(c)) {
error("invalid input character code %1", int(c));
c = getc(fp);
bol = 0;
}
if (bol && c == '.') {
c = getc(fp);
if (c == 'P') {
c = getc(fp);
if (c == 'F' || c == 'E') {
int d = getc(fp);
if (d != EOF)
ungetc(d, fp);
if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
eof = 1;
flyback_flag = c == 'F';
return EOF;
}
push_back[0] = c;
push_back[1] = 'P';
push_back[2] = '.';
return '.';
}
if (c == 'S') {
c = getc(fp);
if (c != EOF)
ungetc(c, fp);
if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
error("nested .PS");
eof = 1;
return EOF;
}
push_back[0] = 'S';
push_back[1] = 'P';
push_back[2] = '.';
return '.';
}
if (c != EOF)
ungetc(c, fp);
push_back[0] = 'P';
push_back[1] = '.';
return '.';
}
else {
if (c != EOF)
ungetc(c, fp);
push_back[0] = '.';
return '.';
}
}
if (c != EOF)
ungetc(c, fp);
if (c == '\n')
return '\n';
return c;
}
int top_input::get_location(const char **filenamep, int *linenop)
{
*filenamep = current_filename;
*linenop = current_lineno;
return 1;
}
void do_picture(FILE *fp)
{
flyback_flag = 0;
int c;
while ((c = getc(fp)) == ' ')
;
if (c == '<') {
string filename;
while ((c = getc(fp)) == ' ')
;
while (c != EOF && c != ' ' && c != '\n') {
filename += char(c);
c = getc(fp);
}
if (c == ' ') {
do {
c = getc(fp);
} while (c != EOF && c != '\n');
}
if (c == '\n')
current_lineno++;
if (filename.length() == 0)
error("missing filename after `<'");
else {
filename += '\0';
const char *old_filename = current_filename;
int old_lineno = current_lineno;
// filenames must be permanent
do_file(strsave(filename.contents()));
current_filename = old_filename;
current_lineno = old_lineno;
}
out->set_location(current_filename, current_lineno);
}
else {
out->set_location(current_filename, current_lineno);
string start_line;
while (c != EOF) {
if (c == '\n') {
current_lineno++;
break;
}
start_line += c;
c = getc(fp);
}
if (c == EOF)
return;
start_line += '\0';
double wid, ht;
switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
case 1:
ht = 0.0;
break;
case 2:
break;
default:
ht = wid = 0.0;
break;
}
out->set_desired_width_height(wid, ht);
out->set_args(start_line.contents());
lex_init(new top_input(fp));
if (yyparse()) {
had_parse_error = 1;
lex_error("giving up on this picture");
}
parse_cleanup();
lex_cleanup();
// skip the rest of the .PF/.PE line
while ((c = getc(fp)) != EOF && c != '\n')
;
if (c == '\n')
current_lineno++;
out->set_location(current_filename, current_lineno);
}
}
void do_file(const char *filename)
{
FILE *fp;
if (strcmp(filename, "-") == 0)
fp = stdin;
else {
errno = 0;
fp = fopen(filename, "r");
if (fp == 0)
fatal("can't open `%1': %2", filename, strerror(errno));
}
out->set_location(filename, 1);
current_filename = filename;
current_lineno = 1;
enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
for (;;) {
int c = getc(fp);
if (c == EOF)
break;
switch (state) {
case START:
if (c == '.')
state = HAD_DOT;
else {
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case MIDDLE:
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
break;
case HAD_DOT:
if (c == 'P')
state = HAD_P;
else if (lf_flag && c == 'l')
state = HAD_l;
else {
putchar('.');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_P:
if (c == 'S')
state = HAD_PS;
else {
putchar('.');
putchar('P');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_PS:
if (c == ' ' || c == '\n' || compatible_flag) {
ungetc(c, fp);
do_picture(fp);
state = START;
}
else {
fputs(".PS", stdout);
putchar(c);
state = MIDDLE;
}
break;
case HAD_l:
if (c == 'f')
state = HAD_lf;
else {
putchar('.');
putchar('l');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_lf:
if (c == ' ' || c == '\n' || compatible_flag) {
string line;
while (c != EOF) {
line += c;
if (c == '\n') {
current_lineno++;
break;
}
c = getc(fp);
}
line += '\0';
interpret_lf_args(line.contents());
printf(".lf%s", line.contents());
state = START;
}
else {
fputs(".lf", stdout);
putchar(c);
state = MIDDLE;
}
break;
default:
assert(0);
}
}
switch (state) {
case START:
break;
case MIDDLE:
putchar('\n');
break;
case HAD_DOT:
fputs(".\n", stdout);
break;
case HAD_P:
fputs(".P\n", stdout);
break;
case HAD_PS:
fputs(".PS\n", stdout);
break;
case HAD_l:
fputs(".l\n", stdout);
break;
case HAD_lf:
fputs(".lf\n", stdout);
break;
}
if (fp != stdin)
fclose(fp);
}
#ifdef FIG_SUPPORT
void do_whole_file(const char *filename)
{
// Do not set current_filename.
FILE *fp;
if (strcmp(filename, "-") == 0)
fp = stdin;
else {
errno = 0;
fp = fopen(filename, "r");
if (fp == 0)
fatal("can't open `%1': %2", filename, strerror(errno));
}
lex_init(new file_input(fp, filename));
if (yyparse())
had_parse_error = 1;
parse_cleanup();
lex_cleanup();
}
#endif
void usage(FILE *stream)
{
fprintf(stream, "usage: %s [ -nvC ] [ filename ... ]\n", program_name);
#ifdef TEX_SUPPORT
fprintf(stream, " %s -t [ -cvzC ] [ filename ... ]\n", program_name);
#endif
#ifdef FIG_SUPPORT
fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name);
#endif
}
#if defined(__MSDOS__) || defined(__EMX__)
static char *fix_program_name(char *arg, char *dflt)
{
if (!arg)
return dflt;
char *prog = strchr(arg, '\0');
for (;;) {
if (prog == arg)
break;
--prog;
if (strchr("\\/:", *prog)) {
prog++;
break;
}
}
char *ext = strchr(prog, '.');
if (ext)
*ext = '\0';
for (char *p = prog; *p; p++)
if ('A' <= *p && *p <= 'Z')
*p = 'a' + (*p - 'A');
return prog;
}
#endif /* __MSDOS__ || __EMX__ */
int main(int argc, char **argv)
{
#if defined(__MSDOS__) || defined(__EMX__)
argv[0] = fix_program_name(argv[0], "pic");
#endif /* __MSDOS__ || __EMX__ */
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
int opt;
#ifdef TEX_SUPPORT
int tex_flag = 0;
int tpic_flag = 0;
#endif
#ifdef FIG_SUPPORT
int whole_file_flag = 0;
int fig_flag = 0;
#endif
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, "T:CDSUtcvnxzpf", long_options, NULL))
!= EOF)
switch (opt) {
case 'C':
compatible_flag = 1;
break;
case 'D':
case 'T':
break;
case 'S':
safer_flag = 1;
break;
case 'U':
safer_flag = 0;
break;
case 'f':
#ifdef FIG_SUPPORT
whole_file_flag++;
fig_flag++;
#else
fatal("fig support not included");
#endif
break;
case 'n':
driver_extension_flag = 0;
break;
case 'p':
case 'x':
warning("-%1 option is obsolete", char(opt));
break;
case 't':
#ifdef TEX_SUPPORT
tex_flag++;
#else
fatal("TeX support not included");
#endif
break;
case 'c':
#ifdef TEX_SUPPORT
tpic_flag++;
#else
fatal("TeX support not included");
#endif
break;
case 'v':
{
printf("GNU pic (groff) version %s\n", Version_string);
exit(0);
break;
}
case 'z':
// zero length lines will be printed as dots
zero_length_line_flag++;
break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
parse_init();
#ifdef TEX_SUPPORT
if (tpic_flag) {
out = make_tpic_output();
lf_flag = 0;
}
else if (tex_flag) {
out = make_tex_output();
command_char = '\\';
lf_flag = 0;
}
else
#endif
#ifdef FIG_SUPPORT
if (fig_flag)
out = make_fig_output();
else
#endif
out = make_troff_output();
#ifdef FIG_SUPPORT
if (whole_file_flag) {
if (optind >= argc)
do_whole_file("-");
else if (argc - optind > 1) {
usage(stderr);
exit(1);
} else
do_whole_file(argv[optind]);
}
else {
#endif
if (optind >= argc)
do_file("-");
else
for (int i = optind; i < argc; i++)
do_file(argv[i]);
#ifdef FIG_SUPPORT
}
#endif
delete out;
if (ferror(stdout) || fflush(stdout) < 0)
fatal("output error");
return had_parse_error;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,438 +0,0 @@
// -*- 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 "pic.h"
#ifdef TEX_SUPPORT
#include "common.h"
class tex_output : public common_output {
public:
tex_output();
~tex_output();
void start_picture(double, const position &ll, const position &ur);
void finish_picture();
void text(const position &, text_piece *, int, double);
void line(const position &, const position *, int n,
const line_type &);
void polygon(const position *, int n,
const line_type &, double);
void spline(const position &, const position *, int n,
const line_type &);
void arc(const position &, const position &, const position &,
const line_type &);
void circle(const position &, double rad, const line_type &, double);
void ellipse(const position &, const distance &, const line_type &, double);
void command(const char *, const char *, int);
void set_color(char *, char *);
void reset_color();
char *get_last_filled();
char *get_outline_color();
int supports_filled_polygons();
private:
position upper_left;
double height;
double width;
double scale;
double pen_size;
void point(const position &);
void dot(const position &, const line_type &);
void solid_arc(const position &cent, double rad, double start_angle,
double end_angle, const line_type &lt);
position transform(const position &);
protected:
virtual void set_pen_size(double ps);
};
// convert inches to milliinches
inline int milliinches(double x)
{
return int(x*1000.0 + .5);
}
inline position tex_output::transform(const position &pos)
{
return position((pos.x - upper_left.x)/scale,
(upper_left.y - pos.y)/scale);
}
output *make_tex_output()
{
return new tex_output;
}
tex_output::tex_output()
{
}
tex_output::~tex_output()
{
}
const int DEFAULT_PEN_SIZE = 8;
void tex_output::set_pen_size(double ps)
{
if (ps < 0.0)
ps = -1.0;
if (ps != pen_size) {
pen_size = ps;
printf(" \\special{pn %d}%%\n",
ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
}
}
void tex_output::start_picture(double sc, const position &ll,
const position &ur)
{
upper_left.x = ll.x;
upper_left.y = ur.y;
scale = compute_scale(sc, ll, ur);
height = (ur.y - ll.y)/scale;
width = (ur.x - ll.x)/scale;
/* the point of \vskip 0pt is to ensure that the vtop gets
a height of 0 rather than the height of the hbox; this
might be non-zero if text from text attributes lies outside pic's
idea of the bounding box of the picture. */
fputs("\\expandafter\\ifx\\csname graph\\endcsname\\relax \\csname newbox\\endcsname\\graph\\fi\n"
"\\expandafter\\ifx\\csname graphtemp\\endcsname\\relax \\csname newdimen\\endcsname\\graphtemp\\fi\n"
"\\setbox\\graph=\\vtop{\\vskip 0pt\\hbox{%\n",
stdout);
pen_size = -2.0;
}
void tex_output::finish_picture()
{
printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
" \\kern %.3fin\n"
" }%%\n"
"}%%\n",
height, width);
}
void tex_output::text(const position &center, text_piece *v, int n, double)
{
position c = transform(center);
for (int i = 0; i < n; i++)
if (v[i].text != 0 && *v[i].text != '\0') {
int j = 2*i - n + 1;
if (v[i].adj.v == ABOVE_ADJUST)
j--;
else if (v[i].adj.v == BELOW_ADJUST)
j++;
if (j == 0) {
printf(" \\graphtemp=.5ex\\advance\\graphtemp by %.3fin\n", c.y);
}
else {
printf(" \\graphtemp=\\baselineskip"
"\\multiply\\graphtemp by %d"
"\\divide\\graphtemp by 2\n"
" \\advance\\graphtemp by .5ex"
"\\advance\\graphtemp by %.3fin\n",
j, c.y);
}
printf(" \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
fputs("\\hbox to 0pt{", stdout);
if (v[i].adj.h != LEFT_ADJUST)
fputs("\\hss ", stdout);
fputs(v[i].text, stdout);
if (v[i].adj.h != RIGHT_ADJUST)
fputs("\\hss", stdout);
fputs("}}%\n", stdout);
}
}
void tex_output::point(const position &pos)
{
position p = transform(pos);
printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
}
void tex_output::line(const position &start, const position *v, int n,
const line_type &lt)
{
set_pen_size(lt.thickness);
point(start);
for (int i = 0; i < n; i++)
point(v[i]);
fputs(" \\special{", stdout);
switch(lt.type) {
case line_type::invisible:
fputs("ip", stdout);
break;
case line_type::solid:
fputs("fp", stdout);
break;
case line_type::dotted:
printf("dt %.3f", lt.dash_width/scale);
break;
case line_type::dashed:
printf("da %.3f", lt.dash_width/scale);
break;
}
fputs("}%\n", stdout);
}
void tex_output::polygon(const position *v, int n,
const line_type &lt, double fill)
{
if (fill >= 0.0) {
if (fill > 1.0)
fill = 1.0;
printf(" \\special{sh %.3f}%%\n", fill);
}
line(v[n-1], v, n, lt);
}
void tex_output::spline(const position &start, const position *v, int n,
const line_type &lt)
{
if (lt.type == line_type::invisible)
return;
set_pen_size(lt.thickness);
point(start);
for (int i = 0; i < n; i++)
point(v[i]);
fputs(" \\special{sp", stdout);
switch(lt.type) {
case line_type::solid:
break;
case line_type::dotted:
printf(" %.3f", -lt.dash_width/scale);
break;
case line_type::dashed:
printf(" %.3f", lt.dash_width/scale);
break;
case line_type::invisible:
assert(0);
}
fputs("}%\n", stdout);
}
void tex_output::solid_arc(const position &cent, double rad,
double start_angle, double end_angle,
const line_type &lt)
{
set_pen_size(lt.thickness);
position c = transform(cent);
printf(" \\special{ar %d %d %d %d %f %f}%%\n",
milliinches(c.x),
milliinches(c.y),
milliinches(rad/scale),
milliinches(rad/scale),
-end_angle,
(-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle
: -start_angle);
}
void tex_output::arc(const position &start, const position &cent,
const position &end, const line_type &lt)
{
switch (lt.type) {
case line_type::invisible:
break;
case line_type::dashed:
dashed_arc(start, cent, end, lt);
break;
case line_type::dotted:
dotted_arc(start, cent, end, lt);
break;
case line_type::solid:
{
position c;
if (!compute_arc_center(start, cent, end, &c)) {
line(start, &end, 1, lt);
break;
}
solid_arc(c,
hypot(cent - start),
atan2(start.y - c.y, start.x - c.x),
atan2(end.y - c.y, end.x - c.x),
lt);
break;
}
}
}
void tex_output::circle(const position &cent, double rad,
const line_type &lt, double fill)
{
if (fill >= 0.0 && lt.type != line_type::solid) {
if (fill > 1.0)
fill = 1.0;
line_type ilt;
ilt.type = line_type::invisible;
ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
}
switch (lt.type) {
case line_type::dashed:
dashed_circle(cent, rad, lt);
break;
case line_type::invisible:
break;
case line_type::solid:
ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
break;
case line_type::dotted:
dotted_circle(cent, rad, lt);
break;
default:
assert(0);
}
}
void tex_output::ellipse(const position &cent, const distance &dim,
const line_type &lt, double fill)
{
if (lt.type == line_type::invisible) {
if (fill < 0.0)
return;
}
else
set_pen_size(lt.thickness);
if (fill >= 0.0) {
if (fill > 1.0)
fill = 1.0;
printf(" \\special{sh %.3f}%%\n", fill);
}
position c = transform(cent);
printf(" \\special{%s %d %d %d %d 0 6.28319}%%\n",
(lt.type == line_type::invisible ? "ia" : "ar"),
milliinches(c.x),
milliinches(c.y),
milliinches(dim.x/(2.0*scale)),
milliinches(dim.y/(2.0*scale)));
}
void tex_output::command(const char *s, const char *, int)
{
fputs(s, stdout);
putchar('%'); // avoid unwanted spaces
putchar('\n');
}
int tex_output::supports_filled_polygons()
{
return 1;
}
void tex_output::dot(const position &pos, const line_type &lt)
{
if (zero_length_line_flag) {
line_type slt = lt;
slt.type = line_type::solid;
line(pos, &pos, 1, slt);
}
else {
int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
if (dot_rad == 0)
dot_rad = 1;
position p = transform(pos);
printf(" \\special{sh 1}%%\n"
" \\special{ia %d %d %d %d 0 6.28319}%%\n",
milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
}
}
void tex_output::set_color(char *, char *)
{
/* not implemented yet */
}
void tex_output::reset_color()
{
/* not implemented yet */
}
char *tex_output::get_last_filled()
{
/* not implemented yet */
return NULL;
}
char *tex_output::get_outline_color()
{
/* not implemented yet */
return NULL;
}
class tpic_output : public tex_output {
public:
tpic_output();
void command(const char *, const char *, int);
private:
void set_pen_size(double ps);
int default_pen_size;
int prev_default_pen_size;
};
tpic_output::tpic_output()
: default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
{
}
void tpic_output::command(const char *s, const char *filename, int lineno)
{
assert(s[0] == '.');
if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
const char *p = s + 3;
while (csspace(*p))
p++;
if (*p == '\0') {
int temp = default_pen_size;
default_pen_size = prev_default_pen_size;
prev_default_pen_size = temp;
}
else {
char *ptr;
int temp = (int)strtol(p, &ptr, 10);
if (temp == 0 && ptr == p)
error_with_file_and_line(filename, lineno,
"argument to `.ps' not an integer");
else if (temp < 0)
error_with_file_and_line(filename, lineno,
"negative pen size");
else {
prev_default_pen_size = default_pen_size;
default_pen_size = temp;
}
}
}
else
printf("\\%s%%\n", s + 1);
}
void tpic_output::set_pen_size(double ps)
{
if (ps < 0.0)
printf(" \\special{pn %d}%%\n", default_pen_size);
else
tex_output::set_pen_size(ps);
}
output *make_tpic_output()
{
return new tpic_output;
}
#endif

View File

@ -1,561 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
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 "pic.h"
#include "common.h"
const double RELATIVE_THICKNESS = -1.0;
const double BAD_THICKNESS = -2.0;
class simple_output : public common_output {
virtual void simple_line(const position &, const position &) = 0;
virtual void simple_spline(const position &, const position *, int n) = 0;
virtual void simple_arc(const position &, const position &,
const position &) = 0;
virtual void simple_circle(int, const position &, double rad) = 0;
virtual void simple_ellipse(int, const position &, const distance &) = 0;
virtual void simple_polygon(int, const position *, int) = 0;
virtual void line_thickness(double) = 0;
virtual void set_fill(double) = 0;
virtual void set_color(char *, char *) = 0;
virtual void reset_color() = 0;
virtual char *get_last_filled() = 0;
void dot(const position &, const line_type &) = 0;
public:
void start_picture(double sc, const position &ll, const position &ur) = 0;
void finish_picture() = 0;
void text(const position &, text_piece *, int, double) = 0;
void line(const position &, const position *, int n,
const line_type &);
void polygon(const position *, int n,
const line_type &, double);
void spline(const position &, const position *, int n,
const line_type &);
void arc(const position &, const position &, const position &,
const line_type &);
void circle(const position &, double rad, const line_type &, double);
void ellipse(const position &, const distance &, const line_type &, double);
int supports_filled_polygons();
};
int simple_output::supports_filled_polygons()
{
return driver_extension_flag != 0;
}
void simple_output::arc(const position &start, const position &cent,
const position &end, const line_type &lt)
{
switch (lt.type) {
case line_type::solid:
line_thickness(lt.thickness);
simple_arc(start, cent, end);
break;
case line_type::invisible:
break;
case line_type::dashed:
dashed_arc(start, cent, end, lt);
break;
case line_type::dotted:
dotted_arc(start, cent, end, lt);
break;
}
}
void simple_output::line(const position &start, const position *v, int n,
const line_type &lt)
{
position pos = start;
line_thickness(lt.thickness);
for (int i = 0; i < n; i++) {
switch (lt.type) {
case line_type::solid:
simple_line(pos, v[i]);
break;
case line_type::dotted:
{
distance vec(v[i] - pos);
double dist = hypot(vec);
int ndots = int(dist/lt.dash_width + .5);
if (ndots == 0)
dot(pos, lt);
else {
vec /= double(ndots);
for (int j = 0; j <= ndots; j++)
dot(pos + vec*j, lt);
}
}
break;
case line_type::dashed:
{
distance vec(v[i] - pos);
double dist = hypot(vec);
if (dist <= lt.dash_width*2.0)
simple_line(pos, v[i]);
else {
int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
distance dash_vec = vec*(lt.dash_width/dist);
double dash_gap = (dist - lt.dash_width)/ndashes;
distance dash_gap_vec = vec*(dash_gap/dist);
for (int j = 0; j <= ndashes; j++) {
position s(pos + dash_gap_vec*j);
simple_line(s, s + dash_vec);
}
}
}
break;
case line_type::invisible:
break;
default:
assert(0);
}
pos = v[i];
}
}
void simple_output::spline(const position &start, const position *v, int n,
const line_type &lt)
{
line_thickness(lt.thickness);
simple_spline(start, v, n);
}
void simple_output::polygon(const position *v, int n,
const line_type &lt, double fill)
{
if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) {
if (get_last_filled() == 0)
set_fill(fill);
simple_polygon(1, v, n);
}
if (lt.type == line_type::solid && driver_extension_flag) {
line_thickness(lt.thickness);
simple_polygon(0, v, n);
}
else if (lt.type != line_type::invisible) {
line_thickness(lt.thickness);
line(v[n - 1], v, n, lt);
}
}
void simple_output::circle(const position &cent, double rad,
const line_type &lt, double fill)
{
if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) {
if (get_last_filled() == 0)
set_fill(fill);
simple_circle(1, cent, rad);
}
line_thickness(lt.thickness);
switch (lt.type) {
case line_type::invisible:
break;
case line_type::dashed:
dashed_circle(cent, rad, lt);
break;
case line_type::dotted:
dotted_circle(cent, rad, lt);
break;
case line_type::solid:
simple_circle(0, cent, rad);
break;
default:
assert(0);
}
}
void simple_output::ellipse(const position &cent, const distance &dim,
const line_type &lt, double fill)
{
if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) {
if (get_last_filled() == 0)
set_fill(fill);
simple_ellipse(1, cent, dim);
}
if (lt.type != line_type::invisible)
line_thickness(lt.thickness);
switch (lt.type) {
case line_type::invisible:
break;
case line_type::dotted:
case line_type::dashed:
case line_type::solid:
simple_ellipse(0, cent, dim);
break;
default:
assert(0);
}
}
#define FILL_MAX 1000
class troff_output : public simple_output {
const char *last_filename;
position upper_left;
double height;
double scale;
double last_line_thickness;
double last_fill;
char *last_filled; // color
char *last_outlined; // color
public:
troff_output();
~troff_output();
void start_picture(double, const position &ll, const position &ur);
void finish_picture();
void text(const position &, text_piece *, int, double);
void dot(const position &, const line_type &);
void command(const char *, const char *, int);
void set_location(const char *, int);
void simple_line(const position &, const position &);
void simple_spline(const position &, const position *, int n);
void simple_arc(const position &, const position &, const position &);
void simple_circle(int, const position &, double rad);
void simple_ellipse(int, const position &, const distance &);
void simple_polygon(int, const position *, int);
void line_thickness(double p);
void set_fill(double);
void set_color(char *, char *);
void reset_color();
char *get_last_filled();
char *get_outline_color();
position transform(const position &);
};
output *make_troff_output()
{
return new troff_output;
}
troff_output::troff_output()
: last_filename(0), last_line_thickness(BAD_THICKNESS),
last_fill(-1.0), last_filled(0), last_outlined(0)
{
}
troff_output::~troff_output()
{
}
inline position troff_output::transform(const position &pos)
{
return position((pos.x - upper_left.x)/scale,
(upper_left.y - pos.y)/scale);
}
#define FILL_REG "00"
// If this register > 0, then pic will generate \X'ps: ...' commands
// if the aligned attribute is used.
#define GROPS_REG "0p"
// If this register is defined, geqn won't produce `\x's.
#define EQN_NO_EXTRA_SPACE_REG "0x"
void troff_output::start_picture(double sc,
const position &ll, const position &ur)
{
upper_left.x = ll.x;
upper_left.y = ur.y;
scale = compute_scale(sc, ll, ur);
height = (ur.y - ll.y)/scale;
double width = (ur.x - ll.x)/scale;
printf(".PS %.3fi %.3fi", height, width);
if (args)
printf(" %s\n", args);
else
putchar('\n');
printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y);
printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0);
printf(".nr " FILL_REG " \\n(.u\n.nf\n");
printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n");
// This guarantees that if the picture is used in a diversion it will
// have the right width.
printf("\\h'%.3fi'\n.sp -1\n", width);
}
void troff_output::finish_picture()
{
line_thickness(BAD_THICKNESS);
last_fill = -1.0; // force it to be reset for each picture
reset_color();
if (!flyback_flag)
printf(".sp %.3fi+1\n", height);
printf(".if \\n(" FILL_REG " .fi\n");
printf(".br\n");
printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
// this is a little gross
set_location(current_filename, current_lineno);
fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout);
}
void troff_output::command(const char *s,
const char *filename, int lineno)
{
if (filename != 0)
set_location(filename, lineno);
fputs(s, stdout);
putchar('\n');
}
void troff_output::simple_circle(int filled, const position &cent, double rad)
{
position c = transform(cent);
printf("\\h'%.3fi'"
"\\v'%.3fi'"
"\\D'%c%.3fi'"
"\n.sp -1\n",
c.x - rad/scale,
c.y,
(filled ? 'C' : 'c'),
rad*2.0/scale);
}
void troff_output::simple_ellipse(int filled, const position &cent,
const distance &dim)
{
position c = transform(cent);
printf("\\h'%.3fi'"
"\\v'%.3fi'"
"\\D'%c%.3fi %.3fi'"
"\n.sp -1\n",
c.x - dim.x/(2.0*scale),
c.y,
(filled ? 'E' : 'e'),
dim.x/scale, dim.y/scale);
}
void troff_output::simple_arc(const position &start, const distance &cent,
const distance &end)
{
position s = transform(start);
position c = transform(cent);
distance cv = c - s;
distance ev = transform(end) - c;
printf("\\h'%.3fi'"
"\\v'%.3fi'"
"\\D'a%.3fi %.3fi %.3fi %.3fi'"
"\n.sp -1\n",
s.x, s.y, cv.x, cv.y, ev.x, ev.y);
}
void troff_output::simple_line(const position &start, const position &end)
{
position s = transform(start);
distance ev = transform(end) - s;
printf("\\h'%.3fi'"
"\\v'%.3fi'"
"\\D'l%.3fi %.3fi'"
"\n.sp -1\n",
s.x, s.y, ev.x, ev.y);
}
void troff_output::simple_spline(const position &start,
const position *v, int n)
{
position pos = transform(start);
printf("\\h'%.3fi'"
"\\v'%.3fi'",
pos.x, pos.y);
fputs("\\D'~", stdout);
for (int i = 0; i < n; i++) {
position temp = transform(v[i]);
distance d = temp - pos;
pos = temp;
if (i != 0)
putchar(' ');
printf("%.3fi %.3fi", d.x, d.y);
}
printf("'\n.sp -1\n");
}
// a solid polygon
void troff_output::simple_polygon(int filled, const position *v, int n)
{
position pos = transform(v[0]);
printf("\\h'%.3fi'"
"\\v'%.3fi'",
pos.x, pos.y);
printf("\\D'%c", (filled ? 'P' : 'p'));
for (int i = 1; i < n; i++) {
position temp = transform(v[i]);
distance d = temp - pos;
pos = temp;
if (i != 1)
putchar(' ');
printf("%.3fi %.3fi", d.x, d.y);
}
printf("'\n.sp -1\n");
}
const double TEXT_AXIS = 0.22; // in ems
static const char *choose_delimiter(const char *text)
{
if (strchr(text, '\'') == 0)
return "'";
else
return "\\(ts";
}
void troff_output::text(const position &center, text_piece *v, int n,
double ang)
{
line_thickness(BAD_THICKNESS); // the text might use lines (eg in equations)
int rotate_flag = 0;
if (driver_extension_flag && ang != 0.0) {
rotate_flag = 1;
position c = transform(center);
printf(".if \\n(" GROPS_REG " \\{\\\n"
"\\h'%.3fi'"
"\\v'%.3fi'"
"\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
"\n.sp -1\n"
".\\}\n",
c.x, c.y, -ang*180.0/M_PI);
}
for (int i = 0; i < n; i++)
if (v[i].text != 0 && *v[i].text != '\0') {
position c = transform(center);
if (v[i].filename != 0)
set_location(v[i].filename, v[i].lineno);
printf("\\h'%.3fi", c.x);
const char *delim = choose_delimiter(v[i].text);
if (v[i].adj.h == RIGHT_ADJUST)
printf("-\\w%s%s%su", delim, v[i].text, delim);
else if (v[i].adj.h != LEFT_ADJUST)
printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim);
putchar('\'');
printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
c.y,
n - 1,
i,
TEXT_AXIS);
if (v[i].adj.v == ABOVE_ADJUST)
printf("-.5v");
else if (v[i].adj.v == BELOW_ADJUST)
printf("+.5v");
putchar('\'');
fputs(v[i].text, stdout);
fputs("\n.sp -1\n", stdout);
}
if (rotate_flag)
printf(".if '\\*(.T'ps' \\{\\\n"
"\\X'ps: exec grestore'\n.sp -1\n"
".\\}\n");
}
void troff_output::line_thickness(double p)
{
if (p < 0.0)
p = RELATIVE_THICKNESS;
if (driver_extension_flag && p != last_line_thickness) {
printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p);
last_line_thickness = p;
}
}
void troff_output::set_fill(double f)
{
if (driver_extension_flag && f != last_fill) {
printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX));
last_fill = f;
}
if (last_filled) {
free(last_filled);
last_filled = 0;
printf("\\M[]\n.sp -1\n");
}
}
void troff_output::set_color(char *color_fill, char *color_outlined)
{
if (driver_extension_flag) {
if (last_filled || last_outlined) {
reset_color();
}
if (color_fill) {
printf("\\M[%s]\n.sp -1\n", color_fill);
last_filled = strdup(color_fill);
}
if (color_outlined) {
printf("\\m[%s]\n.sp -1\n", color_outlined);
last_outlined = strdup(color_outlined);
}
}
}
void troff_output::reset_color()
{
if (driver_extension_flag) {
if (last_filled) {
printf("\\M[]\n.sp -1\n");
free(last_filled);
last_filled = 0;
}
if (last_outlined) {
printf("\\m[]\n.sp -1\n");
free(last_outlined);
last_outlined = 0;
}
}
}
char *troff_output::get_last_filled()
{
return last_filled;
}
char *troff_output::get_outline_color()
{
return last_outlined;
}
const double DOT_AXIS = .044;
void troff_output::dot(const position &cent, const line_type &lt)
{
if (driver_extension_flag) {
line_thickness(lt.thickness);
simple_line(cent, cent);
}
else {
position c = transform(cent);
printf("\\h'%.3fi-(\\w'.'u/2u)'"
"\\v'%.3fi+%.2fm'"
".\n.sp -1\n",
c.x,
c.y,
DOT_AXIS);
}
}
void troff_output::set_location(const char *s, int n)
{
if (last_filename != 0 && strcmp(s, last_filename) == 0)
printf(".lf %d\n", n);
else {
printf(".lf %d %s\n", n, s);
last_filename = s;
}
}

View File

@ -1,809 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
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 "refer.h"
#include "refid.h"
#include "search.h"
#include "command.h"
cset cs_field_name = csalpha;
class input_item {
input_item *next;
char *filename;
int first_lineno;
string buffer;
const char *ptr;
const char *end;
public:
input_item(string &, const char *, int = 1);
~input_item();
int get_char();
int peek_char();
void skip_char();
int get_location(const char **, int *);
friend class input_stack;
};
input_item::input_item(string &s, const char *fn, int ln)
: filename(strsave(fn)), first_lineno(ln)
{
buffer.move(s);
ptr = buffer.contents();
end = ptr + buffer.length();
}
input_item::~input_item()
{
a_delete filename;
}
inline int input_item::peek_char()
{
if (ptr >= end)
return EOF;
else
return (unsigned char)*ptr;
}
inline int input_item::get_char()
{
if (ptr >= end)
return EOF;
else
return (unsigned char)*ptr++;
}
inline void input_item::skip_char()
{
ptr++;
}
int input_item::get_location(const char **filenamep, int *linenop)
{
*filenamep = filename;
if (ptr == buffer.contents())
*linenop = first_lineno;
else {
int ln = first_lineno;
const char *e = ptr - 1;
for (const char *p = buffer.contents(); p < e; p++)
if (*p == '\n')
ln++;
*linenop = ln;
}
return 1;
}
class input_stack {
static input_item *top;
public:
static void init();
static int get_char();
static int peek_char();
static void skip_char() { top->skip_char(); }
static void push_file(const char *);
static void push_string(string &, const char *, int);
static void error(const char *format,
const errarg &arg1 = empty_errarg,
const errarg &arg2 = empty_errarg,
const errarg &arg3 = empty_errarg);
};
input_item *input_stack::top = 0;
void input_stack::init()
{
while (top) {
input_item *tem = top;
top = top->next;
delete tem;
}
}
int input_stack::get_char()
{
while (top) {
int c = top->get_char();
if (c >= 0)
return c;
input_item *tem = top;
top = top->next;
delete tem;
}
return -1;
}
int input_stack::peek_char()
{
while (top) {
int c = top->peek_char();
if (c >= 0)
return c;
input_item *tem = top;
top = top->next;
delete tem;
}
return -1;
}
void input_stack::push_file(const char *fn)
{
FILE *fp;
if (strcmp(fn, "-") == 0) {
fp = stdin;
fn = "<standard input>";
}
else {
errno = 0;
fp = fopen(fn, "r");
if (fp == 0) {
error("can't open `%1': %2", fn, strerror(errno));
return;
}
}
string buf;
int bol = 1;
int lineno = 1;
for (;;) {
int c = getc(fp);
if (bol && c == '.') {
// replace lines beginning with .R1 or .R2 with a blank line
c = getc(fp);
if (c == 'R') {
c = getc(fp);
if (c == '1' || c == '2') {
int cc = c;
c = getc(fp);
if (compatible_flag || c == ' ' || c == '\n' || c == EOF) {
while (c != '\n' && c != EOF)
c = getc(fp);
}
else {
buf += '.';
buf += 'R';
buf += cc;
}
}
else {
buf += '.';
buf += 'R';
}
}
else
buf += '.';
}
if (c == EOF)
break;
if (invalid_input_char(c))
error_with_file_and_line(fn, lineno,
"invalid input character code %1", int(c));
else {
buf += c;
if (c == '\n') {
bol = 1;
lineno++;
}
else
bol = 0;
}
}
if (fp != stdin)
fclose(fp);
if (buf.length() > 0 && buf[buf.length() - 1] != '\n')
buf += '\n';
input_item *it = new input_item(buf, fn);
it->next = top;
top = it;
}
void input_stack::push_string(string &s, const char *filename, int lineno)
{
input_item *it = new input_item(s, filename, lineno);
it->next = top;
top = it;
}
void input_stack::error(const char *format, const errarg &arg1,
const errarg &arg2, const errarg &arg3)
{
const char *filename;
int lineno;
for (input_item *it = top; it; it = it->next)
if (it->get_location(&filename, &lineno)) {
error_with_file_and_line(filename, lineno, format, arg1, arg2, arg3);
return;
}
::error(format, arg1, arg2, arg3);
}
void command_error(const char *format, const errarg &arg1,
const errarg &arg2, const errarg &arg3)
{
input_stack::error(format, arg1, arg2, arg3);
}
// # not recognized in ""
// \<newline> is recognized in ""
// # does not conceal newline
// if missing closing quote, word extends to end of line
// no special treatment of \ other than before newline
// \<newline> not recognized after #
// ; allowed as alternative to newline
// ; not recognized in ""
// don't clear word_buffer; just append on
// return -1 for EOF, 0 for newline, 1 for word
int get_word(string &word_buffer)
{
int c = input_stack::get_char();
for (;;) {
if (c == '#') {
do {
c = input_stack::get_char();
} while (c != '\n' && c != EOF);
break;
}
if (c == '\\' && input_stack::peek_char() == '\n')
input_stack::skip_char();
else if (c != ' ' && c != '\t')
break;
c = input_stack::get_char();
}
if (c == EOF)
return -1;
if (c == '\n' || c == ';')
return 0;
if (c == '"') {
for (;;) {
c = input_stack::peek_char();
if (c == EOF || c == '\n')
break;
input_stack::skip_char();
if (c == '"') {
int d = input_stack::peek_char();
if (d == '"')
input_stack::skip_char();
else
break;
}
else if (c == '\\') {
int d = input_stack::peek_char();
if (d == '\n')
input_stack::skip_char();
else
word_buffer += '\\';
}
else
word_buffer += c;
}
return 1;
}
word_buffer += c;
for (;;) {
c = input_stack::peek_char();
if (c == ' ' || c == '\t' || c == '\n' || c == '#' || c == ';')
break;
input_stack::skip_char();
if (c == '\\') {
int d = input_stack::peek_char();
if (d == '\n')
input_stack::skip_char();
else
word_buffer += '\\';
}
else
word_buffer += c;
}
return 1;
}
union argument {
const char *s;
int n;
};
// This is for debugging.
static void echo_command(int argc, argument *argv)
{
for (int i = 0; i < argc; i++)
fprintf(stderr, "%s\n", argv[i].s);
}
static void include_command(int argc, argument *argv)
{
assert(argc == 1);
input_stack::push_file(argv[0].s);
}
static void capitalize_command(int argc, argument *argv)
{
if (argc > 0)
capitalize_fields = argv[0].s;
else
capitalize_fields.clear();
}
static void accumulate_command(int, argument *)
{
accumulate = 1;
}
static void no_accumulate_command(int, argument *)
{
accumulate = 0;
}
static void move_punctuation_command(int, argument *)
{
move_punctuation = 1;
}
static void no_move_punctuation_command(int, argument *)
{
move_punctuation = 0;
}
static void sort_command(int argc, argument *argv)
{
if (argc == 0)
sort_fields = "AD";
else
sort_fields = argv[0].s;
accumulate = 1;
}
static void no_sort_command(int, argument *)
{
sort_fields.clear();
}
static void articles_command(int argc, argument *argv)
{
articles.clear();
int i;
for (i = 0; i < argc; i++) {
articles += argv[i].s;
articles += '\0';
}
int len = articles.length();
for (i = 0; i < len; i++)
articles[i] = cmlower(articles[i]);
}
static void database_command(int argc, argument *argv)
{
for (int i = 0; i < argc; i++)
database_list.add_file(argv[i].s);
}
static void default_database_command(int, argument *)
{
search_default = 1;
}
static void no_default_database_command(int, argument *)
{
search_default = 0;
}
static void bibliography_command(int argc, argument *argv)
{
const char *saved_filename = current_filename;
int saved_lineno = current_lineno;
int saved_label_in_text = label_in_text;
label_in_text = 0;
if (!accumulate)
fputs(".]<\n", stdout);
for (int i = 0; i < argc; i++)
do_bib(argv[i].s);
if (accumulate)
output_references();
else
fputs(".]>\n", stdout);
current_filename = saved_filename;
current_lineno = saved_lineno;
label_in_text = saved_label_in_text;
}
static void annotate_command(int argc, argument *argv)
{
if (argc > 0)
annotation_field = argv[0].s[0];
else
annotation_field = 'X';
if (argc == 2)
annotation_macro = argv[1].s;
else
annotation_macro = "AP";
}
static void no_annotate_command(int, argument *)
{
annotation_macro.clear();
annotation_field = -1;
}
static void reverse_command(int, argument *argv)
{
reverse_fields = argv[0].s;
}
static void no_reverse_command(int, argument *)
{
reverse_fields.clear();
}
static void abbreviate_command(int argc, argument *argv)
{
abbreviate_fields = argv[0].s;
period_before_initial = argc > 1 ? argv[1].s : ". ";
period_before_last_name = argc > 2 ? argv[2].s : ". ";
period_before_other = argc > 3 ? argv[3].s : ". ";
period_before_hyphen = argc > 4 ? argv[4].s : ".";
}
static void no_abbreviate_command(int, argument *)
{
abbreviate_fields.clear();
}
string search_ignore_fields;
static void search_ignore_command(int argc, argument *argv)
{
if (argc > 0)
search_ignore_fields = argv[0].s;
else
search_ignore_fields = "XYZ";
search_ignore_fields += '\0';
linear_ignore_fields = search_ignore_fields.contents();
}
static void no_search_ignore_command(int, argument *)
{
linear_ignore_fields = "";
}
static void search_truncate_command(int argc, argument *argv)
{
if (argc > 0)
linear_truncate_len = argv[0].n;
else
linear_truncate_len = 6;
}
static void no_search_truncate_command(int, argument *)
{
linear_truncate_len = -1;
}
static void discard_command(int argc, argument *argv)
{
if (argc == 0)
discard_fields = "XYZ";
else
discard_fields = argv[0].s;
accumulate = 1;
}
static void no_discard_command(int, argument *)
{
discard_fields.clear();
}
static void label_command(int, argument *argv)
{
set_label_spec(argv[0].s);
}
static void abbreviate_label_ranges_command(int argc, argument *argv)
{
abbreviate_label_ranges = 1;
label_range_indicator = argc > 0 ? argv[0].s : "-";
}
static void no_abbreviate_label_ranges_command(int, argument *)
{
abbreviate_label_ranges = 0;
}
static void label_in_reference_command(int, argument *)
{
label_in_reference = 1;
}
static void no_label_in_reference_command(int, argument *)
{
label_in_reference = 0;
}
static void label_in_text_command(int, argument *)
{
label_in_text = 1;
}
static void no_label_in_text_command(int, argument *)
{
label_in_text = 0;
}
static void sort_adjacent_labels_command(int, argument *)
{
sort_adjacent_labels = 1;
}
static void no_sort_adjacent_labels_command(int, argument *)
{
sort_adjacent_labels = 0;
}
static void date_as_label_command(int argc, argument *argv)
{
if (set_date_label_spec(argc > 0 ? argv[0].s : "D%a*"))
date_as_label = 1;
}
static void no_date_as_label_command(int, argument *)
{
date_as_label = 0;
}
static void short_label_command(int, argument *argv)
{
if (set_short_label_spec(argv[0].s))
short_label_flag = 1;
}
static void no_short_label_command(int, argument *)
{
short_label_flag = 0;
}
static void compatible_command(int, argument *)
{
compatible_flag = 1;
}
static void no_compatible_command(int, argument *)
{
compatible_flag = 0;
}
static void join_authors_command(int argc, argument *argv)
{
join_authors_exactly_two = argv[0].s;
join_authors_default = argc > 1 ? argv[1].s : argv[0].s;
join_authors_last_two = argc == 3 ? argv[2].s : argv[0].s;
}
static void bracket_label_command(int, argument *argv)
{
pre_label = argv[0].s;
post_label = argv[1].s;
sep_label = argv[2].s;
}
static void separate_label_second_parts_command(int, argument *argv)
{
separate_label_second_parts = argv[0].s;
}
static void et_al_command(int argc, argument *argv)
{
et_al = argv[0].s;
et_al_min_elide = argv[1].n;
if (et_al_min_elide < 1)
et_al_min_elide = 1;
et_al_min_total = argc >= 3 ? argv[2].n : 0;
}
static void no_et_al_command(int, argument *)
{
et_al.clear();
et_al_min_elide = 0;
}
typedef void (*command_t)(int, argument *);
/* arg_types is a string describing the numbers and types of arguments.
s means a string, i means an integer, f is a list of fields, F is
a single field,
? means that the previous argument is optional, * means that the
previous argument can occur any number of times. */
struct {
const char *name;
command_t func;
const char *arg_types;
} command_table[] = {
{ "include", include_command, "s" },
{ "echo", echo_command, "s*" },
{ "capitalize", capitalize_command, "f?" },
{ "accumulate", accumulate_command, "" },
{ "no-accumulate", no_accumulate_command, "" },
{ "move-punctuation", move_punctuation_command, "" },
{ "no-move-punctuation", no_move_punctuation_command, "" },
{ "sort", sort_command, "s?" },
{ "no-sort", no_sort_command, "" },
{ "articles", articles_command, "s*" },
{ "database", database_command, "ss*" },
{ "default-database", default_database_command, "" },
{ "no-default-database", no_default_database_command, "" },
{ "bibliography", bibliography_command, "ss*" },
{ "annotate", annotate_command, "F?s?" },
{ "no-annotate", no_annotate_command, "" },
{ "reverse", reverse_command, "s" },
{ "no-reverse", no_reverse_command, "" },
{ "abbreviate", abbreviate_command, "ss?s?s?s?" },
{ "no-abbreviate", no_abbreviate_command, "" },
{ "search-ignore", search_ignore_command, "f?" },
{ "no-search-ignore", no_search_ignore_command, "" },
{ "search-truncate", search_truncate_command, "i?" },
{ "no-search-truncate", no_search_truncate_command, "" },
{ "discard", discard_command, "f?" },
{ "no-discard", no_discard_command, "" },
{ "label", label_command, "s" },
{ "abbreviate-label-ranges", abbreviate_label_ranges_command, "s?" },
{ "no-abbreviate-label-ranges", no_abbreviate_label_ranges_command, "" },
{ "label-in-reference", label_in_reference_command, "" },
{ "no-label-in-reference", no_label_in_reference_command, "" },
{ "label-in-text", label_in_text_command, "" },
{ "no-label-in-text", no_label_in_text_command, "" },
{ "sort-adjacent-labels", sort_adjacent_labels_command, "" },
{ "no-sort-adjacent-labels", no_sort_adjacent_labels_command, "" },
{ "date-as-label", date_as_label_command, "s?" },
{ "no-date-as-label", no_date_as_label_command, "" },
{ "short-label", short_label_command, "s" },
{ "no-short-label", no_short_label_command, "" },
{ "compatible", compatible_command, "" },
{ "no-compatible", no_compatible_command, "" },
{ "join-authors", join_authors_command, "sss?" },
{ "bracket-label", bracket_label_command, "sss" },
{ "separate-label-second-parts", separate_label_second_parts_command, "s" },
{ "et-al", et_al_command, "sii?" },
{ "no-et-al", no_et_al_command, "" },
};
static int check_args(const char *types, const char *name,
int argc, argument *argv)
{
int argno = 0;
while (*types) {
if (argc == 0) {
if (types[1] == '?')
break;
else if (types[1] == '*') {
assert(types[2] == '\0');
break;
}
else {
input_stack::error("missing argument for command `%1'", name);
return 0;
}
}
switch (*types) {
case 's':
break;
case 'i':
{
char *ptr;
long n = strtol(argv->s, &ptr, 10);
if ((n == 0 && ptr == argv->s)
|| *ptr != '\0') {
input_stack::error("argument %1 for command `%2' must be an integer",
argno + 1, name);
return 0;
}
argv->n = (int)n;
break;
}
case 'f':
{
for (const char *ptr = argv->s; *ptr != '\0'; ptr++)
if (!cs_field_name(*ptr)) {
input_stack::error("argument %1 for command `%2' must be a list of fields",
argno + 1, name);
return 0;
}
break;
}
case 'F':
if (argv->s[0] == '\0' || argv->s[1] != '\0'
|| !cs_field_name(argv->s[0])) {
input_stack::error("argument %1 for command `%2' must be a field name",
argno + 1, name);
return 0;
}
break;
default:
assert(0);
}
if (types[1] == '?')
types += 2;
else if (types[1] != '*')
types += 1;
--argc;
++argv;
++argno;
}
if (argc > 0) {
input_stack::error("too many arguments for command `%1'", name);
return 0;
}
return 1;
}
static void execute_command(const char *name, int argc, argument *argv)
{
for (unsigned int i = 0;
i < sizeof(command_table)/sizeof(command_table[0]); i++)
if (strcmp(name, command_table[i].name) == 0) {
if (check_args(command_table[i].arg_types, name, argc, argv))
(*command_table[i].func)(argc, argv);
return;
}
input_stack::error("unknown command `%1'", name);
}
static void command_loop()
{
string command;
for (;;) {
command.clear();
int res = get_word(command);
if (res != 1) {
if (res == 0)
continue;
break;
}
int argc = 0;
command += '\0';
while ((res = get_word(command)) == 1) {
argc++;
command += '\0';
}
argument *argv = new argument[argc];
const char *ptr = command.contents();
for (int i = 0; i < argc; i++)
argv[i].s = ptr = strchr(ptr, '\0') + 1;
execute_command(command.contents(), argc, argv);
a_delete argv;
if (res == -1)
break;
}
}
void process_commands(const char *file)
{
input_stack::init();
input_stack::push_file(file);
command_loop();
}
void process_commands(string &s, const char *file, int lineno)
{
input_stack::init();
input_stack::push_string(s, file, lineno);
command_loop();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,378 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 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 "refer.h"
#include "token.h"
#define TOKEN_TABLE_SIZE 1009
// I believe in Icelandic thorn sorts after z.
#define THORN_SORT_KEY "{"
struct token_table_entry {
const char *tok;
token_info ti;
token_table_entry();
};
token_table_entry token_table[TOKEN_TABLE_SIZE];
int ntokens = 0;
static void skip_name(const char **ptr, const char *end)
{
if (*ptr < end) {
switch (*(*ptr)++) {
case '(':
if (*ptr < end) {
*ptr += 1;
if (*ptr < end)
*ptr += 1;
}
break;
case '[':
while (*ptr < end)
if (*(*ptr)++ == ']')
break;
break;
}
}
}
int get_token(const char **ptr, const char *end)
{
if (*ptr >= end)
return 0;
char c = *(*ptr)++;
if (c == '\\' && *ptr < end) {
switch (**ptr) {
default:
*ptr += 1;
break;
case '(':
case '[':
skip_name(ptr, end);
break;
case '*':
case 'f':
*ptr += 1;
skip_name(ptr, end);
break;
}
}
return 1;
}
token_info::token_info()
: type(TOKEN_OTHER), sort_key(0), other_case(0)
{
}
void token_info::set(token_type t, const char *sk, const char *oc)
{
assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER);
type = t;
sort_key = sk;
other_case = oc;
}
void token_info::sortify(const char *start, const char *end, string &result)
const
{
if (sort_key)
result += sort_key;
else if (type == TOKEN_UPPER || type == TOKEN_LOWER) {
for (; start < end; start++)
if (csalpha(*start))
result += cmlower(*start);
}
}
int token_info::sortify_non_empty(const char *start, const char *end) const
{
if (sort_key)
return *sort_key != '\0';
if (type != TOKEN_UPPER && type != TOKEN_LOWER)
return 0;
for (; start < end; start++)
if (csalpha(*start))
return 1;
return 0;
}
void token_info::lower_case(const char *start, const char *end,
string &result) const
{
if (type != TOKEN_UPPER) {
while (start < end)
result += *start++;
}
else if (other_case)
result += other_case;
else {
while (start < end)
result += cmlower(*start++);
}
}
void token_info::upper_case(const char *start, const char *end,
string &result) const
{
if (type != TOKEN_LOWER) {
while (start < end)
result += *start++;
}
else if (other_case)
result += other_case;
else {
while (start < end)
result += cmupper(*start++);
}
}
token_table_entry::token_table_entry()
: tok(0)
{
}
static void store_token(const char *tok, token_type typ,
const char *sk = 0, const char *oc = 0)
{
unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE;
for (;;) {
if (token_table[n].tok == 0) {
if (++ntokens == TOKEN_TABLE_SIZE)
assert(0);
token_table[n].tok = tok;
break;
}
if (strcmp(tok, token_table[n].tok) == 0)
break;
if (n == 0)
n = TOKEN_TABLE_SIZE - 1;
else
--n;
}
token_table[n].ti.set(typ, sk, oc);
}
token_info default_token_info;
const token_info *lookup_token(const char *start, const char *end)
{
unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE;
for (;;) {
if (token_table[n].tok == 0)
break;
if (strlen(token_table[n].tok) == size_t(end - start)
&& memcmp(token_table[n].tok, start, end - start) == 0)
return &(token_table[n].ti);
if (n == 0)
n = TOKEN_TABLE_SIZE - 1;
else
--n;
}
return &default_token_info;
}
static void init_ascii()
{
const char *p;
for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) {
char buf[2];
buf[0] = *p;
buf[1] = '\0';
store_token(strsave(buf), TOKEN_LOWER);
buf[0] = cmupper(buf[0]);
store_token(strsave(buf), TOKEN_UPPER);
}
for (p = "0123456789"; *p; p++) {
char buf[2];
buf[0] = *p;
buf[1] = '\0';
const char *s = strsave(buf);
store_token(s, TOKEN_OTHER, s);
}
for (p = ".,:;?!"; *p; p++) {
char buf[2];
buf[0] = *p;
buf[1] = '\0';
store_token(strsave(buf), TOKEN_PUNCT);
}
store_token("-", TOKEN_HYPHEN);
}
static void store_letter(const char *lower, const char *upper,
const char *sort_key = 0)
{
store_token(lower, TOKEN_LOWER, sort_key, upper);
store_token(upper, TOKEN_UPPER, sort_key, lower);
}
static void init_letter(unsigned char uc_code, unsigned char lc_code,
const char *sort_key)
{
char lbuf[2];
lbuf[0] = lc_code;
lbuf[1] = 0;
char ubuf[2];
ubuf[0] = uc_code;
ubuf[1] = 0;
store_letter(strsave(lbuf), strsave(ubuf), sort_key);
}
static void init_latin1()
{
init_letter(0xc0, 0xe0, "a");
init_letter(0xc1, 0xe1, "a");
init_letter(0xc2, 0xe2, "a");
init_letter(0xc3, 0xe3, "a");
init_letter(0xc4, 0xe4, "a");
init_letter(0xc5, 0xe5, "a");
init_letter(0xc6, 0xe6, "ae");
init_letter(0xc7, 0xe7, "c");
init_letter(0xc8, 0xe8, "e");
init_letter(0xc9, 0xe9, "e");
init_letter(0xca, 0xea, "e");
init_letter(0xcb, 0xeb, "e");
init_letter(0xcc, 0xec, "i");
init_letter(0xcd, 0xed, "i");
init_letter(0xce, 0xee, "i");
init_letter(0xcf, 0xef, "i");
init_letter(0xd0, 0xf0, "d");
init_letter(0xd1, 0xf1, "n");
init_letter(0xd2, 0xf2, "o");
init_letter(0xd3, 0xf3, "o");
init_letter(0xd4, 0xf4, "o");
init_letter(0xd5, 0xf5, "o");
init_letter(0xd6, 0xf6, "o");
init_letter(0xd8, 0xf8, "o");
init_letter(0xd9, 0xf9, "u");
init_letter(0xda, 0xfa, "u");
init_letter(0xdb, 0xfb, "u");
init_letter(0xdc, 0xfc, "u");
init_letter(0xdd, 0xfd, "y");
init_letter(0xde, 0xfe, THORN_SORT_KEY);
store_token("\337", TOKEN_LOWER, "ss", "SS");
store_token("\377", TOKEN_LOWER, "y", "Y");
}
static void init_two_char_letter(char l1, char l2, char u1, char u2,
const char *sk = 0)
{
char buf[6];
buf[0] = '\\';
buf[1] = '(';
buf[2] = l1;
buf[3] = l2;
buf[4] = '\0';
const char *p = strsave(buf);
buf[2] = u1;
buf[3] = u2;
store_letter(p, strsave(buf), sk);
buf[1] = '[';
buf[4] = ']';
buf[5] = '\0';
p = strsave(buf);
buf[2] = l1;
buf[3] = l2;
store_letter(strsave(buf), p, sk);
}
static void init_special_chars()
{
const char *p;
for (p = "':^`~"; *p; p++)
for (const char *q = "aeiouy"; *q; q++) {
// Use a variable to work around bug in gcc 2.0
char c = cmupper(*q);
init_two_char_letter(*p, *q, *p, c);
}
for (p = "/l/o~n,coeaeij"; *p; p += 2) {
// Use variables to work around bug in gcc 2.0
char c0 = cmupper(p[0]);
char c1 = cmupper(p[1]);
init_two_char_letter(p[0], p[1], c0, c1);
}
init_two_char_letter('v', 's', 'v', 'S', "s");
init_two_char_letter('v', 'z', 'v', 'Z', "z");
init_two_char_letter('o', 'a', 'o', 'A', "a");
init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY);
init_two_char_letter('-', 'd', '-', 'D');
store_token("\\(ss", TOKEN_LOWER, 0, "SS");
store_token("\\[ss]", TOKEN_LOWER, 0, "SS");
store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D");
store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]");
store_token("\\(hy", TOKEN_HYPHEN);
store_token("\\[hy]", TOKEN_HYPHEN);
store_token("\\(en", TOKEN_RANGE_SEP);
store_token("\\[en]", TOKEN_RANGE_SEP);
}
static void init_strings()
{
char buf[6];
buf[0] = '\\';
buf[1] = '*';
for (const char *p = "'`^^,:~v_o./;"; *p; p++) {
buf[2] = *p;
buf[3] = '\0';
store_token(strsave(buf), TOKEN_ACCENT);
buf[2] = '[';
buf[3] = *p;
buf[4] = ']';
buf[5] = '\0';
store_token(strsave(buf), TOKEN_ACCENT);
}
// -ms special letters
store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY);
store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY);
store_letter("\\*(d-", "\\*(D-");
store_letter("\\*[d-]", "\\*[D-]");
store_letter("\\*(ae", "\\*(Ae", "ae");
store_letter("\\*[ae]", "\\*[Ae]", "ae");
store_letter("\\*(oe", "\\*(Oe", "oe");
store_letter("\\*[oe]", "\\*[Oe]", "oe");
store_token("\\*3", TOKEN_LOWER, "y", "Y");
store_token("\\*8", TOKEN_LOWER, "ss", "SS");
store_token("\\*q", TOKEN_LOWER, "o", "O");
}
struct token_initer {
token_initer();
};
static token_initer the_token_initer;
token_initer::token_initer()
{
init_ascii();
init_latin1();
init_special_chars();
init_strings();
default_token_info.set(TOKEN_OTHER);
}

View File

@ -1,346 +0,0 @@
// -*- 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 "lib.h"
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include "errarg.h"
#include "error.h"
#include "stringclass.h"
#include "nonposix.h"
static size_t include_list_length;
static char **include_list;
int compatible_flag = 0;
extern int interpret_lf_args(const char *);
extern "C" const char *Version_string;
int do_file(const char *filename);
static void
include_path_append(char *path)
{
++include_list_length;
size_t nbytes = include_list_length * sizeof(char *);
if (include_list)
include_list = (char **)realloc((void *)include_list, nbytes);
else
include_list = (char **)malloc(nbytes);
if (include_list == NULL)
{
fprintf(stderr, "%s: out of memory\n", program_name);
exit(2);
}
include_list[include_list_length - 1] = path;
}
void usage(FILE *stream)
{
fprintf(stream, "usage: %s [ -vC ] [ -I file ] [ files ]\n", program_name);
}
int main(int argc, char **argv)
{
program_name = argv[0];
include_path_append(".");
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, "CI:v", long_options, NULL)) != EOF)
switch (opt) {
case 'v':
{
printf("GNU soelim (groff) version %s\n", Version_string);
exit(0);
break;
}
case 'C':
compatible_flag = 1;
break;
case 'I':
include_path_append(optarg);
break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
}
int nbad = 0;
if (optind >= argc)
nbad += !do_file("-");
else
for (int i = optind; i < argc; i++)
nbad += !do_file(argv[i]);
if (ferror(stdout) || fflush(stdout) < 0)
fatal("output error");
return nbad != 0;
}
void set_location()
{
printf(".lf %d %s\n", current_lineno, current_filename);
}
void do_so(const char *line)
{
const char *p = line;
while (*p == ' ')
p++;
string filename;
int success = 1;
for (const char *q = p;
success && *q != '\0' && *q != '\n' && *q != ' ';
q++)
if (*q == '\\') {
switch (*++q) {
case 'e':
case '\\':
filename += '\\';
break;
case ' ':
filename += ' ';
break;
default:
success = 0;
break;
}
}
else
filename += char(*q);
if (success && filename.length() > 0) {
filename += '\0';
const char *fn = current_filename;
int ln = current_lineno;
current_lineno--;
if (do_file(filename.contents())) {
current_filename = fn;
current_lineno = ln;
set_location();
return;
}
current_lineno++;
}
fputs(".so", stdout);
fputs(line, stdout);
}
int do_file(const char *filename)
{
FILE *fp;
string whole_filename;
if (strcmp(filename, "-") == 0) {
fp = stdin;
whole_filename = filename;
whole_filename += '\0';
}
else if (IS_ABSOLUTE(filename)) {
whole_filename = filename;
whole_filename += '\0';
errno = 0;
fp = fopen(filename, "r");
if (fp == 0) {
error("can't open `%1': %2", filename, strerror(errno));
return 0;
}
}
else {
size_t j;
for (j = 0; j < include_list_length; ++j)
{
char *path = include_list[j];
if (0 == strcmp(path, "."))
whole_filename = filename;
else
whole_filename = string(path) + "/" + filename;
whole_filename += '\0';
errno = 0;
fp = fopen(whole_filename.contents(), "r");
if (fp != 0)
break;
if (errno != ENOENT) {
error("can't open `%1': %2",
whole_filename.contents(), strerror(errno));
return 0;
}
}
if (j >= include_list_length)
{
errno = ENOENT;
error("can't open `%1': %2", filename, strerror(errno));
return 0;
}
}
current_filename = whole_filename.contents();
current_lineno = 1;
set_location();
enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
for (;;) {
int c = getc(fp);
if (c == EOF)
break;
switch (state) {
case START:
if (c == '.')
state = HAD_DOT;
else {
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case MIDDLE:
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
break;
case HAD_DOT:
if (c == 's')
state = HAD_s;
else if (c == 'l')
state = HAD_l;
else {
putchar('.');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_s:
if (c == 'o')
state = HAD_so;
else {
putchar('.');
putchar('s');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_so:
if (c == ' ' || c == '\n' || compatible_flag) {
string line;
for (; c != EOF && c != '\n'; c = getc(fp))
line += c;
current_lineno++;
line += '\n';
line += '\0';
do_so(line.contents());
state = START;
}
else {
fputs(".so", stdout);
putchar(c);
state = MIDDLE;
}
break;
case HAD_l:
if (c == 'f')
state = HAD_lf;
else {
putchar('.');
putchar('l');
putchar(c);
if (c == '\n') {
current_lineno++;
state = START;
}
else
state = MIDDLE;
}
break;
case HAD_lf:
if (c == ' ' || c == '\n' || compatible_flag) {
string line;
for (; c != EOF && c != '\n'; c = getc(fp))
line += c;
current_lineno++;
line += '\n';
line += '\0';
interpret_lf_args(line.contents());
printf(".lf%s", line.contents());
state = START;
}
else {
fputs(".lf", stdout);
putchar(c);
state = MIDDLE;
}
break;
default:
assert(0);
}
}
switch (state) {
case HAD_DOT:
fputs(".\n", stdout);
break;
case HAD_l:
fputs(".l\n", stdout);
break;
case HAD_s:
fputs(".s\n", stdout);
break;
case HAD_lf:
fputs(".lf\n", stdout);
break;
case HAD_so:
fputs(".so\n", stdout);
break;
case MIDDLE:
putc('\n', stdout);
break;
case START:
break;
}
if (fp != stdin)
fclose(fp);
current_filename = 0;
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,753 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989-2000, 2001, 2002 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. */
// A front end for groff.
#include "lib.h"
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include "assert.h"
#include "errarg.h"
#include "error.h"
#include "stringclass.h"
#include "cset.h"
#include "font.h"
#include "device.h"
#include "pipeline.h"
#include "nonposix.h"
#include "defs.h"
#define GXDITVIEW "gxditview"
// troff will be passed an argument of -rXREG=1 if the -X option is
// specified
#define XREG ".X"
#ifdef NEED_DECLARATION_PUTENV
extern "C" {
int putenv(const char *);
}
#endif /* NEED_DECLARATION_PUTENV */
// The number of commands must be in sync with MAX_COMMANDS in pipeline.h
const int SOELIM_INDEX = 0;
const int REFER_INDEX = SOELIM_INDEX + 1;
const int GRAP_INDEX = REFER_INDEX + 1;
const int PIC_INDEX = GRAP_INDEX + 1;
const int TBL_INDEX = PIC_INDEX + 1;
const int GRN_INDEX = TBL_INDEX + 1;
const int EQN_INDEX = GRN_INDEX + 1;
const int TROFF_INDEX = EQN_INDEX + 1;
const int POST_INDEX = TROFF_INDEX + 1;
const int SPOOL_INDEX = POST_INDEX + 1;
const int NCOMMANDS = SPOOL_INDEX + 1;
class possible_command {
char *name;
string args;
char **argv;
void build_argv();
public:
possible_command();
~possible_command();
void set_name(const char *);
void set_name(const char *, const char *);
const char *get_name();
void append_arg(const char *, const char * = 0);
void insert_arg(const char *);
void insert_args(string s);
void clear_args();
char **get_argv();
void print(int is_last, FILE *fp);
};
extern "C" const char *Version_string;
int lflag = 0;
char *spooler = 0;
char *postdriver = 0;
char *predriver = 0;
possible_command commands[NCOMMANDS];
int run_commands(int no_pipe);
void print_commands();
void append_arg_to_string(const char *arg, string &str);
void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno);
const char *xbasename(const char *);
void usage(FILE *stream);
void help();
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
assert(NCOMMANDS <= MAX_COMMANDS);
string Pargs, Largs, Fargs;
int vflag = 0;
int Vflag = 0;
int zflag = 0;
int iflag = 0;
int Xflag = 0;
int safer_flag = 1;
int opt;
const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
if (!command_prefix)
command_prefix = PROG_PREFIX;
commands[TROFF_INDEX].set_name(command_prefix, "troff");
static const struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
while ((opt = getopt_long(argc, argv,
"abcCd:eEf:F:gGhiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ",
long_options, NULL))
!= EOF) {
char buf[3];
buf[0] = '-';
buf[1] = opt;
buf[2] = '\0';
switch (opt) {
case 'i':
iflag = 1;
break;
case 'I':
commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
commands[SOELIM_INDEX].append_arg(buf, optarg);
break;
case 't':
commands[TBL_INDEX].set_name(command_prefix, "tbl");
break;
case 'p':
commands[PIC_INDEX].set_name(command_prefix, "pic");
break;
case 'g':
commands[GRN_INDEX].set_name(command_prefix, "grn");
break;
case 'G':
commands[GRAP_INDEX].set_name(command_prefix, "grap");
break;
case 'e':
commands[EQN_INDEX].set_name(command_prefix, "eqn");
break;
case 's':
commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
break;
case 'R':
commands[REFER_INDEX].set_name(command_prefix, "refer");
break;
case 'z':
case 'a':
commands[TROFF_INDEX].append_arg(buf);
// fall through
case 'Z':
zflag++;
break;
case 'l':
lflag++;
break;
case 'V':
Vflag++;
break;
case 'v':
vflag = 1;
{
printf("GNU groff version %s\n", Version_string);
printf("Copyright (C) 2002 Free Software Foundation, Inc.\n"
"GNU groff comes with ABSOLUTELY NO WARRANTY.\n"
"You may redistribute copies of groff and its subprograms\n"
"under the terms of the GNU General Public License.\n"
"For more information about these matters, see the file named COPYING.\n");
printf("\ncalled subprograms:\n\n");
fflush(stdout);
}
commands[POST_INDEX].append_arg(buf);
// fall through
case 'C':
commands[SOELIM_INDEX].append_arg(buf);
commands[REFER_INDEX].append_arg(buf);
commands[PIC_INDEX].append_arg(buf);
commands[GRAP_INDEX].append_arg(buf);
commands[TBL_INDEX].append_arg(buf);
commands[GRN_INDEX].append_arg(buf);
commands[EQN_INDEX].append_arg(buf);
commands[TROFF_INDEX].append_arg(buf);
break;
case 'N':
commands[EQN_INDEX].append_arg(buf);
break;
case 'h':
help();
break;
case 'E':
case 'b':
commands[TROFF_INDEX].append_arg(buf);
break;
case 'c':
commands[TROFF_INDEX].append_arg(buf);
break;
case 'S':
safer_flag = 1;
break;
case 'U':
safer_flag = 0;
break;
case 'T':
if (strcmp(optarg, "html") == 0) {
// force soelim to aid the html preprocessor
commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
}
if (strcmp(optarg, "Xps") == 0) {
warning("-TXps option is obsolete: use -X -Tps instead");
device = "ps";
Xflag++;
}
else
device = optarg;
break;
case 'F':
font::command_line_font_dir(optarg);
if (Fargs.length() > 0) {
Fargs += PATH_SEP[0];
Fargs += optarg;
}
else
Fargs = optarg;
break;
case 'f':
case 'o':
case 'm':
case 'r':
case 'd':
case 'n':
case 'w':
case 'W':
commands[TROFF_INDEX].append_arg(buf, optarg);
break;
case 'M':
commands[EQN_INDEX].append_arg(buf, optarg);
commands[GRAP_INDEX].append_arg(buf, optarg);
commands[GRN_INDEX].append_arg(buf, optarg);
commands[TROFF_INDEX].append_arg(buf, optarg);
break;
case 'P':
Pargs += optarg;
Pargs += '\0';
break;
case 'L':
append_arg_to_string(optarg, Largs);
break;
case 'X':
Xflag++;
break;
case '?':
usage(stderr);
exit(1);
break;
default:
assert(0);
break;
}
}
if (safer_flag)
commands[PIC_INDEX].append_arg("-S");
else
commands[TROFF_INDEX].insert_arg("-U");
font::set_unknown_desc_command_handler(handle_unknown_desc_command);
if (!font::load_desc())
fatal("invalid device `%1'", device);
if (!postdriver)
fatal("no `postpro' command in DESC file for device `%1'", device);
if (predriver && !zflag) {
commands[TROFF_INDEX].insert_arg(commands[TROFF_INDEX].get_name());
commands[TROFF_INDEX].set_name(predriver);
// pass the device arguments to the predrivers as well
commands[TROFF_INDEX].insert_args(Pargs);
if (vflag)
commands[TROFF_INDEX].insert_arg("-v");
}
const char *real_driver = 0;
if (Xflag) {
real_driver = postdriver;
postdriver = GXDITVIEW;
commands[TROFF_INDEX].append_arg("-r" XREG "=", "1");
}
if (postdriver)
commands[POST_INDEX].set_name(postdriver);
int gxditview_flag = postdriver && strcmp(xbasename(postdriver), GXDITVIEW) == 0;
if (gxditview_flag && argc - optind == 1) {
commands[POST_INDEX].append_arg("-title");
commands[POST_INDEX].append_arg(argv[optind]);
commands[POST_INDEX].append_arg("-xrm");
commands[POST_INDEX].append_arg("*iconName:", argv[optind]);
string filename_string("|");
append_arg_to_string(argv[0], filename_string);
append_arg_to_string("-Z", filename_string);
for (int i = 1; i < argc; i++)
append_arg_to_string(argv[i], filename_string);
filename_string += '\0';
commands[POST_INDEX].append_arg("-filename");
commands[POST_INDEX].append_arg(filename_string.contents());
}
if (gxditview_flag && Xflag) {
string print_string(real_driver);
if (spooler) {
print_string += " | ";
print_string += spooler;
print_string += Largs;
}
print_string += '\0';
commands[POST_INDEX].append_arg("-printCommand");
commands[POST_INDEX].append_arg(print_string.contents());
}
const char *p = Pargs.contents();
const char *end = p + Pargs.length();
while (p < end) {
commands[POST_INDEX].append_arg(p);
p = strchr(p, '\0') + 1;
}
if (gxditview_flag)
commands[POST_INDEX].append_arg("-");
if (lflag && !Xflag && spooler) {
commands[SPOOL_INDEX].set_name(BSHELL);
commands[SPOOL_INDEX].append_arg(BSHELL_DASH_C);
Largs += '\0';
Largs = spooler + Largs;
commands[SPOOL_INDEX].append_arg(Largs.contents());
}
if (zflag) {
commands[POST_INDEX].set_name(0);
commands[SPOOL_INDEX].set_name(0);
}
commands[TROFF_INDEX].append_arg("-T", device);
// html renders equations as images via ps
if (strcmp(device, "html") == 0)
commands[EQN_INDEX].append_arg("-Tps:html");
else
commands[EQN_INDEX].append_arg("-T", device);
commands[GRN_INDEX].append_arg("-T", device);
int first_index;
for (first_index = 0; first_index < TROFF_INDEX; first_index++)
if (commands[first_index].get_name() != 0)
break;
if (optind < argc) {
if (argv[optind][0] == '-' && argv[optind][1] != '\0')
commands[first_index].append_arg("--");
for (int i = optind; i < argc; i++)
commands[first_index].append_arg(argv[i]);
if (iflag)
commands[first_index].append_arg("-");
}
if (Fargs.length() > 0) {
string e = "GROFF_FONT_PATH";
e += '=';
e += Fargs;
char *fontpath = getenv("GROFF_FONT_PATH");
if (fontpath && *fontpath) {
e += PATH_SEP[0];
e += fontpath;
}
e += '\0';
if (putenv(strsave(e.contents())))
fatal("putenv failed");
}
{
// we save the original path in GROFF_PATH__ and put it into the
// environment -- troff will pick it up later.
char *path = getenv("PATH");
string e = "GROFF_PATH__";
e += '=';
if (path && *path)
e += path;
e += '\0';
if (putenv(strsave(e.contents())))
fatal("putenv failed");
char *binpath = getenv("GROFF_BIN_PATH");
string f = "PATH";
f += '=';
if (binpath && *binpath)
f += binpath;
else
f += BINPATH;
if (path && *path) {
f += PATH_SEP[0];
f += path;
}
f += '\0';
if (putenv(strsave(f.contents())))
fatal("putenv failed");
}
if (Vflag) {
print_commands();
exit(0);
}
return run_commands(vflag);
}
const char *xbasename(const char *s)
{
if (!s)
return 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 *p = strrchr(s, DIR_SEPS[0]), *p1;
const char *sep = &DIR_SEPS[1];
while (*sep)
{
p1 = strrchr(s, *sep);
if (p1 && (!p || p1 > p))
p = p1;
sep++;
}
return p ? p + 1 : s;
}
void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno)
{
if (strcmp(command, "print") == 0) {
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`print' command requires an argument");
else
spooler = strsave(arg);
}
if (strcmp(command, "prepro") == 0) {
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`prepro' command requires an argument");
else {
for (const char *p = arg; *p; p++)
if (csspace(*p)) {
error_with_file_and_line(filename, lineno,
"invalid `prepro' argument `%1'"
": program name required", arg);
return;
}
predriver = strsave(arg);
}
}
if (strcmp(command, "postpro") == 0) {
if (arg == 0)
error_with_file_and_line(filename, lineno,
"`postpro' command requires an argument");
else {
for (const char *p = arg; *p; p++)
if (csspace(*p)) {
error_with_file_and_line(filename, lineno,
"invalid `postpro' argument `%1'"
": program name required", arg);
return;
}
postdriver = strsave(arg);
}
}
}
void print_commands()
{
int last;
for (last = SPOOL_INDEX; last >= 0; last--)
if (commands[last].get_name() != 0)
break;
for (int i = 0; i <= last; i++)
if (commands[i].get_name() != 0)
commands[i].print(i == last, stdout);
}
// Run the commands. Return the code with which to exit.
int run_commands(int no_pipe)
{
char **v[NCOMMANDS];
int j = 0;
for (int i = 0; i < NCOMMANDS; i++)
if (commands[i].get_name() != 0)
v[j++] = commands[i].get_argv();
return run_pipeline(j, v, no_pipe);
}
possible_command::possible_command()
: name(0), argv(0)
{
}
possible_command::~possible_command()
{
a_delete name;
a_delete argv;
}
void possible_command::set_name(const char *s)
{
a_delete name;
name = strsave(s);
}
void possible_command::set_name(const char *s1, const char *s2)
{
a_delete name;
name = new char[strlen(s1) + strlen(s2) + 1];
strcpy(name, s1);
strcat(name, s2);
}
const char *possible_command::get_name()
{
return name;
}
void possible_command::clear_args()
{
args.clear();
}
void possible_command::append_arg(const char *s, const char *t)
{
args += s;
if (t)
args += t;
args += '\0';
}
void possible_command::insert_arg(const char *s)
{
string str(s);
str += '\0';
str += args;
args = str;
}
void possible_command::insert_args(string s)
{
const char *p = s.contents();
const char *end = p + s.length();
int l = 0;
if (p >= end)
return;
// find the total number of arguments in our string
do {
l++;
p = strchr(p, '\0') + 1;
} while (p < end);
// now insert each argument preserving the order
for (int i = l - 1; i >= 0; i--) {
p = s.contents();
for (int j = 0; j < i; j++)
p = strchr(p, '\0') + 1;
insert_arg(p);
}
}
void possible_command::build_argv()
{
if (argv)
return;
// Count the number of arguments.
int len = args.length();
int argc = 1;
char *p = 0;
if (len > 0) {
p = &args[0];
for (int i = 0; i < len; i++)
if (p[i] == '\0')
argc++;
}
// Build an argument vector.
argv = new char *[argc + 1];
argv[0] = name;
for (int i = 1; i < argc; i++) {
argv[i] = p;
p = strchr(p, '\0') + 1;
}
argv[argc] = 0;
}
void possible_command::print(int is_last, FILE *fp)
{
build_argv();
if (IS_BSHELL(argv[0])
&& argv[1] != 0 && strcmp(argv[1], BSHELL_DASH_C) == 0
&& argv[2] != 0 && argv[3] == 0)
fputs(argv[2], fp);
else {
fputs(argv[0], fp);
string str;
for (int i = 1; argv[i] != 0; i++) {
str.clear();
append_arg_to_string(argv[i], str);
put_string(str, fp);
}
}
if (is_last)
putc('\n', fp);
else
fputs(" | ", fp);
}
void append_arg_to_string(const char *arg, string &str)
{
str += ' ';
int needs_quoting = 0;
int contains_single_quote = 0;
const char*p;
for (p = arg; *p != '\0'; p++)
switch (*p) {
case ';':
case '&':
case '(':
case ')':
case '|':
case '^':
case '<':
case '>':
case '\n':
case ' ':
case '\t':
case '\\':
case '"':
case '$':
case '?':
case '*':
needs_quoting = 1;
break;
case '\'':
contains_single_quote = 1;
break;
}
if (contains_single_quote || arg[0] == '\0') {
str += '"';
for (p = arg; *p != '\0'; p++)
switch (*p) {
case '"':
case '\\':
case '$':
str += '\\';
// fall through
default:
str += *p;
break;
}
str += '"';
}
else if (needs_quoting) {
str += '\'';
str += arg;
str += '\'';
}
else
str += arg;
}
char **possible_command::get_argv()
{
build_argv();
return argv;
}
void synopsis(FILE *stream)
{
fprintf(stream,
"usage: %s [-abceghilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
" [-wname] [-Wname] [-Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n"
" [-Larg] [-Idir] [files...]\n",
program_name);
}
void help()
{
synopsis(stdout);
fputs("\n"
"-h\tprint this message\n"
"-t\tpreprocess with tbl\n"
"-p\tpreprocess with pic\n"
"-e\tpreprocess with eqn\n"
"-g\tpreprocess with grn\n"
"-G\tpreprocess with grap\n"
"-s\tpreprocess with soelim\n"
"-R\tpreprocess with refer\n"
"-Tdev\tuse device dev\n"
"-X\tuse X11 previewer rather than usual postprocessor\n"
"-mname\tread macros tmac.name\n"
"-dcs\tdefine a string c as s\n"
"-rcn\tdefine a number register c as n\n"
"-nnum\tnumber first page n\n"
"-olist\toutput only pages in list\n"
"-ffam\tuse fam as the default font family\n"
"-Fdir\tsearch dir for device directories\n"
"-Mdir\tsearch dir for macro files\n"
"-v\tprint version number\n"
"-z\tsuppress formatted output\n"
"-Z\tdon't postprocess\n"
"-a\tproduce ASCII description of output\n"
"-i\tread standard input after named input files\n"
"-wname\tenable warning name\n"
"-Wname\tinhibit warning name\n"
"-E\tinhibit all errors\n"
"-b\tprint backtraces with errors or warnings\n"
"-l\tspool the output\n"
"-c\tdisable color output\n"
"-C\tenable compatibility mode\n"
"-V\tprint commands on stdout instead of running them\n"
"-Parg\tpass arg to the postprocessor\n"
"-Larg\tpass arg to the spooler\n"
"-N\tdon't allow newlines within eqn delimiters\n"
"-S\tenable safer mode (the default)\n"
"-U\tenable unsafe mode\n"
"-Idir\tsearch dir for soelim. Implies -s\n"
"\n",
stdout);
exit(0);
}
void usage(FILE *stream)
{
synopsis(stream);
fprintf(stream, "%s -h gives more help\n", program_name);
}
extern "C" {
void c_error(const char *format, const char *arg1, const char *arg2,
const char *arg3)
{
error(format, arg1, arg2, arg3);
}
void c_fatal(const char *format, const char *arg1, const char *arg2,
const char *arg3)
{
fatal(format, arg1, arg2, arg3);
}
}

View File

@ -1,732 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 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. */
#ifdef COLUMN
#include "troff.h"
#include "symbol.h"
#include "dictionary.h"
#include "hvunits.h"
#include "env.h"
#include "request.h"
#include "node.h"
#include "token.h"
#include "div.h"
#include "reg.h"
#include "stringclass.h"
void output_file::vjustify(vunits, symbol)
{
// do nothing
}
struct justification_spec;
struct output_line;
class column : public output_file {
private:
output_file *out;
vunits bottom;
output_line *col;
output_line **tail;
void add_output_line(output_line *);
void begin_page(int pageno, vunits page_length);
void flush();
void print_line(hunits, vunits, node *, vunits, vunits);
void vjustify(vunits, symbol);
void transparent_char(unsigned char c);
void copy_file(hunits, vunits, const char *);
int is_printing();
void check_bottom();
public:
column();
~column();
void start();
void output();
void justify(const justification_spec &);
void trim();
void reset();
vunits get_bottom();
vunits get_last_extra_space();
int is_active() { return out != 0; }
};
column *the_column = 0;
struct transparent_output_line;
struct vjustify_output_line;
class output_line {
output_line *next;
public:
output_line();
virtual ~output_line();
virtual void output(output_file *, vunits);
virtual transparent_output_line *as_transparent_output_line();
virtual vjustify_output_line *as_vjustify_output_line();
virtual vunits distance();
virtual vunits height();
virtual void reset();
virtual vunits extra_space(); // post line
friend class column;
friend class justification_spec;
};
class position_output_line : public output_line {
vunits dist;
public:
position_output_line(vunits);
vunits distance();
};
class node_output_line : public position_output_line {
node *nd;
hunits page_offset;
vunits before;
vunits after;
public:
node_output_line(vunits, node *, hunits, vunits, vunits);
~node_output_line();
void output(output_file *, vunits);
vunits height();
vunits extra_space();
};
class vjustify_output_line : public position_output_line {
vunits current;
symbol typ;
public:
vjustify_output_line(vunits dist, symbol);
vunits height();
vjustify_output_line *as_vjustify_output_line();
void vary(vunits amount);
void reset();
symbol type();
};
inline symbol vjustify_output_line::type()
{
return typ;
}
class copy_file_output_line : public position_output_line {
symbol filename;
hunits hpos;
public:
copy_file_output_line(vunits, const char *, hunits);
void output(output_file *, vunits);
};
class transparent_output_line : public output_line {
string buf;
public:
transparent_output_line();
void output(output_file *, vunits);
void append_char(unsigned char c);
transparent_output_line *as_transparent_output_line();
};
output_line::output_line() : next(0)
{
}
output_line::~output_line()
{
}
void output_line::reset()
{
}
transparent_output_line *output_line::as_transparent_output_line()
{
return 0;
}
vjustify_output_line *output_line::as_vjustify_output_line()
{
return 0;
}
void output_line::output(output_file *, vunits)
{
}
vunits output_line::distance()
{
return V0;
}
vunits output_line::height()
{
return V0;
}
vunits output_line::extra_space()
{
return V0;
}
position_output_line::position_output_line(vunits d)
: dist(d)
{
}
vunits position_output_line::distance()
{
return dist;
}
node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a)
: position_output_line(d), nd(n), page_offset(po), before(b), after(a)
{
}
node_output_line::~node_output_line()
{
delete_node_list(nd);
}
void node_output_line::output(output_file *out, vunits pos)
{
out->print_line(page_offset, pos, nd, before, after);
nd = 0;
}
vunits node_output_line::height()
{
return after;
}
vunits node_output_line::extra_space()
{
return after;
}
vjustify_output_line::vjustify_output_line(vunits d, symbol t)
: position_output_line(d), typ(t)
{
}
void vjustify_output_line::reset()
{
current = V0;
}
vunits vjustify_output_line::height()
{
return current;
}
vjustify_output_line *vjustify_output_line::as_vjustify_output_line()
{
return this;
}
inline void vjustify_output_line::vary(vunits amount)
{
current += amount;
}
transparent_output_line::transparent_output_line()
{
}
transparent_output_line *transparent_output_line::as_transparent_output_line()
{
return this;
}
void transparent_output_line::append_char(unsigned char c)
{
assert(c != 0);
buf += c;
}
void transparent_output_line::output(output_file *out, vunits)
{
int len = buf.length();
for (int i = 0; i < len; i++)
out->transparent_char(buf[i]);
}
copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h)
: position_output_line(d), hpos(h), filename(f)
{
}
void copy_file_output_line::output(output_file *out, vunits pos)
{
out->copy_file(hpos, pos, filename.contents());
}
column::column()
: bottom(V0), col(0), tail(&col), out(0)
{
}
column::~column()
{
assert(out != 0);
error("automatically outputting column before exiting");
output();
delete the_output;
}
void column::start()
{
assert(out == 0);
if (!the_output)
init_output();
assert(the_output != 0);
out = the_output;
the_output = this;
}
void column::begin_page(int pageno, vunits page_length)
{
assert(out != 0);
if (col) {
error("automatically outputting column before beginning next page");
output();
the_output->begin_page(pageno, page_length);
}
else
out->begin_page(pageno, page_length);
}
void column::flush()
{
assert(out != 0);
out->flush();
}
int column::is_printing()
{
assert(out != 0);
return out->is_printing();
}
vunits column::get_bottom()
{
return bottom;
}
void column::add_output_line(output_line *ln)
{
*tail = ln;
bottom += ln->distance();
bottom += ln->height();
ln->next = 0;
tail = &(*tail)->next;
}
void column::print_line(hunits page_offset, vunits pos, node *nd,
vunits before, vunits after)
{
assert(out != 0);
add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after));
}
void column::vjustify(vunits pos, symbol typ)
{
assert(out != 0);
add_output_line(new vjustify_output_line(pos - bottom, typ));
}
void column::transparent_char(unsigned char c)
{
assert(out != 0);
transparent_output_line *tl = 0;
if (*tail)
tl = (*tail)->as_transparent_output_line();
if (!tl) {
tl = new transparent_output_line;
add_output_line(tl);
}
tl->append_char(c);
}
void column::copy_file(hunits page_offset, vunits pos, const char *filename)
{
assert(out != 0);
add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset));
}
void column::trim()
{
output_line **spp = 0;
for (output_line **pp = &col; *pp; pp = &(*pp)->next)
if ((*pp)->as_vjustify_output_line() == 0)
spp = 0;
else if (!spp)
spp = pp;
if (spp) {
output_line *ln = *spp;
*spp = 0;
tail = spp;
while (ln) {
output_line *tem = ln->next;
bottom -= ln->distance();
bottom -= ln->height();
delete ln;
ln = tem;
}
}
}
void column::reset()
{
bottom = V0;
for (output_line *ln = col; ln; ln = ln->next) {
bottom += ln->distance();
ln->reset();
bottom += ln->height();
}
}
void column::check_bottom()
{
vunits b;
for (output_line *ln = col; ln; ln = ln->next) {
b += ln->distance();
b += ln->height();
}
assert(b == bottom);
}
void column::output()
{
assert(out != 0);
vunits vpos(V0);
output_line *ln = col;
while (ln) {
vpos += ln->distance();
ln->output(out, vpos);
vpos += ln->height();
output_line *tem = ln->next;
delete ln;
ln = tem;
}
tail = &col;
bottom = V0;
col = 0;
the_output = out;
out = 0;
}
vunits column::get_last_extra_space()
{
if (!col)
return V0;
for (output_line *p = col; p->next; p = p->next)
;
return p->extra_space();
}
class justification_spec {
vunits height;
symbol *type;
vunits *amount;
int n;
int maxn;
public:
justification_spec(vunits);
~justification_spec();
void append(symbol t, vunits v);
void justify(output_line *, vunits *bottomp) const;
};
justification_spec::justification_spec(vunits h)
: height(h), n(0), maxn(10)
{
type = new symbol[maxn];
amount = new vunits[maxn];
}
justification_spec::~justification_spec()
{
a_delete type;
a_delete amount;
}
void justification_spec::append(symbol t, vunits v)
{
if (v <= V0) {
if (v < V0)
warning(WARN_RANGE,
"maximum space for vertical justification must not be negative");
else
warning(WARN_RANGE,
"maximum space for vertical justification must not be zero");
return;
}
if (n >= maxn) {
maxn *= 2;
symbol *old_type = type;
type = new symbol[maxn];
int i;
for (i = 0; i < n; i++)
type[i] = old_type[i];
a_delete old_type;
vunits *old_amount = amount;
amount = new vunits[maxn];
for (i = 0; i < n; i++)
amount[i] = old_amount[i];
a_delete old_amount;
}
assert(n < maxn);
type[n] = t;
amount[n] = v;
n++;
}
void justification_spec::justify(output_line *col, vunits *bottomp) const
{
if (*bottomp >= height)
return;
vunits total;
output_line *p;
for (p = col; p; p = p->next) {
vjustify_output_line *sp = p->as_vjustify_output_line();
if (sp) {
symbol t = sp->type();
for (int i = 0; i < n; i++) {
if (t == type[i])
total += amount[i];
}
}
}
vunits gap = height - *bottomp;
for (p = col; p; p = p->next) {
vjustify_output_line *sp = p->as_vjustify_output_line();
if (sp) {
symbol t = sp->type();
for (int i = 0; i < n; i++) {
if (t == type[i]) {
if (total <= gap) {
sp->vary(amount[i]);
gap -= amount[i];
}
else {
// gap < total
vunits v = scale(amount[i], gap, total);
sp->vary(v);
gap -= v;
}
total -= amount[i];
}
}
}
}
assert(total == V0);
*bottomp = height - gap;
}
void column::justify(const justification_spec &js)
{
check_bottom();
js.justify(col, &bottom);
check_bottom();
}
void column_justify()
{
vunits height;
if (!the_column->is_active())
error("can't justify column - column not active");
else if (get_vunits(&height, 'v')) {
justification_spec js(height);
symbol nm = get_long_name(1);
if (!nm.is_null()) {
vunits v;
if (get_vunits(&v, 'v')) {
js.append(nm, v);
int err = 0;
while (has_arg()) {
nm = get_long_name(1);
if (nm.is_null()) {
err = 1;
break;
}
if (!get_vunits(&v, 'v')) {
err = 1;
break;
}
js.append(nm, v);
}
if (!err)
the_column->justify(js);
}
}
}
skip_line();
}
void column_start()
{
if (the_column->is_active())
error("can't start column - column already active");
else
the_column->start();
skip_line();
}
void column_output()
{
if (!the_column->is_active())
error("can't output column - column not active");
else
the_column->output();
skip_line();
}
void column_trim()
{
if (!the_column->is_active())
error("can't trim column - column not active");
else
the_column->trim();
skip_line();
}
void column_reset()
{
if (!the_column->is_active())
error("can't reset column - column not active");
else
the_column->reset();
skip_line();
}
class column_bottom_reg : public reg {
public:
const char *get_string();
};
const char *column_bottom_reg::get_string()
{
return i_to_a(the_column->get_bottom().to_units());
}
class column_extra_space_reg : public reg {
public:
const char *get_string();
};
const char *column_extra_space_reg::get_string()
{
return i_to_a(the_column->get_last_extra_space().to_units());
}
class column_active_reg : public reg {
public:
const char *get_string();
};
const char *column_active_reg::get_string()
{
return the_column->is_active() ? "1" : "0";
}
static int no_vjustify_mode = 0;
class vjustify_node : public node {
symbol typ;
public:
vjustify_node(symbol);
int reread(int *);
const char *type();
int same(node *);
node *copy();
};
vjustify_node::vjustify_node(symbol t)
: typ(t)
{
}
node *vjustify_node::copy()
{
return new vjustify_node(typ);
}
const char *vjustify_node::type()
{
return "vjustify_node";
}
int vjustify_node::same(node *nd)
{
return typ == ((vjustify_node *)nd)->typ;
}
int vjustify_node::reread(int *bolp)
{
curdiv->vjustify(typ);
*bolp = 1;
return 1;
}
void macro_diversion::vjustify(symbol type)
{
if (!no_vjustify_mode)
mac->append(new vjustify_node(type));
}
void top_level_diversion::vjustify(symbol type)
{
if (no_space_mode || no_vjustify_mode)
return;
assert(first_page_begun); // I'm not sure about this.
the_output->vjustify(vertical_position, type);
}
void no_vjustify()
{
skip_line();
no_vjustify_mode = 1;
}
void restore_vjustify()
{
skip_line();
no_vjustify_mode = 0;
}
void init_column_requests()
{
the_column = new column;
init_request("cols", column_start);
init_request("colo", column_output);
init_request("colj", column_justify);
init_request("colr", column_reset);
init_request("colt", column_trim);
init_request("nvj", no_vjustify);
init_request("rvj", restore_vjustify);
number_reg_dictionary.define(".colb", new column_bottom_reg);
number_reg_dictionary.define(".colx", new column_extra_space_reg);
number_reg_dictionary.define(".cola", new column_active_reg);
number_reg_dictionary.define(".nvj",
new constant_int_reg(&no_vjustify_mode));
}
#endif /* COLUMN */

View File

@ -1,212 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 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 "troff.h"
#include "symbol.h"
#include "dictionary.h"
// is `p' a good size for a hash table
static int is_good_size(unsigned int p)
{
const unsigned int SMALL = 10;
unsigned int i;
for (i = 2; i <= p/2; i++)
if (p % i == 0)
return 0;
for (i = 0x100; i != 0; i <<= 8)
if (i % p <= SMALL || i % p > p - SMALL)
return 0;
return 1;
}
dictionary::dictionary(int n) : size(n), used(0), threshold(0.5), factor(1.5)
{
table = new association[n];
}
// see Knuth, Sorting and Searching, p518, Algorithm L
// we can't use double-hashing because we want a remove function
void *dictionary::lookup(symbol s, void *v)
{
int i;
for (i = int(s.hash() % size);
table[i].v != 0;
i == 0 ? i = size - 1: --i)
if (s == table[i].s) {
if (v != 0) {
void *temp = table[i].v;
table[i].v = v;
return temp;
}
else
return table[i].v;
}
if (v == 0)
return 0;
++used;
table[i].v = v;
table[i].s = s;
if ((double)used/(double)size >= threshold || used + 1 >= size) {
int old_size = size;
size = int(size*factor);
while (!is_good_size(size))
++size;
association *old_table = table;
table = new association[size];
used = 0;
for (i = 0; i < old_size; i++)
if (old_table[i].v != 0)
(void)lookup(old_table[i].s, old_table[i].v);
a_delete old_table;
}
return 0;
}
void *dictionary::lookup(const char *p)
{
symbol s(p, MUST_ALREADY_EXIST);
if (s.is_null())
return 0;
else
return lookup(s);
}
// see Knuth, Sorting and Searching, p527, Algorithm R
void *dictionary::remove(symbol s)
{
// this relies on the fact that we are using linear probing
int i;
for (i = int(s.hash() % size);
table[i].v != 0 && s != table[i].s;
i == 0 ? i = size - 1: --i)
;
void *p = table[i].v;
while (table[i].v != 0) {
table[i].v = 0;
int j = i;
int r;
do {
--i;
if (i < 0)
i = size - 1;
if (table[i].v == 0)
break;
r = int(table[i].s.hash() % size);
} while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r));
table[j] = table[i];
}
if (p != 0)
--used;
return p;
}
dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0)
{
}
int dictionary_iterator::get(symbol *sp, void **vp)
{
for (; i < dict->size; i++)
if (dict->table[i].v) {
*sp = dict->table[i].s;
*vp = dict->table[i].v;
i++;
return 1;
}
return 0;
}
object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od)
: di(od.d)
{
}
object::object() : rcount(0)
{
}
object::~object()
{
}
void object::add_reference()
{
rcount += 1;
}
void object::remove_reference()
{
if (--rcount == 0)
delete this;
}
object_dictionary::object_dictionary(int n) : d(n)
{
}
object *object_dictionary::lookup(symbol nm)
{
return (object *)d.lookup(nm);
}
void object_dictionary::define(symbol nm, object *obj)
{
obj->add_reference();
obj = (object *)d.lookup(nm, obj);
if (obj)
obj->remove_reference();
}
void object_dictionary::rename(symbol oldnm, symbol newnm)
{
object *obj = (object *)d.remove(oldnm);
if (obj) {
obj = (object *)d.lookup(newnm, obj);
if (obj)
obj->remove_reference();
}
}
void object_dictionary::remove(symbol nm)
{
object *obj = (object *)d.remove(nm);
if (obj)
obj->remove_reference();
}
// Return non-zero if oldnm was defined.
int object_dictionary::alias(symbol newnm, symbol oldnm)
{
object *obj = (object *)d.lookup(oldnm);
if (obj) {
obj->add_reference();
obj = (object *)d.lookup(newnm, obj);
if (obj)
obj->remove_reference();
return 1;
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,697 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
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 "troff.h"
#include "symbol.h"
#include "hvunits.h"
#include "env.h"
#include "token.h"
#include "div.h"
vunits V0;
hunits H0;
int hresolution = 1;
int vresolution = 1;
int units_per_inch;
int sizescale;
static int parse_expr(units *v, int scale_indicator,
int parenthesised, int rigid = 0);
static int start_number();
int get_vunits(vunits *res, unsigned char si)
{
if (!start_number())
return 0;
units x;
if (parse_expr(&x, si, 0)) {
*res = vunits(x);
return 1;
}
else
return 0;
}
int get_hunits(hunits *res, unsigned char si)
{
if (!start_number())
return 0;
units x;
if (parse_expr(&x, si, 0)) {
*res = hunits(x);
return 1;
}
else
return 0;
}
// for \B
int get_number_rigidly(units *res, unsigned char si)
{
if (!start_number())
return 0;
units x;
if (parse_expr(&x, si, 0, 1)) {
*res = x;
return 1;
}
else
return 0;
}
int get_number(units *res, unsigned char si)
{
if (!start_number())
return 0;
units x;
if (parse_expr(&x, si, 0)) {
*res = x;
return 1;
}
else
return 0;
}
int get_integer(int *res)
{
if (!start_number())
return 0;
units x;
if (parse_expr(&x, 0, 0)) {
*res = x;
return 1;
}
else
return 0;
}
enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
static incr_number_result get_incr_number(units *res, unsigned char);
int get_vunits(vunits *res, unsigned char si, vunits prev_value)
{
units v;
switch (get_incr_number(&v, si)) {
case BAD:
return 0;
case ABSOLUTE:
*res = v;
break;
case INCREMENT:
*res = prev_value + v;
break;
case DECREMENT:
*res = prev_value - v;
break;
default:
assert(0);
}
return 1;
}
int get_hunits(hunits *res, unsigned char si, hunits prev_value)
{
units v;
switch (get_incr_number(&v, si)) {
case BAD:
return 0;
case ABSOLUTE:
*res = v;
break;
case INCREMENT:
*res = prev_value + v;
break;
case DECREMENT:
*res = prev_value - v;
break;
default:
assert(0);
}
return 1;
}
int get_number(units *res, unsigned char si, units prev_value)
{
units v;
switch (get_incr_number(&v, si)) {
case BAD:
return 0;
case ABSOLUTE:
*res = v;
break;
case INCREMENT:
*res = prev_value + v;
break;
case DECREMENT:
*res = prev_value - v;
break;
default:
assert(0);
}
return 1;
}
int get_integer(int *res, int prev_value)
{
units v;
switch (get_incr_number(&v, 0)) {
case BAD:
return 0;
case ABSOLUTE:
*res = v;
break;
case INCREMENT:
*res = prev_value + int(v);
break;
case DECREMENT:
*res = prev_value - int(v);
break;
default:
assert(0);
}
return 1;
}
static incr_number_result get_incr_number(units *res, unsigned char si)
{
if (!start_number())
return BAD;
incr_number_result result = ABSOLUTE;
if (tok.ch() == '+') {
tok.next();
result = INCREMENT;
}
else if (tok.ch() == '-') {
tok.next();
result = DECREMENT;
}
if (parse_expr(res, si, 0))
return result;
else
return BAD;
}
static int start_number()
{
while (tok.space())
tok.next();
if (tok.newline()) {
warning(WARN_MISSING, "missing number");
return 0;
}
if (tok.tab()) {
warning(WARN_TAB, "tab character where number expected");
return 0;
}
if (tok.right_brace()) {
warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
return 0;
}
return 1;
}
enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
#define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
static int parse_term(units *v, int scale_indicator,
int parenthesised, int rigid);
static int parse_expr(units *v, int scale_indicator,
int parenthesised, int rigid)
{
int result = parse_term(v, scale_indicator, parenthesised, rigid);
while (result) {
if (parenthesised)
tok.skip();
int op = tok.ch();
switch (op) {
case '+':
case '-':
case '/':
case '*':
case '%':
case ':':
case '&':
tok.next();
break;
case '>':
tok.next();
if (tok.ch() == '=') {
tok.next();
op = OP_GEQ;
}
else if (tok.ch() == '?') {
tok.next();
op = OP_MAX;
}
break;
case '<':
tok.next();
if (tok.ch() == '=') {
tok.next();
op = OP_LEQ;
}
else if (tok.ch() == '?') {
tok.next();
op = OP_MIN;
}
break;
case '=':
tok.next();
if (tok.ch() == '=')
tok.next();
break;
default:
return result;
}
units v2;
if (!parse_term(&v2, scale_indicator, parenthesised, rigid))
return 0;
int overflow = 0;
switch (op) {
case '<':
*v = *v < v2;
break;
case '>':
*v = *v > v2;
break;
case OP_LEQ:
*v = *v <= v2;
break;
case OP_GEQ:
*v = *v >= v2;
break;
case OP_MIN:
if (*v > v2)
*v = v2;
break;
case OP_MAX:
if (*v < v2)
*v = v2;
break;
case '=':
*v = *v == v2;
break;
case '&':
*v = *v > 0 && v2 > 0;
break;
case ':':
*v = *v > 0 || v2 > 0;
break;
case '+':
if (v2 < 0) {
if (*v < INT_MIN - v2)
overflow = 1;
}
else if (v2 > 0) {
if (*v > INT_MAX - v2)
overflow = 1;
}
if (overflow) {
error("addition overflow");
return 0;
}
*v += v2;
break;
case '-':
if (v2 < 0) {
if (*v > INT_MAX + v2)
overflow = 1;
}
else if (v2 > 0) {
if (*v < INT_MIN + v2)
overflow = 1;
}
if (overflow) {
error("subtraction overflow");
return 0;
}
*v -= v2;
break;
case '*':
if (v2 < 0) {
if (*v > 0) {
if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
overflow = 1;
}
else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
overflow = 1;
}
else if (v2 > 0) {
if (*v > 0) {
if (*v > INT_MAX / v2)
overflow = 1;
}
else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
overflow = 1;
}
if (overflow) {
error("multiplication overflow");
return 0;
}
*v *= v2;
break;
case '/':
if (v2 == 0) {
error("division by zero");
return 0;
}
*v /= v2;
break;
case '%':
if (v2 == 0) {
error("modulus by zero");
return 0;
}
*v %= v2;
break;
default:
assert(0);
}
}
return result;
}
static int parse_term(units *v, int scale_indicator,
int parenthesised, int rigid)
{
int negative = 0;
for (;;)
if (parenthesised && tok.space())
tok.next();
else if (tok.ch() == '+')
tok.next();
else if (tok.ch() == '-') {
tok.next();
negative = !negative;
}
else
break;
unsigned char c = tok.ch();
switch (c) {
case '|':
// | is not restricted to the outermost level
// tbl uses this
tok.next();
if (!parse_term(v, scale_indicator, parenthesised, rigid))
return 0;
int tem;
tem = (scale_indicator == 'v'
? curdiv->get_vertical_position().to_units()
: curenv->get_input_line_position().to_units());
if (tem >= 0) {
if (*v < INT_MIN + tem) {
error("numeric overflow");
return 0;
}
}
else {
if (*v > INT_MAX + tem) {
error("numeric overflow");
return 0;
}
}
*v -= tem;
if (negative) {
if (*v == INT_MIN) {
error("numeric overflow");
return 0;
}
*v = -*v;
}
return 1;
case '(':
tok.next();
c = tok.ch();
if (c == ')') {
if (rigid)
return 0;
warning(WARN_SYNTAX, "empty parentheses");
tok.next();
*v = 0;
return 1;
}
else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
tok.next();
if (tok.ch() == ';') {
tok.next();
scale_indicator = c;
}
else {
error("expected `;' after scale-indicator (got %1)",
tok.description());
return 0;
}
}
else if (c == ';') {
scale_indicator = 0;
tok.next();
}
if (!parse_expr(v, scale_indicator, 1, rigid))
return 0;
tok.skip();
if (tok.ch() != ')') {
if (rigid)
return 0;
warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
}
else
tok.next();
if (negative) {
if (*v == INT_MIN) {
error("numeric overflow");
return 0;
}
*v = -*v;
}
return 1;
case '.':
*v = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
*v = 0;
do {
if (*v > INT_MAX/10) {
error("numeric overflow");
return 0;
}
*v *= 10;
if (*v > INT_MAX - (int(c) - '0')) {
error("numeric overflow");
return 0;
}
*v += c - '0';
tok.next();
c = tok.ch();
} while (csdigit(c));
break;
case '/':
case '*':
case '%':
case ':':
case '&':
case '>':
case '<':
case '=':
warning(WARN_SYNTAX, "empty left operand");
*v = 0;
return rigid ? 0 : 1;
default:
warning(WARN_NUMBER, "numeric expression expected (got %1)",
tok.description());
return 0;
}
int divisor = 1;
if (tok.ch() == '.') {
tok.next();
for (;;) {
c = tok.ch();
if (!csdigit(c))
break;
// we may multiply the divisor by 254 later on
if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
*v *= 10;
*v += c - '0';
divisor *= 10;
}
tok.next();
}
}
int si = scale_indicator;
int do_next = 0;
if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
switch (scale_indicator) {
case 'z':
if (c != 'u' && c != 'z') {
warning(WARN_SCALE,
"only `z' and `u' scale indicators valid in this context");
break;
}
si = c;
break;
case 0:
warning(WARN_SCALE, "scale indicator invalid in this context");
break;
case 'u':
si = c;
break;
default:
if (c == 'z') {
warning(WARN_SCALE, "`z' scale indicator invalid in this context");
break;
}
si = c;
break;
}
// Don't do tok.next() here because the next token might be \s, which
// would affect the interpretation of m.
do_next = 1;
}
switch (si) {
case 'i':
*v = scale(*v, units_per_inch, divisor);
break;
case 'c':
*v = scale(*v, units_per_inch*100, divisor*254);
break;
case 0:
case 'u':
if (divisor != 1)
*v /= divisor;
break;
case 'f':
*v = scale(*v, 65536, divisor);
break;
case 'p':
*v = scale(*v, units_per_inch, divisor*72);
break;
case 'P':
*v = scale(*v, units_per_inch, divisor*6);
break;
case 'm':
{
// Convert to hunits so that with -Tascii `m' behaves as in nroff.
hunits em = curenv->get_size();
*v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
}
break;
case 'M':
{
hunits em = curenv->get_size();
*v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
}
break;
case 'n':
{
// Convert to hunits so that with -Tascii `n' behaves as in nroff.
hunits en = curenv->get_size()/2;
*v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
}
break;
case 'v':
*v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
break;
case 's':
while (divisor > INT_MAX/(sizescale*72)) {
divisor /= 10;
*v /= 10;
}
*v = scale(*v, units_per_inch, divisor*sizescale*72);
break;
case 'z':
*v = scale(*v, sizescale, divisor);
break;
default:
assert(0);
}
if (do_next)
tok.next();
if (negative) {
if (*v == INT_MIN) {
error("numeric overflow");
return 0;
}
*v = -*v;
}
return 1;
}
units scale(units n, units x, units y)
{
assert(x >= 0 && y > 0);
if (x == 0)
return 0;
if (n >= 0) {
if (n <= INT_MAX/x)
return (n*x)/y;
}
else {
if (-(unsigned)n <= -(unsigned)INT_MIN/x)
return (n*x)/y;
}
double res = n*double(x)/double(y);
if (res > INT_MAX) {
error("numeric overflow");
return INT_MAX;
}
else if (res < INT_MIN) {
error("numeric overflow");
return INT_MIN;
}
return int(res);
}
vunits::vunits(units x)
{
// don't depend on the rounding direction for division of negative integers
if (vresolution == 1)
n = x;
else
n = (x < 0
? -((-x + vresolution/2 - 1)/vresolution)
: (x + vresolution/2 - 1)/vresolution);
}
hunits::hunits(units x)
{
// don't depend on the rounding direction for division of negative integers
if (hresolution == 1)
n = x;
else
n = (x < 0
? -((-x + hresolution/2 - 1)/hresolution)
: (x + hresolution/2 - 1)/hresolution);
}

View File

@ -1,474 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 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 "troff.h"
#include "symbol.h"
#include "dictionary.h"
#include "token.h"
#include "request.h"
#include "reg.h"
object_dictionary number_reg_dictionary(101);
int reg::get_value(units * /*d*/)
{
return 0;
}
void reg::increment()
{
error("can't increment read-only register");
}
void reg::decrement()
{
error("can't decrement read-only register");
}
void reg::set_increment(units /*n*/)
{
error("can't auto increment read-only register");
}
void reg::alter_format(char /*f*/, int /*w*/)
{
error("can't alter format of read-only register");
}
const char *reg::get_format()
{
return "0";
}
void reg::set_value(units /*n*/)
{
error("can't write read-only register");
}
general_reg::general_reg() : format('1'), width(0), inc(0)
{
}
static char uppercase_array[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z',
};
static char lowercase_array[] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z',
};
static const char *number_value_to_ascii(int value, char format, int width)
{
static char buf[128]; // must be at least 21
switch(format) {
case '1':
if (width <= 0)
return i_to_a(value);
else if (width > int(sizeof(buf) - 2))
sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value));
else
sprintf(buf, "%.*d", width, int(value));
break;
case 'i':
case 'I':
{
char *p = buf;
// troff uses z and w to represent 10000 and 5000 in Roman
// numerals; I can find no historical basis for this usage
const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI";
int n = int(value);
if (n >= 40000 || n <= -40000) {
error("magnitude of `%1' too big for i or I format", n);
return i_to_a(n);
}
if (n == 0) {
*p++ = '0';
*p = 0;
break;
}
if (n < 0) {
*p++ = '-';
n = -n;
}
while (n >= 10000) {
*p++ = s[0];
n -= 10000;
}
for (int i = 1000; i > 0; i /= 10, s += 2) {
int m = n/i;
n -= m*i;
switch (m) {
case 3:
*p++ = s[2];
/* falls through */
case 2:
*p++ = s[2];
/* falls through */
case 1:
*p++ = s[2];
break;
case 4:
*p++ = s[2];
*p++ = s[1];
break;
case 8:
*p++ = s[1];
*p++ = s[2];
*p++ = s[2];
*p++ = s[2];
break;
case 7:
*p++ = s[1];
*p++ = s[2];
*p++ = s[2];
break;
case 6:
*p++ = s[1];
*p++ = s[2];
break;
case 5:
*p++ = s[1];
break;
case 9:
*p++ = s[2];
*p++ = s[0];
}
}
*p = 0;
break;
}
case 'a':
case 'A':
{
int n = value;
char *p = buf;
if (n == 0) {
*p++ = '0';
*p = 0;
}
else {
if (n < 0) {
n = -n;
*p++ = '-';
}
// this is a bit tricky
while (n > 0) {
int d = n % 26;
if (d == 0)
d = 26;
n -= d;
n /= 26;
*p++ = format == 'a' ? lowercase_array[d - 1] :
uppercase_array[d - 1];
}
*p-- = 0;
char *q = buf[0] == '-' ? buf + 1 : buf;
while (q < p) {
char temp = *q;
*q = *p;
*p = temp;
--p;
++q;
}
}
break;
}
default:
assert(0);
break;
}
return buf;
}
const char *general_reg::get_string()
{
units n;
if (!get_value(&n))
return "";
return number_value_to_ascii(n, format, width);
}
void general_reg::increment()
{
int n;
if (get_value(&n))
set_value(n + inc);
}
void general_reg::decrement()
{
int n;
if (get_value(&n))
set_value(n - inc);
}
void general_reg::set_increment(units n)
{
inc = n;
}
void general_reg::alter_format(char f, int w)
{
format = f;
width = w;
}
static const char *number_format_to_ascii(char format, int width)
{
static char buf[24];
if (format == '1') {
if (width > 0) {
int n = width;
if (n > int(sizeof(buf)) - 1)
n = int(sizeof(buf)) - 1;
sprintf(buf, "%.*d", n, 0);
return buf;
}
else
return "0";
}
else {
buf[0] = format;
buf[1] = '\0';
return buf;
}
}
const char *general_reg::get_format()
{
return number_format_to_ascii(format, width);
}
class number_reg : public general_reg {
units value;
public:
number_reg();
int get_value(units *);
void set_value(units);
};
number_reg::number_reg() : value(0)
{
}
int number_reg::get_value(units *res)
{
*res = value;
return 1;
}
void number_reg::set_value(units n)
{
value = n;
}
variable_reg::variable_reg(units *p) : ptr(p)
{
}
void variable_reg::set_value(units n)
{
*ptr = n;
}
int variable_reg::get_value(units *res)
{
*res = *ptr;
return 1;
}
void define_number_reg()
{
symbol nm = get_name(1);
if (nm.is_null()) {
skip_line();
return;
}
reg *r = (reg *)number_reg_dictionary.lookup(nm);
units v;
units prev_value;
if (!r || !r->get_value(&prev_value))
prev_value = 0;
if (get_number(&v, 'u', prev_value)) {
if (r == 0) {
r = new number_reg;
number_reg_dictionary.define(nm, r);
}
r->set_value(v);
if (tok.space() && has_arg() && get_number(&v, 'u'))
r->set_increment(v);
}
skip_line();
}
#if 0
void inline_define_reg()
{
token start;
start.next();
if (!start.delimiter(1))
return;
tok.next();
symbol nm = get_name(1);
if (nm.is_null())
return;
reg *r = (reg *)number_reg_dictionary.lookup(nm);
if (r == 0) {
r = new number_reg;
number_reg_dictionary.define(nm, r);
}
units v;
units prev_value;
if (!r->get_value(&prev_value))
prev_value = 0;
if (get_number(&v, 'u', prev_value)) {
r->set_value(v);
if (start != tok) {
if (get_number(&v, 'u')) {
r->set_increment(v);
if (start != tok)
warning(WARN_DELIM, "closing delimiter does not match");
}
}
}
}
#endif
void set_number_reg(symbol nm, units n)
{
reg *r = (reg *)number_reg_dictionary.lookup(nm);
if (r == 0) {
r = new number_reg;
number_reg_dictionary.define(nm, r);
}
r->set_value(n);
}
reg *lookup_number_reg(symbol nm)
{
reg *r = (reg *)number_reg_dictionary.lookup(nm);
if (r == 0) {
warning(WARN_REG, "number register `%1' not defined", nm.contents());
r = new number_reg;
number_reg_dictionary.define(nm, r);
}
return r;
}
void alter_format()
{
symbol nm = get_name(1);
if (nm.is_null()) {
skip_line();
return;
}
reg *r = (reg *)number_reg_dictionary.lookup(nm);
if (r == 0) {
r = new number_reg;
number_reg_dictionary.define(nm, r);
}
tok.skip();
char c = tok.ch();
if (csdigit(c)) {
int n = 0;
do {
++n;
tok.next();
} while (csdigit(tok.ch()));
r->alter_format('1', n);
}
else if (c == 'i' || c == 'I' || c == 'a' || c == 'A')
r->alter_format(c);
else if (tok.newline() || tok.eof())
warning(WARN_MISSING, "missing number register format");
else
error("bad number register format (got %1)", tok.description());
skip_line();
}
void remove_reg()
{
for (;;) {
symbol s = get_name();
if (s.is_null())
break;
number_reg_dictionary.remove(s);
}
skip_line();
}
void alias_reg()
{
symbol s1 = get_name(1);
if (!s1.is_null()) {
symbol s2 = get_name(1);
if (!s2.is_null()) {
if (!number_reg_dictionary.alias(s1, s2))
warning(WARN_REG, "number register `%1' not defined", s2.contents());
}
}
skip_line();
}
void rename_reg()
{
symbol s1 = get_name(1);
if (!s1.is_null()) {
symbol s2 = get_name(1);
if (!s2.is_null())
number_reg_dictionary.rename(s1, s2);
}
skip_line();
}
void print_number_regs()
{
object_dictionary_iterator iter(number_reg_dictionary);
reg *r;
symbol s;
while (iter.get(&s, (object **)&r)) {
assert(!s.is_null());
errprint("%1\t", s.contents());
const char *p = r->get_string();
if (p)
errprint(p);
errprint("\n");
}
fflush(stderr);
skip_line();
}
void init_reg_requests()
{
init_request("rr", remove_reg);
init_request("nr", define_number_reg);
init_request("af", alter_format);
init_request("aln", alias_reg);
init_request("rnn", rename_reg);
init_request("pnr", print_number_regs);
}

View File

@ -1,154 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "troff.h"
#include "symbol.h"
const char **symbol::table = 0;
int symbol::table_used = 0;
int symbol::table_size = 0;
char *symbol::block = 0;
int symbol::block_size = 0;
const symbol NULL_SYMBOL;
const symbol EMPTY_SYMBOL("");
#ifdef BLOCK_SIZE
#undef BLOCK_SIZE
#endif
const int BLOCK_SIZE = 1024;
// the table will increase in size as necessary
// the size will be chosen from the following array
// add some more if you want
static const unsigned int table_sizes[] = {
101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021,
160001, 500009, 1000003, 1500007, 2000003, 0
};
const double FULL_MAX = 0.3; // don't let the table get more than this full
static unsigned int hash_string(const char *p)
{
// compute a hash code; this assumes 32-bit unsigned ints
// see p436 of Compilers by Aho, Sethi & Ullman
// give special treatment to two-character names
unsigned int hc = 0, g;
if (*p != 0) {
hc = *p++;
if (*p != 0) {
hc <<= 7;
hc += *p++;
for (; *p != 0; p++) {
hc <<= 4;
hc += *p;
if ((g = (hc & 0xf0000000)) == 0) {
hc ^= g >> 24;
hc ^= g;
}
}
}
}
return hc;
}
// Tell compiler that a variable is intentionally unused.
inline void unused(void *) { }
symbol::symbol(const char *p, int how)
{
if (p == 0) {
s = 0;
return;
}
if (*p == 0) {
s = "";
return;
}
if (table == 0) {
table_size = table_sizes[0];
table = (const char **)new char*[table_size];
for (int i = 0; i < table_size; i++)
table[i] = 0;
table_used = 0;
}
unsigned int hc = hash_string(p);
const char **pp;
for (pp = table + hc % table_size;
*pp != 0;
(pp == table ? pp = table + table_size - 1 : --pp))
if (strcmp(p, *pp) == 0) {
s = *pp;
return;
}
if (how == MUST_ALREADY_EXIST) {
s = 0;
return;
}
if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) {
const char **old_table = table;
unsigned int old_table_size = table_size;
int i;
for (i = 1; table_sizes[i] <= old_table_size; i++)
if (table_sizes[i] == 0)
fatal("too many symbols");
table_size = table_sizes[i];
table_used = 0;
table = (const char **)new char*[table_size];
for (i = 0; i < table_size; i++)
table[i] = 0;
for (pp = old_table + old_table_size - 1;
pp >= old_table;
--pp) {
symbol temp(*pp, 1); /* insert it into the new table */
unused(&temp);
}
a_delete old_table;
for (pp = table + hc % table_size;
*pp != 0;
(pp == table ? pp = table + table_size - 1 : --pp))
;
}
++table_used;
if (how == DONT_STORE) {
s = *pp = p;
}
else {
int len = strlen(p)+1;
if (block == 0 || block_size < len) {
block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE;
block = new char [block_size];
}
(void)strcpy(block, p);
s = *pp = block;
block += len;
block_size -= len;
}
}
symbol concat(symbol s1, symbol s2)
{
char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1];
strcpy(buf, s1.contents());
strcat(buf, s2.contents());
symbol res(buf);
a_delete buf;
return res;
}

View File

@ -1,218 +0,0 @@
// -*- 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 "lib.h"
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include "errarg.h"
#include "error.h"
#include "stringclass.h"
#include "cset.h"
#include "guess.h"
extern "C" const char *Version_string;
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];
int i;
for (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;
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
if (argv[i][1] == '-' && argv[i][2] == '\0') {
i++;
break;
}
if (i + 1 >= argc)
usage();
size_t 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()
{
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 &param, 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);
}
}

View File

@ -1,490 +0,0 @@
// -*- 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 &param, 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
}
}

View File

@ -1,809 +0,0 @@
// -*- 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 "lib.h"
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include "assert.h"
#include "posix.h"
#include "errarg.h"
#include "error.h"
#include "cset.h"
#include "nonposix.h"
extern "C" const char *Version_string;
#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;
unsigned int msl_name_table_size = 0;
name_list **msl_name_table = 0;
unsigned 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':
{
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;
}
void File::skip(int n)
{
if (end_ - ptr_ < n)
fatal("unexpected end of file");
ptr_ += n;
}
void File::seek(uint32 n)
{
if ((uint32)(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];
unsigned 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);
unsigned 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++) {
unsigned 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;
unsigned 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 (unsigned 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");
unsigned 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 ((size_t)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;
}

View File

@ -1,789 +0,0 @@
// -*- C++ -*-
/* Copyright (C) 1989-1992, 2000, 2001, 2002 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 "lib.h"
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "posix.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" const char *Version_string;
#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();
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':
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++;
}
size_t name_max;
if (p) {
char *dir = strsave(basename);
dir[p - basename] = '\0';
name_max = file_name_max(dir);
a_delete dir;
}
else
name_max = file_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);
}
catch_fatal_signals();
int fd = mkstemp(temp_index_file);
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
#ifdef __EMX__
unline(index_file);
#endif /* __EMX__ */
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) != (size_t)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);
}
}

View File

@ -1,137 +0,0 @@
// -*- 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 "lib.h"
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include "errarg.h"
#include "error.h"
#include "defs.h"
#include "refid.h"
#include "search.h"
extern "C" const char *Version_string;
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':
{
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) != (size_t)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;
}

View File

@ -1,141 +0,0 @@
// -*- 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 "lib.h"
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "errarg.h"
#include "error.h"
#include "cset.h"
#include "refid.h"
#include "search.h"
/* for isatty() */
#include "posix.h"
extern "C" {
const char *Version_string;
}
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':
{
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) != (size_t)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;
}

Some files were not shown because too many files have changed in this diff Show More