diff options
author | ru <ru@FreeBSD.org> | 2003-05-01 13:15:22 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2003-05-01 13:15:22 +0000 |
commit | 1a17e98fb2e3ecba5ba136f8d1ae8d39061d2f65 (patch) | |
tree | e6cd9552c06f55c81873906321c3f600223592c7 /contrib/groff/src/devices | |
parent | c96557721be60d942f4d486b9ea7f9b7cbb034cc (diff) | |
download | FreeBSD-src-1a17e98fb2e3ecba5ba136f8d1ae8d39061d2f65.zip FreeBSD-src-1a17e98fb2e3ecba5ba136f8d1ae8d39061d2f65.tar.gz |
Removed files not present in v1.19 import.
Diffstat (limited to 'contrib/groff/src/devices')
-rw-r--r-- | contrib/groff/src/devices/grodvi/dvi.cc | 947 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-table.cc | 687 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-text.cc | 964 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/output.cc | 356 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/post-html.cc | 3745 | ||||
-rw-r--r-- | contrib/groff/src/devices/grolbp/lbp.cc | 740 | ||||
-rw-r--r-- | contrib/groff/src/devices/grolj4/lj4.cc | 708 | ||||
-rw-r--r-- | contrib/groff/src/devices/grops/ps.cc | 1642 | ||||
-rw-r--r-- | contrib/groff/src/devices/grops/psrm.cc | 1147 | ||||
-rw-r--r-- | contrib/groff/src/devices/grotty/tty.cc | 776 |
10 files changed, 0 insertions, 11712 deletions
diff --git a/contrib/groff/src/devices/grodvi/dvi.cc b/contrib/groff/src/devices/grodvi/dvi.cc deleted file mode 100644 index 8412636..0000000 --- a/contrib/groff/src/devices/grodvi/dvi.cc +++ /dev/null @@ -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); -} diff --git a/contrib/groff/src/devices/grohtml/html-table.cc b/contrib/groff/src/devices/grohtml/html-table.cc deleted file mode 100644 index a2bb255..0000000 --- a/contrib/groff/src/devices/grohtml/html-table.cc +++ /dev/null @@ -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; -} diff --git a/contrib/groff/src/devices/grohtml/html-text.cc b/contrib/groff/src/devices/grohtml/html-text.cc deleted file mode 100644 index 31e4311..0000000 --- a/contrib/groff/src/devices/grohtml/html-text.cc +++ /dev/null @@ -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); -} - diff --git a/contrib/groff/src/devices/grohtml/output.cc b/contrib/groff/src/devices/grohtml/output.cc deleted file mode 100644 index 67d5874..0000000 --- a/contrib/groff/src/devices/grohtml/output.cc +++ /dev/null @@ -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); - } - } -} diff --git a/contrib/groff/src/devices/grohtml/post-html.cc b/contrib/groff/src/devices/grohtml/post-html.cc deleted file mode 100644 index 4431f17..0000000 --- a/contrib/groff/src/devices/grohtml/post-html.cc +++ /dev/null @@ -1,3745 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - * - * Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cc - * but it owes a huge amount of ideas and raw code from - * James Clark (jjc@jclark.com) grops/ps.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 "html.h" -#include "html-text.h" -#include "html-table.h" - -#include <time.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include <stdio.h> -#include <fcntl.h> - -extern "C" const char *Version_string; - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - -#define MAX_LINE_LENGTH 60 /* maximum characters we want in a line */ -#define SIZE_INCREMENT 2 /* font size increment <big> = +2 */ -#define BASE_POINT_SIZE 10 /* 10 points is the base size ie html size 3 */ -#define CENTER_TOLERANCE 2 /* how many pixels off center will we still */ -#define ANCHOR_TEMPLATE "heading" /* if simple anchor is set we use this */ -#define UNICODE_DESC_START 0x80 /* all character entities above this are */ - /* either encoded by their glyph names or if */ - /* there is no name then we use &#nnn; */ -typedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT; -typedef enum {col_tag, tab_tag, tab0_tag, none} colType; - -#undef DEBUG_TABLES - - -/* - * prototypes - */ - -char *get_html_translation (font *f, const string &name); -int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single); - - -static int auto_links = TRUE; /* by default we enable automatic links at */ - /* top of the document. */ -static int auto_rule = TRUE; /* by default we enable an automatic rule */ - /* at the top and bottom of the document */ -static int simple_anchors = FALSE; /* default to anchors with heading text */ -static int manufacture_headings = FALSE; /* default is to use the Hn html headings, */ - /* rather than manufacture our own. */ -static color *default_background = NULL; /* has user requested initial bg color? */ - - -/* - * start with a few favorites - */ - -void stop () {} - -static int min (int a, int b) -{ - if (a < b) - return a; - else - return b; -} - -static int max (int a, int b) -{ - if (a > b) - return a; - else - return b; -} - -/* - * is_intersection - returns TRUE if range a1..a2 intersects with b1..b2 - */ - -static int is_intersection (int a1, int a2, int b1, int b2) -{ - // easier to prove NOT outside limits - return( ! ((a1 > b2) || (a2 < b1)) ); -} - -/* - * is_digit - returns TRUE if character, ch, is a digit. - */ - -static int is_digit (char ch) -{ - return( (ch >= '0') && (ch <= '9') ); -} - -/* - * the classes and methods for maintaining a list of files. - */ - -struct file { - FILE *fp; - file *next; - - file (FILE *f); -}; - -/* - * file - initialize all fields to NULL - */ - -file::file (FILE *f) - : fp(f), next(0) -{ -} - -class files { -public: - files (); - FILE *get_file (void); - void start_of_list (void); - void move_next (void); - void add_new_file (FILE *f); -private: - file *head; - file *tail; - file *ptr; -}; - -/* - * files - create an empty list of files. - */ - -files::files () - : head(0), tail(0), ptr(0) -{ -} - -/* - * get_file - returns the FILE associated with ptr. - */ - -FILE *files::get_file (void) -{ - if (ptr) { - return( ptr->fp ); - } else { - return( 0 ); - } -} - -/* - * start_of_list - reset the ptr to the start of the list. - */ - -void files::start_of_list (void) -{ - ptr = head; -} - -/* - * move_next - moves the ptr to the next element on the list. - */ - -void files::move_next (void) -{ - if (ptr != 0) - ptr = ptr->next; -} - -/* - * add_new_file - adds a new file, f, to the list. - */ - -void files::add_new_file (FILE *f) -{ - if (head == 0) { - head = new file(f); - tail = head; - } else { - tail->next = new file(f); - tail = tail->next; - } - ptr = tail; -} - -/* - * the class and methods for styles - */ - -struct style { - font *f; - int point_size; - int font_no; - int height; - int slant; - color col; - style (); - style (font *, int, int, int, int, color); - int operator == (const style &) const; - int operator != (const style &) const; -}; - -style::style() - : f(0) -{ -} - -style::style(font *p, int sz, int h, int sl, int no, color c) - : f(p), point_size(sz), font_no(no), height(h), slant(sl), col(c) -{ -} - -int style::operator==(const style &s) const -{ - return (f == s.f && point_size == s.point_size - && height == s.height && slant == s.slant && col == s.col); -} - -int style::operator!=(const style &s) const -{ - return !(*this == s); -} - -/* - * the class and methods for retaining ascii text - */ - -struct char_block { - enum { SIZE = 256 }; - char *buffer; - int used; - char_block *next; - - char_block(); - char_block::char_block(int length); -}; - -char_block::char_block() -: buffer(NULL), used(0), next(0) -{ -} - -char_block::char_block(int length) -: used(0), next(0) -{ - buffer = (char *)malloc(max(length, char_block::SIZE)); - if (buffer == NULL) - fatal("out of memory error"); -} - -class char_buffer { -public: - char_buffer(); - ~char_buffer(); - char *add_string(const char *, unsigned int); - char *add_string(const string &); -private: - char_block *head; - char_block *tail; -}; - -char_buffer::char_buffer() -: head(0), tail(0) -{ -} - -char_buffer::~char_buffer() -{ - while (head != 0) { - char_block *temp = head; - head = head->next; - delete temp; - } -} - -char *char_buffer::add_string (const char *s, unsigned int length) -{ - int i=0; - unsigned int old_used; - - if (s == NULL || length == 0) - return NULL; - - if (tail == 0) { - tail = new char_block(length+1); - head = tail; - } else { - if (tail->used + length+1 > char_block::SIZE) { - tail->next = new char_block(length+1); - tail = tail->next; - } - } - - old_used = tail->used; - do { - tail->buffer[tail->used] = s[i]; - tail->used++; - i++; - length--; - } while (length>0); - - // add terminating nul character - - tail->buffer[tail->used] = '\0'; - tail->used++; - - // and return start of new string - - return( &tail->buffer[old_used] ); -} - -char *char_buffer::add_string (const string &s) -{ - return add_string(s.contents(), s.length()); -} - -/* - * the classes and methods for maintaining glyph positions. - */ - -class text_glob { -public: - void text_glob_html (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_special (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_line (style *s, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal, - int thickness); - void text_glob_auto_image(style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_tag (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - - text_glob (void); - ~text_glob (void); - int is_a_line (void); - int is_a_tag (void); - int is_eol (void); - int is_auto_img (void); - int is_br (void); - int is_in (void); - int is_po (void); - int is_ti (void); - int is_ce (void); - int is_eol_ce (void); - int is_col (void); - int is_tab (void); - int is_tab0 (void); - int is_ta (void); - int is_tab_ts (void); - int is_tab_te (void); - int is_nf (void); - int is_fi (void); - int get_arg (void); - int get_tab_args (char *align); - - void remember_table (html_table *t); - html_table *get_table (void); - - style text_style; - const char *text_string; - unsigned int text_length; - int minv, minh, maxv, maxh; - int is_tag; // is this a .br, .sp, .tl etc - int is_img_auto; // image created by eqn delim - int is_special; // text has come via 'x X html:' - int is_line; // is the command a <line>? - int thickness; // the thickness of a line - html_table *tab; // table description - -private: - text_glob (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal, - bool is_troff_command, - bool is_auto_image, bool is_special_command, - bool is_a_line , int thickness); -}; - -text_glob::text_glob (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal, - bool is_troff_command, - bool is_auto_image, bool is_special_command, - bool is_a_line, int line_thickness) - : text_style(*s), text_string(str), text_length(length), - minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal), - is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command), - is_line(is_a_line), thickness(line_thickness), tab(NULL) -{ -} - -text_glob::text_glob () - : text_string(0), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1), - is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL) -{ -} - -text_glob::~text_glob () -{ - if (tab != NULL) - delete tab; -} - -/* - * text_glob_html - used to place html text into the glob buffer. - */ - -void text_glob::text_glob_html (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_html - used to place html specials into the glob buffer. - * This text is essentially html commands coming through - * from the macro sets, with special designated sequences of - * characters translated into html. See add_and_encode. - */ - -void text_glob::text_glob_special (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, TRUE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_line - record horizontal draw line commands. - */ - -void text_glob::text_glob_line (style *s, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal, - int thickness) -{ - text_glob *g = new text_glob(s, "", 0, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, TRUE, thickness); - *this = *g; -} - -/* - * text_glob_auto_image - record the presence of a .auto-image tag command. - * Used to mark that an image has been created automatically - * by a preprocessor and (pre-grohtml/troff) combination. - * Under some circumstances images may not be created. - * (consider .EQ - * delim $$ - * .EN - * .TS - * tab(!), center; - * l!l. - * $1 over x$!recripical of x - * .TE - * - * the first auto-image marker is created via .EQ/.EN pair - * and no image is created. - * The second auto-image marker occurs at $1 over x$ - * Currently this image will not be created - * as the whole of the table is created as an image. - * (Once html tables are handled by grohtml this will change. - * Shortly this will be the case). - */ - -void text_glob::text_glob_auto_image(style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - TRUE, TRUE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_tag - records a troff tag. - */ - -void text_glob::text_glob_tag (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - TRUE, FALSE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * is_a_line - returns TRUE if glob should be converted into an <hr> - */ - -int text_glob::is_a_line (void) -{ - return is_line; -} - -/* - * is_a_tag - returns TRUE if glob contains a troff directive. - */ - -int text_glob::is_a_tag (void) -{ - return is_tag; -} - -/* - * is_eol - returns TRUE if glob contains the tag eol - */ - -int text_glob::is_eol (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:eol") == 0) ); -} - -/* - * is_eol_ce - returns TRUE if glob contains the tag eol.ce - */ - -int text_glob::is_eol_ce (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0) ); -} - - -/* - * is_nf - returns TRUE if glob contains the tag .nf - */ - -int text_glob::is_nf (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.nf") == 0) ); -} - -/* - * is_fi - returns TRUE if glob contains the tag .fi - */ - -int text_glob::is_fi (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.fi") == 0) ); -} - -/* - * is_ce - returns TRUE if glob contains the tag .ce - */ - -int text_glob::is_ce (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.ce") == 0) ); -} - -/* - * is_in - returns TRUE if glob contains the tag .in - */ - -int text_glob::is_in (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.in ", strlen("html-tag:.in ")) == 0) ); -} - -/* - * is_po - returns TRUE if glob contains the tag .po - */ - -int text_glob::is_po (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.po ", strlen("html-tag:.po ")) == 0) ); -} - -/* - * is_ti - returns TRUE if glob contains the tag .ti - */ - -int text_glob::is_ti (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.ti ", strlen("html-tag:.ti ")) == 0) ); -} - -/* - * is_col - returns TRUE if glob contains the tag .col - */ - -int text_glob::is_col (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.col", strlen("html-tag:.col")) == 0) ); -} - -/* - * is_tab_ts - returns TRUE if glob contains the tag .tab_ts - */ - -int text_glob::is_tab_ts (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0) ); -} - -/* - * is_tab_te - returns TRUE if glob contains the tag .tab_te - */ - -int text_glob::is_tab_te (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0) ); -} - -/* - * is_ta - returns TRUE if glob contains the tag .ta - */ - -int text_glob::is_ta (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.ta ", strlen("html-tag:.ta ")) == 0) ); -} - -/* - * is_tab - returns TRUE if glob contains the tag tab - */ - -int text_glob::is_tab (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:tab ", strlen("html-tag:tab ")) == 0) ); -} - -/* - * is_tab0 - returns TRUE if glob contains the tag tab0 - */ - -int text_glob::is_tab0 (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:tab0", strlen("html-tag:tab0")) == 0) ); -} - -/* - * is_auto_img - returns TRUE if the glob contains an automatically - * generated image. - */ - -int text_glob::is_auto_img (void) -{ - return is_img_auto; -} - -/* - * is_br - returns TRUE if the glob is a tag containing a .br - * or an implied .br. Note that we do not include .nf or .fi - * as grohtml will place a .br after these commands if they - * should break the line. - */ - -int text_glob::is_br (void) -{ - return( is_a_tag() && ((strcmp ("html-tag:.br", text_string) == 0) || - (strncmp("html-tag:.sp", text_string, 11) == 0) || - (strcmp ("html-tag:.ce", text_string) == 0)) ); -} - -int text_glob::get_arg (void) -{ - if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { - const char *p = text_string; - - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - if (*p == (char)0) - return -1; - return atoi(p); - } - return -1; -} - -/* - * get_tab_args - returns the tab position and alignment of the tab tag - */ - -int text_glob::get_tab_args (char *align) -{ - if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { - const char *p = text_string; - - // firstly the alignment C|R|L - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - *align = *p; - // now the int value - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - if (*p == (char)0) - return -1; - return atoi(p); - } - return -1; -} - -/* - * remember_table - saves table, t, in the text_glob. - */ - -void text_glob::remember_table (html_table *t) -{ - tab = t; -} - -/* - * get_table - returns the stored table description. - */ - -html_table *text_glob::get_table (void) -{ - return tab; -} - -/* - * the class and methods used to construct ordered double linked lists. - * In a previous implementation we used templates via #include "ordered-list.h", - * but this does assume that all C++ compilers can handle this feature. Pragmatically - * it is safer to assume this is not the case. - */ - -struct element_list { - element_list *right; - element_list *left; - text_glob *datum; - int lineno; - int minv, minh, maxv, maxh; - - element_list (text_glob *d, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - element_list (); -}; - -element_list::element_list () - : right(0), left(0), datum(0), lineno(0), minv(-1), minh(-1), maxv(-1), maxh(-1) -{ -} - -/* - * element_list - create a list element assigning the datum and region parameters. - */ - -element_list::element_list (text_glob *in, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) - : right(0), left(0), datum(in), lineno(line_number), - minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal) -{ -} - -class list { -public: - list (); - ~list (); - int is_less (element_list *a, element_list *b); - void add (text_glob *in, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void sub_move_right (void); - void move_right (void); - void move_left (void); - int is_empty (void); - int is_equal_to_tail (void); - int is_equal_to_head (void); - void start_from_head (void); - void start_from_tail (void); - void insert (text_glob *in); - void move_to (text_glob *in); - text_glob *move_right_get_data (void); - text_glob *move_left_get_data (void); - text_glob *get_data (void); -private: - element_list *head; - element_list *tail; - element_list *ptr; -}; - -/* - * list - construct an empty list. - */ - -list::list () - : head(0), tail(0), ptr(0) -{ -} - -/* - * ~list - destroy a complete list. - */ - -list::~list() -{ - element_list *temp=head; - - do { - temp = head; - if (temp != 0) { - head = head->right; - delete temp; - } - } while ((head != 0) && (head != tail)); -} - -/* - * is_less - returns TRUE if a is left of b if on the same line or - * if a is higher up the page than b. - */ - -int list::is_less (element_list *a, element_list *b) -{ - // was if (is_intersection(a->minv+1, a->maxv-1, b->minv+1, b->maxv-1)) { - if (a->lineno < b->lineno) { - return( TRUE ); - } else if (a->lineno > b->lineno) { - return( FALSE ); - } else if (is_intersection(a->minv, a->maxv, b->minv, b->maxv)) { - return( a->minh < b->minh ); - } else { - return( a->maxv < b->maxv ); - } -} - -/* - * add - adds a datum to the list in the order specified by the region position. - */ - -void list::add (text_glob *in, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal) -{ - // create a new list element with datum and position fields initialized - element_list *t = new element_list(in, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - element_list *last; - - if (head == 0) { - head = t; - tail = t; - ptr = t; - t->left = t; - t->right = t; - } else { - last = tail; - - while ((last != head) && (is_less(t, last))) { - last = last->left; - } - - if (is_less(t, last)) { - t->right = last; - last->left->right = t; - t->left = last->left; - last->left = t; - // now check for a new head - if (last == head) { - head = t; - } - } else { - // add t beyond last - t->right = last->right; - t->left = last; - last->right->left = t; - last->right = t; - // now check for a new tail - if (last == tail) { - tail = t; - } - } - } -} - -/* - * sub_move_right - removes the element which is currently pointed to by ptr - * from the list and moves ptr to the right. - */ - -void list::sub_move_right (void) -{ - element_list *t=ptr->right; - - if (head == tail) { - head = 0; - if (tail != 0) { - delete tail; - } - tail = 0; - ptr = 0; - } else { - if (head == ptr) { - head = head->right; - } - if (tail == ptr) { - tail = tail->left; - } - ptr->left->right = ptr->right; - ptr->right->left = ptr->left; - ptr=t; - } -} - -/* - * start_from_head - assigns ptr to the head. - */ - -void list::start_from_head (void) -{ - ptr = head; -} - -/* - * start_from_tail - assigns ptr to the tail. - */ - -void list::start_from_tail (void) -{ - ptr = tail; -} - -/* - * is_empty - returns TRUE if the list has no elements. - */ - -int list::is_empty (void) -{ - return( head == 0 ); -} - -/* - * is_equal_to_tail - returns TRUE if the ptr equals the tail. - */ - -int list::is_equal_to_tail (void) -{ - return( ptr == tail ); -} - -/* - * is_equal_to_head - returns TRUE if the ptr equals the head. - */ - -int list::is_equal_to_head (void) -{ - return( ptr == head ); -} - -/* - * move_left - moves the ptr left. - */ - -void list::move_left (void) -{ - ptr = ptr->left; -} - -/* - * move_right - moves the ptr right. - */ - -void list::move_right (void) -{ - ptr = ptr->right; -} - -/* - * get_datum - returns the datum referenced via ptr. - */ - -text_glob* list::get_data (void) -{ - return( ptr->datum ); -} - -/* - * move_right_get_data - returns the datum referenced via ptr and moves - * ptr right. - */ - -text_glob* list::move_right_get_data (void) -{ - ptr = ptr->right; - if (ptr == head) { - return( 0 ); - } else { - return( ptr->datum ); - } -} - -/* - * move_left_get_data - returns the datum referenced via ptr and moves - * ptr right. - */ - -text_glob* list::move_left_get_data (void) -{ - ptr = ptr->left; - if (ptr == tail) { - return( 0 ); - } else { - return( ptr->datum ); - } -} - -/* - * insert - inserts data after the current position. - */ - -void list::insert (text_glob *in) -{ - if (is_empty()) - fatal("list must not be empty if we are inserting data"); - else { - if (ptr == 0) - ptr = head; - - element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, ptr->maxv, ptr->maxh); - if (ptr == tail) - tail = t; - ptr->right->left = t; - t->right = ptr->right; - ptr->right = t; - t->left = ptr; - } -} - -/* - * move_to - moves the current position to the point where data, in, exists. - * This is an expensive method and should be used sparingly. - */ - -void list::move_to (text_glob *in) -{ - ptr = head; - while (ptr != tail && ptr->datum != in) - ptr = ptr->right; -} - -/* - * page class and methods - */ - -class page { -public: - page (void); - void add (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_tag (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_and_encode (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_line (style *s, - int line_number, - int x1, int y1, int x2, int y2, - int thickness); - void insert_tag (const string &str); - void dump_page (void); // debugging method - - // and the data - - list glyphs; // position of glyphs and specials on page - char_buffer buffer; // all characters for this page -}; - -page::page() -{ -} - -/* - * insert_tag - inserts a tag after the current position. - */ - -void page::insert_tag (const string &str) -{ - if (str.length() > 0) { - text_glob *g=new text_glob(); - text_glob *f=glyphs.get_data(); - g->text_glob_tag(&f->text_style, buffer.add_string(str), str.length(), - f->minv, f->minh, f->maxv, f->maxh); - glyphs.insert(g); - } -} - -/* - * add - add html text to the list of glyphs. - */ - -void page::add (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - if (str.length() > 0) { - text_glob *g=new text_glob(); - g->text_glob_html(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * add_tag - adds a troff tag, for example: .tl .sp .br - */ - -void page::add_tag (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - if (str.length() > 0) { - text_glob *g; - - if (strncmp((str+'\0').contents(), "html-tag:.auto-image", 20) == 0) { - g = new text_glob(); - g->text_glob_auto_image(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - } else { - g = new text_glob(); - g->text_glob_tag(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - } - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * add_line - adds the <line> primitive providing that y1==y2 - */ - -void page::add_line (style *s, - int line_number, - int x1, int y1, int x2, int y2, - int thickness) -{ - if (y1 == y2) { - text_glob *g = new text_glob(); - g->text_glob_line(s, - min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2), - thickness); - glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2)); - } -} - -/* - * to_unicode - returns a unicode translation of int, ch. - */ - -static char *to_unicode (unsigned int ch) -{ - static char buf[30]; - - sprintf(buf, "&#%u;", ch); - return buf; -} - -/* - * add_and_encode - adds a special string to the page, it translates the string - * into html glyphs. The special string will have come from x X html: - * and can contain troff character encodings which appear as - * \(char\). A sequence of \\ represents \. - * So for example we can write: - * "cost = \(Po\)3.00 file = \\foo\\bar" - * which is translated into: - * "cost = £3.00 file = \foo\bar" - */ - -void page::add_and_encode (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - string html_string; - char *html_glyph; - int i=0; - - if (s->f == NULL) - return; - while (i < str.length()) { - if ((i+1<str.length()) && (str.substring(i, 2) == string("\\("))) { - // start of escape - i += 2; // move over \( - int a = i; - while ((i+1<str.length()) && (str.substring(i, 2) != string("\\)"))) { - i++; - } - int n = i; - if ((i+1<str.length()) && (str.substring(i, 2) == string("\\)"))) - i++; - else - n = -1; - if (n > 0) { - string troff_charname = str.substring(a, n-a); - html_glyph = get_html_translation(s->f, troff_charname); - if (html_glyph) - html_string += html_glyph; - else { - int index=s->f->name_to_index((troff_charname + '\0').contents()); - - if (s->f->contains(index) && (index != 0)) - html_string += s->f->get_code(index); - } - } - } else - html_string += str[i]; - i++; - } - if (html_string.length() > 0) { - text_glob *g=new text_glob(); - g->text_glob_special(s, buffer.add_string(html_string), html_string.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * dump_page - dump the page contents for debugging purposes. - */ - -void page::dump_page(void) -{ -#if defined(DEBUG_TABLES) - text_glob *old_pos = glyphs.get_data(); - text_glob *g; - - printf("\n<!--\n"); - printf("\n\ndebugging start\n"); - glyphs.start_from_head(); - do { - g = glyphs.get_data(); - if (g->is_tab_ts()) { - printf("\n\n"); - if (g->get_table() != NULL) - g->get_table()->dump_table(); - } - printf("%s ", g->text_string); - if (g->is_tab_te()) - printf("\n\n"); - glyphs.move_right(); - } while (! glyphs.is_equal_to_head()); - glyphs.move_to(old_pos); - printf("\ndebugging end\n\n"); - printf("\n-->\n"); - fflush(stdout); -#endif -} - -/* - * font classes and methods - */ - -class html_font : public font { - html_font(const char *); -public: - int encoding_index; - char *encoding; - char *reencoded_name; - ~html_font(); - static html_font *load_html_font(const char *); -}; - -html_font *html_font::load_html_font(const char *s) -{ - html_font *f = new html_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -html_font::html_font(const char *nm) -: font(nm) -{ -} - -html_font::~html_font() -{ -} - -/* - * a simple class to contain the header to this document - */ - -class title_desc { -public: - title_desc (); - ~title_desc (); - - int has_been_written; - int has_been_found; - int with_h1; - string text; -}; - - -title_desc::title_desc () - : has_been_written(FALSE), has_been_found(FALSE), with_h1(FALSE) -{ -} - -title_desc::~title_desc () -{ -} - -class header_desc { -public: - header_desc (); - ~header_desc (); - - int no_of_headings; // how many headings have we found? - char_buffer headings; // all the headings used in the document - list headers; // list of headers built from .NH and .SH - int header_level; // current header level - int written_header; // have we written the header yet? - string header_buffer; // current header text - - void write_headings (FILE *f, int force); -}; - -header_desc::header_desc () - : no_of_headings(0), header_level(2), written_header(0) -{ -} - -header_desc::~header_desc () -{ -} - -/* - * write_headings - emits a list of links for the headings in this document - */ - -void header_desc::write_headings (FILE *f, int force) -{ - text_glob *g; - - if (auto_links || force) { - if (! headers.is_empty()) { - int h=1; - - headers.start_from_head(); - do { - g = headers.get_data(); - fputs("<a href=\"#", f); - if (simple_anchors) { - string buffer(ANCHOR_TEMPLATE); - - buffer += as_string(h); - buffer += '\0'; - fprintf(f, buffer.contents()); - } else - fputs(g->text_string, f); - h++; - fputs("\">", f); - fputs(g->text_string, f); - fputs("</a><br>\n", f); - headers.move_right(); - } while (! headers.is_equal_to_head()); - fputs("\n", f); - } - } -} - -class html_printer : public printer { - files file_list; - simple_output html; - int res; - int space_char_index; - int space_width; - int no_of_printed_pages; - int paper_length; - string sbuf; - int sbuf_start_hpos; - int sbuf_vpos; - int sbuf_end_hpos; - int sbuf_prev_hpos; - int sbuf_kern; - style sbuf_style; - int last_sbuf_length; - int overstrike_detected; - style output_style; - int output_hpos; - int output_vpos; - int output_vpos_max; - int output_draw_point_size; - int line_thickness; - int output_line_thickness; - unsigned char output_space_code; - char *inside_font_style; - int page_number; - title_desc title; - header_desc header; - int header_indent; - int supress_sub_sup; - int cutoff_heading; - page *page_contents; - html_text *current_paragraph; - html_indent *indent; - html_table *table; - int end_center; - int end_tempindent; - TAG_ALIGNMENT next_tag; - int fill_on; - int max_linelength; - int linelength; - int pageoffset; - int indentation; - int prev_indent; - int pointsize; - int vertical_spacing; - int line_number; - color *background; - - void flush_sbuf (); - void set_style (const style &); - void set_space_code (unsigned char c); - void do_exec (char *, const environment *); - void do_import (char *, const environment *); - void do_def (char *, const environment *); - void do_mdef (char *, const environment *); - void do_file (char *, const environment *); - void set_line_thickness (const environment *); - void terminate_current_font (void); - void flush_font (void); - void add_to_sbuf (int index, const string &s); - void write_title (int in_head); - int sbuf_continuation (int index, const char *name, const environment *env, int w); - void flush_page (void); - void troff_tag (text_glob *g); - void flush_globs (void); - void emit_line (text_glob *g); - void emit_raw (text_glob *g); - void emit_html (text_glob *g); - void determine_space (text_glob *g); - void start_font (const char *name); - void end_font (const char *name); - int is_font_courier (font *f); - int is_courier_until_eol (void); - void start_size (int from, int to); - void do_font (text_glob *g); - void do_center (char *arg); - void do_break (void); - void do_eol (void); - void do_eol_ce (void); - void do_title (void); - void do_fill (int on); - void do_heading (char *arg); - void write_header (void); - void determine_header_level (int level); - void do_linelength (char *arg); - void do_pageoffset (char *arg); - void do_indentation (char *arg); - void do_tempindent (char *arg); - void do_indentedparagraph (void); - void do_verticalspacing (char *arg); - void do_pointsize (char *arg); - void do_centered_image (void); - void do_left_image (void); - void do_right_image (void); - void do_auto_image (text_glob *g, const char *filename); - void do_links (void); - void do_flush (void); - int is_in_middle (int left, int right); - void do_sup_or_sub (text_glob *g); - int start_subscript (text_glob *g); - int end_subscript (text_glob *g); - int start_superscript (text_glob *g); - int end_superscript (text_glob *g); - void outstanding_eol (int n); - int is_bold (font *f); - font *make_bold (font *f); - int overstrike (int index, const char *name, const environment *env, int w); - void do_body (void); - int next_horiz_pos (text_glob *g, int nf); - void lookahead_for_tables (void); - void insert_tab_te (void); - text_glob *insert_tab_ts (text_glob *where); - void insert_tab0_foreach_tab (void); - void insert_tab_0 (text_glob *where); - void do_indent (int in, int pageoff, int linelen); - void shutdown_table (void); - void do_tab_ts (text_glob *g); - void do_tab_te (void); - void do_col (char *s); - void do_tab (char *s); - void do_tab0 (void); - int calc_nf (text_glob *g, int nf); - void calc_po_in (text_glob *g, int nf); - void remove_tabs (void); - void remove_courier_tabs (void); - void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g); - void add_table_end (char *debug_string); - // ADD HERE - -public: - html_printer (); - ~html_printer (); - void set_char (int i, font *f, const environment *env, int w, const char *name); - void draw (int code, int *p, int np, const environment *env); - void begin_page (int); - void end_page (int); - void special (char *arg, const environment *env, char type); - font *make_font (const char *); - void end_of_line (); -}; - -printer *make_printer() -{ - return new html_printer; -} - -static void usage(FILE *stream); - -void html_printer::set_style(const style &sty) -{ - const char *fontname = sty.f->get_name(); - if (fontname == NULL) - fatal("no internalname specified for font"); - -#if 0 - change_font(fontname, (font::res/(72*font::sizescale))*sty.point_size); -#endif -} - -/* - * is_bold - returns TRUE if font, f, is bold. - */ - -int html_printer::is_bold (font *f) -{ - const char *fontname = f->get_name(); - return (strcmp(fontname, "B") == 0) || (strcmp(fontname, "BI") == 0); -} - -/* - * make_bold - if a bold font of, f, exists then return it. - */ - -font *html_printer::make_bold (font *f) -{ - const char *fontname = f->get_name(); - - if (strcmp(fontname, "B") == 0) - return f; - if (strcmp(fontname, "I") == 0) - return font::load_font("BI"); - if (strcmp(fontname, "BI") == 0) - return f; - return NULL; -} - -void html_printer::end_of_line() -{ - flush_sbuf(); - line_number++; -} - -/* - * emit_line - writes out a horizontal rule. - */ - -void html_printer::emit_line (text_glob *g) -{ - // --fixme-- needs to know the length in percentage - html.put_string("<hr>"); -} - -/* - * emit_raw - writes the raw html information directly to the device. - */ - -void html_printer::emit_raw (text_glob *g) -{ - do_font(g); - if (next_tag == INLINE) { - determine_space(g); - current_paragraph->do_emittext(g->text_string, g->text_length); - } else { - current_paragraph->done_para(); - switch (next_tag) { - - case CENTERED: - current_paragraph->do_para("align=center"); - break; - case LEFT: - current_paragraph->do_para(&html, "align=left", indentation, pageoffset, linelength); - break; - case RIGHT: - current_paragraph->do_para(&html, "align=right", indentation, pageoffset, linelength); - break; - default: - fatal("unknown enumeration"); - } - current_paragraph->do_emittext(g->text_string, g->text_length); - current_paragraph->done_para(); - next_tag = INLINE; - supress_sub_sup = TRUE; - if (indentation > 0) { - /* - * restore indentation - */ - int newin = indentation; - indentation = 0; - do_indent(newin, pageoffset, linelength); - } - } -} - -/* - * do_center - handle the .ce commands from troff. - */ - -void html_printer::do_center (char *arg) -{ - int n = atoi(arg); - current_paragraph->do_break(); - - if (n > 0) { - current_paragraph->done_para(); - supress_sub_sup = TRUE; - current_paragraph->do_para("align=center"); - end_center += n; - } else { - end_center = 0; - current_paragraph->remove_para_align(); - } -} - -/* - * do_centered_image - set a flag such that the next html-tag is - * placed inside a centered paragraph. - */ - -void html_printer::do_centered_image (void) -{ - next_tag = CENTERED; -} - -/* - * do_right_image - set a flag such that the next html-tag is - * placed inside a right aligned paragraph. - */ - -void html_printer::do_right_image (void) -{ - next_tag = RIGHT; -} - -/* - * do_left_image - set a flag such that the next html-tag is - * placed inside a left aligned paragraph. - */ - -void html_printer::do_left_image (void) -{ - next_tag = LEFT; -} - -/* - * exists - returns TRUE if filename exists. - */ - -static int exists (const char *filename) -{ - FILE *fp = fopen(filename, "r"); - - if (fp == 0) { - return( FALSE ); - } else { - fclose(fp); - return( TRUE ); - } -} - -/* - * generate_img_src - returns a html image tag for the filename - * providing that the image exists. - */ - -static string &generate_img_src (const char *filename) -{ - string *s = new string(""); - - while (filename && (filename[0] == ' ')) { - filename++; - } - if (exists(filename)) - *s += string("<img src=\"") + filename + "\">"; - return *s; -} - -/* - * do_auto_image - tests whether the image, indicated by filename, - * is present, if so then it emits an html image tag. - * An image tag may be passed through from pic, eqn - * but the corresponding image might not be created. - * Consider .EQ delim $$ .EN or an empty .PS .PE. - */ - -void html_printer::do_auto_image (text_glob *g, const char *filename) -{ - string buffer = generate_img_src(filename); - - if (! buffer.empty()) { - /* - * utilize emit_raw by creating a new text_glob. - */ - text_glob h = *g; - - h.text_string = buffer.contents(); - h.text_length = buffer.length(); - emit_raw(&h); - } else - next_tag = INLINE; -} - -/* - * outstanding_eol - call do_eol, n, times. - */ - -void html_printer::outstanding_eol (int n) -{ - while (n > 0) { - do_eol(); - n--; - } -} - -/* - * do_title - handle the .tl commands from troff. - */ - -void html_printer::do_title (void) -{ - text_glob *t; - int removed_from_head; - int eol_ce = 0; - - if (page_number == 1) { - int found_title_start = FALSE; - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.sub_move_right(); /* move onto next word */ - do { - t = page_contents->glyphs.get_data(); - removed_from_head = FALSE; - if (t->is_auto_img()) { - string img = generate_img_src((char *)(t->text_string + 20)); - - if (! img.empty()) { - if (found_title_start) - title.text += " "; - found_title_start = TRUE; - title.has_been_found = TRUE; - title.text += img; - } - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } else if (t->is_eol_ce()) { - /* process the eol associated with .ce - */ - eol_ce++; - page_contents->glyphs.sub_move_right(); /* move onto next word */ - } else if (t->is_eol()) { - /* end of title found - */ - title.has_been_found = TRUE; - outstanding_eol(eol_ce); - return; - } else if (t->is_a_tag()) { - /* end of title found, but move back so that we read this tag and process it - */ - page_contents->glyphs.move_left(); /* move backwards to last word */ - title.has_been_found = TRUE; - outstanding_eol(eol_ce); - return; - } else if (found_title_start) { - title.text += " " + string(t->text_string, t->text_length); - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } else { - title.text += string(t->text_string, t->text_length); - found_title_start = TRUE; - title.has_been_found = TRUE; - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } - } while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head)); - } - outstanding_eol(eol_ce); - } -} - -void html_printer::write_header (void) -{ - if (! header.header_buffer.empty()) { - if (header.header_level > 7) { - header.header_level = 7; - } - - // firstly we must terminate any font and type faces - current_paragraph->done_para(); - supress_sub_sup = TRUE; - - if (cutoff_heading+2 > header.header_level) { - // now we save the header so we can issue a list of links - header.no_of_headings++; - style st; - - text_glob *h=new text_glob(); - h->text_glob_html(&st, - header.headings.add_string(header.header_buffer), - header.header_buffer.length(), - header.no_of_headings, header.header_level, - header.no_of_headings, header.header_level); - - header.headers.add(h, - header.no_of_headings, - header.no_of_headings, header.no_of_headings, - header.no_of_headings, header.no_of_headings); // and add this header to the header list - - // lastly we generate a tag - - html.nl().put_string("<a name=\""); - if (simple_anchors) { - string buffer(ANCHOR_TEMPLATE); - - buffer += as_string(header.no_of_headings); - buffer += '\0'; - html.put_string(buffer.contents()); - } else { - html.put_string(header.header_buffer); - } - html.put_string("\"></a>").nl(); - } - - if (manufacture_headings) { - // line break before a header - if (!current_paragraph->emitted_text()) - current_paragraph->do_space(); - // user wants manufactured headings which look better than <Hn></Hn> - if (header.header_level<4) { - html.put_string("<b><font size=\"+1\">"); - html.put_string(header.header_buffer); - html.put_string("</font></b>").nl(); - } - else { - html.put_string("<b>"); - html.put_string(header.header_buffer); - html.put_string("</b>").nl(); - } - } - else { - // and now we issue the real header - html.put_string("<h"); - html.put_number(header.header_level); - html.put_string(">"); - html.put_string(header.header_buffer); - html.put_string("</h"); - html.put_number(header.header_level); - html.put_string(">").nl(); - } - - current_paragraph->do_para(&html, "", indentation, pageoffset, linelength); - } -} - -void html_printer::determine_header_level (int level) -{ - if (level == 0) { - int i; - - for (i=0; ((i<header.header_buffer.length()) - && ((header.header_buffer[i] == '.') - || is_digit(header.header_buffer[i]))) ; i++) { - if (header.header_buffer[i] == '.') { - level++; - } - } - } - header.header_level = level+1; -} - -/* - * do_heading - handle the .SH and .NH and equivalent commands from troff. - */ - -void html_printer::do_heading (char *arg) -{ - text_glob *g; - text_glob *l = 0; - int level=atoi(arg); - - header.header_buffer.clear(); - page_contents->glyphs.move_right(); - if (! page_contents->glyphs.is_equal_to_head()) { - g = page_contents->glyphs.get_data(); - do { - if (g->is_auto_img()) { - string img=generate_img_src((char *)(g->text_string + 20)); - - if (! img.empty()) { - simple_anchors = TRUE; // we cannot use full heading anchors with images - if (l != 0) - header.header_buffer += " "; - - l = g; - header.header_buffer += img; - } - } else if (! (g->is_a_line() || g->is_a_tag())) { - /* - * we ignore tags commands when constructing a heading - */ - if (l != 0) - header.header_buffer += " "; - l = g; - - header.header_buffer += string(g->text_string, g->text_length); - } - page_contents->glyphs.move_right(); - g = page_contents->glyphs.get_data(); - } while ((! page_contents->glyphs.is_equal_to_head()) && - (! g->is_br())); - } - - determine_header_level(level); - write_header(); - - // finally set the output to neutral for after the header - g = page_contents->glyphs.get_data(); - page_contents->glyphs.move_left(); // so that next time we use old g -} - -/* - * is_courier_until_eol - returns TRUE if we can see a whole line which is courier - */ - -int html_printer::is_courier_until_eol (void) -{ - text_glob *orig = page_contents->glyphs.get_data(); - int result = TRUE; - text_glob *g; - - if (! page_contents->glyphs.is_equal_to_tail()) { - page_contents->glyphs.move_right(); - do { - g = page_contents->glyphs.get_data(); - if (! g->is_a_tag() && (! is_font_courier(g->text_style.f))) - result = FALSE; - page_contents->glyphs.move_right(); - } while (result && - (! page_contents->glyphs.is_equal_to_head()) && - (! g->is_fi()) && (! g->is_eol())); - - /* - * now restore our previous position. - */ - while (page_contents->glyphs.get_data() != orig) - page_contents->glyphs.move_left(); - } - return result; -} - -/* - * do_linelength - handle the .ll command from troff. - */ - -void html_printer::do_linelength (char *arg) -{ - if (max_linelength == -1) - max_linelength = atoi(arg); - - if (fill_on) - do_indent(indentation, pageoffset, atoi(arg)); -} - -/* - * do_pageoffset - handle the .po command from troff. - */ - -void html_printer::do_pageoffset (char *arg) -{ - if (fill_on) - do_indent(indentation, atoi(arg), linelength); -} - -/* - * do_indentation - handle the .in command from troff. - */ - -void html_printer::do_indentation (char *arg) -{ - if (fill_on) - do_indent(atoi(arg), pageoffset, linelength); -} - -/* - * do_tempindent - handle the .ti command from troff. - */ - -void html_printer::do_tempindent (char *arg) -{ - if (fill_on) { - end_tempindent = 1; - prev_indent = indentation; - do_indent(atoi(arg), pageoffset, linelength); - } -} - -/* - * shutdown_table - shuts down the current table. - */ - -void html_printer::shutdown_table (void) -{ - if (table != NULL) { - current_paragraph->done_para(); - table->emit_finish_table(); - // dont delete this table as it will be deleted when we destroy the text_glob - table = NULL; - } -} - -/* - * do_indent - remember the indent parameters and if - * indent is > pageoff and indent has changed - * then we start a html table to implement the indentation. - */ - -void html_printer::do_indent (int in, int pageoff, int linelen) -{ - if ((indentation != -1) && - (pageoffset+indentation != in+pageoff)) { - - current_paragraph->done_para(); - - indentation = in; - pageoffset = pageoff; - if (linelen <= max_linelength) - linelength = linelen; - - current_paragraph->do_para(&html, "", indentation, pageoffset, max_linelength); - } -} - -/* - * do_verticalspacing - handle the .vs command from troff. - */ - -void html_printer::do_verticalspacing (char *arg) -{ - vertical_spacing = atoi(arg); -} - -/* - * do_pointsize - handle the .ps command from troff. - */ - -void html_printer::do_pointsize (char *arg) -{ - pointsize = atoi(arg); -} - -/* - * do_fill - records whether troff has requested that text be filled. - */ - -void html_printer::do_fill (int on) -{ - current_paragraph->do_break(); - output_hpos = indentation+pageoffset; - supress_sub_sup = TRUE; - - if (fill_on != on) { - if (on) - current_paragraph->do_para(""); - else - current_paragraph->do_pre(); - fill_on = on; - } -} - -/* - * do_eol - handle the end of line - */ - -void html_printer::do_eol (void) -{ - if (! fill_on) { - if (current_paragraph->ever_emitted_text()) { - current_paragraph->do_newline(); - current_paragraph->do_break(); - } - } - output_hpos = indentation+pageoffset; -} - -/* - * do_eol_ce - handle end of line specifically for a .ce - */ - -void html_printer::do_eol_ce (void) -{ - if (end_center > 0) { - if (end_center > 1) - if (current_paragraph->emitted_text()) - current_paragraph->do_break(); - - end_center--; - if (end_center == 0) { - current_paragraph->done_para(); - supress_sub_sup = TRUE; - } - } -} - -/* - * do_flush - flushes all output and tags. - */ - -void html_printer::do_flush (void) -{ - current_paragraph->done_para(); -} - -/* - * do_links - moves onto a new temporary file and sets auto_links to FALSE. - */ - -void html_printer::do_links (void) -{ - current_paragraph->done_para(); - auto_links = FALSE; /* from now on only emit under user request */ - file_list.add_new_file(xtmpfile()); - html.set_file(file_list.get_file()); -} - -/* - * do_break - handles the ".br" request and also - * undoes an outstanding ".ti" command. - */ - -void html_printer::do_break (void) -{ - current_paragraph->do_break(); - if (end_tempindent > 0) { - end_tempindent--; - if (end_tempindent == 0) - do_indent(prev_indent, pageoffset, linelength); - } - output_hpos = indentation+pageoffset; - supress_sub_sup = TRUE; -} - -/* - * do_tab_ts - start a table, which will have already been defined. - */ - -void html_printer::do_tab_ts (text_glob *g) -{ - html_table *t = g->get_table(); - - if (t != NULL) { - current_paragraph->done_pre(); - current_paragraph->done_para(); - - html.simple_comment("TABS"); - - t->set_linelength(max_linelength); - t->add_indent(pageoffset); - t->emit_table_header(FALSE); - } - - table = t; -} - -/* - * do_tab_te - finish a table. - */ - -void html_printer::do_tab_te (void) -{ - if (table) { - current_paragraph->done_para(); - table->emit_finish_table(); - } - - table = NULL; - - if (indentation > 0) { - /* - * restore indentation - */ - int newin = indentation; - indentation = 0; - do_indent(newin, pageoffset, linelength); - } -} - -/* - * do_tab - handle the "html-tag:tab" tag - */ - -void html_printer::do_tab (char *s) -{ - if (table) { - while (isspace(*s)) - s++; - s++; - int col = table->find_column(atoi(s) + pageoffset + indentation); - if (col > 0) { - current_paragraph->done_para(); - table->emit_col(col); - } - } -} - -/* - * do_tab0 - handle the "html-tag:tab0" tag - */ - -void html_printer::do_tab0 (void) -{ - if (table) { - int col = table->find_column(pageoffset+indentation); - if (col > 0) { - current_paragraph->done_para(); - table->emit_col(col); - } - } -} - -/* - * do_col - start column, s. - */ - -void html_printer::do_col (char *s) -{ - if (table) { - current_paragraph->done_para(); - table->emit_col(atoi(s)); - } -} - -/* - * troff_tag - processes the troff tag and manipulates the troff state machine. - */ - -void html_printer::troff_tag (text_glob *g) -{ - /* - * firstly skip over html-tag: - */ - char *t=(char *)g->text_string+9; - - if (g->is_eol()) { - do_eol(); - } else if (g->is_eol_ce()) { - do_eol_ce(); - } else if (strncmp(t, ".sp", 3) == 0) { - if (g->get_arg() > 0) - current_paragraph->do_space(); - else - current_paragraph->do_break(); - supress_sub_sup = TRUE; - } else if (strncmp(t, ".br", 3) == 0) { - do_break(); - } else if (strcmp(t, ".centered-image") == 0) { - do_centered_image(); - } else if (strcmp(t, ".right-image") == 0) { - do_right_image(); - } else if (strcmp(t, ".left-image") == 0) { - do_left_image(); - } else if (strncmp(t, ".auto-image", 11) == 0) { - char *a = (char *)t+11; - do_auto_image(g, a); - } else if (strncmp(t, ".ce", 3) == 0) { - char *a = (char *)t+3; - supress_sub_sup = TRUE; - do_center(a); - } else if (strncmp(t, ".tl", 3) == 0) { - supress_sub_sup = TRUE; - title.with_h1 = TRUE; - do_title(); - } else if (strncmp(t, ".html-tl", 8) == 0) { - supress_sub_sup = TRUE; - title.with_h1 = FALSE; - do_title(); - } else if (strncmp(t, ".fi", 3) == 0) { - do_fill(TRUE); - } else if (strncmp(t, ".nf", 3) == 0) { - do_fill(FALSE); - } else if ((strncmp(t, ".SH", 3) == 0) || (strncmp(t, ".NH", 3) == 0)) { - char *a = (char *)t+3; - do_heading(a); - } else if (strncmp(t, ".ll", 3) == 0) { - char *a = (char *)t+3; - do_linelength(a); - } else if (strncmp(t, ".po", 3) == 0) { - char *a = (char *)t+3; - do_pageoffset(a); - } else if (strncmp(t, ".in", 3) == 0) { - char *a = (char *)t+3; - do_indentation(a); - } else if (strncmp(t, ".ti", 3) == 0) { - char *a = (char *)t+3; - do_tempindent(a); - } else if (strncmp(t, ".vs", 3) == 0) { - char *a = (char *)t+3; - do_verticalspacing(a); - } else if (strncmp(t, ".ps", 3) == 0) { - char *a = (char *)t+3; - do_pointsize(a); - } else if (strcmp(t, ".links") == 0) { - do_links(); - } else if (strcmp(t, ".no-auto-rule") == 0) { - auto_rule = FALSE; - } else if (strcmp(t, ".tab-ts") == 0) { - do_tab_ts(g); - } else if (strcmp(t, ".tab-te") == 0) { - do_tab_te(); - } else if (strncmp(t, ".col ", 5) == 0) { - char *a = (char *)t+4; - do_col(a); - } else if (strncmp(t, "tab ", 4) == 0) { - char *a = (char *)t+3; - do_tab(a); - } else if (strncmp(t, "tab0", 4) == 0) { - do_tab0(); - } -} - -/* - * is_in_middle - returns TRUE if the positions left..right are in the center of the page. - */ - -int html_printer::is_in_middle (int left, int right) -{ - return( abs(abs(left-pageoffset) - abs(pageoffset+linelength-right)) <= CENTER_TOLERANCE ); -} - -/* - * flush_globs - runs through the text glob list and emits html. - */ - -void html_printer::flush_globs (void) -{ - text_glob *g; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - do { - g = page_contents->glyphs.get_data(); - - if (strcmp(g->text_string, "XXXXXXX") == 0) - stop(); - - if (g->is_a_tag()) { - troff_tag(g); - } else if (g->is_a_line()) { - emit_line(g); - } else { - emit_html(g); - } - /* - * after processing the title (and removing it) the glyph list might be empty - */ - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.move_right(); - } - } while (! page_contents->glyphs.is_equal_to_head()); - } -} - -/* - * calc_nf - calculates the _no_ format flag, given the - * text glob, g. - */ - -int html_printer::calc_nf (text_glob *g, int nf) -{ - if (g != NULL) { - if (g->is_fi()) - return FALSE; - if (g->is_nf()) - return TRUE; - } - return nf; -} - -/* - * calc_po_in - calculates the, in, po, registers - */ - -void html_printer::calc_po_in (text_glob *g, int nf) -{ - if (g->is_in()) - indentation = g->get_arg(); - else if (g->is_po()) - pageoffset = g->get_arg(); - else if (g->is_ti()) { - prev_indent = indentation; - indentation = g->get_arg(); - end_tempindent = 1; - } else if (g->is_br() && ((end_tempindent > 0) || (nf && g->is_eol()))) { - end_tempindent = 0; - indentation = prev_indent; - } -} - -/* - * next_horiz_pos - returns the next horiz position. - * -1 is returned if it doesn't exist. - */ - -int html_printer::next_horiz_pos (text_glob *g, int nf) -{ - int next = -1; - - if ((g != NULL) && (g->is_br() || (nf && g->is_eol()))) - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.move_right_get_data(); - if (g == NULL) - page_contents->glyphs.start_from_head(); - else { - next = g->minh; - page_contents->glyphs.move_left(); - } - } - return next; -} - -/* - * insert_tab_ts - inserts a tab-ts before, where. - */ - -text_glob *html_printer::insert_tab_ts (text_glob *where) -{ - text_glob *start_of_table; - text_glob *old_pos = page_contents->glyphs.get_data(); - - page_contents->glyphs.move_to(where); - page_contents->glyphs.move_left(); - page_contents->insert_tag(string("html-tag:.tab-ts")); // tab table start - page_contents->glyphs.move_right(); - start_of_table = page_contents->glyphs.get_data(); - page_contents->glyphs.move_to(old_pos); - return start_of_table; -} - -/* - * insert_tab_te - inserts a tab-te before the current position - * (it skips backwards over .sp/.br) - */ - -void html_printer::insert_tab_te (void) -{ - text_glob *g = page_contents->glyphs.get_data(); - page_contents->dump_page(); - - while (page_contents->glyphs.get_data()->is_a_tag()) - page_contents->glyphs.move_left(); - - page_contents->insert_tag(string("html-tag:.tab-te")); // tab table end - while (g != page_contents->glyphs.get_data()) - page_contents->glyphs.move_right(); - page_contents->dump_page(); -} - -/* - * insert_tab_0 - inserts a tab0 before, where. - */ - -void html_printer::insert_tab_0 (text_glob *where) -{ - text_glob *old_pos = page_contents->glyphs.get_data(); - - page_contents->glyphs.move_to(where); - page_contents->glyphs.move_left(); - page_contents->insert_tag(string("html-tag:tab0")); // tab0 start of line - page_contents->glyphs.move_right(); - page_contents->glyphs.move_to(old_pos); -} - -/* - * remove_tabs - removes the tabs tags on this line. - */ - -void html_printer::remove_tabs (void) -{ - text_glob *orig = page_contents->glyphs.get_data(); - text_glob *g; - - if (! page_contents->glyphs.is_equal_to_tail()) { - do { - g = page_contents->glyphs.get_data(); - if (g->is_tab()) { - page_contents->glyphs.sub_move_right(); - if (g == orig) - orig = page_contents->glyphs.get_data(); - } else - page_contents->glyphs.move_right(); - } while ((! page_contents->glyphs.is_equal_to_head()) && - (! g->is_eol())); - - /* - * now restore our previous position. - */ - while (page_contents->glyphs.get_data() != orig) - page_contents->glyphs.move_left(); - } -} - -void html_printer::remove_courier_tabs (void) -{ - text_glob *g; - int line_start = TRUE; - int nf = FALSE; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - line_start = TRUE; - do { - g = page_contents->glyphs.get_data(); - - nf = calc_nf(g, nf); - - if (line_start) { - if (line_start && nf && is_courier_until_eol()) { - remove_tabs(); - g = page_contents->glyphs.get_data(); - } - } - - line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && g->is_eol()); - page_contents->glyphs.move_right(); - } while (! page_contents->glyphs.is_equal_to_head()); - } -} - -void html_printer::insert_tab0_foreach_tab (void) -{ - text_glob *start_of_line = NULL; - text_glob *g = NULL; - int seen_tab = FALSE; - int seen_col = FALSE; - int nf = FALSE; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - start_of_line = page_contents->glyphs.get_data(); - do { - g = page_contents->glyphs.get_data(); - - nf = calc_nf(g, nf); - - if (g->is_tab()) - seen_tab = TRUE; - - if (g->is_col()) - seen_col = TRUE; - - if (g->is_br() || (nf && g->is_eol())) { - do { - page_contents->glyphs.move_right(); - g = page_contents->glyphs.get_data(); - nf = calc_nf(g, nf); - if (page_contents->glyphs.is_equal_to_head()) { - if (seen_tab && !seen_col) - insert_tab_0(start_of_line); - return; - } - } while (g->is_br() || (nf && g->is_eol()) || g->is_ta()); - // printf("\nstart_of_line is: %s\n", g->text_string); - if (seen_tab && !seen_col) { - insert_tab_0(start_of_line); - page_contents->glyphs.move_to(g); - } - - seen_tab = FALSE; - seen_col = FALSE; - start_of_line = g; - } - page_contents->glyphs.move_right(); - } while (! page_contents->glyphs.is_equal_to_head()); - if (seen_tab && !seen_col) - insert_tab_0(start_of_line); - - } -} - -/* - * update_min_max - updates the extent of a column, given the left and right - * extents of a glyph, g. - */ - -void html_printer::update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g) -{ - switch (type_of_col) { - - case tab_tag: - break; - case tab0_tag: - *minimum = g->minh; - break; - case col_tag: - *minimum = g->minh; - *maximum = g->maxh; - break; - default: - break; - } -} - -/* - * add_table_end - moves left one glyph, adds a table end tag and adds a - * debugging string. - */ - -void html_printer::add_table_end (char *debug_string) -{ - page_contents->glyphs.move_left(); - insert_tab_te(); -#if defined(DEBUG_TABLES) - page_contents->insert_tag(string(debug_string)); -#endif -} - -/* - * lookahead_for_tables - checks for .col tags and inserts table start/end tags - */ - -void html_printer::lookahead_for_tables (void) -{ - text_glob *g; - text_glob *start_of_line = NULL; - text_glob *start_of_table = NULL; - text_glob *last = NULL; - colType type_of_col = none; - int left = 0; - int found_col = FALSE; - int seen_text = FALSE; - int ncol = 0; - int colmin; - int colmax; - html_table *table = new html_table(&html, -1); - const char *tab_defs = NULL; - char align = 'L'; - int nf = FALSE; - int old_pageoffset = pageoffset; - - remove_courier_tabs(); - page_contents->dump_page(); - insert_tab0_foreach_tab(); - page_contents->dump_page(); - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - g = page_contents->glyphs.get_data(); - do { -#if defined(DEBUG_TABLES) - fprintf(stderr, " [") ; - fprintf(stderr, g->text_string) ; - fprintf(stderr, "] ") ; - fflush(stderr); - if (strcmp(g->text_string, "XXXXXXX") == 0) - stop(); -#endif - - nf = calc_nf(g, nf); - calc_po_in(g, nf); - if (g->is_col()) { - if (type_of_col == tab_tag && start_of_table != NULL) { - page_contents->glyphs.move_left(); - insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - page_contents->insert_tag(string("*** TAB -> COL ***")); - if (tab_defs != NULL) - table->tab_stops->init(tab_defs); - start_of_table = NULL; - last = NULL; - } - type_of_col = col_tag; - found_col = TRUE; - ncol = g->get_arg(); - align = 'L'; - colmin = 0; - colmax = 0; - } else if (g->is_tab()) { - type_of_col = tab_tag; - colmin = g->get_tab_args(&align); - align = 'L'; // for now as 'C' and 'R' are broken - ncol = table->find_tab_column(colmin); - colmin += pageoffset + indentation; - colmax = table->get_tab_pos(ncol+1); - if (colmax > 0) - colmax += pageoffset + indentation; - } else if (g->is_tab0()) { - if (type_of_col == col_tag && start_of_table != NULL) { - page_contents->glyphs.move_left(); - insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - page_contents->insert_tag(string("*** COL -> TAB ***")); - start_of_table = NULL; - last = NULL; - } - if (tab_defs != NULL) - table->tab_stops->init(tab_defs); - - type_of_col = tab0_tag; - ncol = 1; - colmin = 0; - colmax = table->get_tab_pos(2) + pageoffset + indentation; - } else if (! g->is_a_tag()) - update_min_max(type_of_col, &colmin, &colmax, g); - - if ((! g->is_a_tag()) || g->is_tab()) - seen_text = TRUE; - - if ((g->is_col() || g->is_tab() || g->is_tab0()) - && (start_of_line != NULL) && (start_of_table == NULL)) { - start_of_table = insert_tab_ts(start_of_line); - start_of_line = NULL; - seen_text = FALSE; - } else if (g->is_ce() && (start_of_table != NULL)) { - add_table_end("*** CE ***"); - start_of_table->remember_table(table); - start_of_table = NULL; - last = NULL; - } else if (g->is_ta()) { - tab_defs = g->text_string; - if (!table->tab_stops->compatible(tab_defs)) { - if (start_of_table != NULL) { - add_table_end("*** TABS ***"); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - start_of_table = NULL; - type_of_col = none; - last = NULL; - } - table->tab_stops->init(tab_defs); - } - } - - if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) { - // we are in a table and have a glyph - if ((ncol == 0) || (! table->add_column(ncol, colmin, colmax, align))) { - if (ncol == 0) - add_table_end("*** NCOL == 0 ***"); - else - add_table_end("*** CROSSED COLS ***"); - - start_of_table->remember_table(table); - table = new html_table(&html, -1); - start_of_table = NULL; - type_of_col = none; - last = NULL; - } - } - - /* - * move onto next glob, check whether we are starting a new line - */ - g = page_contents->glyphs.move_right_get_data(); - - if (g == NULL) { - if (found_col) { - page_contents->glyphs.start_from_head(); - last = g; - found_col = FALSE; - } - } else if (g->is_br() || (nf && g->is_eol())) { - do { - g = page_contents->glyphs.move_right_get_data(); - nf = calc_nf(g, nf); - } while ((g != NULL) && (g->is_br() || (nf && g->is_eol()))); - start_of_line = g; - seen_text = FALSE; - ncol = 0; - left = next_horiz_pos(g, nf); - if (found_col) - last = g; - found_col = FALSE; - } - } while ((g != NULL) && (! page_contents->glyphs.is_equal_to_head())); - -#if defined(DEBUG_TABLES) - fprintf(stderr, "finished scanning for tables\n"); -#endif - - page_contents->glyphs.start_from_head(); - if (start_of_table != NULL) { - if (last != NULL) - while (last != page_contents->glyphs.get_data()) - page_contents->glyphs.move_left(); - - insert_tab_te(); - start_of_table->remember_table(table); - table = NULL; - page_contents->insert_tag(string("*** LAST ***")); - } - } - if (table != NULL) - delete table; - - // and reset the registers - pageoffset = old_pageoffset; - indentation = 0; - prev_indent = 0; - end_tempindent = 0; -} - -void html_printer::flush_page (void) -{ - supress_sub_sup = TRUE; - flush_sbuf(); - page_contents->dump_page(); - lookahead_for_tables(); - page_contents->dump_page(); - - flush_globs(); - current_paragraph->done_para(); - - // move onto a new page - delete page_contents; -#if defined(DEBUG_TABLES) - fprintf(stderr, "\n\n*** flushed page ***\n\n"); - - html.simple_comment("new page called"); -#endif - page_contents = new page; -} - -/* - * determine_space - works out whether we need to write a space. - * If last glyph is ajoining then no space emitted. - */ - -void html_printer::determine_space (text_glob *g) -{ - if (current_paragraph->is_in_pre()) { - /* - * .nf has been specified - */ - while (output_hpos < g->minh) { - output_hpos += space_width; - current_paragraph->emit_space(); - } - } else { - if ((output_vpos != g->minv) || (output_hpos < g->minh)) { - current_paragraph->emit_space(); - } - } -} - -/* - * is_font_courier - returns TRUE if the font, f, is courier. - */ - -int html_printer::is_font_courier (font *f) -{ - if (f != 0) { - const char *fontname = f->get_name(); - - return( (fontname != 0) && (fontname[0] == 'C') ); - } - return( FALSE ); -} - -/* - * end_font - shuts down the font corresponding to fontname. - */ - -void html_printer::end_font (const char *fontname) -{ - if (strcmp(fontname, "B") == 0) { - current_paragraph->done_bold(); - } else if (strcmp(fontname, "I") == 0) { - current_paragraph->done_italic(); - } else if (strcmp(fontname, "BI") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - } else if (strcmp(fontname, "CR") == 0) { - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CI") == 0) { - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CB") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CBI") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } -} - -/* - * start_font - starts the font corresponding to name. - */ - -void html_printer::start_font (const char *fontname) -{ - if (strcmp(fontname, "R") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "B") == 0) { - current_paragraph->do_bold(); - } else if (strcmp(fontname, "I") == 0) { - current_paragraph->do_italic(); - } else if (strcmp(fontname, "BI") == 0) { - current_paragraph->do_bold(); - current_paragraph->do_italic(); - } else if (strcmp(fontname, "CR") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - } else if (strcmp(fontname, "CI") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_italic(); - } else if (strcmp(fontname, "CB") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_bold(); - } else if (strcmp(fontname, "CBI") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_italic(); - current_paragraph->do_bold(); - } -} - -/* - * start_size - from is old font size, to is the new font size. - * The html increase <big> and <small> decrease alters the - * font size by 20%. We try and map these onto glyph sizes. - */ - -void html_printer::start_size (int from, int to) -{ - if (from < to) { - while (from < to) { - current_paragraph->do_big(); - from += SIZE_INCREMENT; - } - } else if (from > to) { - while (from > to) { - current_paragraph->do_small(); - from -= SIZE_INCREMENT; - } - } -} - -/* - * do_font - checks to see whether we need to alter the html font. - */ - -void html_printer::do_font (text_glob *g) -{ - /* - * check if the output_style.point_size has not been set yet - * this allow users to place .ps at the top of their troff files - * and grohtml can then treat the .ps value as the base font size (3) - */ - if (output_style.point_size == -1) { - output_style.point_size = pointsize; - } - - if (g->text_style.f != output_style.f) { - if (output_style.f != 0) { - end_font(output_style.f->get_name()); - } - output_style.f = g->text_style.f; - if (output_style.f != 0) { - start_font(output_style.f->get_name()); - } - } - if (output_style.point_size != g->text_style.point_size) { - do_sup_or_sub(g); - if ((output_style.point_size > 0) && - (g->text_style.point_size > 0)) { - start_size(output_style.point_size, g->text_style.point_size); - } - if (g->text_style.point_size > 0) { - output_style.point_size = g->text_style.point_size; - } - } - if (output_style.col != g->text_style.col) { - current_paragraph->done_color(); - output_style.col = g->text_style.col; - current_paragraph->do_color(&output_style.col); - } -} - -/* - * start_subscript - returns TRUE if, g, looks like a subscript start. - */ - -int html_printer::start_subscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (output_vpos < g->minv) && - (output_vpos-height > g->maxv) && - (output_style.point_size > g->text_style.point_size) ); -} - -/* - * start_superscript - returns TRUE if, g, looks like a superscript start. - */ - -int html_printer::start_superscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (output_vpos > g->minv) && - (output_vpos-height < g->maxv) && - (output_style.point_size > g->text_style.point_size) ); -} - -/* - * end_subscript - returns TRUE if, g, looks like the end of a subscript. - */ - -int html_printer::end_subscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (g->minv < output_vpos) && - (output_vpos-height > g->maxv) && - (output_style.point_size < g->text_style.point_size) ); -} - -/* - * end_superscript - returns TRUE if, g, looks like the end of a superscript. - */ - -int html_printer::end_superscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (g->minv > output_vpos) && - (output_vpos-height < g->maxv) && - (output_style.point_size < g->text_style.point_size) ); -} - -/* - * do_sup_or_sub - checks to see whether the next glyph is a subscript/superscript - * start/end and it calls the services of html-text to issue the - * appropriate tags. - */ - -void html_printer::do_sup_or_sub (text_glob *g) -{ - if (! supress_sub_sup) { - if (start_subscript(g)) { - current_paragraph->do_sub(); - } else if (start_superscript(g)) { - current_paragraph->do_sup(); - } else if (end_subscript(g)) { - current_paragraph->done_sub(); - } else if (end_superscript(g)) { - current_paragraph->done_sup(); - } - } -} - -/* - * emit_html - write out the html text - */ - -void html_printer::emit_html (text_glob *g) -{ - do_font(g); - determine_space(g); - current_paragraph->do_emittext(g->text_string, g->text_length); - output_vpos = g->minv; - output_hpos = g->maxh; - output_vpos_max = g->maxv; - supress_sub_sup = FALSE; -} - -/* - * flush_sbuf - flushes the current sbuf into the list of glyphs. - */ - -void html_printer::flush_sbuf() -{ - if (sbuf.length() > 0) { - int r=font::res; // resolution of the device - set_style(sbuf_style); - if (overstrike_detected && (! is_bold(sbuf_style.f))) { - font *bold_font = make_bold(sbuf_style.f); - if (bold_font != NULL) - sbuf_style.f = bold_font; - } - - page_contents->add(&sbuf_style, sbuf, - line_number, - sbuf_vpos-sbuf_style.point_size*r/72, sbuf_start_hpos, - sbuf_vpos , sbuf_end_hpos); - - output_hpos = sbuf_end_hpos; - output_vpos = sbuf_vpos; - last_sbuf_length = 0; - sbuf_prev_hpos = sbuf_end_hpos; - overstrike_detected = FALSE; - sbuf.clear(); - } -} - -void html_printer::set_line_thickness(const environment *env) -{ - line_thickness = env->size; -} - -void html_printer::draw(int code, int *p, int np, const environment *env) -{ - switch (code) { - - case 'l': -# if 0 - if (np == 2) { - page_contents->add_line(&sbuf_style, - line_number, - env->hpos, env->vpos, env->hpos+p[0], env->vpos+p[1], line_thickness); - } else { - error("2 arguments required for line"); - } -# endif - 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 'P': - break; - case 'p': - break; - case 'E': - break; - case 'e': - break; - case 'C': - break; - case 'c': - break; - case 'a': - break; - case '~': - break; - case 'f': - break; - case 'F': - // fill with color env->fill - if (background != NULL) - delete background; - background = new color; - *background = *env->fill; - break; - - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } -} - -html_printer::html_printer() -: html(0, MAX_LINE_LENGTH), - no_of_printed_pages(0), - last_sbuf_length(0), - overstrike_detected(FALSE), - output_hpos(-1), - output_vpos(-1), - output_vpos_max(-1), - line_thickness(-1), - inside_font_style(0), - page_number(0), - header_indent(-1), - supress_sub_sup(TRUE), - cutoff_heading(100), - indent(NULL), - table(NULL), - end_center(0), - end_tempindent(0), - next_tag(INLINE), - fill_on(TRUE), - max_linelength(-1), - linelength(0), - pageoffset(0), - indentation(0), - prev_indent(0), - pointsize(0), - line_number(0), - background(default_background) -{ - file_list.add_new_file(xtmpfile()); - html.set_file(file_list.get_file()); - if (font::hor != 24) - fatal("horizontal resolution must be 24"); - if (font::vert != 40) - fatal("vertical resolution must be 40"); -#if 0 - // should be sorted html.. - if (font::res % (font::sizescale*72) != 0) - fatal("res must be a multiple of 72*sizescale"); -#endif - int r = font::res; - int point = 0; - while (r % 10 == 0) { - r /= 10; - point++; - } - res = r; - html.set_fixed_point(point); - space_char_index = font::name_to_index("space"); - space_width = font::hor; - paper_length = font::paperlength; - linelength = font::res*13/2; - if (paper_length == 0) - paper_length = 11*font::res; - - page_contents = new page(); -} - -/* - * add_to_sbuf - adds character code or name to the sbuf. - */ - -void html_printer::add_to_sbuf (int index, const string &s) -{ - if (sbuf_style.f == NULL) - return; - - char *html_glyph = NULL; - unsigned int code = sbuf_style.f->get_code(index); - - if (s.empty()) { - if (sbuf_style.f->contains(index)) - html_glyph = (char *)sbuf_style.f->get_special_device_encoding(index); - else - html_glyph = NULL; - - if ((html_glyph == NULL) && (code >= UNICODE_DESC_START)) - html_glyph = to_unicode(code); - } else - html_glyph = get_html_translation(sbuf_style.f, s); - - last_sbuf_length = sbuf.length(); - if (html_glyph == NULL) - sbuf += ((char)code); - else - sbuf += html_glyph; -} - -int html_printer::sbuf_continuation (int index, const char *name, - const environment *env, int w) -{ - /* - * lets see whether the glyph is closer to the end of sbuf - */ - if ((sbuf_end_hpos == env->hpos) - || ((sbuf_prev_hpos < sbuf_end_hpos) - && (env->hpos < sbuf_end_hpos) - && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) { - add_to_sbuf(index, name); - sbuf_prev_hpos = sbuf_end_hpos; - sbuf_end_hpos += w + sbuf_kern; - return TRUE; - } else { - if ((env->hpos >= sbuf_end_hpos) && - ((sbuf_kern == 0) || (sbuf_end_hpos - sbuf_kern != env->hpos))) { - /* - * lets see whether a space is needed or not - */ - - if (env->hpos-sbuf_end_hpos < space_width) { - add_to_sbuf(index, name); - sbuf_prev_hpos = sbuf_end_hpos; - sbuf_end_hpos = env->hpos + w; - return TRUE; - } - } - } - return FALSE ; -} - -/* - * get_html_translation - given the position of the character and its name - * return the device encoding for such character. - */ - -char *get_html_translation (font *f, const string &name) -{ - int index; - - if ((f == 0) || name.empty()) - return NULL; - else { - index = f->name_to_index((char *)(name + '\0').contents()); - if (index == 0) { - error("character `%s' not found", (name + '\0').contents()); - return NULL; - } else - if (f->contains(index)) - return (char *)f->get_special_device_encoding(index); - else - return NULL; - } -} - -/* - * overstrike - returns TRUE if the glyph (i, name) is going to overstrike - * a previous glyph in sbuf. - * If TRUE the font is changed to bold and the previous sbuf - * is flushed. - */ - -int html_printer::overstrike(int index, const char *name, const environment *env, int w) -{ - if ((env->hpos < sbuf_end_hpos) - || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) { - /* - * at this point we have detected an overlap - */ - if (overstrike_detected) { - /* already detected, remove previous glyph and use this glyph */ - sbuf.set_length(last_sbuf_length); - add_to_sbuf(index, name); - sbuf_end_hpos = env->hpos + w; - return TRUE; - } else { - /* first time we have detected an overstrike in the sbuf */ - sbuf.set_length(last_sbuf_length); /* remove previous glyph */ - if (! is_bold(sbuf_style.f)) - flush_sbuf(); - overstrike_detected = TRUE; - add_to_sbuf(index, name); - sbuf_end_hpos = env->hpos + w; - return TRUE; - } - } - return FALSE ; -} - -/* - * set_char - adds a character into the sbuf if it is a continuation with the previous - * word otherwise flush the current sbuf and add character anew. - */ - -void html_printer::set_char(int i, font *f, const environment *env, int w, const char *name) -{ - style sty(f, env->size, env->height, env->slant, env->fontno, *env->col); - if (sty.slant != 0) { - if (sty.slant > 80 || sty.slant < -80) { - error("silly slant `%1' degrees", sty.slant); - sty.slant = 0; - } - } - if (((! sbuf.empty()) && (sty == sbuf_style) && (sbuf_vpos == env->vpos)) - && (sbuf_continuation(i, name, env, w) || overstrike(i, name, env, w))) - return; - - flush_sbuf(); - add_to_sbuf(i, name); - sbuf_end_hpos = env->hpos + w; - sbuf_start_hpos = env->hpos; - sbuf_prev_hpos = env->hpos; - sbuf_vpos = env->vpos; - sbuf_style = sty; - sbuf_kern = 0; -} - -/* - * write_title - writes the title to this document - */ - -void html_printer::write_title (int in_head) -{ - if (title.has_been_found) { - if (in_head) { - html.put_string("<title>"); - html.put_string(title.text); - html.put_string("</title>").nl().nl(); - } else { - title.has_been_written = TRUE; - if (title.with_h1) { - html.put_string("<h1 align=center>"); - html.put_string(title.text); - html.put_string("</h1>").nl().nl(); - } - } - } else if (in_head) { - // place empty title tags to help conform to `tidy' - html.put_string("<title></title>").nl(); - } -} - -/* - * write_rule - emits a html rule tag, if the auto_rule boolean is true. - */ - -static void write_rule (void) -{ - if (auto_rule) - fputs("<hr>\n", stdout); -} - -void html_printer::begin_page(int n) -{ - page_number = n; -#if defined(DEBUGGING) - html.begin_comment("Page: ").put_string(i_to_a(page_number)).end_comment();; -#endif - no_of_printed_pages++; - - output_style.f = 0; - output_style.point_size= -1; - output_space_code = 32; - output_draw_point_size = -1; - output_line_thickness = -1; - output_hpos = -1; - output_vpos = -1; - output_vpos_max = -1; - current_paragraph = new html_text(&html); - do_indent(indentation, pageoffset, linelength); - current_paragraph->do_para(""); -} - -void html_printer::end_page(int) -{ - flush_sbuf(); - flush_page(); -} - -font *html_printer::make_font(const char *nm) -{ - return html_font::load_html_font(nm); -} - -void html_printer::do_body (void) -{ - if (background == NULL) - fputs("<body>\n\n", stdout); - else { - unsigned int r, g, b; - char buf[6+1]; - - background->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); - - fputs("<body bgcolor=\"#", stdout); - fputs(buf, stdout); - fputs("\">\n\n", stdout); - } -} - -html_printer::~html_printer() -{ -#ifdef LONG_FOR_TIME_T - long t; -#else - time_t t; -#endif - - current_paragraph->flush_text(); - html.end_line(); - html.set_file(stdout); - html.begin_comment("Creator : ") - .put_string("groff ") - .put_string("version ") - .put_string(Version_string) - .end_comment(); - - t = time(0); - html.begin_comment("CreationDate: ") - .put_string(ctime(&t), strlen(ctime(&t))-1) - .end_comment(); - - /* - * 'HTML: The definitive guide', O'Reilly, p47. advises against specifying - * the dtd. - */ - // fputs("<!doctype html public \"-//IETF//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n", stdout); - fputs("<html>\n", stdout); - fputs("<head>\n", stdout); - fputs("<meta name=\"generator\" content=\"groff -Thtml, see www.gnu.org\">\n", stdout); - fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout); - write_title(TRUE); - fputs("</head>\n", stdout); - do_body(); - - write_title(FALSE); - header.write_headings(stdout, FALSE); - write_rule(); -#if defined(DEBUGGING) - html.begin_comment("Total number of pages: ").put_string(i_to_a(no_of_printed_pages)).end_comment(); -#endif - html.end_line(); - html.end_line(); - /* - * now run through the file list copying each temporary file in turn and emitting the links. - */ - file_list.start_of_list(); - while (file_list.get_file() != 0) { - if (fseek(file_list.get_file(), 0L, 0) < 0) - fatal("fseek on temporary file failed"); - html.copy_file(file_list.get_file()); - fclose(file_list.get_file()); - file_list.move_next(); - if (file_list.get_file() != 0) - header.write_headings(stdout, TRUE); - } - write_rule(); - fputs("</body>\n", stdout); - fputs("</html>\n", stdout); -} - -/* - * special - handle all x X requests from troff. For post-html they allow users - * to pass raw html commands, turn auto linked headings off/on and - * also allow troff to emit tags to indicate when a: .br, .sp etc occurs. - */ - -void html_printer::special(char *s, const environment *env, char type) -{ - if (type != 'p') - return; - if (s != 0) { - flush_sbuf(); - if (env->fontno >= 0) { - style sty(get_font_from_index(env->fontno), env->size, env->height, - env->slant, env->fontno, *env->col); - sbuf_style = sty; - } - - if (strncmp(s, "html:", 5) == 0) { - int r=font::res; /* resolution of the device */ - font *f=sbuf_style.f; - - if (f == NULL) { - int found=FALSE; - - f = font::load_font("TR", &found); - } - - /* - * need to pass rest of string through to html output during flush - */ - page_contents->add_and_encode(&sbuf_style, string(&s[5]), - line_number, - env->vpos-env->size*r/72, env->hpos, - env->vpos , env->hpos); - - /* - * assume that the html command has no width, if it does then hopefully troff - * will have fudged this in a macro by requesting that the formatting move right by - * the appropriate amount. - */ - } else if (strncmp(s, "index:", 6) == 0) { - cutoff_heading = atoi(&s[6]); - } else if (strncmp(s, "html-tag:", 9) == 0) { - int r=font::res; /* resolution of the device */ - - page_contents->add_tag(&sbuf_style, string(s), - line_number, - env->vpos-env->size*r/72, env->hpos, - env->vpos , env->hpos); - } - } -} - -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, "a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL)) - != EOF) - switch(c) { - case 'v': - printf("GNU post-grohtml (groff) version %s\n", Version_string); - exit(0); - break; - case 'a': - /* text antialiasing bits - handled by pre-html */ - break; - case 'g': - /* graphic antialiasing bits - handled by pre-html */ - break; - case 'b': - // set background color to white - default_background = new color; - default_background->set_gray(color::MAX_COLOR_VAL); - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'l': - auto_links = FALSE; - break; - case 'r': - auto_rule = FALSE; - break; - case 'd': - /* handled by pre-html */ - break; - case 'h': - /* do not use the Hn headings of html, but manufacture our own */ - manufacture_headings = TRUE; - break; - case 'o': - /* handled by pre-html */ - break; - case 'p': - /* handled by pre-html */ - break; - case 'i': - /* handled by pre-html */ - break; - case 'I': - /* handled by pre-html */ - break; - case 'D': - /* handled by pre-html */ - break; - case 'n': - simple_anchors = TRUE; - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - 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 [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grolbp/lbp.cc b/contrib/groff/src/devices/grolbp/lbp.cc deleted file mode 100644 index 76db32a..0000000 --- a/contrib/groff/src/devices/grolbp/lbp.cc +++ /dev/null @@ -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; -} diff --git a/contrib/groff/src/devices/grolj4/lj4.cc b/contrib/groff/src/devices/grolj4/lj4.cc deleted file mode 100644 index 0c3150d..0000000 --- a/contrib/groff/src/devices/grolj4/lj4.cc +++ /dev/null @@ -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); -} diff --git a/contrib/groff/src/devices/grops/ps.cc b/contrib/groff/src/devices/grops/ps.cc deleted file mode 100644 index 47d1f65..0000000 --- a/contrib/groff/src/devices/grops/ps.cc +++ /dev/null @@ -1,1642 +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 "stringclass.h" -#include "cset.h" -#include "nonposix.h" -#include "paper.h" - -#include "ps.h" -#include <time.h> - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -extern "C" const char *Version_string; - -static int landscape_flag = 0; -static int manual_feed_flag = 0; -static int ncopies = 1; -static int linewidth = -1; -// Non-zero means generate PostScript code that guesses the paper -// length using the imageable area. -static int guess_flag = 0; -static double user_paper_length = 0; - -// Non-zero if -b was specified on the command line. -static int bflag = 0; -unsigned broken_flags = 0; - -#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */ -#define MAX_LINE_LENGTH 72 -#define FILL_MAX 1000 - -const char *const dict_name = "grops"; -const char *const defs_dict_name = "DEFS"; -const int DEFS_DICT_SPARE = 50; - -double degrees(double r) -{ - return r*180.0/PI; -} - -double radians(double d) -{ - return d*PI/180.0; -} - -inline double transform_fill(int fill) -{ - return 1 - fill/double(FILL_MAX); -} - -// This is used for testing whether a character should be output in the -// PostScript file using \nnn, so we really want the character to be -// less than 0200. - -inline int is_ascii(char c) -{ - return (unsigned char)c < 0200; -} - -ps_output::ps_output(FILE *f, int n) -: fp(f), col(0), max_line_length(n), need_space(0), fixed_point(0) -{ -} - -ps_output &ps_output::set_file(FILE *f) -{ - fp = f; - col = 0; - return *this; -} - -ps_output &ps_output::copy_file(FILE *infp) -{ - int c; - while ((c = getc(infp)) != EOF) - putc(c, fp); - return *this; -} - -ps_output &ps_output::end_line() -{ - if (col != 0) { - putc('\n', fp); - col = 0; - need_space = 0; - } - return *this; -} - -ps_output &ps_output::special(const char *s) -{ - if (s == 0 || *s == '\0') - return *this; - if (col != 0) { - putc('\n', fp); - col = 0; - } - fputs(s, fp); - if (strchr(s, '\0')[-1] != '\n') - putc('\n', fp); - need_space = 0; - return *this; -} - -ps_output &ps_output::simple_comment(const char *s) -{ - if (col != 0) - putc('\n', fp); - putc('%', fp); - putc('%', fp); - fputs(s, fp); - putc('\n', fp); - col = 0; - need_space = 0; - return *this; -} - -ps_output &ps_output::begin_comment(const char *s) -{ - if (col != 0) - putc('\n', fp); - putc('%', fp); - putc('%', fp); - fputs(s, fp); - col = 2 + strlen(s); - return *this; -} - -ps_output &ps_output::end_comment() -{ - if (col != 0) { - putc('\n', fp); - col = 0; - } - need_space = 0; - return *this; -} - -ps_output &ps_output::comment_arg(const char *s) -{ - int len = strlen(s); - if (col + len + 1 > max_line_length) { - putc('\n', fp); - fputs("%%+", fp); - col = 3; - } - putc(' ', fp); - fputs(s, fp); - col += len + 1; - return *this; -} - -ps_output &ps_output::set_fixed_point(int n) -{ - assert(n >= 0 && n <= 10); - fixed_point = n; - return *this; -} - -ps_output &ps_output::put_delimiter(char c) -{ - if (col + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc(c, fp); - col++; - need_space = 0; - return *this; -} - -ps_output &ps_output::put_string(const char *s, int n) -{ - int len = 0; - int i; - for (i = 0; i < n; i++) { - char c = s[i]; - if (is_ascii(c) && csprint(c)) { - if (c == '(' || c == ')' || c == '\\') - len += 2; - else - len += 1; - } - else - len += 4; - } - if (len > n*2) { - if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) { - putc('\n', fp); - col = 0; - } - if (col + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('<', fp); - col++; - for (i = 0; i < n; i++) { - if (col + 2 > max_line_length) { - putc('\n', fp); - col = 0; - } - fprintf(fp, "%02x", s[i] & 0377); - col += 2; - } - putc('>', fp); - col++; - } - else { - if (col + len + 2 > max_line_length && len + 2 <= max_line_length) { - putc('\n', fp); - col = 0; - } - if (col + 2 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('(', fp); - col++; - for (i = 0; i < n; i++) { - char c = s[i]; - if (is_ascii(c) && csprint(c)) { - if (c == '(' || c == ')' || c == '\\') - len = 2; - else - len = 1; - } - else - len = 4; - if (col + len + 1 > max_line_length) { - putc('\\', fp); - putc('\n', fp); - col = 0; - } - switch (len) { - case 1: - putc(c, fp); - break; - case 2: - putc('\\', fp); - putc(c, fp); - break; - case 4: - fprintf(fp, "\\%03o", c & 0377); - break; - default: - assert(0); - } - col += len; - } - putc(')', fp); - col++; - } - need_space = 0; - return *this; -} - -ps_output &ps_output::put_number(int n) -{ - char buf[1 + INT_DIGITS + 1]; - sprintf(buf, "%d", n); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_fix_number(int i) -{ - const char *p = if_to_a(i, fixed_point); - int len = strlen(p); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(p, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_float(double d) -{ - char buf[128]; - sprintf(buf, "%.3g", d); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_symbol(const char *s) -{ - int len = strlen(s); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(s, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_color(unsigned int c) -{ - char buf[128]; - sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_literal_symbol(const char *s) -{ - int len = strlen(s); - if (col > 0 && col + len + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('/', fp); - fputs(s, fp); - col += len + 1; - need_space = 1; - return *this; -} - -class ps_font : public font { - ps_font(const char *); -public: - int encoding_index; - char *encoding; - char *reencoded_name; - ~ps_font(); - void handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno); - static ps_font *load_ps_font(const char *); -}; - -ps_font *ps_font::load_ps_font(const char *s) -{ - ps_font *f = new ps_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -ps_font::ps_font(const char *nm) -: font(nm), encoding_index(-1), encoding(0), reencoded_name(0) -{ -} - -ps_font::~ps_font() -{ - a_delete encoding; - a_delete reencoded_name; -} - -void ps_font::handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "encoding") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`encoding' command requires an argument"); - else - encoding = strsave(arg); - } -} - -static void handle_unknown_desc_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "broken") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`broken' command requires an argument"); - else if (!bflag) - broken_flags = atoi(arg); - } -} - -struct style { - font *f; - int point_size; - int height; - int slant; - style(); - style(font *, int, int, int); - int operator==(const style &) const; - int operator!=(const style &) const; -}; - -style::style() : f(0) -{ -} - -style::style(font *p, int sz, int h, int sl) -: f(p), point_size(sz), height(h), slant(sl) -{ -} - -int style::operator==(const style &s) const -{ - return (f == s.f && point_size == s.point_size - && height == s.height && slant == s.slant); -} - -int style::operator!=(const style &s) const -{ - return !(*this == s); -} - -class ps_printer : public printer { - FILE *tempfp; - ps_output out; - int res; - int space_char_index; - int pages_output; - int paper_length; - int equalise_spaces; - enum { SBUF_SIZE = 256 }; - char sbuf[SBUF_SIZE]; - int sbuf_len; - int sbuf_start_hpos; - int sbuf_vpos; - int sbuf_end_hpos; - int sbuf_space_width; - int sbuf_space_count; - int sbuf_space_diff_count; - int sbuf_space_code; - int sbuf_kern; - style sbuf_style; - color sbuf_color; // the current PS color - style output_style; - int output_hpos; - int output_vpos; - int output_draw_point_size; - int line_thickness; - int output_line_thickness; - unsigned char output_space_code; - enum { MAX_DEFINED_STYLES = 50 }; - style defined_styles[MAX_DEFINED_STYLES]; - int ndefined_styles; - int next_encoding_index; - string defs; - int ndefs; - resource_manager rm; - int invis_count; - - void flush_sbuf(); - void set_style(const style &); - void set_space_code(unsigned char c); - int set_encoding_index(ps_font *); - void do_exec(char *, const environment *); - void do_import(char *, const environment *); - void do_def(char *, const environment *); - void do_mdef(char *, const environment *); - void do_file(char *, const environment *); - void do_invis(char *, const environment *); - void do_endinvis(char *, const environment *); - void set_line_thickness_and_color(const environment *); - void fill_path(const environment *); - void encode_fonts(); - void define_encoding(const char *, int); - void reencode_font(ps_font *); - void set_color(color *c, int fill = 0); - -public: - ps_printer(double); - ~ps_printer(); - void set_char(int i, font *f, const environment *env, int w, const char *name); - void draw(int code, int *p, int np, const environment *env); - void begin_page(int); - void end_page(int); - void special(char *arg, const environment *env, char type); - font *make_font(const char *); - void end_of_line(); -}; - -// `pl' is in inches -ps_printer::ps_printer(double pl) -: out(0, MAX_LINE_LENGTH), - pages_output(0), - sbuf_len(0), - output_hpos(-1), - output_vpos(-1), - line_thickness(-1), - ndefined_styles(0), - next_encoding_index(0), - ndefs(0), - invis_count(0) -{ - tempfp = xtmpfile(); - out.set_file(tempfp); - if (linewidth < 0) - linewidth = DEFAULT_LINEWIDTH; - if (font::hor != 1) - fatal("horizontal resolution must be 1"); - if (font::vert != 1) - fatal("vertical resolution must be 1"); - if (font::res % (font::sizescale*72) != 0) - fatal("res must be a multiple of 72*sizescale"); - int r = font::res; - int point = 0; - while (r % 10 == 0) { - r /= 10; - point++; - } - res = r; - out.set_fixed_point(point); - space_char_index = font::name_to_index("space"); - if (pl == 0) - paper_length = font::paperlength; - else - paper_length = int(pl * font::res + 0.5); - if (paper_length == 0) - paper_length = 11 * font::res; - equalise_spaces = font::res >= 72000; -} - -int ps_printer::set_encoding_index(ps_font *f) -{ - if (f->encoding_index >= 0) - return f->encoding_index; - for (font_pointer_list *p = font_list; p; p = p->next) - if (p->p != f) { - char *encoding = ((ps_font *)p->p)->encoding; - int encoding_index = ((ps_font *)p->p)->encoding_index; - if (encoding != 0 && encoding_index >= 0 - && strcmp(f->encoding, encoding) == 0) { - return f->encoding_index = encoding_index; - } - } - return f->encoding_index = next_encoding_index++; -} - -void ps_printer::set_char(int i, font *f, const environment *env, int w, const char *name) -{ - if (i == space_char_index || invis_count > 0) - return; - unsigned char code = f->get_code(i); - style sty(f, env->size, env->height, env->slant); - if (sty.slant != 0) { - if (sty.slant > 80 || sty.slant < -80) { - error("silly slant `%1' degrees", sty.slant); - sty.slant = 0; - } - } - if (sbuf_len > 0) { - if (sbuf_len < SBUF_SIZE - && sty == sbuf_style - && sbuf_vpos == env->vpos - && sbuf_color == *env->col) { - if (sbuf_end_hpos == env->hpos) { - sbuf[sbuf_len++] = code; - sbuf_end_hpos += w + sbuf_kern; - return; - } - if (sbuf_len == 1 && sbuf_kern == 0) { - sbuf_kern = env->hpos - sbuf_end_hpos; - sbuf_end_hpos = env->hpos + sbuf_kern + w; - sbuf[sbuf_len++] = code; - return; - } - /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off - starting a new string. */ - if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos - && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) { - if (sbuf_space_code < 0) { - if (f->contains(space_char_index)) { - sbuf_space_code = f->get_code(space_char_index); - sbuf_space_width = env->hpos - sbuf_end_hpos; - sbuf_end_hpos = env->hpos + w + sbuf_kern; - sbuf[sbuf_len++] = sbuf_space_code; - sbuf[sbuf_len++] = code; - sbuf_space_count++; - return; - } - } - else { - int diff = env->hpos - sbuf_end_hpos - sbuf_space_width; - if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) { - sbuf_end_hpos = env->hpos + w + sbuf_kern; - sbuf[sbuf_len++] = sbuf_space_code; - sbuf[sbuf_len++] = code; - sbuf_space_count++; - if (diff == 1) - sbuf_space_diff_count++; - else if (diff == -1) - sbuf_space_diff_count--; - return; - } - } - } - } - flush_sbuf(); - } - sbuf_len = 1; - sbuf[0] = code; - sbuf_end_hpos = env->hpos + w; - sbuf_start_hpos = env->hpos; - sbuf_vpos = env->vpos; - sbuf_style = sty; - sbuf_space_code = -1; - sbuf_space_width = 0; - sbuf_space_count = sbuf_space_diff_count = 0; - sbuf_kern = 0; - if (sbuf_color != *env->col) - set_color(env->col); -} - -static char *make_encoding_name(int encoding_index) -{ - static char buf[3 + INT_DIGITS + 1]; - sprintf(buf, "ENC%d", encoding_index); - return buf; -} - -const char *const WS = " \t\n\r"; - -void ps_printer::define_encoding(const char *encoding, int encoding_index) -{ - char *vec[256]; - int i; - for (i = 0; i < 256; i++) - vec[i] = 0; - char *path; - FILE *fp = font::open_file(encoding, &path); - if (fp == 0) - fatal("can't open encoding file `%1'", encoding); - int lineno = 1; - char buf[256]; - while (fgets(buf, 512, fp) != 0) { - char *p = buf; - while (csspace(*p)) - p++; - if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { - char *q = strtok(0, WS); - int n; - if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) - fatal_with_file_and_line(path, lineno, "bad second field"); - vec[n] = new char[strlen(p) + 1]; - strcpy(vec[n], p); - } - lineno++; - } - a_delete path; - out.put_literal_symbol(make_encoding_name(encoding_index)); - out.put_delimiter('['); - for (i = 0; i < 256; i++) { - if (vec[i] == 0) - out.put_literal_symbol(".notdef"); - else { - out.put_literal_symbol(vec[i]); - a_delete vec[i]; - } - } - out.put_delimiter(']') - .put_symbol("def"); -} - -void ps_printer::reencode_font(ps_font *f) -{ - out.put_literal_symbol(f->reencoded_name) - .put_symbol(make_encoding_name(f->encoding_index)) - .put_literal_symbol(f->get_internal_name()) - .put_symbol("RE"); -} - -void ps_printer::encode_fonts() -{ - if (next_encoding_index == 0) - return; - char *done_encoding = new char[next_encoding_index]; - for (int i = 0; i < next_encoding_index; i++) - done_encoding[i] = 0; - for (font_pointer_list *f = font_list; f; f = f->next) { - int encoding_index = ((ps_font *)f->p)->encoding_index; - if (encoding_index >= 0) { - assert(encoding_index < next_encoding_index); - if (!done_encoding[encoding_index]) { - done_encoding[encoding_index] = 1; - define_encoding(((ps_font *)f->p)->encoding, encoding_index); - } - reencode_font((ps_font *)f->p); - } - } - a_delete done_encoding; -} - -void ps_printer::set_style(const style &sty) -{ - char buf[1 + INT_DIGITS + 1]; - for (int i = 0; i < ndefined_styles; i++) - if (sty == defined_styles[i]) { - sprintf(buf, "F%d", i); - out.put_symbol(buf); - return; - } - if (ndefined_styles >= MAX_DEFINED_STYLES) - ndefined_styles = 0; - sprintf(buf, "F%d", ndefined_styles); - out.put_literal_symbol(buf); - const char *psname = sty.f->get_internal_name(); - if (psname == 0) - fatal("no internalname specified for font `%1'", sty.f->get_name()); - char *encoding = ((ps_font *)sty.f)->encoding; - if (encoding != 0) { - char *s = ((ps_font *)sty.f)->reencoded_name; - if (s == 0) { - int ei = set_encoding_index((ps_font *)sty.f); - char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; - sprintf(tem, "%s@%d", psname, ei); - psname = tem; - ((ps_font *)sty.f)->reencoded_name = tem; - } - else - psname = s; - } - out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); - if (sty.height != 0 || sty.slant != 0) { - int h = sty.height == 0 ? sty.point_size : sty.height; - h *= font::res/(72*font::sizescale); - int c = int(h*tan(radians(sty.slant)) + .5); - out.put_fix_number(c) - .put_fix_number(h) - .put_literal_symbol(psname) - .put_symbol("MF"); - } - else { - out.put_literal_symbol(psname) - .put_symbol("SF"); - } - defined_styles[ndefined_styles++] = sty; -} - -void ps_printer::set_color(color *col, int fill) -{ - sbuf_color = *col; - unsigned int components[4]; - char s[3]; - color_scheme cs = col->get_components(components); - s[0] = fill ? 'F' : 'C'; - s[2] = 0; - switch (cs) { - case DEFAULT: // black - out.put_symbol("0"); - s[1] = 'g'; - break; - case RGB: - out.put_color(Red) - .put_color(Green) - .put_color(Blue); - s[1] = 'r'; - break; - case CMY: - col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); - // fall through - case CMYK: - out.put_color(Cyan) - .put_color(Magenta) - .put_color(Yellow) - .put_color(Black); - s[1] = 'k'; - break; - case GRAY: - out.put_color(Gray); - s[1] = 'g'; - break; - } - out.put_symbol(s); -} - -void ps_printer::set_space_code(unsigned char c) -{ - out.put_literal_symbol("SC") - .put_number(c) - .put_symbol("def"); -} - -void ps_printer::end_of_line() -{ - flush_sbuf(); - // this ensures that we do an absolute motion to the beginning of a line - output_vpos = output_hpos = -1; -} - -void ps_printer::flush_sbuf() -{ - enum { - NONE, - RELATIVE_H, - RELATIVE_V, - RELATIVE_HV, - ABSOLUTE - } motion = NONE; - int space_flag = 0; - if (sbuf_len == 0) - return; - if (output_style != sbuf_style) { - set_style(sbuf_style); - output_style = sbuf_style; - } - int extra_space = 0; - if (output_hpos < 0 || output_vpos < 0) - motion = ABSOLUTE; - else { - if (output_hpos != sbuf_start_hpos) - motion = RELATIVE_H; - if (output_vpos != sbuf_vpos) { - if (motion != NONE) - motion = RELATIVE_HV; - else - motion = RELATIVE_V; - } - } - if (sbuf_space_code >= 0) { - int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size); - if (w + sbuf_kern != sbuf_space_width) { - if (sbuf_space_code != output_space_code) { - set_space_code(sbuf_space_code); - output_space_code = sbuf_space_code; - } - space_flag = 1; - extra_space = sbuf_space_width - w - sbuf_kern; - if (sbuf_space_diff_count > sbuf_space_count/2) - extra_space++; - else if (sbuf_space_diff_count < -(sbuf_space_count/2)) - extra_space--; - } - } - if (space_flag) - out.put_fix_number(extra_space); - if (sbuf_kern != 0) - out.put_fix_number(sbuf_kern); - out.put_string(sbuf, sbuf_len); - char command_array[] = {'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T'}; - char sym[2]; - sym[0] = command_array[motion*4 + space_flag + 2*(sbuf_kern != 0)]; - sym[1] = '\0'; - switch (motion) { - case NONE: - break; - case ABSOLUTE: - out.put_fix_number(sbuf_start_hpos) - .put_fix_number(sbuf_vpos); - break; - case RELATIVE_H: - out.put_fix_number(sbuf_start_hpos - output_hpos); - break; - case RELATIVE_V: - out.put_fix_number(sbuf_vpos - output_vpos); - break; - case RELATIVE_HV: - out.put_fix_number(sbuf_start_hpos - output_hpos) - .put_fix_number(sbuf_vpos - output_vpos); - break; - default: - assert(0); - } - out.put_symbol(sym); - output_hpos = sbuf_end_hpos; - output_vpos = sbuf_vpos; - sbuf_len = 0; -} - -void ps_printer::set_line_thickness_and_color(const environment *env) -{ - if (line_thickness < 0) { - if (output_draw_point_size != env->size) { - // we ought to check for overflow here - int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; - out.put_fix_number(lw) - .put_symbol("LW"); - output_draw_point_size = env->size; - output_line_thickness = -1; - } - } - else { - if (output_line_thickness != line_thickness) { - out.put_fix_number(line_thickness) - .put_symbol("LW"); - output_line_thickness = line_thickness; - output_draw_point_size = -1; - } - } - if (sbuf_color != *env->col) - set_color(env->col); -} - -void ps_printer::fill_path(const environment *env) -{ - if (sbuf_color == *env->fill) - out.put_symbol("FL"); - else - set_color(env->fill, 1); -} - -void ps_printer::draw(int code, int *p, int np, const environment *env) -{ - if (invis_count > 0) - return; - flush_sbuf(); - 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; - } - out.put_fix_number(env->hpos + p[0]/2) - .put_fix_number(env->vpos) - .put_fix_number(p[0]/2) - .put_symbol("DC"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - case 'l': - if (np != 2) { - error("2 arguments required for line"); - break; - } - set_line_thickness_and_color(env); - out.put_fix_number(p[0] + env->hpos) - .put_fix_number(p[1] + env->vpos) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("DL"); - break; - case 'E': - fill_flag = 1; - // fall through - case 'e': - if (np != 2) { - error("2 arguments required for ellipse"); - break; - } - out.put_fix_number(p[0]) - .put_fix_number(p[1]) - .put_fix_number(env->hpos + p[0]/2) - .put_fix_number(env->vpos) - .put_symbol("DE"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - 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; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("MT"); - for (int i = 0; i < np; i += 2) - out.put_fix_number(p[i]) - .put_fix_number(p[i+1]) - .put_symbol("RL"); - out.put_symbol("CL"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - } - case '~': - { - if (np & 1) { - error("even number of arguments required for spline"); - break; - } - if (np == 0) { - error("no arguments for spline"); - break; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("MT"); - out.put_fix_number(p[0]/2) - .put_fix_number(p[1]/2) - .put_symbol("RL"); - /* tnum/tden should be between 0 and 1; the closer it is to 1 - the tighter the curve will be to the guiding lines; 2/3 - is the standard value */ - const int tnum = 2; - const int tden = 3; - for (int i = 0; i < np - 2; i += 2) { - out.put_fix_number((p[i]*tnum)/(2*tden)) - .put_fix_number((p[i + 1]*tnum)/(2*tden)) - .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) - .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) - .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) - .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) - .put_symbol("RC"); - } - out.put_fix_number(p[np - 2] - p[np - 2]/2) - .put_fix_number(p[np - 1] - p[np - 1]/2) - .put_symbol("RL"); - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - case 'a': - { - if (np != 4) { - error("4 arguments required for arc"); - break; - } - set_line_thickness_and_color(env); - double c[2]; - if (adjust_arc_center(p, c)) - out.put_fix_number(env->hpos + int(c[0])) - .put_fix_number(env->vpos + int(c[1])) - .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1]))) - .put_float(degrees(atan2(-c[1], -c[0]))) - .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]))) - .put_symbol("DA"); - else - out.put_fix_number(p[0] + p[2] + env->hpos) - .put_fix_number(p[1] + p[3] + env->vpos) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("DL"); - } - 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; - } - output_hpos = output_vpos = -1; -} - -void ps_printer::begin_page(int n) -{ - out.begin_comment("Page:") - .comment_arg(i_to_a(n)); - out.comment_arg(i_to_a(++pages_output)) - .end_comment(); - output_style.f = 0; - output_space_code = 32; - output_draw_point_size = -1; - output_line_thickness = -1; - output_hpos = output_vpos = -1; - ndefined_styles = 0; - out.simple_comment("BeginPageSetup") - .put_symbol("BP") - .simple_comment("EndPageSetup"); - if (sbuf_color != default_color) - set_color(&sbuf_color); -} - -void ps_printer::end_page(int) -{ - flush_sbuf(); - set_color(&default_color); - out.put_symbol("EP"); - if (invis_count != 0) { - error("missing `endinvis' command"); - invis_count = 0; - } -} - -font *ps_printer::make_font(const char *nm) -{ - return ps_font::load_ps_font(nm); -} - -ps_printer::~ps_printer() -{ - out.simple_comment("Trailer") - .put_symbol("end") - .simple_comment("EOF"); - if (fseek(tempfp, 0L, 0) < 0) - fatal("fseek on temporary file failed"); - fputs("%!PS-Adobe-", stdout); - fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout); - putchar('\n'); - out.set_file(stdout); - { - out.begin_comment("Creator:") - .comment_arg("groff") - .comment_arg("version") - .comment_arg(Version_string) - .end_comment(); - } - { - fputs("%%CreationDate: ", out.get_file()); -#ifdef LONG_FOR_TIME_T - long -#else - time_t -#endif - t = time(0); - fputs(ctime(&t), out.get_file()); - } - for (font_pointer_list *f = font_list; f; f = f->next) { - ps_font *psf = (ps_font *)(f->p); - rm.need_font(psf->get_internal_name()); - } - rm.print_header_comments(out); - out.begin_comment("Pages:") - .comment_arg(i_to_a(pages_output)) - .end_comment(); - out.begin_comment("PageOrder:") - .comment_arg("Ascend") - .end_comment(); -#if 0 - fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n", - font::paperwidth*72.0/font::res, - paper_length*72.0/font::res); -#endif - out.begin_comment("Orientation:") - .comment_arg(landscape_flag ? "Landscape" : "Portrait") - .end_comment(); - if (ncopies != 1) { - out.end_line(); - fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies); - } - out.simple_comment("EndComments"); - out.simple_comment("BeginProlog"); - rm.output_prolog(out); - if (!(broken_flags & NO_SETUP_SECTION)) { - out.simple_comment("EndProlog"); - out.simple_comment("BeginSetup"); - } - rm.document_setup(out); - out.put_symbol(dict_name) - .put_symbol("begin"); - if (ndefs > 0) - ndefs += DEFS_DICT_SPARE; - out.put_literal_symbol(defs_dict_name) - .put_number(ndefs + 1) - .put_symbol("dict") - .put_symbol("def"); - out.put_symbol(defs_dict_name) - .put_symbol("begin"); - out.put_literal_symbol("u") - .put_delimiter('{') - .put_fix_number(1) - .put_symbol("mul") - .put_delimiter('}') - .put_symbol("bind") - .put_symbol("def"); - defs += '\0'; - out.special(defs.contents()); - out.put_symbol("end"); - if (ncopies != 1) - out.put_literal_symbol("#copies") - .put_number(ncopies) - .put_symbol("def"); - out.put_literal_symbol("RES") - .put_number(res) - .put_symbol("def"); - out.put_literal_symbol("PL"); - if (guess_flag) - out.put_symbol("PLG"); - else - out.put_fix_number(paper_length); - out.put_symbol("def"); - out.put_literal_symbol("LS") - .put_symbol(landscape_flag ? "true" : "false") - .put_symbol("def"); - if (manual_feed_flag) { - out.begin_comment("BeginFeature:") - .comment_arg("*ManualFeed") - .comment_arg("True") - .end_comment() - .put_symbol("MANUAL") - .simple_comment("EndFeature"); - } - encode_fonts(); - out.simple_comment((broken_flags & NO_SETUP_SECTION) - ? "EndProlog" - : "EndSetup"); - out.end_line(); - out.copy_file(tempfp); - fclose(tempfp); -} - -void ps_printer::special(char *arg, const environment *env, char type) -{ - if (type != 'p') - return; - typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *); - static struct { - const char *name; - SPECIAL_PROCP proc; - } proc_table[] = { - { "exec", &ps_printer::do_exec }, - { "def", &ps_printer::do_def }, - { "mdef", &ps_printer::do_mdef }, - { "import", &ps_printer::do_import }, - { "file", &ps_printer::do_file }, - { "invis", &ps_printer::do_invis }, - { "endinvis", &ps_printer::do_endinvis }, - }; - 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, "ps", p - tag) != 0) { - error("X command without `ps:' 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; - } - for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++) - if (strncmp(command, proc_table[i].name, p - command) == 0) { - (this->*(proc_table[i].proc))(p, env); - return; - } - error("X command `%1' not recognised", command); -} - -// A conforming PostScript document must not have lines longer -// than 255 characters (excluding line termination characters). - -static int check_line_lengths(const char *p) -{ - for (;;) { - const char *end = strchr(p, '\n'); - if (end == 0) - end = strchr(p, '\0'); - if (end - p > 255) - return 0; - if (*end == '\0') - break; - p = end + 1; - } - return 1; -} - -void ps_printer::do_exec(char *arg, const environment *env) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (*arg == '\0') { - error("missing argument to X exec command"); - return; - } - if (!check_line_lengths(arg)) { - error("lines in X exec command must not be more than 255 characters long"); - return; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("EBEGIN") - .special(arg) - .put_symbol("EEND"); - output_hpos = output_vpos = -1; - output_style.f = 0; - output_draw_point_size = -1; - output_line_thickness = -1; - ndefined_styles = 0; - if (!ndefs) - ndefs = 1; -} - -void ps_printer::do_file(char *arg, const environment *env) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (*arg == '\0') { - error("missing argument to X file command"); - return; - } - const char *filename = arg; - do { - ++arg; - } while (*arg != '\0' && *arg != ' ' && *arg != '\n'); - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("EBEGIN"); - rm.import_file(filename, out); - out.put_symbol("EEND"); - output_hpos = output_vpos = -1; - output_style.f = 0; - output_draw_point_size = -1; - output_line_thickness = -1; - ndefined_styles = 0; - if (!ndefs) - ndefs = 1; -} - -void ps_printer::do_def(char *arg, const environment *) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (!check_line_lengths(arg)) { - error("lines in X def command must not be more than 255 characters long"); - return; - } - defs += arg; - if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') - defs += '\n'; - ndefs++; -} - -// Like def, but the first argument says how many definitions it contains. - -void ps_printer::do_mdef(char *arg, const environment *) -{ - flush_sbuf(); - char *p; - int n = (int)strtol(arg, &p, 10); - if (n == 0 && p == arg) { - error("first argument to X mdef must be an integer"); - return; - } - if (n < 0) { - error("out of range argument `%1' to X mdef command", int(n)); - return; - } - arg = p; - while (csspace(*arg)) - arg++; - if (!check_line_lengths(arg)) { - error("lines in X mdef command must not be more than 255 characters long"); - return; - } - defs += arg; - if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') - defs += '\n'; - ndefs += n; -} - -void ps_printer::do_import(char *arg, const environment *env) -{ - flush_sbuf(); - while (*arg == ' ' || *arg == '\n') - arg++; - char *p; - for (p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++) - ; - if (*p != '\0') - *p++ = '\0'; - int parms[6]; - int nparms = 0; - while (nparms < 6) { - char *end; - long n = strtol(p, &end, 10); - if (n == 0 && end == p) - break; - parms[nparms++] = int(n); - p = end; - } - if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) { - error("scaling indicators not allowed in arguments for X import command"); - return; - } - while (*p == ' ' || *p == '\n') - p++; - if (nparms < 5) { - if (*p == '\0') - error("too few arguments for X import command"); - else - error("invalid argument `%1' for X import command", p); - return; - } - if (*p != '\0') { - error("superflous argument `%1' for X import command", p); - return; - } - int llx = parms[0]; - int lly = parms[1]; - int urx = parms[2]; - int ury = parms[3]; - int desired_width = parms[4]; - int desired_height = parms[5]; - if (desired_width <= 0) { - error("bad width argument `%1' for X import command: must be > 0", - desired_width); - return; - } - if (nparms == 6 && desired_height <= 0) { - error("bad height argument `%1' for X import command: must be > 0", - desired_height); - return; - } - if (llx == urx) { - error("llx and urx arguments for X import command must not be equal"); - return; - } - if (lly == ury) { - error("lly and ury arguments for X import command must not be equal"); - return; - } - if (nparms == 5) { - int old_wid = urx - llx; - int old_ht = ury - lly; - if (old_wid < 0) - old_wid = -old_wid; - if (old_ht < 0) - old_ht = -old_ht; - desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5); - } - if (env->vpos - desired_height < 0) - warning("top of imported graphic is above the top of the page"); - out.put_number(llx) - .put_number(lly) - .put_fix_number(desired_width) - .put_number(urx - llx) - .put_fix_number(-desired_height) - .put_number(ury - lly) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("PBEGIN"); - rm.import_file(arg, out); - // do this here just in case application defines PEND - out.put_symbol("end"); - out.put_symbol("PEND"); -} - -void ps_printer::do_invis(char *, const environment *) -{ - invis_count++; -} - -void ps_printer::do_endinvis(char *, const environment *) -{ - if (invis_count == 0) - error("unbalanced `endinvis' command"); - else - --invis_count; -} - -printer *make_printer() -{ - return new ps_printer(user_paper_length); -} - -static void usage(FILE *stream); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - string env; - 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, "b:c:F:glmp:P:vw:", long_options, NULL)) - != EOF) - switch(c) { - case 'b': - // XXX check this - broken_flags = atoi(optarg); - bflag = 1; - break; - case 'c': - if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { - error("bad number of copies `%s'", optarg); - ncopies = 1; - } - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'g': - guess_flag = 1; - break; - case 'l': - landscape_flag = 1; - break; - case 'm': - manual_feed_flag = 1; - break; - case 'p': - if (!font::scan_papersize(optarg, 0, &user_paper_length, 0)) - error("invalid custom paper size `%1' ignored", optarg); - break; - case 'P': - env = "GROPS_PROLOGUE"; - env += '='; - env += optarg; - env += '\0'; - if (putenv(strsave(env.contents()))) - fatal("putenv failed"); - break; - case 'v': - printf("GNU grops (groff) version %s\n", Version_string); - exit(0); - break; - case 'w': - if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { - error("bad linewidth `%1'", optarg); - linewidth = -1; - } - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - font::set_unknown_desc_command_handler(handle_unknown_desc_command); -#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 [-glmv] [-b n] [-c n] [-w n] [-P prologue] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grops/psrm.cc b/contrib/groff/src/devices/grops/psrm.cc deleted file mode 100644 index f2177da..0000000 --- a/contrib/groff/src/devices/grops/psrm.cc +++ /dev/null @@ -1,1147 +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 "stringclass.h" -#include "cset.h" - -#include "ps.h" - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -#define GROPS_PROLOGUE "prologue" - -static void print_ps_string(const string &s, FILE *outfp); - -cset white_space("\n\r \t"); -string an_empty_string; - -const char *extension_table[] = { - "DPS", - "CMYK", - "Composite", - "FileSystem", -}; - -const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]); - -const char *resource_table[] = { - "font", - "procset", - "file", - "encoding", - "form", - "pattern", -}; - -const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]); - -static int read_uint_arg(const char **pp, unsigned *res) -{ - while (white_space(**pp)) - *pp += 1; - if (**pp == '\0') { - error("missing argument"); - return 0; - } - const char *start = *pp; - // XXX use strtoul - long n = strtol(start, (char **)pp, 10); - if (n == 0 && *pp == start) { - error("not an integer"); - return 0; - } - if (n < 0) { - error("argument must not be negative"); - return 0; - } - *res = unsigned(n); - return 1; -} - -struct resource { - resource *next; - resource_type type; - string name; - enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 }; - unsigned flags; - string version; - unsigned revision; - char *filename; - int rank; - resource(resource_type, string &, string & = an_empty_string, unsigned = 0); - ~resource(); - void print_type_and_name(FILE *outfp); -}; - -resource::resource(resource_type t, string &n, string &v, unsigned r) -: next(0), type(t), flags(0), revision(r), filename(0), rank(-1) -{ - name.move(n); - version.move(v); - if (type == RESOURCE_FILE) { - if (name.search('\0') >= 0) - error("filename contains a character with code 0"); - filename = name.extract(); - } -} - -resource::~resource() -{ - a_delete filename; -} - -void resource::print_type_and_name(FILE *outfp) -{ - fputs(resource_table[type], outfp); - putc(' ', outfp); - print_ps_string(name, outfp); - if (type == RESOURCE_PROCSET) { - putc(' ', outfp); - print_ps_string(version, outfp); - fprintf(outfp, " %u", revision); - } -} - -resource_manager::resource_manager() -: extensions(0), language_level(0), resource_list(0) -{ - read_download_file(); - string procset_name("grops"); - extern const char *version_string; - extern const char *revision_string; - unsigned revision_uint; - if ( !read_uint_arg( &revision_string, &revision_uint) ) - revision_uint = 0; - string procset_version(version_string); - procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name, - procset_version, revision_uint); - procset_resource->flags |= resource::SUPPLIED; -} - -resource_manager::~resource_manager() -{ - while (resource_list) { - resource *tem = resource_list; - resource_list = resource_list->next; - delete tem; - } -} - -resource *resource_manager::lookup_resource(resource_type type, - string &name, - string &version, - unsigned revision) -{ - resource *r; - for (r = resource_list; r; r = r->next) - if (r->type == type - && r->name == name - && r->version == version - && r->revision == revision) - return r; - r = new resource(type, name, version, revision); - r->next = resource_list; - resource_list = r; - return r; -} - -// Just a specialized version of lookup_resource(). - -resource *resource_manager::lookup_font(const char *name) -{ - resource *r; - for (r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT - && strlen(name) == (size_t)r->name.length() - && memcmp(name, r->name.contents(), r->name.length()) == 0) - return r; - string s(name); - r = new resource(RESOURCE_FONT, s); - r->next = resource_list; - resource_list = r; - return r; -} - -void resource_manager::need_font(const char *name) -{ - lookup_font(name)->flags |= resource::FONT_NEEDED; -} - -typedef resource *Presource; // Work around g++ bug. - -void resource_manager::document_setup(ps_output &out) -{ - int nranks = 0; - resource *r; - for (r = resource_list; r; r = r->next) - if (r->rank >= nranks) - nranks = r->rank + 1; - if (nranks > 0) { - // Sort resource_list in reverse order of rank. - Presource *head = new Presource[nranks + 1]; - Presource **tail = new Presource *[nranks + 1]; - int i; - for (i = 0; i < nranks + 1; i++) { - head[i] = 0; - tail[i] = &head[i]; - } - for (r = resource_list; r; r = r->next) { - i = r->rank < 0 ? 0 : r->rank + 1; - *tail[i] = r; - tail[i] = &(*tail[i])->next; - } - resource_list = 0; - for (i = 0; i < nranks + 1; i++) - if (head[i]) { - *tail[i] = resource_list; - resource_list = head[i]; - } - a_delete head; - a_delete tail; - // check it - for (r = resource_list; r; r = r->next) - if (r->next) - assert(r->rank >= r->next->rank); - for (r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT && r->rank >= 0) - supply_resource(r, -1, out.get_file()); - } -} - -void resource_manager::print_resources_comment(unsigned flag, FILE *outfp) -{ - int continued = 0; - for (resource *r = resource_list; r; r = r->next) - if (r->flags & flag) { - if (continued) - fputs("%%+ ", outfp); - else { - fputs(flag == resource::NEEDED - ? "%%DocumentNeededResources: " - : "%%DocumentSuppliedResources: ", - outfp); - continued = 1; - } - r->print_type_and_name(outfp); - putc('\n', outfp); - } -} - -void resource_manager::print_header_comments(ps_output &out) -{ - for (resource *r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED)) - supply_resource(r, 0, 0); - print_resources_comment(resource::NEEDED, out.get_file()); - print_resources_comment(resource::SUPPLIED, out.get_file()); - print_language_level_comment(out.get_file()); - print_extensions_comment(out.get_file()); -} - -void resource_manager::output_prolog(ps_output &out) -{ - FILE *outfp = out.get_file(); - out.end_line(); - char *path; - if (!getenv("GROPS_PROLOGUE")) { - string e = "GROPS_PROLOGUE"; - e += '='; - e += GROPS_PROLOGUE; - e += '\0'; - if (putenv(strsave(e.contents()))) - fatal("putenv failed"); - } - char *prologue = getenv("GROPS_PROLOGUE"); - FILE *fp = font::open_file(prologue, &path); - if (!fp) - fatal("can't find `%1'", prologue); - fputs("%%BeginResource: ", outfp); - procset_resource->print_type_and_name(outfp); - putc('\n', outfp); - process_file(-1, fp, path, outfp); - fclose(fp); - a_delete path; - fputs("%%EndResource\n", outfp); -} - -void resource_manager::import_file(const char *filename, ps_output &out) -{ - out.end_line(); - string name(filename); - resource *r = lookup_resource(RESOURCE_FILE, name); - supply_resource(r, -1, out.get_file(), 1); -} - -void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, - int is_document) -{ - if (r->flags & resource::BUSY) { - r->name += '\0'; - fatal("loop detected in dependency graph for %1 `%2'", - resource_table[r->type], - r->name.contents()); - } - r->flags |= resource::BUSY; - if (rank > r->rank) - r->rank = rank; - char *path; - FILE *fp = 0; - if (r->filename != 0) { - if (r->type == RESOURCE_FONT) { - fp = font::open_file(r->filename, &path); - if (!fp) { - error("can't find `%1'", r->filename); - a_delete r->filename; - r->filename = 0; - } - } - else { - errno = 0; - fp = fopen(r->filename, "r"); - if (!fp) { - error("can't open `%1': %2", r->filename, strerror(errno)); - a_delete r->filename; - r->filename = 0; - } - else - path = r->filename; - } - } - if (fp) { - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) { - fputs("%%BeginDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - process_file(rank, fp, path, outfp); - fclose(fp); - if (r->type == RESOURCE_FONT) - a_delete path; - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) - fputs("%%EndDocument\n", outfp); - else - fputs("%%EndResource\n", outfp); - } - r->flags |= resource::SUPPLIED; - } - else { - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) { - fputs("%%IncludeDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%IncludeResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - r->flags |= resource::NEEDED; - } - r->flags &= ~resource::BUSY; -} - - -#define PS_LINE_MAX 255 -#define PS_MAGIC "%!PS-Adobe-" - -static int ps_get_line(char *buf, FILE *fp) -{ - int c = getc(fp); - if (c == EOF) { - buf[0] = '\0'; - return 0; - } - current_lineno++; - int i = 0; - int err = 0; - while (c != '\r' && c != '\n' && c != EOF) { - if ((c < 0x1b && !white_space(c)) || c == 0x7f) - error("invalid input character code %1", int(c)); - else if (i < PS_LINE_MAX) - buf[i++] = c; - else if (!err) { - err = 1; - error("PostScript file non-conforming " - "because length of line exceeds 255"); - } - c = getc(fp); - } - buf[i++] = '\n'; - buf[i] = '\0'; - if (c == '\r') { - c = getc(fp); - if (c != EOF && c != '\n') - ungetc(c, fp); - } - return 1; -} - -static int read_text_arg(const char **pp, string &res) -{ - res.clear(); - while (white_space(**pp)) - *pp += 1; - if (**pp == '\0') { - error("missing argument"); - return 0; - } - if (**pp != '(') { - for (; **pp != '\0' && !white_space(**pp); *pp += 1) - res += **pp; - return 1; - } - *pp += 1; - res.clear(); - int level = 0; - for (;;) { - if (**pp == '\0' || **pp == '\r' || **pp == '\n') { - error("missing ')'"); - return 0; - } - if (**pp == ')') { - if (level == 0) { - *pp += 1; - break; - } - res += **pp; - level--; - } - else if (**pp == '(') { - level++; - res += **pp; - } - else if (**pp == '\\') { - *pp += 1; - switch (**pp) { - case 'n': - res += '\n'; - break; - case 'r': - res += '\n'; - break; - case 't': - res += '\t'; - break; - case 'b': - res += '\b'; - break; - case 'f': - res += '\f'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int val = **pp - '0'; - if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { - *pp += 1; - val = val*8 + (**pp - '0'); - if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { - *pp += 1; - val = val*8 + (**pp - '0'); - } - } - } - break; - default: - res += **pp; - break; - } - } - else - res += **pp; - *pp += 1; - } - return 1; -} - -resource *resource_manager::read_file_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(RESOURCE_FILE, arg); -} - -resource *resource_manager::read_font_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(RESOURCE_FONT, arg); -} - -resource *resource_manager::read_procset_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - string version; - if (!read_text_arg(ptr, version)) - return 0; - unsigned revision; - if (!read_uint_arg(ptr, &revision)) - return 0; - return lookup_resource(RESOURCE_PROCSET, arg, version, revision); -} - -resource *resource_manager::read_resource_arg(const char **ptr) -{ - while (white_space(**ptr)) - *ptr += 1; - const char *name = *ptr; - while (**ptr != '\0' && !white_space(**ptr)) - *ptr += 1; - if (name == *ptr) { - error("missing resource type"); - return 0; - } - int ri; - for (ri = 0; ri < NRESOURCES; ri++) - if (strlen(resource_table[ri]) == size_t(*ptr - name) - && memcmp(resource_table[ri], name, *ptr - name) == 0) - break; - if (ri >= NRESOURCES) { - error("unknown resource type"); - return 0; - } - if (ri == RESOURCE_PROCSET) - return read_procset_arg(ptr); - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(resource_type(ri), arg); -} - -static const char *matches_comment(const char *buf, const char *comment) -{ - if (buf[0] != '%' || buf[1] != '%') - return 0; - for (buf += 2; *comment; comment++, buf++) - if (*buf != *comment) - return 0; - if (comment[-1] == ':') - return buf; - if (*buf == '\0' || white_space(*buf)) - return buf; - return 0; -} - -// Return 1 if the line should be copied out. - -int resource_manager::do_begin_resource(const char *ptr, int, FILE *, - FILE *) -{ - resource *r = read_resource_arg(&ptr); - if (r) - r->flags |= resource::SUPPLIED; - return 1; -} - -int resource_manager::do_include_resource(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_resource_arg(&ptr); - if (r) { - if (r->type == RESOURCE_FONT) { - if (rank >= 0) - supply_resource(r, rank + 1, outfp); - else - r->flags |= resource::FONT_NEEDED; - } - else - supply_resource(r, rank, outfp); - } - return 0; -} - -int resource_manager::do_begin_document(const char *ptr, int, FILE *, - FILE *) -{ - resource *r = read_file_arg(&ptr); - if (r) - r->flags |= resource::SUPPLIED; - return 1; -} - -int resource_manager::do_include_document(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) - supply_resource(r, rank, outfp, 1); - return 0; -} - -int resource_manager::do_begin_procset(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_procset_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_procset(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_procset_arg(&ptr); - if (r) - supply_resource(r, rank, outfp); - return 0; -} - -int resource_manager::do_begin_file(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_file(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) - supply_resource(r, rank, outfp); - return 0; -} - -int resource_manager::do_begin_font(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_font_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_font(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_font_arg(&ptr); - if (r) { - if (rank >= 0) - supply_resource(r, rank + 1, outfp); - else - r->flags |= resource::FONT_NEEDED; - } - return 0; -} - -int resource_manager::change_to_end_resource(const char *, int, FILE *, - FILE *outfp) -{ - if (outfp) - fputs("%%EndResource\n", outfp); - return 0; -} - -int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *) -{ - char buf[PS_LINE_MAX + 2]; - do { - if (!ps_get_line(buf, fp)) { - error("end of file in preview section"); - break; - } - } while (!matches_comment(buf, "EndPreview")); - return 0; -} - -int read_one_of(const char **ptr, const char **s, int n) -{ - while (white_space(**ptr)) - *ptr += 1; - if (**ptr == '\0') - return -1; - const char *start = *ptr; - do { - ++(*ptr); - } while (**ptr != '\0' && !white_space(**ptr)); - for (int i = 0; i < n; i++) - if (strlen(s[i]) == size_t(*ptr - start) - && memcmp(s[i], start, *ptr - start) == 0) - return i; - return -1; -} - -void skip_possible_newline(const char *ptr, FILE *fp, FILE *outfp) -{ - int c = getc(fp); - if (c == '\r') { - current_lineno++; - if (outfp) - putc(c, outfp); - int cc = getc(fp); - if (cc != '\n') { - if (cc != EOF) - ungetc(cc, fp); - } - else { - if (outfp) - putc(cc, outfp); - } - } - else if (c == '\n') { - current_lineno++; - if (outfp) - putc(c, outfp); - } - else if (c != EOF) - ungetc(c, fp); -} - -int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, - FILE *outfp) -{ - while (white_space(*ptr)) - ptr++; - const char *start = ptr; - unsigned numberof; - if (!read_uint_arg(&ptr, &numberof)) - return 0; - static const char *types[] = { "Binary", "Hex", "ASCII" }; - const int Binary = 0; - int type = 0; - static const char *units[] = { "Bytes", "Lines" }; - const int Bytes = 0; - int unit = Bytes; - while (white_space(*ptr)) - ptr++; - if (*ptr != '\0') { - type = read_one_of(&ptr, types, 3); - if (type < 0) { - error("bad data type"); - return 0; - } - while (white_space(*ptr)) - ptr++; - if (*ptr != '\0') { - unit = read_one_of(&ptr, units, 2); - if (unit < 0) { - error("expected `Bytes' or `Lines'"); - return 0; - } - } - } - if (type != Binary) - return 1; - if (outfp) { - fputs("%%BeginData: ", outfp); - fputs(start, outfp); - } - if (numberof > 0) { - unsigned bytecount = 0; - unsigned linecount = 0; - do { - int c = getc(fp); - if (c == EOF) { - error("end of file within data section"); - return 0; - } - if (outfp) - putc(c, outfp); - bytecount++; - if (c == '\r') { - int cc = getc(fp); - if (cc != '\n') { - linecount++; - current_lineno++; - } - if (cc != EOF) - ungetc(c, fp); - } - else if (c == '\n') { - linecount++; - current_lineno++; - } - } while ((unit == Bytes ? bytecount : linecount) < numberof); - } - skip_possible_newline(ptr, fp, outfp); - char buf[PS_LINE_MAX + 2]; - if (!ps_get_line(buf, fp)) { - error("missing %%%%EndData line"); - return 0; - } - if (!matches_comment(buf, "EndData")) - error("bad %%%%EndData line"); - if (outfp) - fputs(buf, outfp); - return 0; -} - -int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, - FILE *outfp) -{ - if (!outfp) - return 0; - unsigned count; - if (!read_uint_arg(&ptr, &count)) - return 0; - if (outfp) - fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count); - while (count != 0) { - int c = getc(fp); - if (c == EOF) { - error("end of file within binary section"); - return 0; - } - if (outfp) - putc(c, outfp); - --count; - if (c == '\r') { - int cc = getc(fp); - if (cc != '\n') - current_lineno++; - if (cc != EOF) - ungetc(cc, fp); - } - else if (c == '\n') - current_lineno++; - } - skip_possible_newline(ptr, fp, outfp); - char buf[PS_LINE_MAX + 2]; - if (!ps_get_line(buf, fp)) { - error("missing %%%%EndBinary line"); - return 0; - } - if (!matches_comment(buf, "EndBinary")) { - error("bad %%%%EndBinary line"); - if (outfp) - fputs(buf, outfp); - } - else if (outfp) - fputs("%%EndData\n", outfp); - return 0; -} - -static unsigned parse_extensions(const char *ptr) -{ - unsigned flags = 0; - for (;;) { - while (white_space(*ptr)) - ptr++; - if (*ptr == '\0') - break; - const char *name = ptr; - do { - ++ptr; - } while (*ptr != '\0' && !white_space(*ptr)); - int i; - for (i = 0; i < NEXTENSIONS; i++) - if (strlen(extension_table[i]) == size_t(ptr - name) - && memcmp(extension_table[i], name, ptr - name) == 0) { - flags |= (1 << i); - break; - } - if (i >= NEXTENSIONS) { - string s(name, ptr - name); - s += '\0'; - error("unknown extension `%1'", s.contents()); - } - } - return flags; -} - -// XXX if it has not been surrounded with {Begin,End}Document need to strip -// out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections. - -// XXX Perhaps the decision whether to use BeginDocument or -// BeginResource: file should be postponed till we have seen -// the first line of the file. - -void resource_manager::process_file(int rank, FILE *fp, const char *filename, - FILE *outfp) -{ - // If none of these comments appear in the header section, and we are - // just analyzing the file (ie outfp is 0), then we can return immediately. - static const char *header_comment_table[] = { - "DocumentNeededResources:", - "DocumentSuppliedResources:", - "DocumentNeededFonts:", - "DocumentSuppliedFonts:", - "DocumentNeededProcSets:", - "DocumentSuppliedProcSets:", - "DocumentNeededFiles:", - "DocumentSuppliedFiles:", - }; - - const int NHEADER_COMMENTS = (sizeof(header_comment_table) - / sizeof(header_comment_table[0])); - struct comment_info { - const char *name; - int (resource_manager::*proc)(const char *, int, FILE *, FILE *); - }; - - static comment_info comment_table[] = { - { "BeginResource:", &resource_manager::do_begin_resource }, - { "IncludeResource:", &resource_manager::do_include_resource }, - { "BeginDocument:", &resource_manager::do_begin_document }, - { "IncludeDocument:", &resource_manager::do_include_document }, - { "BeginProcSet:", &resource_manager::do_begin_procset }, - { "IncludeProcSet:", &resource_manager::do_include_procset }, - { "BeginFont:", &resource_manager::do_begin_font }, - { "IncludeFont:", &resource_manager::do_include_font }, - { "BeginFile:", &resource_manager::do_begin_file }, - { "IncludeFile:", &resource_manager::do_include_file }, - { "EndProcSet", &resource_manager::change_to_end_resource }, - { "EndFont", &resource_manager::change_to_end_resource }, - { "EndFile", &resource_manager::change_to_end_resource }, - { "BeginPreview:", &resource_manager::do_begin_preview }, - { "BeginData:", &resource_manager::do_begin_data }, - { "BeginBinary:", &resource_manager::do_begin_binary }, - }; - - const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]); - char buf[PS_LINE_MAX + 2]; - int saved_lineno = current_lineno; - const char *saved_filename = current_filename; - current_filename = filename; - current_lineno = 0; - if (!ps_get_line(buf, fp)) { - current_filename = saved_filename; - current_lineno = saved_lineno; - return; - } - if (strlen(buf) < sizeof(PS_MAGIC) - 1 - || memcmp(buf, PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) { - if (outfp) { - do { - if (!(broken_flags & STRIP_PERCENT_BANG) - || buf[0] != '%' || buf[1] != '!') - fputs(buf, outfp); - } while (ps_get_line(buf, fp)); - } - } - else { - if (!(broken_flags & STRIP_PERCENT_BANG) && outfp) - fputs(buf, outfp); - int in_header = 1; - int interesting = 0; - int had_extensions_comment = 0; - int had_language_level_comment = 0; - for (;;) { - if (!ps_get_line(buf, fp)) - break; - int copy_this_line = 1; - if (buf[0] == '%') { - if (buf[1] == '%') { - const char *ptr; - int i; - for (i = 0; i < NCOMMENTS; i++) - if ((ptr = matches_comment(buf, comment_table[i].name))) { - copy_this_line - = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp); - break; - } - if (i >= NCOMMENTS && in_header) { - if ((ptr = matches_comment(buf, "EndComments"))) - in_header = 0; - else if (!had_extensions_comment - && (ptr = matches_comment(buf, "Extensions:"))) { - extensions |= parse_extensions(ptr); - // XXX handle possibility that next line is %%+ - had_extensions_comment = 1; - } - else if (!had_language_level_comment - && (ptr = matches_comment(buf, "LanguageLevel:"))) { - unsigned ll; - if (read_uint_arg(&ptr, &ll) && ll > language_level) - language_level = ll; - had_language_level_comment = 1; - } - else { - for (i = 0; i < NHEADER_COMMENTS; i++) - if (matches_comment(buf, header_comment_table[i])) { - interesting = 1; - break; - } - } - } - if ((broken_flags & STRIP_STRUCTURE_COMMENTS) - && (matches_comment(buf, "EndProlog") - || matches_comment(buf, "Page:") - || matches_comment(buf, "Trailer"))) - copy_this_line = 0; - } - else if (buf[1] == '!') { - if (broken_flags & STRIP_PERCENT_BANG) - copy_this_line = 0; - } - } - else - in_header = 0; - if (!outfp && !in_header && !interesting) - break; - if (copy_this_line && outfp) - fputs(buf, outfp); - } - } - current_filename = saved_filename; - current_lineno = saved_lineno; -} - -void resource_manager::read_download_file() -{ - char *path = 0; - FILE *fp = font::open_file("download", &path); - if (!fp) - fatal("can't find `download'"); - char buf[512]; - int lineno = 0; - while (fgets(buf, sizeof(buf), fp)) { - lineno++; - char *p = strtok(buf, " \t\r\n"); - if (p == 0 || *p == '#') - continue; - char *q = strtok(0, " \t\r\n"); - if (!q) - fatal_with_file_and_line(path, lineno, "missing filename"); - lookup_font(p)->filename = strsave(q); - } - a_delete path; - fclose(fp); -} - -// XXX Can we share some code with ps_output::put_string()? - -static void print_ps_string(const string &s, FILE *outfp) -{ - int len = s.length(); - const char *str = s.contents(); - int funny = 0; - if (str[0] == '(') - funny = 1; - else { - for (int i = 0; i < len; i++) - if (str[i] <= 040 || str[i] > 0176) { - funny = 1; - break; - } - } - if (!funny) { - put_string(s, outfp); - return; - } - int level = 0; - int i; - for (i = 0; i < len; i++) - if (str[i] == '(') - level++; - else if (str[i] == ')' && --level < 0) - break; - putc('(', outfp); - for (i = 0; i < len; i++) - switch (str[i]) { - case '(': - case ')': - if (level != 0) - putc('\\', outfp); - putc(str[i], outfp); - break; - case '\\': - fputs("\\\\", outfp); - break; - case '\n': - fputs("\\n", outfp); - break; - case '\r': - fputs("\\r", outfp); - break; - case '\t': - fputs("\\t", outfp); - break; - case '\b': - fputs("\\b", outfp); - break; - case '\f': - fputs("\\f", outfp); - break; - default: - if (str[i] < 040 || str[i] > 0176) - fprintf(outfp, "\\%03o", str[i] & 0377); - else - putc(str[i], outfp); - break; - } - putc(')', outfp); -} - -void resource_manager::print_extensions_comment(FILE *outfp) -{ - if (extensions) { - fputs("%%Extensions:", outfp); - for (int i = 0; i < NEXTENSIONS; i++) - if (extensions & (1 << i)) { - putc(' ', outfp); - fputs(extension_table[i], outfp); - } - putc('\n', outfp); - } -} - -void resource_manager::print_language_level_comment(FILE *outfp) -{ - if (language_level) - fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level); -} - diff --git a/contrib/groff/src/devices/grotty/tty.cc b/contrib/groff/src/devices/grotty/tty.cc deleted file mode 100644 index 7cfb658..0000000 --- a/contrib/groff/src/devices/grotty/tty.cc +++ /dev/null @@ -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); -} |