diff options
Diffstat (limited to 'contrib/groff/grops/ps.cc')
-rw-r--r-- | contrib/groff/grops/ps.cc | 1541 |
1 files changed, 0 insertions, 1541 deletions
diff --git a/contrib/groff/grops/ps.cc b/contrib/groff/grops/ps.cc deleted file mode 100644 index c065dafae7c0..000000000000 --- a/contrib/groff/grops/ps.cc +++ /dev/null @@ -1,1541 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "driver.h" -#include "stringclass.h" -#include "cset.h" -#include "nonposix.h" - -#include "ps.h" -#include <time.h> - -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; - -// 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, "%.4f", 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_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; - style output_style; - int output_hpos; - int output_vpos; - int output_draw_point_size; - int line_thickness; - int output_line_thickness; - int fill; - 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(const environment *); - void fill_path(); - void encode_fonts(); - void define_encoding(const char *, int); - void reencode_font(ps_font *); -public: - ps_printer(); - ~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); - font *make_font(const char *); - void end_of_line(); -}; - -ps_printer::ps_printer() -: out(0, MAX_LINE_LENGTH), - pages_output(0), - sbuf_len(0), - output_hpos(-1), - output_vpos(-1), - line_thickness(-1), - fill(FILL_MAX + 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"); - paper_length = font::paperlength; - 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) { - 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; -} - -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_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(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; - } - } -} - -void ps_printer::fill_path() -{ - if (fill > FILL_MAX) - out.put_symbol("BL"); - else - out.put_float(transform_fill(fill)).put_symbol("FL"); -} - -void ps_printer::draw(int code, int *p, int np, const environment *env) -{ - if (invis_count > 0) - return; - 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(); - } - else { - set_line_thickness(env); - out.put_symbol("ST"); - } - break; - case 'l': - if (np != 2) { - error("2 arguments required for line"); - break; - } - set_line_thickness(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(); - } - else { - set_line_thickness(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(); - } - else { - set_line_thickness(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(env); - out.put_symbol("ST"); - } - 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)) - 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; - } - case 'f': - { - if (np != 1 && np != 2) { - error("1 argument required for fill"); - break; - } - fill = p[0]; - if (fill < 0 || fill > FILL_MAX) { - // This means fill with the current color. - fill = FILL_MAX + 1; - } - 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"); - out.put_symbol("BP"); - out.simple_comment("EndPageSetup"); -} - -void ps_printer::end_page(int) -{ - flush_sbuf(); - 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"); - out.put_symbol("end"); - out.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); - { - extern const char *Version_string; - 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) -{ - 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("X command without `ps:' tag ignored"); - return; - } - for (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; -} - -static void usage(); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - while ((c = getopt(argc, argv, "F:glmc:w:vb:")) != EOF) - switch(c) { - case 'v': - { - extern const char *Version_string; - fprintf(stderr, "grops version %s\n", Version_string); - fflush(stderr); - break; - } - case 'c': - if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { - error("bad number of copies `%s'", optarg); - ncopies = 1; - } - break; - case 'g': - guess_flag = 1; - break; - case 'l': - landscape_flag = 1; - break; - case 'm': - manual_feed_flag = 1; - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'w': - if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { - error("bad linewidth `%1'", optarg); - linewidth = -1; - } - break; - case 'b': - // XXX check this - broken_flags = atoi(optarg); - bflag = 1; - break; - case '?': - usage(); - 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() -{ - fprintf(stderr, "usage: %s [-glmv] [-b n] [-c n] [-w n] [-F dir] [files ...]\n", - program_name); - exit(1); -} |