Removed files not present in v1.19 import.
This commit is contained in:
parent
c96557721b
commit
1a17e98fb2
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -1 +0,0 @@
|
||||
const char *current_filename = 0;
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
};
|
@ -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;
|
||||
}
|
@ -1 +0,0 @@
|
||||
int current_lineno = 0;
|
@ -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);
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -1 +0,0 @@
|
||||
const char *program_name = 0;
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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 */
|
||||
}
|
@ -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", ¹ },
|
||||
{ "sup2", ² },
|
||||
{ "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>");
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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, " }");
|
||||
}
|
@ -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, " }");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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, " }");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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, " }");
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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 */
|
@ -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
@ -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 );
|
||||
}
|
@ -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 ¢, double rad,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢,
|
||||
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 ¢,
|
||||
const position &end, const line_type <)
|
||||
{
|
||||
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 ¢,
|
||||
const position &end, const line_type <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
double start_angle, double end_angle,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢, const distance &dim,
|
||||
double rad, const line_type <, 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 ¢,
|
||||
const distance &dim, double rad,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
double start_angle, double end_angle,
|
||||
const line_type <,
|
||||
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 <,
|
||||
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 ¢,
|
||||
const distance &dim, double rad,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
double start_angle, double end_angle,
|
||||
const line_type <, 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 <, 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 ¢,
|
||||
const distance &dim, double rad,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢,
|
||||
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
@ -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
@ -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 ¢, double rad, double start_angle,
|
||||
double end_angle, const line_type <);
|
||||
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 ¢er, 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 <)
|
||||
{
|
||||
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 <, 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 <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
double start_angle, double end_angle,
|
||||
const line_type <)
|
||||
{
|
||||
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 ¢,
|
||||
const position &end, const line_type <)
|
||||
{
|
||||
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 ¢, double rad,
|
||||
const line_type <, 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 ¢, const distance &dim,
|
||||
const line_type <, 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 <)
|
||||
{
|
||||
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
|
@ -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 ¢,
|
||||
const position &end, const line_type <)
|
||||
{
|
||||
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 <)
|
||||
{
|
||||
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 <)
|
||||
{
|
||||
line_thickness(lt.thickness);
|
||||
simple_spline(start, v, n);
|
||||
}
|
||||
|
||||
void simple_output::polygon(const position *v, int n,
|
||||
const line_type <, 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 ¢, double rad,
|
||||
const line_type <, 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 ¢, const distance &dim,
|
||||
const line_type <, 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 ¢, 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 ¢,
|
||||
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 ¢,
|
||||
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 ¢er, 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 ¢, const line_type <)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 */
|
@ -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
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 ¶m, FILE *infp, FILE *outfp)
|
||||
{
|
||||
string s;
|
||||
while (get_line(infp, &s)) {
|
||||
put_string(s, outfp);
|
||||
if (s.length() >= 8
|
||||
&& strncmp(&s[0], "charset", 7))
|
||||
break;
|
||||
}
|
||||
while (get_line(infp, &s)) {
|
||||
s += '\0';
|
||||
string name;
|
||||
const char *p = s.contents();
|
||||
while (csspace(*p))
|
||||
p++;
|
||||
while (*p != '\0' && !csspace(*p))
|
||||
name += *p++;
|
||||
while (csspace(*p))
|
||||
p++;
|
||||
for (const char *q = s.contents(); q < p; q++)
|
||||
putc(*q, outfp);
|
||||
char *next;
|
||||
char_metric metric;
|
||||
metric.width = (int)strtol(p, &next, 10);
|
||||
if (next != p) {
|
||||
printf("%d", metric.width);
|
||||
p = next;
|
||||
metric.type = (int)strtol(p, &next, 10);
|
||||
if (next != p) {
|
||||
name += '\0';
|
||||
guess(name.contents(), param, &metric);
|
||||
if (metric.sk == 0) {
|
||||
if (metric.left_ic == 0) {
|
||||
if (metric.ic == 0) {
|
||||
if (metric.depth == 0) {
|
||||
if (metric.height != 0)
|
||||
printf(",%d", metric.height);
|
||||
}
|
||||
else
|
||||
printf(",%d,%d", metric.height, metric.depth);
|
||||
}
|
||||
else
|
||||
printf(",%d,%d,%d", metric.height, metric.depth, metric.ic);
|
||||
}
|
||||
else
|
||||
printf(",%d,%d,%d,%d", metric.height, metric.depth, metric.ic,
|
||||
metric.left_ic);
|
||||
}
|
||||
else
|
||||
printf(",%d,%d,%d,%d,%d", metric.height, metric.depth, metric.ic,
|
||||
metric.left_ic, metric.sk);
|
||||
}
|
||||
}
|
||||
fputs(p, outfp);
|
||||
}
|
||||
}
|
||||
|
@ -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 ¶m, char_metric *metric)
|
||||
{
|
||||
int &height = metric->height;
|
||||
int &depth = metric->depth;
|
||||
|
||||
metric->ic = 0;
|
||||
metric->left_ic = 0;
|
||||
metric->sk = 0;
|
||||
height = 0;
|
||||
depth = 0;
|
||||
if (s[0] == '\0' || (s[1] != '\0' && s[2] != '\0'))
|
||||
goto do_default;
|
||||
#define HASH(c1, c2) (((unsigned char)(c1) << 8) | (unsigned char)(c2))
|
||||
switch (HASH(s[0], s[1])) {
|
||||
default:
|
||||
do_default:
|
||||
if (metric->type & 01)
|
||||
depth = param.desc_depth;
|
||||
if (metric->type & 02)
|
||||
height = param.asc_height;
|
||||
else
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH('\\', '|'):
|
||||
case HASH('\\', '^'):
|
||||
case HASH('\\', '&'):
|
||||
// these have zero height and depth
|
||||
break;
|
||||
case HASH('f', 0):
|
||||
height = param.asc_height;
|
||||
if (param.italic)
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('a', 0):
|
||||
case HASH('c', 0):
|
||||
case HASH('e', 0):
|
||||
case HASH('m', 0):
|
||||
case HASH('n', 0):
|
||||
case HASH('o', 0):
|
||||
case HASH('r', 0):
|
||||
case HASH('s', 0):
|
||||
case HASH('u', 0):
|
||||
case HASH('v', 0):
|
||||
case HASH('w', 0):
|
||||
case HASH('x', 0):
|
||||
case HASH('z', 0):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH('i', 0):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH('b', 0):
|
||||
case HASH('d', 0):
|
||||
case HASH('h', 0):
|
||||
case HASH('k', 0):
|
||||
case HASH('l', 0):
|
||||
case HASH('F', 'i'):
|
||||
case HASH('F', 'l'):
|
||||
case HASH('f', 'f'):
|
||||
case HASH('f', 'i'):
|
||||
case HASH('f', 'l'):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('t', 0):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('g', 0):
|
||||
case HASH('p', 0):
|
||||
case HASH('q', 0):
|
||||
case HASH('y', 0):
|
||||
height = param.x_height;
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('j', 0):
|
||||
height = param.x_height;
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('A', 0):
|
||||
case HASH('B', 0):
|
||||
case HASH('C', 0):
|
||||
case HASH('D', 0):
|
||||
case HASH('E', 0):
|
||||
case HASH('F', 0):
|
||||
case HASH('G', 0):
|
||||
case HASH('H', 0):
|
||||
case HASH('I', 0):
|
||||
case HASH('J', 0):
|
||||
case HASH('K', 0):
|
||||
case HASH('L', 0):
|
||||
case HASH('M', 0):
|
||||
case HASH('N', 0):
|
||||
case HASH('O', 0):
|
||||
case HASH('P', 0):
|
||||
case HASH('Q', 0):
|
||||
case HASH('R', 0):
|
||||
case HASH('S', 0):
|
||||
case HASH('T', 0):
|
||||
case HASH('U', 0):
|
||||
case HASH('V', 0):
|
||||
case HASH('W', 0):
|
||||
case HASH('X', 0):
|
||||
case HASH('Y', 0):
|
||||
case HASH('Z', 0):
|
||||
height = param.cap_height;
|
||||
break;
|
||||
case HASH('*', 'A'):
|
||||
case HASH('*', 'B'):
|
||||
case HASH('*', 'C'):
|
||||
case HASH('*', 'D'):
|
||||
case HASH('*', 'E'):
|
||||
case HASH('*', 'F'):
|
||||
case HASH('*', 'G'):
|
||||
case HASH('*', 'H'):
|
||||
case HASH('*', 'I'):
|
||||
case HASH('*', 'K'):
|
||||
case HASH('*', 'L'):
|
||||
case HASH('*', 'M'):
|
||||
case HASH('*', 'N'):
|
||||
case HASH('*', 'O'):
|
||||
case HASH('*', 'P'):
|
||||
case HASH('*', 'Q'):
|
||||
case HASH('*', 'R'):
|
||||
case HASH('*', 'S'):
|
||||
case HASH('*', 'T'):
|
||||
case HASH('*', 'U'):
|
||||
case HASH('*', 'W'):
|
||||
case HASH('*', 'X'):
|
||||
case HASH('*', 'Y'):
|
||||
case HASH('*', 'Z'):
|
||||
height = param.cap_height;
|
||||
break;
|
||||
case HASH('0', 0):
|
||||
case HASH('1', 0):
|
||||
case HASH('2', 0):
|
||||
case HASH('3', 0):
|
||||
case HASH('4', 0):
|
||||
case HASH('5', 0):
|
||||
case HASH('6', 0):
|
||||
case HASH('7', 0):
|
||||
case HASH('8', 0):
|
||||
case HASH('9', 0):
|
||||
case HASH('1', '2'):
|
||||
case HASH('1', '4'):
|
||||
case HASH('3', '4'):
|
||||
height = param.fig_height;
|
||||
break;
|
||||
case HASH('(', 0):
|
||||
case HASH(')', 0):
|
||||
case HASH('[', 0):
|
||||
case HASH(']', 0):
|
||||
case HASH('{', 0):
|
||||
case HASH('}', 0):
|
||||
height = param.body_height;
|
||||
depth = param.body_depth;
|
||||
break;
|
||||
case HASH('i', 's'):
|
||||
height = (param.em*3)/4;
|
||||
depth = param.em/4;
|
||||
break;
|
||||
case HASH('*', 'a'):
|
||||
case HASH('*', 'e'):
|
||||
case HASH('*', 'i'):
|
||||
case HASH('*', 'k'):
|
||||
case HASH('*', 'n'):
|
||||
case HASH('*', 'o'):
|
||||
case HASH('*', 'p'):
|
||||
case HASH('*', 's'):
|
||||
case HASH('*', 't'):
|
||||
case HASH('*', 'u'):
|
||||
case HASH('*', 'w'):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH('*', 'd'):
|
||||
case HASH('*', 'l'):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('*', 'g'):
|
||||
case HASH('*', 'h'):
|
||||
case HASH('*', 'm'):
|
||||
case HASH('*', 'r'):
|
||||
case HASH('*', 'x'):
|
||||
case HASH('*', 'y'):
|
||||
height = param.x_height;
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('*', 'b'):
|
||||
case HASH('*', 'c'):
|
||||
case HASH('*', 'f'):
|
||||
case HASH('*', 'q'):
|
||||
case HASH('*', 'z'):
|
||||
height = param.asc_height;
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('t', 's'):
|
||||
height = param.x_height;
|
||||
depth = param.desc_depth;
|
||||
break;
|
||||
case HASH('!', 0):
|
||||
case HASH('?', 0):
|
||||
case HASH('"', 0):
|
||||
case HASH('#', 0):
|
||||
case HASH('$', 0):
|
||||
case HASH('%', 0):
|
||||
case HASH('&', 0):
|
||||
case HASH('*', 0):
|
||||
case HASH('+', 0):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('`', 0):
|
||||
case HASH('\'', 0):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('~', 0):
|
||||
case HASH('^', 0):
|
||||
case HASH('a', 'a'):
|
||||
case HASH('g', 'a'):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('r', 'u'):
|
||||
case HASH('.', 0):
|
||||
break;
|
||||
case HASH(',', 0):
|
||||
depth = param.comma_depth;
|
||||
break;
|
||||
case HASH('m', 'i'):
|
||||
case HASH('-', 0):
|
||||
case HASH('h', 'y'):
|
||||
case HASH('e', 'm'):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH(':', 0):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH(';', 0):
|
||||
height = param.x_height;
|
||||
depth = param.comma_depth;
|
||||
break;
|
||||
case HASH('=', 0):
|
||||
case HASH('e', 'q'):
|
||||
height = param.x_height;
|
||||
break;
|
||||
case HASH('<', 0):
|
||||
case HASH('>', 0):
|
||||
case HASH('>', '='):
|
||||
case HASH('<', '='):
|
||||
case HASH('@', 0):
|
||||
case HASH('/', 0):
|
||||
case HASH('|', 0):
|
||||
case HASH('\\', 0):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('_', 0):
|
||||
case HASH('u', 'l'):
|
||||
case HASH('\\', '_'):
|
||||
depth = param.em/4;
|
||||
break;
|
||||
case HASH('r', 'n'):
|
||||
height = (param.em*3)/4;
|
||||
break;
|
||||
case HASH('s', 'r'):
|
||||
height = (param.em*3)/4;
|
||||
depth = param.em/4;
|
||||
break;
|
||||
case HASH('b', 'u'):
|
||||
case HASH('s', 'q'):
|
||||
case HASH('d', 'e'):
|
||||
case HASH('d', 'g'):
|
||||
case HASH('f', 'm'):
|
||||
case HASH('c', 't'):
|
||||
case HASH('r', 'g'):
|
||||
case HASH('c', 'o'):
|
||||
case HASH('p', 'l'):
|
||||
case HASH('*', '*'):
|
||||
case HASH('s', 'c'):
|
||||
case HASH('s', 'l'):
|
||||
case HASH('=', '='):
|
||||
case HASH('~', '='):
|
||||
case HASH('a', 'p'):
|
||||
case HASH('!', '='):
|
||||
case HASH('-', '>'):
|
||||
case HASH('<', '-'):
|
||||
case HASH('u', 'a'):
|
||||
case HASH('d', 'a'):
|
||||
case HASH('m', 'u'):
|
||||
case HASH('d', 'i'):
|
||||
case HASH('+', '-'):
|
||||
case HASH('c', 'u'):
|
||||
case HASH('c', 'a'):
|
||||
case HASH('s', 'b'):
|
||||
case HASH('s', 'p'):
|
||||
case HASH('i', 'b'):
|
||||
case HASH('i', 'p'):
|
||||
case HASH('i', 'f'):
|
||||
case HASH('p', 'd'):
|
||||
case HASH('g', 'r'):
|
||||
case HASH('n', 'o'):
|
||||
case HASH('p', 't'):
|
||||
case HASH('e', 's'):
|
||||
case HASH('m', 'o'):
|
||||
case HASH('b', 'r'):
|
||||
case HASH('d', 'd'):
|
||||
case HASH('r', 'h'):
|
||||
case HASH('l', 'h'):
|
||||
case HASH('o', 'r'):
|
||||
case HASH('c', 'i'):
|
||||
height = param.asc_height;
|
||||
break;
|
||||
case HASH('l', 't'):
|
||||
case HASH('l', 'b'):
|
||||
case HASH('r', 't'):
|
||||
case HASH('r', 'b'):
|
||||
case HASH('l', 'k'):
|
||||
case HASH('r', 'k'):
|
||||
case HASH('b', 'v'):
|
||||
case HASH('l', 'f'):
|
||||
case HASH('r', 'f'):
|
||||
case HASH('l', 'c'):
|
||||
case HASH('r', 'c'):
|
||||
height = (param.em*3)/4;
|
||||
depth = param.em/4;
|
||||
break;
|
||||
#if 0
|
||||
case HASH('%', '0'):
|
||||
case HASH('-', '+'):
|
||||
case HASH('-', 'D'):
|
||||
case HASH('-', 'd'):
|
||||
case HASH('-', 'd'):
|
||||
case HASH('-', 'h'):
|
||||
case HASH('.', 'i'):
|
||||
case HASH('.', 'j'):
|
||||
case HASH('/', 'L'):
|
||||
case HASH('/', 'O'):
|
||||
case HASH('/', 'l'):
|
||||
case HASH('/', 'o'):
|
||||
case HASH('=', '~'):
|
||||
case HASH('A', 'E'):
|
||||
case HASH('A', 'h'):
|
||||
case HASH('A', 'N'):
|
||||
case HASH('C', 's'):
|
||||
case HASH('D', 'o'):
|
||||
case HASH('F', 'c'):
|
||||
case HASH('F', 'o'):
|
||||
case HASH('I', 'J'):
|
||||
case HASH('I', 'm'):
|
||||
case HASH('O', 'E'):
|
||||
case HASH('O', 'f'):
|
||||
case HASH('O', 'K'):
|
||||
case HASH('O', 'm'):
|
||||
case HASH('O', 'R'):
|
||||
case HASH('P', 'o'):
|
||||
case HASH('R', 'e'):
|
||||
case HASH('S', '1'):
|
||||
case HASH('S', '2'):
|
||||
case HASH('S', '3'):
|
||||
case HASH('T', 'P'):
|
||||
case HASH('T', 'p'):
|
||||
case HASH('Y', 'e'):
|
||||
case HASH('\\', '-'):
|
||||
case HASH('a', '"'):
|
||||
case HASH('a', '-'):
|
||||
case HASH('a', '.'):
|
||||
case HASH('a', '^'):
|
||||
case HASH('a', 'b'):
|
||||
case HASH('a', 'c'):
|
||||
case HASH('a', 'd'):
|
||||
case HASH('a', 'e'):
|
||||
case HASH('a', 'h'):
|
||||
case HASH('a', 'o'):
|
||||
case HASH('a', 't'):
|
||||
case HASH('a', '~'):
|
||||
case HASH('b', 'a'):
|
||||
case HASH('b', 'b'):
|
||||
case HASH('b', 's'):
|
||||
case HASH('c', '*'):
|
||||
case HASH('c', '+'):
|
||||
case HASH('f', '/'):
|
||||
case HASH('f', 'a'):
|
||||
case HASH('f', 'c'):
|
||||
case HASH('f', 'o'):
|
||||
case HASH('h', 'a'):
|
||||
case HASH('h', 'o'):
|
||||
case HASH('i', 'j'):
|
||||
case HASH('l', 'A'):
|
||||
case HASH('l', 'B'):
|
||||
case HASH('l', 'C'):
|
||||
case HASH('m', 'd'):
|
||||
case HASH('n', 'c'):
|
||||
case HASH('n', 'e'):
|
||||
case HASH('n', 'm'):
|
||||
case HASH('o', 'A'):
|
||||
case HASH('o', 'a'):
|
||||
case HASH('o', 'e'):
|
||||
case HASH('o', 'q'):
|
||||
case HASH('p', 'l'):
|
||||
case HASH('p', 'p'):
|
||||
case HASH('p', 's'):
|
||||
case HASH('r', '!'):
|
||||
case HASH('r', '?'):
|
||||
case HASH('r', 'A'):
|
||||
case HASH('r', 'B'):
|
||||
case HASH('r', 'C'):
|
||||
case HASH('r', 's'):
|
||||
case HASH('s', 'h'):
|
||||
case HASH('s', 's'):
|
||||
case HASH('t', 'e'):
|
||||
case HASH('t', 'f'):
|
||||
case HASH('t', 'i'):
|
||||
case HASH('t', 'm'):
|
||||
case HASH('~', '~'):
|
||||
case HASH('v', 'S'):
|
||||
case HASH('v', 'Z'):
|
||||
case HASH('v', 's'):
|
||||
case HASH('v', 'z'):
|
||||
case HASH('^', 'A'):
|
||||
case HASH('^', 'E'):
|
||||
case HASH('^', 'I'):
|
||||
case HASH('^', 'O'):
|
||||
case HASH('^', 'U'):
|
||||
case HASH('^', 'a'):
|
||||
case HASH('^', 'e'):
|
||||
case HASH('^', 'i'):
|
||||
case HASH('^', 'o'):
|
||||
case HASH('^', 'u'):
|
||||
case HASH('`', 'A'):
|
||||
case HASH('`', 'E'):
|
||||
case HASH('`', 'I'):
|
||||
case HASH('`', 'O'):
|
||||
case HASH('`', 'U'):
|
||||
case HASH('`', 'a'):
|
||||
case HASH('`', 'e'):
|
||||
case HASH('`', 'i'):
|
||||
case HASH('`', 'o'):
|
||||
case HASH('`', 'u'):
|
||||
case HASH('~', 'A'):
|
||||
case HASH('~', 'N'):
|
||||
case HASH('~', 'O'):
|
||||
case HASH('~', 'a'):
|
||||
case HASH('~', 'n'):
|
||||
case HASH('~', 'o'):
|
||||
case HASH('\'', 'A'):
|
||||
case HASH('\'', 'C'):
|
||||
case HASH('\'', 'E'):
|
||||
case HASH('\'', 'I'):
|
||||
case HASH('\'', 'O'):
|
||||
case HASH('\'', 'U'):
|
||||
case HASH('\'', 'a'):
|
||||
case HASH('\'', 'c'):
|
||||
case HASH('\'', 'e'):
|
||||
case HASH('\'', 'i'):
|
||||
case HASH('\'', 'o'):
|
||||
case HASH('\'', 'u')
|
||||
case HASH(':', 'A'):
|
||||
case HASH(':', 'E'):
|
||||
case HASH(':', 'I'):
|
||||
case HASH(':', 'O'):
|
||||
case HASH(':', 'U'):
|
||||
case HASH(':', 'Y'):
|
||||
case HASH(':', 'a'):
|
||||
case HASH(':', 'e'):
|
||||
case HASH(':', 'i'):
|
||||
case HASH(':', 'o'):
|
||||
case HASH(':', 'u'):
|
||||
case HASH(':', 'y'):
|
||||
case HASH(',', 'C'):
|
||||
case HASH(',', 'c'):
|
||||
#endif
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user