/contrib/groff/src/devices/grops/ps.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 1881 lines · 1685 code · 97 blank · 99 comment · 452 complexity · 195c286c3997beffa5b6a3eaf9e50ebd MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. /*
  18. * PostScript documentation:
  19. * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf
  20. * http://partners.adobe.com/asn/developer/pdfs/tn/5001.DSC_Spec.pdf
  21. */
  22. #include "driver.h"
  23. #include "stringclass.h"
  24. #include "cset.h"
  25. #include "nonposix.h"
  26. #include "paper.h"
  27. #include "ps.h"
  28. #include <time.h>
  29. #ifdef NEED_DECLARATION_PUTENV
  30. extern "C" {
  31. int putenv(const char *);
  32. }
  33. #endif /* NEED_DECLARATION_PUTENV */
  34. extern "C" const char *Version_string;
  35. // search path defaults to the current directory
  36. search_path include_search_path(0, 0, 0, 1);
  37. static int landscape_flag = 0;
  38. static int manual_feed_flag = 0;
  39. static int ncopies = 1;
  40. static int linewidth = -1;
  41. // Non-zero means generate PostScript code that guesses the paper
  42. // length using the imageable area.
  43. static int guess_flag = 0;
  44. static double user_paper_length = 0;
  45. static double user_paper_width = 0;
  46. // Non-zero if -b was specified on the command line.
  47. static int bflag = 0;
  48. unsigned broken_flags = 0;
  49. // Non-zero means we need the CMYK extension for PostScript Level 1
  50. static int cmyk_flag = 0;
  51. #define DEFAULT_LINEWIDTH 40 /* in ems/1000 */
  52. #define MAX_LINE_LENGTH 72
  53. #define FILL_MAX 1000
  54. const char *const dict_name = "grops";
  55. const char *const defs_dict_name = "DEFS";
  56. const int DEFS_DICT_SPARE = 50;
  57. double degrees(double r)
  58. {
  59. return r*180.0/PI;
  60. }
  61. double radians(double d)
  62. {
  63. return d*PI/180.0;
  64. }
  65. // This is used for testing whether a character should be output in the
  66. // PostScript file using \nnn, so we really want the character to be
  67. // less than 0200.
  68. inline int is_ascii(char c)
  69. {
  70. return (unsigned char)c < 0200;
  71. }
  72. ps_output::ps_output(FILE *f, int n)
  73. : fp(f), col(0), max_line_length(n), need_space(0), fixed_point(0)
  74. {
  75. }
  76. ps_output &ps_output::set_file(FILE *f)
  77. {
  78. fp = f;
  79. col = 0;
  80. return *this;
  81. }
  82. ps_output &ps_output::copy_file(FILE *infp)
  83. {
  84. int c;
  85. while ((c = getc(infp)) != EOF)
  86. putc(c, fp);
  87. return *this;
  88. }
  89. ps_output &ps_output::end_line()
  90. {
  91. if (col != 0) {
  92. putc('\n', fp);
  93. col = 0;
  94. need_space = 0;
  95. }
  96. return *this;
  97. }
  98. ps_output &ps_output::special(const char *s)
  99. {
  100. if (s == 0 || *s == '\0')
  101. return *this;
  102. if (col != 0) {
  103. putc('\n', fp);
  104. col = 0;
  105. }
  106. fputs(s, fp);
  107. if (strchr(s, '\0')[-1] != '\n')
  108. putc('\n', fp);
  109. need_space = 0;
  110. return *this;
  111. }
  112. ps_output &ps_output::simple_comment(const char *s)
  113. {
  114. if (col != 0)
  115. putc('\n', fp);
  116. putc('%', fp);
  117. putc('%', fp);
  118. fputs(s, fp);
  119. putc('\n', fp);
  120. col = 0;
  121. need_space = 0;
  122. return *this;
  123. }
  124. ps_output &ps_output::begin_comment(const char *s)
  125. {
  126. if (col != 0)
  127. putc('\n', fp);
  128. putc('%', fp);
  129. putc('%', fp);
  130. fputs(s, fp);
  131. col = 2 + strlen(s);
  132. return *this;
  133. }
  134. ps_output &ps_output::end_comment()
  135. {
  136. if (col != 0) {
  137. putc('\n', fp);
  138. col = 0;
  139. }
  140. need_space = 0;
  141. return *this;
  142. }
  143. ps_output &ps_output::comment_arg(const char *s)
  144. {
  145. int len = strlen(s);
  146. if (col + len + 1 > max_line_length) {
  147. putc('\n', fp);
  148. fputs("%%+", fp);
  149. col = 3;
  150. }
  151. putc(' ', fp);
  152. fputs(s, fp);
  153. col += len + 1;
  154. return *this;
  155. }
  156. ps_output &ps_output::set_fixed_point(int n)
  157. {
  158. assert(n >= 0 && n <= 10);
  159. fixed_point = n;
  160. return *this;
  161. }
  162. ps_output &ps_output::put_delimiter(char c)
  163. {
  164. if (col + 1 > max_line_length) {
  165. putc('\n', fp);
  166. col = 0;
  167. }
  168. putc(c, fp);
  169. col++;
  170. need_space = 0;
  171. return *this;
  172. }
  173. ps_output &ps_output::put_string(const char *s, int n)
  174. {
  175. int len = 0;
  176. int i;
  177. for (i = 0; i < n; i++) {
  178. char c = s[i];
  179. if (is_ascii(c) && csprint(c)) {
  180. if (c == '(' || c == ')' || c == '\\')
  181. len += 2;
  182. else
  183. len += 1;
  184. }
  185. else
  186. len += 4;
  187. }
  188. if (len > n*2) {
  189. if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) {
  190. putc('\n', fp);
  191. col = 0;
  192. }
  193. if (col + 1 > max_line_length) {
  194. putc('\n', fp);
  195. col = 0;
  196. }
  197. putc('<', fp);
  198. col++;
  199. for (i = 0; i < n; i++) {
  200. if (col + 2 > max_line_length) {
  201. putc('\n', fp);
  202. col = 0;
  203. }
  204. fprintf(fp, "%02x", s[i] & 0377);
  205. col += 2;
  206. }
  207. putc('>', fp);
  208. col++;
  209. }
  210. else {
  211. if (col + len + 2 > max_line_length && len + 2 <= max_line_length) {
  212. putc('\n', fp);
  213. col = 0;
  214. }
  215. if (col + 2 > max_line_length) {
  216. putc('\n', fp);
  217. col = 0;
  218. }
  219. putc('(', fp);
  220. col++;
  221. for (i = 0; i < n; i++) {
  222. char c = s[i];
  223. if (is_ascii(c) && csprint(c)) {
  224. if (c == '(' || c == ')' || c == '\\')
  225. len = 2;
  226. else
  227. len = 1;
  228. }
  229. else
  230. len = 4;
  231. if (col + len + 1 > max_line_length) {
  232. putc('\\', fp);
  233. putc('\n', fp);
  234. col = 0;
  235. }
  236. switch (len) {
  237. case 1:
  238. putc(c, fp);
  239. break;
  240. case 2:
  241. putc('\\', fp);
  242. putc(c, fp);
  243. break;
  244. case 4:
  245. fprintf(fp, "\\%03o", c & 0377);
  246. break;
  247. default:
  248. assert(0);
  249. }
  250. col += len;
  251. }
  252. putc(')', fp);
  253. col++;
  254. }
  255. need_space = 0;
  256. return *this;
  257. }
  258. ps_output &ps_output::put_number(int n)
  259. {
  260. char buf[1 + INT_DIGITS + 1];
  261. sprintf(buf, "%d", n);
  262. int len = strlen(buf);
  263. if (col > 0 && col + len + need_space > max_line_length) {
  264. putc('\n', fp);
  265. col = 0;
  266. need_space = 0;
  267. }
  268. if (need_space) {
  269. putc(' ', fp);
  270. col++;
  271. }
  272. fputs(buf, fp);
  273. col += len;
  274. need_space = 1;
  275. return *this;
  276. }
  277. ps_output &ps_output::put_fix_number(int i)
  278. {
  279. const char *p = if_to_a(i, fixed_point);
  280. int len = strlen(p);
  281. if (col > 0 && col + len + need_space > max_line_length) {
  282. putc('\n', fp);
  283. col = 0;
  284. need_space = 0;
  285. }
  286. if (need_space) {
  287. putc(' ', fp);
  288. col++;
  289. }
  290. fputs(p, fp);
  291. col += len;
  292. need_space = 1;
  293. return *this;
  294. }
  295. ps_output &ps_output::put_float(double d)
  296. {
  297. char buf[128];
  298. sprintf(buf, "%.4f", d);
  299. int last = strlen(buf) - 1;
  300. while (buf[last] == '0')
  301. last--;
  302. if (buf[last] == '.')
  303. last--;
  304. buf[++last] = '\0';
  305. if (col > 0 && col + last + need_space > max_line_length) {
  306. putc('\n', fp);
  307. col = 0;
  308. need_space = 0;
  309. }
  310. if (need_space) {
  311. putc(' ', fp);
  312. col++;
  313. }
  314. fputs(buf, fp);
  315. col += last;
  316. need_space = 1;
  317. return *this;
  318. }
  319. ps_output &ps_output::put_symbol(const char *s)
  320. {
  321. int len = strlen(s);
  322. if (col > 0 && col + len + need_space > max_line_length) {
  323. putc('\n', fp);
  324. col = 0;
  325. need_space = 0;
  326. }
  327. if (need_space) {
  328. putc(' ', fp);
  329. col++;
  330. }
  331. fputs(s, fp);
  332. col += len;
  333. need_space = 1;
  334. return *this;
  335. }
  336. ps_output &ps_output::put_color(unsigned int c)
  337. {
  338. char buf[128];
  339. sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL);
  340. int len = strlen(buf);
  341. if (col > 0 && col + len + need_space > max_line_length) {
  342. putc('\n', fp);
  343. col = 0;
  344. need_space = 0;
  345. }
  346. if (need_space) {
  347. putc(' ', fp);
  348. col++;
  349. }
  350. fputs(buf, fp);
  351. col += len;
  352. need_space = 1;
  353. return *this;
  354. }
  355. ps_output &ps_output::put_literal_symbol(const char *s)
  356. {
  357. int len = strlen(s);
  358. if (col > 0 && col + len + 1 > max_line_length) {
  359. putc('\n', fp);
  360. col = 0;
  361. }
  362. putc('/', fp);
  363. fputs(s, fp);
  364. col += len + 1;
  365. need_space = 1;
  366. return *this;
  367. }
  368. class ps_font : public font {
  369. ps_font(const char *);
  370. public:
  371. int encoding_index;
  372. char *encoding;
  373. char *reencoded_name;
  374. ~ps_font();
  375. void handle_unknown_font_command(const char *command, const char *arg,
  376. const char *filename, int lineno);
  377. static ps_font *load_ps_font(const char *);
  378. };
  379. ps_font *ps_font::load_ps_font(const char *s)
  380. {
  381. ps_font *f = new ps_font(s);
  382. if (!f->load()) {
  383. delete f;
  384. return 0;
  385. }
  386. return f;
  387. }
  388. ps_font::ps_font(const char *nm)
  389. : font(nm), encoding_index(-1), encoding(0), reencoded_name(0)
  390. {
  391. }
  392. ps_font::~ps_font()
  393. {
  394. a_delete encoding;
  395. a_delete reencoded_name;
  396. }
  397. void ps_font::handle_unknown_font_command(const char *command, const char *arg,
  398. const char *filename, int lineno)
  399. {
  400. if (strcmp(command, "encoding") == 0) {
  401. if (arg == 0)
  402. error_with_file_and_line(filename, lineno,
  403. "`encoding' command requires an argument");
  404. else
  405. encoding = strsave(arg);
  406. }
  407. }
  408. static void handle_unknown_desc_command(const char *command, const char *arg,
  409. const char *filename, int lineno)
  410. {
  411. if (strcmp(command, "broken") == 0) {
  412. if (arg == 0)
  413. error_with_file_and_line(filename, lineno,
  414. "`broken' command requires an argument");
  415. else if (!bflag)
  416. broken_flags = atoi(arg);
  417. }
  418. }
  419. struct subencoding {
  420. font *p;
  421. unsigned int num;
  422. int idx;
  423. char *subfont;
  424. const char *glyphs[256];
  425. subencoding *next;
  426. subencoding(font *, unsigned int, int, subencoding *);
  427. ~subencoding();
  428. };
  429. subencoding::subencoding(font *f, unsigned int n, int ix, subencoding *s)
  430. : p(f), num(n), idx(ix), subfont(0), next(s)
  431. {
  432. for (int i = 0; i < 256; i++)
  433. glyphs[i] = 0;
  434. }
  435. subencoding::~subencoding()
  436. {
  437. a_delete subfont;
  438. }
  439. struct style {
  440. font *f;
  441. subencoding *sub;
  442. int point_size;
  443. int height;
  444. int slant;
  445. style();
  446. style(font *, subencoding *, int, int, int);
  447. int operator==(const style &) const;
  448. int operator!=(const style &) const;
  449. };
  450. style::style() : f(0)
  451. {
  452. }
  453. style::style(font *p, subencoding *s, int sz, int h, int sl)
  454. : f(p), sub(s), point_size(sz), height(h), slant(sl)
  455. {
  456. }
  457. int style::operator==(const style &s) const
  458. {
  459. return (f == s.f
  460. && sub == s.sub
  461. && point_size == s.point_size
  462. && height == s.height
  463. && slant == s.slant);
  464. }
  465. int style::operator!=(const style &s) const
  466. {
  467. return !(*this == s);
  468. }
  469. class ps_printer : public printer {
  470. FILE *tempfp;
  471. ps_output out;
  472. int res;
  473. int space_char_index;
  474. int pages_output;
  475. int paper_length;
  476. int equalise_spaces;
  477. enum { SBUF_SIZE = 256 };
  478. char sbuf[SBUF_SIZE];
  479. int sbuf_len;
  480. int sbuf_start_hpos;
  481. int sbuf_vpos;
  482. int sbuf_end_hpos;
  483. int sbuf_space_width;
  484. int sbuf_space_count;
  485. int sbuf_space_diff_count;
  486. int sbuf_space_code;
  487. int sbuf_kern;
  488. style sbuf_style;
  489. color sbuf_color; // the current PS color
  490. style output_style;
  491. subencoding *subencodings;
  492. int output_hpos;
  493. int output_vpos;
  494. int output_draw_point_size;
  495. int line_thickness;
  496. int output_line_thickness;
  497. unsigned char output_space_code;
  498. enum { MAX_DEFINED_STYLES = 50 };
  499. style defined_styles[MAX_DEFINED_STYLES];
  500. int ndefined_styles;
  501. int next_encoding_index;
  502. int next_subencoding_index;
  503. string defs;
  504. int ndefs;
  505. resource_manager rm;
  506. int invis_count;
  507. void flush_sbuf();
  508. void set_style(const style &);
  509. void set_space_code(unsigned char c);
  510. int set_encoding_index(ps_font *);
  511. subencoding *set_subencoding(font *, int, unsigned char *);
  512. char *get_subfont(subencoding *, const char *);
  513. void do_exec(char *, const environment *);
  514. void do_import(char *, const environment *);
  515. void do_def(char *, const environment *);
  516. void do_mdef(char *, const environment *);
  517. void do_file(char *, const environment *);
  518. void do_invis(char *, const environment *);
  519. void do_endinvis(char *, const environment *);
  520. void set_line_thickness_and_color(const environment *);
  521. void fill_path(const environment *);
  522. void encode_fonts();
  523. void encode_subfont(subencoding *);
  524. void define_encoding(const char *, int);
  525. void reencode_font(ps_font *);
  526. void set_color(color *c, int fill = 0);
  527. const char *media_name();
  528. int media_width();
  529. int media_height();
  530. void media_set();
  531. public:
  532. ps_printer(double);
  533. ~ps_printer();
  534. void set_char(int i, font *f, const environment *env, int w,
  535. const char *name);
  536. void draw(int code, int *p, int np, const environment *env);
  537. void begin_page(int);
  538. void end_page(int);
  539. void special(char *arg, const environment *env, char type);
  540. font *make_font(const char *);
  541. void end_of_line();
  542. };
  543. // `pl' is in inches
  544. ps_printer::ps_printer(double pl)
  545. : out(0, MAX_LINE_LENGTH),
  546. pages_output(0),
  547. sbuf_len(0),
  548. subencodings(0),
  549. output_hpos(-1),
  550. output_vpos(-1),
  551. line_thickness(-1),
  552. ndefined_styles(0),
  553. next_encoding_index(0),
  554. next_subencoding_index(0),
  555. ndefs(0),
  556. invis_count(0)
  557. {
  558. tempfp = xtmpfile();
  559. out.set_file(tempfp);
  560. if (linewidth < 0)
  561. linewidth = DEFAULT_LINEWIDTH;
  562. if (font::hor != 1)
  563. fatal("horizontal resolution must be 1");
  564. if (font::vert != 1)
  565. fatal("vertical resolution must be 1");
  566. if (font::res % (font::sizescale*72) != 0)
  567. fatal("res must be a multiple of 72*sizescale");
  568. int r = font::res;
  569. int point = 0;
  570. while (r % 10 == 0) {
  571. r /= 10;
  572. point++;
  573. }
  574. res = r;
  575. out.set_fixed_point(point);
  576. space_char_index = font::name_to_index("space");
  577. if (pl == 0)
  578. paper_length = font::paperlength;
  579. else
  580. paper_length = int(pl * font::res + 0.5);
  581. if (paper_length == 0)
  582. paper_length = 11 * font::res;
  583. equalise_spaces = font::res >= 72000;
  584. }
  585. int ps_printer::set_encoding_index(ps_font *f)
  586. {
  587. if (f->encoding_index >= 0)
  588. return f->encoding_index;
  589. for (font_pointer_list *p = font_list; p; p = p->next)
  590. if (p->p != f) {
  591. char *encoding = ((ps_font *)p->p)->encoding;
  592. int encoding_index = ((ps_font *)p->p)->encoding_index;
  593. if (encoding != 0 && encoding_index >= 0
  594. && strcmp(f->encoding, encoding) == 0) {
  595. return f->encoding_index = encoding_index;
  596. }
  597. }
  598. return f->encoding_index = next_encoding_index++;
  599. }
  600. subencoding *ps_printer::set_subencoding(font *f, int i, unsigned char *codep)
  601. {
  602. unsigned int idx = f->get_code(i);
  603. *codep = idx % 256;
  604. unsigned int num = idx >> 8;
  605. if (num == 0)
  606. return 0;
  607. subencoding *p = 0;
  608. for (p = subencodings; p; p = p->next)
  609. if (p->p == f && p->num == num)
  610. break;
  611. if (p == 0)
  612. p = subencodings = new subencoding(f, num, next_subencoding_index++,
  613. subencodings);
  614. p->glyphs[*codep] = f->get_special_device_encoding(i);
  615. return p;
  616. }
  617. char *ps_printer::get_subfont(subencoding *sub, const char *stem)
  618. {
  619. assert(sub != 0);
  620. if (!sub->subfont) {
  621. char *tem = new char[strlen(stem) + 2 + INT_DIGITS + 1];
  622. sprintf(tem, "%s@@%d", stem, next_subencoding_index);
  623. sub->subfont = tem;
  624. }
  625. return sub->subfont;
  626. }
  627. void ps_printer::set_char(int i, font *f, const environment *env, int w,
  628. const char *)
  629. {
  630. if (i == space_char_index || invis_count > 0)
  631. return;
  632. unsigned char code;
  633. subencoding *sub = set_subencoding(f, i, &code);
  634. style sty(f, sub, env->size, env->height, env->slant);
  635. if (sty.slant != 0) {
  636. if (sty.slant > 80 || sty.slant < -80) {
  637. error("silly slant `%1' degrees", sty.slant);
  638. sty.slant = 0;
  639. }
  640. }
  641. if (sbuf_len > 0) {
  642. if (sbuf_len < SBUF_SIZE
  643. && sty == sbuf_style
  644. && sbuf_vpos == env->vpos
  645. && sbuf_color == *env->col) {
  646. if (sbuf_end_hpos == env->hpos) {
  647. sbuf[sbuf_len++] = code;
  648. sbuf_end_hpos += w + sbuf_kern;
  649. return;
  650. }
  651. if (sbuf_len == 1 && sbuf_kern == 0) {
  652. sbuf_kern = env->hpos - sbuf_end_hpos;
  653. sbuf_end_hpos = env->hpos + sbuf_kern + w;
  654. sbuf[sbuf_len++] = code;
  655. return;
  656. }
  657. /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off
  658. starting a new string. */
  659. if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos
  660. && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) {
  661. if (sbuf_space_code < 0) {
  662. if (f->contains(space_char_index)) {
  663. sbuf_space_code = f->get_code(space_char_index);
  664. sbuf_space_width = env->hpos - sbuf_end_hpos;
  665. sbuf_end_hpos = env->hpos + w + sbuf_kern;
  666. sbuf[sbuf_len++] = sbuf_space_code;
  667. sbuf[sbuf_len++] = code;
  668. sbuf_space_count++;
  669. return;
  670. }
  671. }
  672. else {
  673. int diff = env->hpos - sbuf_end_hpos - sbuf_space_width;
  674. if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) {
  675. sbuf_end_hpos = env->hpos + w + sbuf_kern;
  676. sbuf[sbuf_len++] = sbuf_space_code;
  677. sbuf[sbuf_len++] = code;
  678. sbuf_space_count++;
  679. if (diff == 1)
  680. sbuf_space_diff_count++;
  681. else if (diff == -1)
  682. sbuf_space_diff_count--;
  683. return;
  684. }
  685. }
  686. }
  687. }
  688. flush_sbuf();
  689. }
  690. sbuf_len = 1;
  691. sbuf[0] = code;
  692. sbuf_end_hpos = env->hpos + w;
  693. sbuf_start_hpos = env->hpos;
  694. sbuf_vpos = env->vpos;
  695. sbuf_style = sty;
  696. sbuf_space_code = -1;
  697. sbuf_space_width = 0;
  698. sbuf_space_count = sbuf_space_diff_count = 0;
  699. sbuf_kern = 0;
  700. if (sbuf_color != *env->col)
  701. set_color(env->col);
  702. }
  703. static char *make_encoding_name(int encoding_index)
  704. {
  705. static char buf[3 + INT_DIGITS + 1];
  706. sprintf(buf, "ENC%d", encoding_index);
  707. return buf;
  708. }
  709. static char *make_subencoding_name(int subencoding_index)
  710. {
  711. static char buf[6 + INT_DIGITS + 1];
  712. sprintf(buf, "SUBENC%d", subencoding_index);
  713. return buf;
  714. }
  715. const char *const WS = " \t\n\r";
  716. void ps_printer::define_encoding(const char *encoding, int encoding_index)
  717. {
  718. char *vec[256];
  719. int i;
  720. for (i = 0; i < 256; i++)
  721. vec[i] = 0;
  722. char *path;
  723. FILE *fp = font::open_file(encoding, &path);
  724. if (fp == 0)
  725. fatal("can't open encoding file `%1'", encoding);
  726. int lineno = 1;
  727. const int BUFFER_SIZE = 512;
  728. char buf[BUFFER_SIZE];
  729. while (fgets(buf, BUFFER_SIZE, fp) != 0) {
  730. char *p = buf;
  731. while (csspace(*p))
  732. p++;
  733. if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) {
  734. char *q = strtok(0, WS);
  735. int n = 0; // pacify compiler
  736. if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256)
  737. fatal_with_file_and_line(path, lineno, "bad second field");
  738. vec[n] = new char[strlen(p) + 1];
  739. strcpy(vec[n], p);
  740. }
  741. lineno++;
  742. }
  743. a_delete path;
  744. out.put_literal_symbol(make_encoding_name(encoding_index))
  745. .put_delimiter('[');
  746. for (i = 0; i < 256; i++) {
  747. if (vec[i] == 0)
  748. out.put_literal_symbol(".notdef");
  749. else {
  750. out.put_literal_symbol(vec[i]);
  751. a_delete vec[i];
  752. }
  753. }
  754. out.put_delimiter(']')
  755. .put_symbol("def");
  756. fclose(fp);
  757. }
  758. void ps_printer::reencode_font(ps_font *f)
  759. {
  760. out.put_literal_symbol(f->reencoded_name)
  761. .put_symbol(make_encoding_name(f->encoding_index))
  762. .put_literal_symbol(f->get_internal_name())
  763. .put_symbol("RE");
  764. }
  765. void ps_printer::encode_fonts()
  766. {
  767. if (next_encoding_index == 0)
  768. return;
  769. char *done_encoding = new char[next_encoding_index];
  770. for (int i = 0; i < next_encoding_index; i++)
  771. done_encoding[i] = 0;
  772. for (font_pointer_list *f = font_list; f; f = f->next) {
  773. int encoding_index = ((ps_font *)f->p)->encoding_index;
  774. if (encoding_index >= 0) {
  775. assert(encoding_index < next_encoding_index);
  776. if (!done_encoding[encoding_index]) {
  777. done_encoding[encoding_index] = 1;
  778. define_encoding(((ps_font *)f->p)->encoding, encoding_index);
  779. }
  780. reencode_font((ps_font *)f->p);
  781. }
  782. }
  783. a_delete done_encoding;
  784. }
  785. void ps_printer::encode_subfont(subencoding *sub)
  786. {
  787. assert(sub->glyphs != 0);
  788. out.put_literal_symbol(make_subencoding_name(sub->idx))
  789. .put_delimiter('[');
  790. for (int i = 0; i < 256; i++)
  791. {
  792. if (sub->glyphs[i])
  793. out.put_literal_symbol(sub->glyphs[i]);
  794. else
  795. out.put_literal_symbol(".notdef");
  796. }
  797. out.put_delimiter(']')
  798. .put_symbol("def");
  799. }
  800. void ps_printer::set_style(const style &sty)
  801. {
  802. char buf[1 + INT_DIGITS + 1];
  803. for (int i = 0; i < ndefined_styles; i++)
  804. if (sty == defined_styles[i]) {
  805. sprintf(buf, "F%d", i);
  806. out.put_symbol(buf);
  807. return;
  808. }
  809. if (ndefined_styles >= MAX_DEFINED_STYLES)
  810. ndefined_styles = 0;
  811. sprintf(buf, "F%d", ndefined_styles);
  812. out.put_literal_symbol(buf);
  813. const char *psname = sty.f->get_internal_name();
  814. if (psname == 0)
  815. fatal("no internalname specified for font `%1'", sty.f->get_name());
  816. char *encoding = ((ps_font *)sty.f)->encoding;
  817. if (sty.sub == 0) {
  818. if (encoding != 0) {
  819. char *s = ((ps_font *)sty.f)->reencoded_name;
  820. if (s == 0) {
  821. int ei = set_encoding_index((ps_font *)sty.f);
  822. char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1];
  823. sprintf(tem, "%s@%d", psname, ei);
  824. psname = tem;
  825. ((ps_font *)sty.f)->reencoded_name = tem;
  826. }
  827. else
  828. psname = s;
  829. }
  830. }
  831. else
  832. psname = get_subfont(sty.sub, psname);
  833. out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size);
  834. if (sty.height != 0 || sty.slant != 0) {
  835. int h = sty.height == 0 ? sty.point_size : sty.height;
  836. h *= font::res/(72*font::sizescale);
  837. int c = int(h*tan(radians(sty.slant)) + .5);
  838. out.put_fix_number(c)
  839. .put_fix_number(h)
  840. .put_literal_symbol(psname)
  841. .put_symbol("MF");
  842. }
  843. else {
  844. out.put_literal_symbol(psname)
  845. .put_symbol("SF");
  846. }
  847. defined_styles[ndefined_styles++] = sty;
  848. }
  849. void ps_printer::set_color(color *col, int fill)
  850. {
  851. sbuf_color = *col;
  852. unsigned int components[4];
  853. char s[3];
  854. color_scheme cs = col->get_components(components);
  855. s[0] = fill ? 'F' : 'C';
  856. s[2] = 0;
  857. switch (cs) {
  858. case DEFAULT: // black
  859. out.put_symbol("0");
  860. s[1] = 'g';
  861. break;
  862. case RGB:
  863. out.put_color(Red)
  864. .put_color(Green)
  865. .put_color(Blue);
  866. s[1] = 'r';
  867. break;
  868. case CMY:
  869. col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black);
  870. // fall through
  871. case CMYK:
  872. out.put_color(Cyan)
  873. .put_color(Magenta)
  874. .put_color(Yellow)
  875. .put_color(Black);
  876. s[1] = 'k';
  877. cmyk_flag = 1;
  878. break;
  879. case GRAY:
  880. out.put_color(Gray);
  881. s[1] = 'g';
  882. break;
  883. }
  884. out.put_symbol(s);
  885. }
  886. void ps_printer::set_space_code(unsigned char c)
  887. {
  888. out.put_literal_symbol("SC")
  889. .put_number(c)
  890. .put_symbol("def");
  891. }
  892. void ps_printer::end_of_line()
  893. {
  894. flush_sbuf();
  895. // this ensures that we do an absolute motion to the beginning of a line
  896. output_vpos = output_hpos = -1;
  897. }
  898. void ps_printer::flush_sbuf()
  899. {
  900. enum {
  901. NONE,
  902. RELATIVE_H,
  903. RELATIVE_V,
  904. RELATIVE_HV,
  905. ABSOLUTE
  906. } motion = NONE;
  907. int space_flag = 0;
  908. if (sbuf_len == 0)
  909. return;
  910. if (output_style != sbuf_style) {
  911. set_style(sbuf_style);
  912. output_style = sbuf_style;
  913. }
  914. int extra_space = 0;
  915. if (output_hpos < 0 || output_vpos < 0)
  916. motion = ABSOLUTE;
  917. else {
  918. if (output_hpos != sbuf_start_hpos)
  919. motion = RELATIVE_H;
  920. if (output_vpos != sbuf_vpos) {
  921. if (motion != NONE)
  922. motion = RELATIVE_HV;
  923. else
  924. motion = RELATIVE_V;
  925. }
  926. }
  927. if (sbuf_space_code >= 0) {
  928. int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size);
  929. if (w + sbuf_kern != sbuf_space_width) {
  930. if (sbuf_space_code != output_space_code) {
  931. set_space_code(sbuf_space_code);
  932. output_space_code = sbuf_space_code;
  933. }
  934. space_flag = 1;
  935. extra_space = sbuf_space_width - w - sbuf_kern;
  936. if (sbuf_space_diff_count > sbuf_space_count/2)
  937. extra_space++;
  938. else if (sbuf_space_diff_count < -(sbuf_space_count/2))
  939. extra_space--;
  940. }
  941. }
  942. if (space_flag)
  943. out.put_fix_number(extra_space);
  944. if (sbuf_kern != 0)
  945. out.put_fix_number(sbuf_kern);
  946. out.put_string(sbuf, sbuf_len);
  947. char command_array[] = {'A', 'B', 'C', 'D',
  948. 'E', 'F', 'G', 'H',
  949. 'I', 'J', 'K', 'L',
  950. 'M', 'N', 'O', 'P',
  951. 'Q', 'R', 'S', 'T'};
  952. char sym[2];
  953. sym[0] = command_array[motion*4 + space_flag + 2*(sbuf_kern != 0)];
  954. sym[1] = '\0';
  955. switch (motion) {
  956. case NONE:
  957. break;
  958. case ABSOLUTE:
  959. out.put_fix_number(sbuf_start_hpos)
  960. .put_fix_number(sbuf_vpos);
  961. break;
  962. case RELATIVE_H:
  963. out.put_fix_number(sbuf_start_hpos - output_hpos);
  964. break;
  965. case RELATIVE_V:
  966. out.put_fix_number(sbuf_vpos - output_vpos);
  967. break;
  968. case RELATIVE_HV:
  969. out.put_fix_number(sbuf_start_hpos - output_hpos)
  970. .put_fix_number(sbuf_vpos - output_vpos);
  971. break;
  972. default:
  973. assert(0);
  974. }
  975. out.put_symbol(sym);
  976. output_hpos = sbuf_end_hpos;
  977. output_vpos = sbuf_vpos;
  978. sbuf_len = 0;
  979. }
  980. void ps_printer::set_line_thickness_and_color(const environment *env)
  981. {
  982. if (line_thickness < 0) {
  983. if (output_draw_point_size != env->size) {
  984. // we ought to check for overflow here
  985. int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000;
  986. out.put_fix_number(lw)
  987. .put_symbol("LW");
  988. output_draw_point_size = env->size;
  989. output_line_thickness = -1;
  990. }
  991. }
  992. else {
  993. if (output_line_thickness != line_thickness) {
  994. out.put_fix_number(line_thickness)
  995. .put_symbol("LW");
  996. output_line_thickness = line_thickness;
  997. output_draw_point_size = -1;
  998. }
  999. }
  1000. if (sbuf_color != *env->col)
  1001. set_color(env->col);
  1002. }
  1003. void ps_printer::fill_path(const environment *env)
  1004. {
  1005. if (sbuf_color == *env->fill)
  1006. out.put_symbol("FL");
  1007. else
  1008. set_color(env->fill, 1);
  1009. }
  1010. void ps_printer::draw(int code, int *p, int np, const environment *env)
  1011. {
  1012. if (invis_count > 0)
  1013. return;
  1014. flush_sbuf();
  1015. int fill_flag = 0;
  1016. switch (code) {
  1017. case 'C':
  1018. fill_flag = 1;
  1019. // fall through
  1020. case 'c':
  1021. // troff adds an extra argument to C
  1022. if (np != 1 && !(code == 'C' && np == 2)) {
  1023. error("1 argument required for circle");
  1024. break;
  1025. }
  1026. out.put_fix_number(env->hpos + p[0]/2)
  1027. .put_fix_number(env->vpos)
  1028. .put_fix_number(p[0]/2)
  1029. .put_symbol("DC");
  1030. if (fill_flag)
  1031. fill_path(env);
  1032. else {
  1033. set_line_thickness_and_color(env);
  1034. out.put_symbol("ST");
  1035. }
  1036. break;
  1037. case 'l':
  1038. if (np != 2) {
  1039. error("2 arguments required for line");
  1040. break;
  1041. }
  1042. set_line_thickness_and_color(env);
  1043. out.put_fix_number(p[0] + env->hpos)
  1044. .put_fix_number(p[1] + env->vpos)
  1045. .put_fix_number(env->hpos)
  1046. .put_fix_number(env->vpos)
  1047. .put_symbol("DL");
  1048. break;
  1049. case 'E':
  1050. fill_flag = 1;
  1051. // fall through
  1052. case 'e':
  1053. if (np != 2) {
  1054. error("2 arguments required for ellipse");
  1055. break;
  1056. }
  1057. out.put_fix_number(p[0])
  1058. .put_fix_number(p[1])
  1059. .put_fix_number(env->hpos + p[0]/2)
  1060. .put_fix_number(env->vpos)
  1061. .put_symbol("DE");
  1062. if (fill_flag)
  1063. fill_path(env);
  1064. else {
  1065. set_line_thickness_and_color(env);
  1066. out.put_symbol("ST");
  1067. }
  1068. break;
  1069. case 'P':
  1070. fill_flag = 1;
  1071. // fall through
  1072. case 'p':
  1073. {
  1074. if (np & 1) {
  1075. error("even number of arguments required for polygon");
  1076. break;
  1077. }
  1078. if (np == 0) {
  1079. error("no arguments for polygon");
  1080. break;
  1081. }
  1082. out.put_fix_number(env->hpos)
  1083. .put_fix_number(env->vpos)
  1084. .put_symbol("MT");
  1085. for (int i = 0; i < np; i += 2)
  1086. out.put_fix_number(p[i])
  1087. .put_fix_number(p[i+1])
  1088. .put_symbol("RL");
  1089. out.put_symbol("CL");
  1090. if (fill_flag)
  1091. fill_path(env);
  1092. else {
  1093. set_line_thickness_and_color(env);
  1094. out.put_symbol("ST");
  1095. }
  1096. break;
  1097. }
  1098. case '~':
  1099. {
  1100. if (np & 1) {
  1101. error("even number of arguments required for spline");
  1102. break;
  1103. }
  1104. if (np == 0) {
  1105. error("no arguments for spline");
  1106. break;
  1107. }
  1108. out.put_fix_number(env->hpos)
  1109. .put_fix_number(env->vpos)
  1110. .put_symbol("MT");
  1111. out.put_fix_number(p[0]/2)
  1112. .put_fix_number(p[1]/2)
  1113. .put_symbol("RL");
  1114. /* tnum/tden should be between 0 and 1; the closer it is to 1
  1115. the tighter the curve will be to the guiding lines; 2/3
  1116. is the standard value */
  1117. const int tnum = 2;
  1118. const int tden = 3;
  1119. for (int i = 0; i < np - 2; i += 2) {
  1120. out.put_fix_number((p[i]*tnum)/(2*tden))
  1121. .put_fix_number((p[i + 1]*tnum)/(2*tden))
  1122. .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden))
  1123. .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden))
  1124. .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2)
  1125. .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2)
  1126. .put_symbol("RC");
  1127. }
  1128. out.put_fix_number(p[np - 2] - p[np - 2]/2)
  1129. .put_fix_number(p[np - 1] - p[np - 1]/2)
  1130. .put_symbol("RL");
  1131. set_line_thickness_and_color(env);
  1132. out.put_symbol("ST");
  1133. }
  1134. break;
  1135. case 'a':
  1136. {
  1137. if (np != 4) {
  1138. error("4 arguments required for arc");
  1139. break;
  1140. }
  1141. set_line_thickness_and_color(env);
  1142. double c[2];
  1143. if (adjust_arc_center(p, c))
  1144. out.put_fix_number(env->hpos + int(c[0]))
  1145. .put_fix_number(env->vpos + int(c[1]))
  1146. .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1])))
  1147. .put_float(degrees(atan2(-c[1], -c[0])))
  1148. .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0])))
  1149. .put_symbol("DA");
  1150. else
  1151. out.put_fix_number(p[0] + p[2] + env->hpos)
  1152. .put_fix_number(p[1] + p[3] + env->vpos)
  1153. .put_fix_number(env->hpos)
  1154. .put_fix_number(env->vpos)
  1155. .put_symbol("DL");
  1156. }
  1157. break;
  1158. case 't':
  1159. if (np == 0)
  1160. line_thickness = -1;
  1161. else {
  1162. // troff gratuitously adds an extra 0
  1163. if (np != 1 && np != 2) {
  1164. error("0 or 1 argument required for thickness");
  1165. break;
  1166. }
  1167. line_thickness = p[0];
  1168. }
  1169. break;
  1170. default:
  1171. error("unrecognised drawing command `%1'", char(code));
  1172. break;
  1173. }
  1174. output_hpos = output_vpos = -1;
  1175. }
  1176. const char *ps_printer::media_name()
  1177. {
  1178. return "Default";
  1179. }
  1180. int ps_printer::media_width()
  1181. {
  1182. /*
  1183. * NOTE:
  1184. * Although paper size is defined as real numbers, it seems to be
  1185. * a common convention to round to the nearest postscript unit.
  1186. * For example, a4 is really 595.276 by 841.89 but we use 595 by 842.
  1187. *
  1188. * This is probably a good compromise, especially since the
  1189. * Postscript definition specifies that media
  1190. * matching should be done within a tolerance of 5 units.
  1191. */
  1192. return int(user_paper_width ? user_paper_width*72.0 + 0.5
  1193. : font::paperwidth*72.0/font::res + 0.5);
  1194. }
  1195. int ps_printer::media_height()
  1196. {
  1197. return int(user_paper_length ? user_paper_length*72.0 + 0.5
  1198. : paper_length*72.0/font::res + 0.5);
  1199. }
  1200. void ps_printer::media_set()
  1201. {
  1202. /*
  1203. * The setpagedevice implies an erasepage and initgraphics, and
  1204. * must thus precede any descriptions for a particular page.
  1205. *
  1206. * NOTE:
  1207. * This does not work with ps2pdf when there are included eps
  1208. * segments that contain PageSize/setpagedevice.
  1209. * This might be a bug in ghostscript -- must be investigated.
  1210. * Using setpagedevice in an .eps is really the wrong concept, anyway.
  1211. *
  1212. * NOTE:
  1213. * For the future, this is really the place to insert other
  1214. * media selection features, like:
  1215. * MediaColor
  1216. * MediaPosition
  1217. * MediaType
  1218. * MediaWeight
  1219. * MediaClass
  1220. * TraySwitch
  1221. * ManualFeed
  1222. * InsertSheet
  1223. * Duplex
  1224. * Collate
  1225. * ProcessColorModel
  1226. * etc.
  1227. */
  1228. if (!(broken_flags & (USE_PS_ADOBE_2_0|NO_PAPERSIZE))) {
  1229. out.begin_comment("BeginFeature:")
  1230. .comment_arg("*PageSize")
  1231. .comment_arg(media_name())
  1232. .end_comment();
  1233. int w = media_width();
  1234. int h = media_height();
  1235. if (w > 0 && h > 0)
  1236. // warning to user is done elsewhere
  1237. fprintf(out.get_file(),
  1238. "<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n",
  1239. w, h);
  1240. out.simple_comment("EndFeature");
  1241. }
  1242. }
  1243. void ps_printer::begin_page(int n)
  1244. {
  1245. out.begin_comment("Page:")
  1246. .comment_arg(i_to_a(n));
  1247. out.comment_arg(i_to_a(++pages_output))
  1248. .end_comment();
  1249. output_style.f = 0;
  1250. output_space_code = 32;
  1251. output_draw_point_size = -1;
  1252. output_line_thickness = -1;
  1253. output_hpos = output_vpos = -1;
  1254. ndefined_styles = 0;
  1255. out.simple_comment("BeginPageSetup");
  1256. #if 0
  1257. /*
  1258. * NOTE:
  1259. * may decide to do this once per page
  1260. */
  1261. media_set();
  1262. #endif
  1263. out.put_symbol("BP")
  1264. .simple_comment("EndPageSetup");
  1265. if (sbuf_color != default_color)
  1266. set_color(&sbuf_color);
  1267. }
  1268. void ps_printer::end_page(int)
  1269. {
  1270. flush_sbuf();
  1271. set_color(&default_color);
  1272. out.put_symbol("EP");
  1273. if (invis_count != 0) {
  1274. error("missing `endinvis' command");
  1275. invis_count = 0;
  1276. }
  1277. }
  1278. font *ps_printer::make_font(const char *nm)
  1279. {
  1280. return ps_font::load_ps_font(nm);
  1281. }
  1282. ps_printer::~ps_printer()
  1283. {
  1284. out.simple_comment("Trailer")
  1285. .put_symbol("end")
  1286. .simple_comment("EOF");
  1287. if (fseek(tempfp, 0L, 0) < 0)
  1288. fatal("fseek on temporary file failed");
  1289. fputs("%!PS-Adobe-", stdout);
  1290. fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout);
  1291. putchar('\n');
  1292. out.set_file(stdout);
  1293. if (cmyk_flag)
  1294. out.begin_comment("Extensions:")
  1295. .comment_arg("CMYK")
  1296. .end_comment();
  1297. out.begin_comment("Creator:")
  1298. .comment_arg("groff")
  1299. .comment_arg("version")
  1300. .comment_arg(Version_string)
  1301. .end_comment();
  1302. {
  1303. fputs("%%CreationDate: ", out.get_file());
  1304. #ifdef LONG_FOR_TIME_T
  1305. long
  1306. #else
  1307. time_t
  1308. #endif
  1309. t = time(0);
  1310. fputs(ctime(&t), out.get_file());
  1311. }
  1312. for (font_pointer_list *f = font_list; f; f = f->next) {
  1313. ps_font *psf = (ps_font *)(f->p);
  1314. rm.need_font(psf->get_internal_name());
  1315. }
  1316. rm.print_header_comments(out);
  1317. out.begin_comment("Pages:")
  1318. .comment_arg(i_to_a(pages_output))
  1319. .end_comment();
  1320. out.begin_comment("PageOrder:")
  1321. .comment_arg("Ascend")
  1322. .end_comment();
  1323. if (!(broken_flags & NO_PAPERSIZE)) {
  1324. int w = media_width();
  1325. int h = media_height();
  1326. if (w > 0 && h > 0)
  1327. fprintf(out.get_file(),
  1328. "%%%%DocumentMedia: %s %d %d %d %s %s\n",
  1329. media_name(), // tag name of media
  1330. w, // media width
  1331. h, // media height
  1332. 0, // weight in g/m2
  1333. "()", // paper color, e.g. white
  1334. "()" // preprinted form type
  1335. );
  1336. else {
  1337. if (h <= 0)
  1338. // see ps_printer::ps_printer
  1339. warning("bad paper height, defaulting to 11i");
  1340. if (w <= 0)
  1341. warning("bad paper width");
  1342. }
  1343. }
  1344. out.begin_comment("Orientation:")
  1345. .comment_arg(landscape_flag ? "Landscape" : "Portrait")
  1346. .end_comment();
  1347. if (ncopies != 1) {
  1348. out.end_line();
  1349. fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies);
  1350. }
  1351. out.simple_comment("EndComments");
  1352. if (!(broken_flags & NO_PAPERSIZE)) {
  1353. /* gv works fine without this one, but it really should be there. */
  1354. out.simple_comment("BeginDefaults");
  1355. fprintf(out.get_file(), "%%%%PageMedia: %s\n", media_name());
  1356. out.simple_comment("EndDefaults");
  1357. }
  1358. out.simple_comment("BeginProlog");
  1359. rm.output_prolog(out);
  1360. if (!(broken_flags & NO_SETUP_SECTION)) {
  1361. out.simple_comment("EndProlog");
  1362. out.simple_comment("BeginSetup");
  1363. }
  1364. #if 1
  1365. /*
  1366. * Define paper (i.e., media) size for entire document here.
  1367. * This allows ps2pdf to correctly determine page size, for instance.
  1368. */
  1369. media_set();
  1370. #endif
  1371. rm.document_setup(out);
  1372. out.put_symbol(dict_name)
  1373. .put_symbol("begin");
  1374. if (ndefs > 0)
  1375. ndefs += DEFS_DICT_SPARE;
  1376. out.put_literal_symbol(defs_dict_name)
  1377. .put_number(ndefs + 1)
  1378. .put_symbol("dict")
  1379. .put_symbol("def");
  1380. out.put_symbol(defs_dict_name)
  1381. .put_symbol("begin");
  1382. out.put_literal_symbol("u")
  1383. .put_delimiter('{')
  1384. .put_fix_number(1)
  1385. .put_symbol("mul")
  1386. .put_delimiter('}')
  1387. .put_symbol("bind")
  1388. .put_symbol("def");
  1389. defs += '\0';
  1390. out.special(defs.contents());
  1391. out.put_symbol("end");
  1392. if (ncopies != 1)
  1393. out.put_literal_symbol("#copies")
  1394. .put_number(ncopies)
  1395. .put_symbol("def");
  1396. out.put_literal_symbol("RES")
  1397. .put_number(res)
  1398. .put_symbol("def");
  1399. out.put_literal_symbol("PL");
  1400. if (guess_flag)
  1401. out.put_symbol("PLG");
  1402. else
  1403. out.put_fix_number(paper_length);
  1404. out.put_symbol("def");
  1405. out.put_literal_symbol("LS")
  1406. .put_symbol(landscape_flag ? "true" : "false")
  1407. .put_symbol("def");
  1408. if (manual_feed_flag) {
  1409. out.begin_comment("BeginFeature:")
  1410. .comment_arg("*ManualFeed")
  1411. .comment_arg("True")
  1412. .end_comment()
  1413. .put_symbol("MANUAL")
  1414. .simple_comment("EndFeature");
  1415. }
  1416. encode_fonts();
  1417. while (subencodings) {
  1418. subencoding *tem = subencodings;
  1419. subencodings = subencodings->next;
  1420. encode_subfont(tem);
  1421. out.put_literal_symbol(tem->subfont)
  1422. .put_symbol(make_subencoding_name(tem->idx))
  1423. .put_literal_symbol(tem->p->get_internal_name())
  1424. .put_symbol("RE");
  1425. delete tem;
  1426. }
  1427. out.simple_comment((broken_flags & NO_SETUP_SECTION)
  1428. ? "EndProlog"
  1429. : "EndSetup");
  1430. out.end_line();
  1431. out.copy_file(tempfp);
  1432. fclose(tempfp);
  1433. }
  1434. void ps_printer::special(char *arg, const environment *env, char type)
  1435. {
  1436. if (type != 'p')
  1437. return;
  1438. typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *);
  1439. static struct {
  1440. const char *name;
  1441. SPECIAL_PROCP proc;
  1442. } proc_table[] = {
  1443. { "exec", &ps_printer::do_exec },
  1444. { "def", &ps_printer::do_def },
  1445. { "mdef", &ps_printer::do_mdef },
  1446. { "import", &ps_printer::do_import },
  1447. { "file", &ps_printer::do_file },
  1448. { "invis", &ps_printer::do_invis },
  1449. { "endinvis", &ps_printer::do_endinvis },
  1450. };
  1451. char *p;
  1452. for (p = arg; *p == ' ' || *p == '\n'; p++)
  1453. ;
  1454. char *tag = p;
  1455. for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
  1456. ;
  1457. if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) {
  1458. error("X command without `ps:' tag ignored");
  1459. return;
  1460. }
  1461. p++;
  1462. for (; *p == ' ' || *p == '\n'; p++)
  1463. ;
  1464. char *command = p;
  1465. for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
  1466. ;
  1467. if (*command == '\0') {
  1468. error("empty X command ignored");
  1469. return;
  1470. }
  1471. for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++)
  1472. if (strncmp(command, proc_table[i].name, p - command) == 0) {
  1473. (this->*(proc_table[i].proc))(p, env);
  1474. return;
  1475. }
  1476. error("X command `%1' not recognised", command);
  1477. }
  1478. // A conforming PostScript document must not have lines longer
  1479. // than 255 characters (excluding line termination characters).
  1480. static int check_line_lengths(const char *p)
  1481. {
  1482. for (;;) {
  1483. const char *end = strchr(p, '\n');
  1484. if (end == 0)
  1485. end = strchr(p, '\0');
  1486. if (end - p > 255)
  1487. return 0;
  1488. if (*end == '\0')
  1489. break;
  1490. p = end + 1;
  1491. }
  1492. return 1;
  1493. }
  1494. void ps_printer::do_exec(char *arg, const environment *env)
  1495. {
  1496. flush_sbuf();
  1497. while (csspace(*arg))
  1498. arg++;
  1499. if (*arg == '\0') {
  1500. error("missing argument to X exec command");
  1501. return;
  1502. }
  1503. if (!check_line_lengths(arg)) {
  1504. error("lines in X exec command must not be more than 255 characters long");
  1505. return;
  1506. }
  1507. out.put_fix_number(env->hpos)
  1508. .put_fix_number(env->vpos)
  1509. .put_symbol("EBEGIN")
  1510. .special(arg)
  1511. .put_symbol("EEND");
  1512. output_hpos = output_vpos = -1;
  1513. output_style.f = 0;
  1514. output_draw_point_size = -1;
  1515. output_line_thickness = -1;
  1516. ndefined_styles = 0;
  1517. if (!ndefs)
  1518. ndefs = 1;
  1519. }
  1520. void ps_printer::do_file(char *arg, const environment *env)
  1521. {
  1522. flush_sbuf();
  1523. while (csspace(*arg))
  1524. arg++;
  1525. if (*arg == '\0') {
  1526. error("missing argument to X file command");
  1527. return;
  1528. }
  1529. const char *filename = arg;
  1530. do {
  1531. ++arg;
  1532. } while (*arg != '\0' && *arg != ' ' && *arg != '\n');
  1533. out.put_fix_number(env->hpos)
  1534. .put_fix_number(env->vpos)
  1535. .put_symbol("EBEGIN");
  1536. rm.import_file(filename, out);
  1537. out.put_symbol("EEND");
  1538. output_hpos = output_vpos = -1;
  1539. output_style.f = 0;
  1540. output_draw_point_size = -1;
  1541. output_line_thickness = -1;
  1542. ndefined_styles = 0;
  1543. if (!ndefs)
  1544. ndefs = 1;
  1545. }
  1546. void ps_printer::do_def(char *arg, const environment *)
  1547. {
  1548. flush_sbuf();
  1549. while (csspace(*arg))
  1550. arg++;
  1551. if (!check_line_lengths(arg)) {
  1552. error("lines in X def command must not be more than 255 characters long");
  1553. return;
  1554. }
  1555. defs += arg;
  1556. if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
  1557. defs += '\n';
  1558. ndefs++;
  1559. }
  1560. // Like def, but the first argument says how many definitions it contains.
  1561. void ps_printer::do_mdef(char *arg, const environment *)
  1562. {
  1563. flush_sbuf();
  1564. char *p;
  1565. int n = (int)strtol(arg, &p, 10);
  1566. if (n == 0 && p == arg) {
  1567. error("first argument to X mdef must be an integer");
  1568. return;
  1569. }
  1570. if (n < 0) {
  1571. error("out of range argument `%1' to X mdef command", int(n));
  1572. return;
  1573. }
  1574. arg = p;
  1575. while (csspace(*arg))
  1576. arg++;
  1577. if (!check_line_lengths(arg)) {
  1578. error("lines in X mdef command must not be more than 255 characters long");
  1579. return;
  1580. }
  1581. defs += arg;
  1582. if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n')
  1583. defs += '\n';
  1584. ndefs += n;
  1585. }
  1586. void ps_printer::do_import(char *arg, const environment *env)
  1587. {
  1588. flush_sbuf();
  1589. while (*arg == ' ' || *arg == '\n')
  1590. arg++;
  1591. char *p;
  1592. for (p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++)
  1593. ;
  1594. if (*p != '\0')
  1595. *p++ = '\0';
  1596. int parms[6];
  1597. int nparms = 0;
  1598. while (nparms < 6) {
  1599. char *end;
  1600. long n = strtol(p, &end, 10);
  1601. if (n == 0 && end == p)
  1602. break;
  1603. parms[nparms++] = int(n);
  1604. p = end;
  1605. }
  1606. if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) {
  1607. error("scaling indicators not allowed in arguments for X import command");
  1608. return;
  1609. }
  1610. while (*p == ' ' || *p == '\n')
  1611. p++;
  1612. if (nparms < 5) {
  1613. if (*p == '\0')
  1614. error("too few arguments for X import command");
  1615. else
  1616. error("invalid argument `%1' for X import command", p);
  1617. return;
  1618. }
  1619. if (*p != '\0') {
  1620. error("superfluous argument `%1' for X import command", p);
  1621. return;
  1622. }
  1623. int llx = parms[0];
  1624. int lly = parms[1];
  1625. int urx = parms[2];
  1626. int ury = parms[3];
  1627. int desired_width = parms[4];
  1628. int desired_height = parms[5];
  1629. if (desired_width <= 0) {
  1630. error("bad width argument `%1' for X import command: must be > 0",
  1631. desired_width);
  1632. return;
  1633. }
  1634. if (nparms == 6 && desired_height <= 0) {
  1635. error("bad height argument `%1' for X import command: must be > 0",
  1636. desired_height);
  1637. return;
  1638. }
  1639. if (llx == urx) {
  1640. error("llx and urx arguments for X import command must not be equal");
  1641. return;
  1642. }
  1643. if (lly == ury) {
  1644. error("lly and ury arguments for X import command must not be equal");
  1645. return;
  1646. }
  1647. if (nparms == 5) {
  1648. int old_wid = urx - llx;
  1649. int old_ht = ury - lly;
  1650. if (old_wid < 0)
  1651. old_wid = -old_wid;
  1652. if (old_ht < 0)
  1653. old_ht = -old_ht;
  1654. desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5);
  1655. }
  1656. if (env->vpos - desired_height < 0)
  1657. warning("top of imported graphic is above the top of the page");
  1658. out.put_number(llx)
  1659. .put_number(lly)
  1660. .put_fix_number(desired_width)
  1661. .put_number(urx - llx)
  1662. .put_fix_number(-desired_height)
  1663. .put_number(ury - lly)
  1664. .put_fix_number(env->hpos)
  1665. .put_fix_number(env->vpos)
  1666. .put_symbol("PBEGIN");
  1667. rm.import_file(arg, out);
  1668. // do this here just in case application defines PEND
  1669. out.put_symbol("end")
  1670. .put_symbol("PEND");
  1671. }
  1672. void ps_printer::do_invis(char *, const environment *)
  1673. {
  1674. invis_count++;
  1675. }
  1676. void ps_printer::do_endinvis(char *, const environment *)
  1677. {
  1678. if (invis_count == 0)
  1679. error("unbalanced `endinvis' command");
  1680. else
  1681. --invis_count;
  1682. }
  1683. printer *make_printer()
  1684. {
  1685. return new ps_printer(user_paper_length);
  1686. }
  1687. static void usage(FILE *stream);
  1688. int main(int argc, char **argv)
  1689. {
  1690. setlocale(LC_NUMERIC, "C");
  1691. program_name = argv[0];
  1692. string env;
  1693. static char stderr_buf[BUFSIZ];
  1694. setbuf(stderr, stderr_buf);
  1695. int c;
  1696. static const struct option long_options[] = {
  1697. { "help", no_argument, 0, CHAR_MAX + 1 },
  1698. { "version", no_argument, 0, 'v' },
  1699. { NULL, 0, 0, 0 }
  1700. };
  1701. while ((c = getopt_long(argc, argv, "b:c:F:gI:lmp:P:vw:", long_options, NULL))
  1702. != EOF)
  1703. switch(c) {
  1704. case 'b':
  1705. // XXX check this
  1706. broken_flags = atoi(optarg);
  1707. bflag = 1;
  1708. break;
  1709. case 'c':
  1710. if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) {
  1711. error("bad number of copies `%s'", optarg);
  1712. ncopies = 1;
  1713. }
  1714. break;
  1715. case 'F':
  1716. font::command_line_font_dir(optarg);
  1717. break;
  1718. case 'g':
  1719. guess_flag = 1;
  1720. break;
  1721. case 'I':
  1722. include_search_path.command_line_dir(optarg);
  1723. break;
  1724. case 'l':
  1725. landscape_flag = 1;
  1726. break;
  1727. case 'm':
  1728. manual_feed_flag = 1;
  1729. break;
  1730. case 'p':
  1731. if (!font::scan_papersize(optarg, 0,
  1732. &user_paper_length, &user_paper_width))
  1733. error("invalid custom paper size `%1' ignored", optarg);
  1734. break;
  1735. case 'P':
  1736. env = "GROPS_PROLOGUE";
  1737. env += '=';
  1738. env += optarg;
  1739. env += '\0';
  1740. if (putenv(strsave(env.contents())))
  1741. fatal("putenv failed");
  1742. break;
  1743. case 'v':
  1744. printf("GNU grops (groff) version %s\n", Version_string);
  1745. exit(0);
  1746. break;
  1747. case 'w':
  1748. if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) {
  1749. error("bad linewidth `%1'", optarg);
  1750. linewidth = -1;
  1751. }
  1752. break;
  1753. case CHAR_MAX + 1: // --help
  1754. usage(stdout);
  1755. exit(0);
  1756. break;
  1757. case '?':
  1758. usage(stderr);
  1759. exit(1);
  1760. break;
  1761. default:
  1762. assert(0);
  1763. }
  1764. font::set_unknown_desc_command_handler(handle_unknown_desc_command);
  1765. SET_BINARY(fileno(stdout));
  1766. if (optind >= argc)
  1767. do_file("-");
  1768. else {
  1769. for (int i = optind; i < argc; i++)
  1770. do_file(argv[i]);
  1771. }
  1772. return 0;
  1773. }
  1774. static void usage(FILE *stream)
  1775. {
  1776. fprintf(stream,
  1777. "usage: %s [-glmv] [-b n] [-c n] [-w n] [-I dir] [-P prologue]\n"
  1778. " [-F dir] [files ...]\n",
  1779. program_name);
  1780. }