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_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_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::end_page(int) { flush_sbuf(); set_color(&default_color); out.put_symbol("EP"); if (invis_count != 0) { error("missing `endinvis' command"); invis_count = 0; } }
void ps_printer::do_def(char *arg, const environment *) { flush_sbuf(); while (csspace(*arg)) arg++; if (!check_line_lengths(arg)) warning("lines in X def command should" " not be more than 255 characters long"); defs += arg; if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') defs += '\n'; ndefs++; }
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) { flush_sbuf(); if (sbuf_color != *env->col) set_color(env->col); (this->*(proc_table[i].proc))(p, env); return; } error("X command `%1' not recognised", command); }
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::set_char(glyph *g, font *f, const environment *env, int w, const char *) { if (g == space_glyph || invis_count > 0) return; unsigned char code; subencoding *sub = set_subencoding(f, g, &code); style sty(f, sub, 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_glyph) && !sub) { sbuf_space_code = f->get_code(space_glyph); 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); }
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::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("superfluous 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") .put_symbol("PEND"); }