blob: b6fa95bebecea4821334ea61deac98eb406d9c9f [file] [log] [blame]
Bram Moolenaar81366db2005-07-24 21:16:51 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * hardcopy.c: printing to paper
12 */
13
14#include "vim.h"
15#include "version.h"
16
17#if defined(FEAT_PRINTER) || defined(PROTO)
18/*
19 * To implement printing on a platform, the following functions must be
20 * defined:
21 *
22 * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
23 * Called once. Code should display printer dialogue (if appropriate) and
24 * determine printer font and margin settings. Reset has_color if the printer
25 * doesn't support colors at all.
26 * Returns FAIL to abort.
27 *
28 * int mch_print_begin(prt_settings_T *settings)
29 * Called to start the print job.
30 * Return FALSE to abort.
31 *
32 * int mch_print_begin_page(char_u *msg)
33 * Called at the start of each page.
34 * "msg" indicates the progress of the print job, can be NULL.
35 * Return FALSE to abort.
36 *
37 * int mch_print_end_page()
38 * Called at the end of each page.
39 * Return FALSE to abort.
40 *
41 * int mch_print_blank_page()
42 * Called to generate a blank page for collated, duplex, multiple copy
43 * document. Return FALSE to abort.
44 *
45 * void mch_print_end(prt_settings_T *psettings)
46 * Called at normal end of print job.
47 *
48 * void mch_print_cleanup()
49 * Called if print job ends normally or is abandoned. Free any memory, close
50 * devices and handles. Also called when mch_print_begin() fails, but not
51 * when mch_print_init() fails.
52 *
53 * void mch_print_set_font(int Bold, int Italic, int Underline);
54 * Called whenever the font style changes.
55 *
Bram Moolenaar551dbcc2006-04-25 22:13:59 +000056 * void mch_print_set_bg(long_u bgcol);
Bram Moolenaar81366db2005-07-24 21:16:51 +000057 * Called to set the background color for the following text. Parameter is an
58 * RGB value.
59 *
Bram Moolenaar551dbcc2006-04-25 22:13:59 +000060 * void mch_print_set_fg(long_u fgcol);
Bram Moolenaar81366db2005-07-24 21:16:51 +000061 * Called to set the foreground color for the following text. Parameter is an
62 * RGB value.
63 *
64 * mch_print_start_line(int margin, int page_line)
65 * Sets the current position at the start of line "page_line".
66 * If margin is TRUE start in the left margin (for header and line number).
67 *
68 * int mch_print_text_out(char_u *p, int len);
69 * Output one character of text p[len] at the current position.
70 * Return TRUE if there is no room for another character in the same line.
71 *
72 * Note that the generic code has no idea of margins. The machine code should
73 * simply make the page look smaller! The header and the line numbers are
74 * printed in the margin.
75 */
76
77#ifdef FEAT_SYN_HL
78static const long_u cterm_color_8[8] =
79{
80 (long_u)0x000000L, (long_u)0xff0000L, (long_u)0x00ff00L, (long_u)0xffff00L,
81 (long_u)0x0000ffL, (long_u)0xff00ffL, (long_u)0x00ffffL, (long_u)0xffffffL
82};
83
84static const long_u cterm_color_16[16] =
85{
86 (long_u)0x000000L, (long_u)0x0000c0L, (long_u)0x008000L, (long_u)0x004080L,
87 (long_u)0xc00000L, (long_u)0xc000c0L, (long_u)0x808000L, (long_u)0xc0c0c0L,
88 (long_u)0x808080L, (long_u)0x6060ffL, (long_u)0x00ff00L, (long_u)0x00ffffL,
89 (long_u)0xff8080L, (long_u)0xff40ffL, (long_u)0xffff00L, (long_u)0xffffffL
90};
91
92static int current_syn_id;
93#endif
94
95#define PRCOLOR_BLACK (long_u)0
96#define PRCOLOR_WHITE (long_u)0xFFFFFFL
97
98static int curr_italic;
99static int curr_bold;
100static int curr_underline;
101static long_u curr_bg;
102static long_u curr_fg;
103static int page_count;
104
105#if defined(FEAT_MBYTE) && defined(FEAT_POSTSCRIPT)
106# define OPT_MBFONT_USECOURIER 0
107# define OPT_MBFONT_ASCII 1
108# define OPT_MBFONT_REGULAR 2
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000109# define OPT_MBFONT_BOLD 3
Bram Moolenaar81366db2005-07-24 21:16:51 +0000110# define OPT_MBFONT_OBLIQUE 4
111# define OPT_MBFONT_BOLDOBLIQUE 5
112# define OPT_MBFONT_NUM_OPTIONS 6
113
114static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =
115{
116 {"c", FALSE, 0, NULL, 0, FALSE},
117 {"a", FALSE, 0, NULL, 0, FALSE},
118 {"r", FALSE, 0, NULL, 0, FALSE},
119 {"b", FALSE, 0, NULL, 0, FALSE},
120 {"i", FALSE, 0, NULL, 0, FALSE},
121 {"o", FALSE, 0, NULL, 0, FALSE},
122};
123#endif
124
125/*
126 * These values determine the print position on a page.
127 */
128typedef struct
129{
130 int lead_spaces; /* remaining spaces for a TAB */
131 int print_pos; /* virtual column for computing TABs */
132 colnr_T column; /* byte column */
133 linenr_T file_line; /* line nr in the buffer */
134 long_u bytes_printed; /* bytes printed so far */
135 int ff; /* seen form feed character */
136} prt_pos_T;
137
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100138static char_u *parse_list_options(char_u *option_str, option_table_T *table, int table_size);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000139
140#ifdef FEAT_SYN_HL
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100141static long_u darken_rgb(long_u rgb);
142static long_u prt_get_term_color(int colorindex);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000143#endif
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100144static void prt_set_fg(long_u fg);
145static void prt_set_bg(long_u bg);
146static void prt_set_font(int bold, int italic, int underline);
147static void prt_line_number(prt_settings_T *psettings, int page_line, linenr_T lnum);
148static void prt_header(prt_settings_T *psettings, int pagenum, linenr_T lnum);
149static void prt_message(char_u *s);
150static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000151#ifdef FEAT_SYN_HL
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100152static void prt_get_attr(int hl_id, prt_text_attr_T* pattr, int modec);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000153#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000154
155/*
156 * Parse 'printoptions' and set the flags in "printer_opts".
157 * Returns an error message or NULL;
158 */
159 char_u *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100160parse_printoptions(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000161{
162 return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS);
163}
164
165#if (defined(FEAT_MBYTE) && defined(FEAT_POSTSCRIPT)) || defined(PROTO)
166/*
167 * Parse 'printoptions' and set the flags in "printer_opts".
168 * Returns an error message or NULL;
169 */
170 char_u *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100171parse_printmbfont(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000172{
173 return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS);
174}
175#endif
176
177/*
178 * Parse a list of options in the form
179 * option:value,option:value,option:value
180 *
181 * "value" can start with a number which is parsed out, e.g. margin:12mm
182 *
183 * Returns an error message for an illegal option, NULL otherwise.
184 * Only used for the printer at the moment...
185 */
186 static char_u *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100187parse_list_options(
188 char_u *option_str,
189 option_table_T *table,
190 int table_size)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000191{
192 char_u *stringp;
193 char_u *colonp;
194 char_u *commap;
195 char_u *p;
196 int idx = 0; /* init for GCC */
197 int len;
198
199 for (idx = 0; idx < table_size; ++idx)
200 table[idx].present = FALSE;
201
202 /*
203 * Repeat for all comma separated parts.
204 */
205 stringp = option_str;
206 while (*stringp)
207 {
208 colonp = vim_strchr(stringp, ':');
209 if (colonp == NULL)
210 return (char_u *)N_("E550: Missing colon");
211 commap = vim_strchr(stringp, ',');
212 if (commap == NULL)
213 commap = option_str + STRLEN(option_str);
214
215 len = (int)(colonp - stringp);
216
217 for (idx = 0; idx < table_size; ++idx)
218 if (STRNICMP(stringp, table[idx].name, len) == 0)
219 break;
220
221 if (idx == table_size)
222 return (char_u *)N_("E551: Illegal component");
223
224 p = colonp + 1;
225 table[idx].present = TRUE;
226
227 if (table[idx].hasnum)
228 {
229 if (!VIM_ISDIGIT(*p))
230 return (char_u *)N_("E552: digit expected");
231
232 table[idx].number = getdigits(&p); /*advances p*/
233 }
234
235 table[idx].string = p;
236 table[idx].strlen = (int)(commap - p);
237
238 stringp = commap;
239 if (*stringp == ',')
240 ++stringp;
241 }
242
243 return NULL;
244}
245
246
247#ifdef FEAT_SYN_HL
248/*
249 * If using a dark background, the colors will probably be too bright to show
250 * up well on white paper, so reduce their brightness.
251 */
252 static long_u
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100253darken_rgb(long_u rgb)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000254{
255 return ((rgb >> 17) << 16)
256 + (((rgb & 0xff00) >> 9) << 8)
257 + ((rgb & 0xff) >> 1);
258}
259
260 static long_u
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100261prt_get_term_color(int colorindex)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000262{
263 /* TODO: Should check for xterm with 88 or 256 colors. */
264 if (t_colors > 8)
265 return cterm_color_16[colorindex % 16];
266 return cterm_color_8[colorindex % 8];
267}
268
269 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100270prt_get_attr(
271 int hl_id,
272 prt_text_attr_T *pattr,
273 int modec)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000274{
275 int colorindex;
276 long_u fg_color;
277 long_u bg_color;
278 char *color;
279
280 pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
281 pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
282 pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
283 pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
284
285# ifdef FEAT_GUI
286 if (gui.in_use)
287 {
288 bg_color = highlight_gui_color_rgb(hl_id, FALSE);
289 if (bg_color == PRCOLOR_BLACK)
290 bg_color = PRCOLOR_WHITE;
291
292 fg_color = highlight_gui_color_rgb(hl_id, TRUE);
293 }
294 else
295# endif
296 {
297 bg_color = PRCOLOR_WHITE;
298
299 color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
300 if (color == NULL)
301 colorindex = 0;
302 else
303 colorindex = atoi(color);
304
305 if (colorindex >= 0 && colorindex < t_colors)
306 fg_color = prt_get_term_color(colorindex);
307 else
308 fg_color = PRCOLOR_BLACK;
309 }
310
311 if (fg_color == PRCOLOR_WHITE)
312 fg_color = PRCOLOR_BLACK;
313 else if (*p_bg == 'd')
314 fg_color = darken_rgb(fg_color);
315
316 pattr->fg_color = fg_color;
317 pattr->bg_color = bg_color;
318}
319#endif /* FEAT_SYN_HL */
320
321 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100322prt_set_fg(long_u fg)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000323{
324 if (fg != curr_fg)
325 {
326 curr_fg = fg;
327 mch_print_set_fg(fg);
328 }
329}
330
331 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100332prt_set_bg(long_u bg)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000333{
334 if (bg != curr_bg)
335 {
336 curr_bg = bg;
337 mch_print_set_bg(bg);
338 }
339}
340
341 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100342prt_set_font(int bold, int italic, int underline)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000343{
344 if (curr_bold != bold
345 || curr_italic != italic
346 || curr_underline != underline)
347 {
348 curr_underline = underline;
349 curr_italic = italic;
350 curr_bold = bold;
351 mch_print_set_font(bold, italic, underline);
352 }
353}
354
355/*
356 * Print the line number in the left margin.
357 */
358 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100359prt_line_number(
360 prt_settings_T *psettings,
361 int page_line,
362 linenr_T lnum)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000363{
364 int i;
365 char_u tbuf[20];
366
367 prt_set_fg(psettings->number.fg_color);
368 prt_set_bg(psettings->number.bg_color);
369 prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
370 mch_print_start_line(TRUE, page_line);
371
372 /* Leave two spaces between the number and the text; depends on
373 * PRINT_NUMBER_WIDTH. */
374 sprintf((char *)tbuf, "%6ld", (long)lnum);
375 for (i = 0; i < 6; i++)
376 (void)mch_print_text_out(&tbuf[i], 1);
377
378#ifdef FEAT_SYN_HL
379 if (psettings->do_syntax)
380 /* Set colors for next character. */
381 current_syn_id = -1;
382 else
383#endif
384 {
385 /* Set colors and font back to normal. */
386 prt_set_fg(PRCOLOR_BLACK);
387 prt_set_bg(PRCOLOR_WHITE);
388 prt_set_font(FALSE, FALSE, FALSE);
389 }
390}
391
Bram Moolenaar81366db2005-07-24 21:16:51 +0000392/*
393 * Get the currently effective header height.
394 */
395 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100396prt_header_height(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000397{
398 if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
399 return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
400 return 2;
401}
402
403/*
404 * Return TRUE if using a line number for printing.
405 */
406 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100407prt_use_number(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000408{
409 return (printer_opts[OPT_PRINT_NUMBER].present
410 && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
411}
412
413/*
414 * Return the unit used in a margin item in 'printoptions'.
415 * Returns PRT_UNIT_NONE if not recognized.
416 */
417 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100418prt_get_unit(int idx)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000419{
420 int u = PRT_UNIT_NONE;
421 int i;
422 static char *(units[4]) = PRT_UNIT_NAMES;
423
424 if (printer_opts[idx].present)
425 for (i = 0; i < 4; ++i)
426 if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
427 {
428 u = i;
429 break;
430 }
431 return u;
432}
433
434/*
435 * Print the page header.
436 */
Bram Moolenaar81366db2005-07-24 21:16:51 +0000437 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100438prt_header(
439 prt_settings_T *psettings,
440 int pagenum,
441 linenr_T lnum UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000442{
443 int width = psettings->chars_per_line;
444 int page_line;
445 char_u *tbuf;
446 char_u *p;
447#ifdef FEAT_MBYTE
448 int l;
449#endif
450
451 /* Also use the space for the line number. */
452 if (prt_use_number())
453 width += PRINT_NUMBER_WIDTH;
454
455 tbuf = alloc(width + IOSIZE);
456 if (tbuf == NULL)
457 return;
458
459#ifdef FEAT_STL_OPT
460 if (*p_header != NUL)
461 {
462 linenr_T tmp_lnum, tmp_topline, tmp_botline;
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000463 int use_sandbox = FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000464
465 /*
466 * Need to (temporarily) set current line number and first/last line
467 * number on the 'window'. Since we don't know how long the page is,
468 * set the first and current line number to the top line, and guess
469 * that the page length is 64.
470 */
471 tmp_lnum = curwin->w_cursor.lnum;
472 tmp_topline = curwin->w_topline;
473 tmp_botline = curwin->w_botline;
474 curwin->w_cursor.lnum = lnum;
475 curwin->w_topline = lnum;
476 curwin->w_botline = lnum + 63;
477 printer_page_num = pagenum;
478
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000479# ifdef FEAT_EVAL
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000480 use_sandbox = was_set_insecurely((char_u *)"printheader", 0);
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000481# endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000482 build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE),
Bram Moolenaarfaa959a2006-02-20 21:37:40 +0000483 p_header, use_sandbox,
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000484 ' ', width, NULL, NULL);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000485
486 /* Reset line numbers */
487 curwin->w_cursor.lnum = tmp_lnum;
488 curwin->w_topline = tmp_topline;
489 curwin->w_botline = tmp_botline;
490 }
491 else
492#endif
493 sprintf((char *)tbuf, _("Page %d"), pagenum);
494
495 prt_set_fg(PRCOLOR_BLACK);
496 prt_set_bg(PRCOLOR_WHITE);
497 prt_set_font(TRUE, FALSE, FALSE);
498
499 /* Use a negative line number to indicate printing in the top margin. */
500 page_line = 0 - prt_header_height();
501 mch_print_start_line(TRUE, page_line);
502 for (p = tbuf; *p != NUL; )
503 {
504 if (mch_print_text_out(p,
505#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000506 (l = (*mb_ptr2len)(p))
Bram Moolenaar81366db2005-07-24 21:16:51 +0000507#else
508 1
509#endif
510 ))
511 {
512 ++page_line;
513 if (page_line >= 0) /* out of room in header */
514 break;
515 mch_print_start_line(TRUE, page_line);
516 }
517#ifdef FEAT_MBYTE
518 p += l;
519#else
520 p++;
521#endif
522 }
523
524 vim_free(tbuf);
525
526#ifdef FEAT_SYN_HL
527 if (psettings->do_syntax)
528 /* Set colors for next character. */
529 current_syn_id = -1;
530 else
531#endif
532 {
533 /* Set colors and font back to normal. */
534 prt_set_fg(PRCOLOR_BLACK);
535 prt_set_bg(PRCOLOR_WHITE);
536 prt_set_font(FALSE, FALSE, FALSE);
537 }
538}
539
540/*
541 * Display a print status message.
542 */
543 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100544prt_message(char_u *s)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000545{
546 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
547 screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R));
548 out_flush();
549}
550
551 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100552ex_hardcopy(exarg_T *eap)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000553{
554 linenr_T lnum;
555 int collated_copies, uncollated_copies;
556 prt_settings_T settings;
557 long_u bytes_to_print = 0;
558 int page_line;
559 int jobsplit;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000560
Bram Moolenaar7db5fc82010-05-24 11:59:29 +0200561 vim_memset(&settings, 0, sizeof(prt_settings_T));
Bram Moolenaar81366db2005-07-24 21:16:51 +0000562 settings.has_color = TRUE;
563
564# ifdef FEAT_POSTSCRIPT
565 if (*eap->arg == '>')
566 {
567 char_u *errormsg = NULL;
568
569 /* Expand things like "%.ps". */
570 if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
571 {
572 if (errormsg != NULL)
573 EMSG(errormsg);
574 return;
575 }
576 settings.outfile = skipwhite(eap->arg + 1);
577 }
578 else if (*eap->arg != NUL)
579 settings.arguments = eap->arg;
580# endif
581
582 /*
583 * Initialise for printing. Ask the user for settings, unless forceit is
584 * set.
585 * The mch_print_init() code should set up margins if applicable. (It may
586 * not be a real printer - for example the engine might generate HTML or
587 * PS.)
588 */
589 if (mch_print_init(&settings,
590 curbuf->b_fname == NULL
591 ? (char_u *)buf_spname(curbuf)
592 : curbuf->b_sfname == NULL
593 ? curbuf->b_fname
594 : curbuf->b_sfname,
595 eap->forceit) == FAIL)
596 return;
597
598#ifdef FEAT_SYN_HL
599# ifdef FEAT_GUI
600 if (gui.in_use)
601 settings.modec = 'g';
602 else
603# endif
604 if (t_colors > 1)
605 settings.modec = 'c';
606 else
607 settings.modec = 't';
608
Bram Moolenaar860cae12010-06-05 23:22:07 +0200609 if (!syntax_present(curwin))
Bram Moolenaar81366db2005-07-24 21:16:51 +0000610 settings.do_syntax = FALSE;
611 else if (printer_opts[OPT_PRINT_SYNTAX].present
612 && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
613 settings.do_syntax =
614 (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
615 else
616 settings.do_syntax = settings.has_color;
617#endif
618
619 /* Set up printing attributes for line numbers */
620 settings.number.fg_color = PRCOLOR_BLACK;
621 settings.number.bg_color = PRCOLOR_WHITE;
622 settings.number.bold = FALSE;
623 settings.number.italic = TRUE;
624 settings.number.underline = FALSE;
625#ifdef FEAT_SYN_HL
626 /*
627 * Syntax highlighting of line numbers.
628 */
629 if (prt_use_number() && settings.do_syntax)
630 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000631 int id;
632
Bram Moolenaar81366db2005-07-24 21:16:51 +0000633 id = syn_name2id((char_u *)"LineNr");
634 if (id > 0)
635 id = syn_get_final_id(id);
636
637 prt_get_attr(id, &settings.number, settings.modec);
638 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000639#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000640
641 /*
642 * Estimate the total lines to be printed
643 */
644 for (lnum = eap->line1; lnum <= eap->line2; lnum++)
645 bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
646 if (bytes_to_print == 0)
647 {
648 MSG(_("No text to be printed"));
649 goto print_fail_no_begin;
650 }
651
652 /* Set colors and font to normal. */
653 curr_bg = (long_u)0xffffffffL;
654 curr_fg = (long_u)0xffffffffL;
655 curr_italic = MAYBE;
656 curr_bold = MAYBE;
657 curr_underline = MAYBE;
658
659 prt_set_fg(PRCOLOR_BLACK);
660 prt_set_bg(PRCOLOR_WHITE);
661 prt_set_font(FALSE, FALSE, FALSE);
662#ifdef FEAT_SYN_HL
663 current_syn_id = -1;
664#endif
665
666 jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
667 && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
668
669 if (!mch_print_begin(&settings))
670 goto print_fail_no_begin;
671
672 /*
673 * Loop over collated copies: 1 2 3, 1 2 3, ...
674 */
675 page_count = 0;
676 for (collated_copies = 0;
677 collated_copies < settings.n_collated_copies;
678 collated_copies++)
679 {
680 prt_pos_T prtpos; /* current print position */
681 prt_pos_T page_prtpos; /* print position at page start */
682 int side;
683
Bram Moolenaar7db5fc82010-05-24 11:59:29 +0200684 vim_memset(&page_prtpos, 0, sizeof(prt_pos_T));
Bram Moolenaar81366db2005-07-24 21:16:51 +0000685 page_prtpos.file_line = eap->line1;
686 prtpos = page_prtpos;
687
688 if (jobsplit && collated_copies > 0)
689 {
690 /* Splitting jobs: Stop a previous job and start a new one. */
691 mch_print_end(&settings);
692 if (!mch_print_begin(&settings))
693 goto print_fail_no_begin;
694 }
695
696 /*
697 * Loop over all pages in the print job: 1 2 3 ...
698 */
699 for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
700 {
701 /*
702 * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
703 * For duplex: 12 12 12 34 34 34, ...
704 */
705 for (uncollated_copies = 0;
706 uncollated_copies < settings.n_uncollated_copies;
707 uncollated_copies++)
708 {
709 /* Set the print position to the start of this page. */
710 prtpos = page_prtpos;
711
712 /*
713 * Do front and rear side of a page.
714 */
715 for (side = 0; side <= settings.duplex; ++side)
716 {
717 /*
718 * Print one page.
719 */
720
721 /* Check for interrupt character every page. */
722 ui_breakcheck();
723 if (got_int || settings.user_abort)
724 goto print_fail;
725
726 sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
727 page_count + 1 + side,
728 prtpos.bytes_printed > 1000000
729 ? (int)(prtpos.bytes_printed /
730 (bytes_to_print / 100))
731 : (int)((prtpos.bytes_printed * 100)
732 / bytes_to_print));
733 if (!mch_print_begin_page(IObuff))
734 goto print_fail;
735
736 if (settings.n_collated_copies > 1)
737 sprintf((char *)IObuff + STRLEN(IObuff),
738 _(" Copy %d of %d"),
739 collated_copies + 1,
740 settings.n_collated_copies);
741 prt_message(IObuff);
742
743 /*
744 * Output header if required
745 */
746 if (prt_header_height() > 0)
747 prt_header(&settings, page_count + 1 + side,
748 prtpos.file_line);
749
750 for (page_line = 0; page_line < settings.lines_per_page;
751 ++page_line)
752 {
753 prtpos.column = hardcopy_line(&settings,
754 page_line, &prtpos);
755 if (prtpos.column == 0)
756 {
757 /* finished a file line */
758 prtpos.bytes_printed +=
759 STRLEN(skipwhite(ml_get(prtpos.file_line)));
760 if (++prtpos.file_line > eap->line2)
761 break; /* reached the end */
762 }
763 else if (prtpos.ff)
764 {
765 /* Line had a formfeed in it - start new page but
766 * stay on the current line */
767 break;
768 }
769 }
770
771 if (!mch_print_end_page())
772 goto print_fail;
773 if (prtpos.file_line > eap->line2)
774 break; /* reached the end */
775 }
776
777 /*
778 * Extra blank page for duplexing with odd number of pages and
779 * more copies to come.
780 */
781 if (prtpos.file_line > eap->line2 && settings.duplex
782 && side == 0
783 && uncollated_copies + 1 < settings.n_uncollated_copies)
784 {
785 if (!mch_print_blank_page())
786 goto print_fail;
787 }
788 }
789 if (settings.duplex && prtpos.file_line <= eap->line2)
790 ++page_count;
791
792 /* Remember the position where the next page starts. */
793 page_prtpos = prtpos;
794 }
795
796 vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"),
797 settings.jobname);
798 prt_message(IObuff);
799 }
800
801print_fail:
802 if (got_int || settings.user_abort)
803 {
804 sprintf((char *)IObuff, "%s", _("Printing aborted"));
805 prt_message(IObuff);
806 }
807 mch_print_end(&settings);
808
809print_fail_no_begin:
810 mch_print_cleanup();
811}
812
813/*
814 * Print one page line.
815 * Return the next column to print, or zero if the line is finished.
816 */
817 static colnr_T
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100818hardcopy_line(
819 prt_settings_T *psettings,
820 int page_line,
821 prt_pos_T *ppos)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000822{
823 colnr_T col;
824 char_u *line;
825 int need_break = FALSE;
826 int outputlen;
827 int tab_spaces;
828 long_u print_pos;
829#ifdef FEAT_SYN_HL
830 prt_text_attr_T attr;
831 int id;
832#endif
833
834 if (ppos->column == 0 || ppos->ff)
835 {
836 print_pos = 0;
837 tab_spaces = 0;
838 if (!ppos->ff && prt_use_number())
839 prt_line_number(psettings, page_line, ppos->file_line);
840 ppos->ff = FALSE;
841 }
842 else
843 {
844 /* left over from wrap halfway a tab */
845 print_pos = ppos->print_pos;
846 tab_spaces = ppos->lead_spaces;
847 }
848
849 mch_print_start_line(0, page_line);
850 line = ml_get(ppos->file_line);
851
852 /*
853 * Loop over the columns until the end of the file line or right margin.
854 */
855 for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
856 {
857 outputlen = 1;
858#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000859 if (has_mbyte && (outputlen = (*mb_ptr2len)(line + col)) < 1)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000860 outputlen = 1;
861#endif
862#ifdef FEAT_SYN_HL
863 /*
864 * syntax highlighting stuff.
865 */
866 if (psettings->do_syntax)
867 {
Bram Moolenaar56cefaf2008-01-12 15:47:10 +0000868 id = syn_get_id(curwin, ppos->file_line, col, 1, NULL, FALSE);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000869 if (id > 0)
870 id = syn_get_final_id(id);
871 else
872 id = 0;
873 /* Get the line again, a multi-line regexp may invalidate it. */
874 line = ml_get(ppos->file_line);
875
876 if (id != current_syn_id)
877 {
878 current_syn_id = id;
879 prt_get_attr(id, &attr, psettings->modec);
880 prt_set_font(attr.bold, attr.italic, attr.underline);
881 prt_set_fg(attr.fg_color);
882 prt_set_bg(attr.bg_color);
883 }
884 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000885#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000886
887 /*
888 * Appropriately expand any tabs to spaces.
889 */
890 if (line[col] == TAB || tab_spaces != 0)
891 {
892 if (tab_spaces == 0)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000893 tab_spaces = (int)(curbuf->b_p_ts - (print_pos % curbuf->b_p_ts));
Bram Moolenaar81366db2005-07-24 21:16:51 +0000894
895 while (tab_spaces > 0)
896 {
897 need_break = mch_print_text_out((char_u *)" ", 1);
898 print_pos++;
899 tab_spaces--;
900 if (need_break)
901 break;
902 }
903 /* Keep the TAB if we didn't finish it. */
904 if (need_break && tab_spaces > 0)
905 break;
906 }
907 else if (line[col] == FF
908 && printer_opts[OPT_PRINT_FORMFEED].present
909 && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
910 == 'y')
911 {
912 ppos->ff = TRUE;
913 need_break = 1;
914 }
915 else
916 {
917 need_break = mch_print_text_out(line + col, outputlen);
918#ifdef FEAT_MBYTE
919 if (has_mbyte)
920 print_pos += (*mb_ptr2cells)(line + col);
921 else
922#endif
923 print_pos++;
924 }
925 }
926
927 ppos->lead_spaces = tab_spaces;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000928 ppos->print_pos = (int)print_pos;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000929
930 /*
931 * Start next line of file if we clip lines, or have reached end of the
932 * line, unless we are doing a formfeed.
933 */
934 if (!ppos->ff
935 && (line[col] == NUL
936 || (printer_opts[OPT_PRINT_WRAP].present
937 && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
938 == 'n')))
939 return 0;
940 return col;
941}
942
943# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
944
945/*
946 * PS printer stuff.
947 *
948 * Sources of information to help maintain the PS printing code:
949 *
950 * 1. PostScript Language Reference, 3rd Edition,
951 * Addison-Wesley, 1999, ISBN 0-201-37922-8
952 * 2. PostScript Language Program Design,
953 * Addison-Wesley, 1988, ISBN 0-201-14396-8
954 * 3. PostScript Tutorial and Cookbook,
955 * Addison Wesley, 1985, ISBN 0-201-10179-3
956 * 4. PostScript Language Document Structuring Conventions Specification,
957 * version 3.0,
958 * Adobe Technote 5001, 25th September 1992
959 * 5. PostScript Printer Description File Format Specification, Version 4.3,
960 * Adobe technote 5003, 9th February 1996
961 * 6. Adobe Font Metrics File Format Specification, Version 4.1,
962 * Adobe Technote 5007, 7th October 1998
963 * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
964 * Adobe Technote 5014, 8th October 1996
965 * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
966 * Adoboe Technote 5094, 8th September, 2001
967 * 9. CJKV Information Processing, 2nd Edition,
968 * O'Reilly, 2002, ISBN 1-56592-224-7
969 *
970 * Some of these documents can be found in PDF form on Adobe's web site -
971 * http://www.adobe.com
972 */
973
974#define NUM_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0]))
975
976#define PRT_PS_DEFAULT_DPI (72) /* Default user space resolution */
977#define PRT_PS_DEFAULT_FONTSIZE (10)
978#define PRT_PS_DEFAULT_BUFFER_SIZE (80)
979
980struct prt_mediasize_S
981{
982 char *name;
983 float width; /* width and height in points for portrait */
984 float height;
985};
986
987#define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
988
989static struct prt_mediasize_S prt_mediasize[] =
990{
991 {"A4", 595.0, 842.0},
992 {"letter", 612.0, 792.0},
993 {"10x14", 720.0, 1008.0},
994 {"A3", 842.0, 1191.0},
995 {"A5", 420.0, 595.0},
996 {"B4", 729.0, 1032.0},
997 {"B5", 516.0, 729.0},
998 {"executive", 522.0, 756.0},
999 {"folio", 595.0, 935.0},
1000 {"ledger", 1224.0, 792.0}, /* Yes, it is wider than taller! */
1001 {"legal", 612.0, 1008.0},
1002 {"quarto", 610.0, 780.0},
1003 {"statement", 396.0, 612.0},
1004 {"tabloid", 792.0, 1224.0}
1005};
1006
1007/* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */
1008struct prt_ps_font_S
1009{
1010 int wx;
1011 int uline_offset;
1012 int uline_width;
1013 int bbox_min_y;
1014 int bbox_max_y;
1015 char *(ps_fontname[4]);
1016};
1017
1018#define PRT_PS_FONT_ROMAN (0)
1019#define PRT_PS_FONT_BOLD (1)
1020#define PRT_PS_FONT_OBLIQUE (2)
1021#define PRT_PS_FONT_BOLDOBLIQUE (3)
1022
1023/* Standard font metrics for Courier family */
1024static struct prt_ps_font_S prt_ps_courier_font =
1025{
1026 600,
1027 -100, 50,
1028 -250, 805,
1029 {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
1030};
1031
1032#ifdef FEAT_MBYTE
1033/* Generic font metrics for multi-byte fonts */
1034static struct prt_ps_font_S prt_ps_mb_font =
1035{
1036 1000,
1037 -100, 50,
1038 -250, 805,
1039 {NULL, NULL, NULL, NULL}
1040};
1041#endif
1042
1043/* Pointer to current font set being used */
1044static struct prt_ps_font_S* prt_ps_font;
1045
1046/* Structures to map user named encoding and mapping to PS equivalents for
1047 * building CID font name */
1048struct prt_ps_encoding_S
1049{
1050 char *encoding;
1051 char *cmap_encoding;
1052 int needs_charset;
1053};
1054
1055struct prt_ps_charset_S
1056{
1057 char *charset;
1058 char *cmap_charset;
1059 int has_charset;
1060};
1061
1062#ifdef FEAT_MBYTE
1063
1064#define CS_JIS_C_1978 (0x01)
1065#define CS_JIS_X_1983 (0x02)
1066#define CS_JIS_X_1990 (0x04)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001067#define CS_NEC (0x08)
1068#define CS_MSWINDOWS (0x10)
1069#define CS_CP932 (0x20)
1070#define CS_KANJITALK6 (0x40)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001071#define CS_KANJITALK7 (0x80)
1072
1073/* Japanese encodings and charsets */
1074static struct prt_ps_encoding_S j_encodings[] =
1075{
1076 {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001077 CS_NEC)},
1078 {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
1079 {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
1080 CS_KANJITALK6|CS_KANJITALK7)},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001081 {"cp932", "RKSJ", CS_JIS_X_1983},
1082 {"ucs-2", "UCS2", CS_JIS_X_1990},
1083 {"utf-8", "UTF8" , CS_JIS_X_1990}
1084};
1085static struct prt_ps_charset_S j_charsets[] =
1086{
1087 {"JIS_C_1978", "78", CS_JIS_C_1978},
1088 {"JIS_X_1983", NULL, CS_JIS_X_1983},
1089 {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001090 {"NEC", "Ext", CS_NEC},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001091 {"MSWINDOWS", "90ms", CS_MSWINDOWS},
1092 {"CP932", "90ms", CS_JIS_X_1983},
1093 {"KANJITALK6", "83pv", CS_KANJITALK6},
1094 {"KANJITALK7", "90pv", CS_KANJITALK7}
1095};
1096
1097#define CS_GB_2312_80 (0x01)
1098#define CS_GBT_12345_90 (0x02)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001099#define CS_GBK2K (0x04)
1100#define CS_SC_MAC (0x08)
1101#define CS_GBT_90_MAC (0x10)
1102#define CS_GBK (0x20)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001103#define CS_SC_ISO10646 (0x40)
1104
1105/* Simplified Chinese encodings and charsets */
1106static struct prt_ps_encoding_S sc_encodings[] =
1107{
1108 {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
1109 {"gb18030", NULL, CS_GBK2K},
1110 {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001111 CS_GBT_90_MAC)},
1112 {"gbk", "EUC", CS_GBK},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001113 {"ucs-2", "UCS2", CS_SC_ISO10646},
1114 {"utf-8", "UTF8", CS_SC_ISO10646}
1115};
1116static struct prt_ps_charset_S sc_charsets[] =
1117{
1118 {"GB_2312-80", "GB", CS_GB_2312_80},
1119 {"GBT_12345-90","GBT", CS_GBT_12345_90},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001120 {"MAC", "GBpc", CS_SC_MAC},
1121 {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
1122 {"GBK", "GBK", CS_GBK},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001123 {"GB18030", "GBK2K", CS_GBK2K},
1124 {"ISO10646", "UniGB", CS_SC_ISO10646}
1125};
1126
1127#define CS_CNS_PLANE_1 (0x01)
1128#define CS_CNS_PLANE_2 (0x02)
1129#define CS_CNS_PLANE_1_2 (0x04)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001130#define CS_B5 (0x08)
1131#define CS_ETEN (0x10)
1132#define CS_HK_GCCS (0x20)
1133#define CS_HK_SCS (0x40)
1134#define CS_HK_SCS_ETEN (0x80)
1135#define CS_MTHKL (0x100)
1136#define CS_MTHKS (0x200)
1137#define CS_DLHKL (0x400)
1138#define CS_DLHKS (0x800)
1139#define CS_TC_ISO10646 (0x1000)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001140
1141/* Traditional Chinese encodings and charsets */
1142static struct prt_ps_encoding_S tc_encodings[] =
1143{
1144 {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
1145 {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001146 {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
1147 CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
1148 CS_DLHKS)},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001149 {"cp950", "B5", CS_B5},
1150 {"ucs-2", "UCS2", CS_TC_ISO10646},
1151 {"utf-8", "UTF8", CS_TC_ISO10646},
1152 {"utf-16", "UTF16", CS_TC_ISO10646},
1153 {"utf-32", "UTF32", CS_TC_ISO10646}
1154};
1155static struct prt_ps_charset_S tc_charsets[] =
1156{
1157 {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
1158 {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
1159 {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001160 {"BIG5", NULL, CS_B5},
1161 {"CP950", NULL, CS_B5},
1162 {"ETEN", "ETen", CS_ETEN},
1163 {"HK_GCCS", "HKgccs", CS_HK_GCCS},
1164 {"SCS", "HKscs", CS_HK_SCS},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001165 {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
1166 {"MTHKL", "HKm471", CS_MTHKL},
1167 {"MTHKS", "HKm314", CS_MTHKS},
1168 {"DLHKL", "HKdla", CS_DLHKL},
1169 {"DLHKS", "HKdlb", CS_DLHKS},
1170 {"ISO10646", "UniCNS", CS_TC_ISO10646}
1171};
1172
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001173#define CS_KR_X_1992 (0x01)
1174#define CS_KR_MAC (0x02)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001175#define CS_KR_X_1992_MS (0x04)
1176#define CS_KR_ISO10646 (0x08)
1177
1178/* Korean encodings and charsets */
1179static struct prt_ps_encoding_S k_encodings[] =
1180{
1181 {"iso-2022-kr", NULL, CS_KR_X_1992},
1182 {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
1183 {"johab", "Johab", CS_KR_X_1992},
1184 {"cp1361", "Johab", CS_KR_X_1992},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001185 {"uhc", "UHC", CS_KR_X_1992_MS},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001186 {"cp949", "UHC", CS_KR_X_1992_MS},
1187 {"ucs-2", "UCS2", CS_KR_ISO10646},
1188 {"utf-8", "UTF8", CS_KR_ISO10646}
1189};
1190static struct prt_ps_charset_S k_charsets[] =
1191{
1192 {"KS_X_1992", "KSC", CS_KR_X_1992},
1193 {"CP1361", "KSC", CS_KR_X_1992},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001194 {"MAC", "KSCpc", CS_KR_MAC},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001195 {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
1196 {"CP949", "KSCms", CS_KR_X_1992_MS},
1197 {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
1198 {"ISO10646", "UniKS", CS_KR_ISO10646}
1199};
1200
1201/* Collections of encodings and charsets for multi-byte printing */
1202struct prt_ps_mbfont_S
1203{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001204 int num_encodings;
1205 struct prt_ps_encoding_S *encodings;
1206 int num_charsets;
1207 struct prt_ps_charset_S *charsets;
1208 char *ascii_enc;
1209 char *defcs;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001210};
1211
1212static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
1213{
1214 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001215 NUM_ELEMENTS(j_encodings),
1216 j_encodings,
1217 NUM_ELEMENTS(j_charsets),
1218 j_charsets,
1219 "jis_roman",
1220 "JIS_X_1983"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001221 },
1222 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001223 NUM_ELEMENTS(sc_encodings),
1224 sc_encodings,
1225 NUM_ELEMENTS(sc_charsets),
1226 sc_charsets,
1227 "gb_roman",
1228 "GB_2312-80"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001229 },
1230 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001231 NUM_ELEMENTS(tc_encodings),
1232 tc_encodings,
1233 NUM_ELEMENTS(tc_charsets),
1234 tc_charsets,
1235 "cns_roman",
1236 "BIG5"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001237 },
1238 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001239 NUM_ELEMENTS(k_encodings),
1240 k_encodings,
1241 NUM_ELEMENTS(k_charsets),
1242 k_charsets,
1243 "ks_roman",
1244 "KS_X_1992"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001245 }
1246};
1247#endif /* FEAT_MBYTE */
1248
1249struct prt_ps_resource_S
1250{
1251 char_u name[64];
1252 char_u filename[MAXPATHL + 1];
1253 int type;
1254 char_u title[256];
1255 char_u version[256];
1256};
1257
1258/* Types of PS resource file currently used */
1259#define PRT_RESOURCE_TYPE_PROCSET (0)
1260#define PRT_RESOURCE_TYPE_ENCODING (1)
1261#define PRT_RESOURCE_TYPE_CMAP (2)
1262
1263/* The PS prolog file version number has to match - if the prolog file is
1264 * updated, increment the number in the file and here. Version checking was
1265 * added as of VIM 6.2.
1266 * The CID prolog file version number behaves as per PS prolog.
1267 * Table of VIM and prolog versions:
1268 *
1269 * VIM Prolog CIDProlog
1270 * 6.2 1.3
1271 * 7.0 1.4 1.0
1272 */
1273#define PRT_PROLOG_VERSION ((char_u *)"1.4")
1274#define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
1275
1276/* String versions of PS resource types - indexed by constants above so don't
1277 * re-order!
1278 */
1279static char *prt_resource_types[] =
1280{
1281 "procset",
1282 "encoding",
1283 "cmap"
1284};
1285
1286/* Strings to look for in a PS resource file */
1287#define PRT_RESOURCE_HEADER "%!PS-Adobe-"
1288#define PRT_RESOURCE_RESOURCE "Resource-"
1289#define PRT_RESOURCE_PROCSET "ProcSet"
1290#define PRT_RESOURCE_ENCODING "Encoding"
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001291#define PRT_RESOURCE_CMAP "CMap"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001292
1293
1294/* Data for table based DSC comment recognition, easy to extend if VIM needs to
1295 * read more comments. */
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001296#define PRT_DSC_MISC_TYPE (-1)
1297#define PRT_DSC_TITLE_TYPE (1)
1298#define PRT_DSC_VERSION_TYPE (2)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001299#define PRT_DSC_ENDCOMMENTS_TYPE (3)
1300
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001301#define PRT_DSC_TITLE "%%Title:"
1302#define PRT_DSC_VERSION "%%Version:"
1303#define PRT_DSC_ENDCOMMENTS "%%EndComments:"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001304
1305struct prt_dsc_comment_S
1306{
1307 char *string;
1308 int len;
1309 int type;
1310};
1311
1312struct prt_dsc_line_S
1313{
1314 int type;
1315 char_u *string;
1316 int len;
1317};
1318
1319
1320#define SIZEOF_CSTR(s) (sizeof(s) - 1)
1321static struct prt_dsc_comment_S prt_dsc_table[] =
1322{
1323 {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE},
1324 {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
1325 PRT_DSC_VERSION_TYPE},
1326 {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
1327 PRT_DSC_ENDCOMMENTS_TYPE}
1328};
1329
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01001330static void prt_write_file_raw_len(char_u *buffer, int bytes);
1331static void prt_write_file(char_u *buffer);
1332static void prt_write_file_len(char_u *buffer, int bytes);
1333static void prt_write_string(char *s);
1334static void prt_write_int(int i);
1335static void prt_write_boolean(int b);
1336static void prt_def_font(char *new_name, char *encoding, int height, char *font);
1337static void prt_real_bits(double real, int precision, int *pinteger, int *pfraction);
1338static void prt_write_real(double val, int prec);
1339static void prt_def_var(char *name, double value, int prec);
1340static void prt_flush_buffer(void);
1341static void prt_resource_name(char_u *filename, void *cookie);
1342static int prt_find_resource(char *name, struct prt_ps_resource_S *resource);
1343static int prt_open_resource(struct prt_ps_resource_S *resource);
1344static int prt_check_resource(struct prt_ps_resource_S *resource, char_u *version);
1345static void prt_dsc_start(void);
1346static void prt_dsc_noarg(char *comment);
1347static void prt_dsc_textline(char *comment, char *text);
1348static void prt_dsc_text(char *comment, char *text);
1349static void prt_dsc_ints(char *comment, int count, int *ints);
1350static void prt_dsc_requirements(int duplex, int tumble, int collate, int color, int num_copies);
1351static void prt_dsc_docmedia(char *paper_name, double width, double height, double weight, char *colour, char *type);
1352static void prt_dsc_resources(char *comment, char *type, char *strings);
1353static void prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font);
1354static float to_device_units(int idx, double physsize, int def_number);
1355static void prt_page_margins(double width, double height, double *left, double *right, double *top, double *bottom);
1356static void prt_font_metrics(int font_scale);
1357static int prt_get_cpl(void);
1358static int prt_get_lpp(void);
1359static int prt_add_resource(struct prt_ps_resource_S *resource);
1360static int prt_resfile_next_line(void);
1361static int prt_resfile_strncmp(int offset, char *string, int len);
1362static int prt_resfile_skip_nonws(int offset);
1363static int prt_resfile_skip_ws(int offset);
1364static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001365#ifdef FEAT_MBYTE
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01001366static int prt_build_cid_fontname(int font, char_u *name, int name_len);
1367static void prt_def_cidfont(char *new_name, int height, char *cidfont);
1368static void prt_dup_cidfont(char *original_name, char *new_name);
1369static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc);
1370static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001371#endif
1372
1373/*
1374 * Variables for the output PostScript file.
1375 */
1376static FILE *prt_ps_fd;
1377static int prt_file_error;
1378static char_u *prt_ps_file_name = NULL;
1379
1380/*
1381 * Various offsets and dimensions in default PostScript user space (points).
1382 * Used for text positioning calculations
1383 */
1384static float prt_page_width;
1385static float prt_page_height;
1386static float prt_left_margin;
1387static float prt_right_margin;
1388static float prt_top_margin;
1389static float prt_bottom_margin;
1390static float prt_line_height;
1391static float prt_first_line_height;
1392static float prt_char_width;
1393static float prt_number_width;
1394static float prt_bgcol_offset;
1395static float prt_pos_x_moveto = 0.0;
1396static float prt_pos_y_moveto = 0.0;
1397
1398/*
1399 * Various control variables used to decide when and how to change the
1400 * PostScript graphics state.
1401 */
1402static int prt_need_moveto;
1403static int prt_do_moveto;
1404static int prt_need_font;
1405static int prt_font;
1406static int prt_need_underline;
1407static int prt_underline;
1408static int prt_do_underline;
1409static int prt_need_fgcol;
1410static int prt_fgcol;
1411static int prt_need_bgcol;
1412static int prt_do_bgcol;
1413static int prt_bgcol;
1414static int prt_new_bgcol;
1415static int prt_attribute_change;
1416static float prt_text_run;
1417static int prt_page_num;
1418static int prt_bufsiz;
1419
1420/*
1421 * Variables controlling physical printing.
1422 */
1423static int prt_media;
1424static int prt_portrait;
1425static int prt_num_copies;
1426static int prt_duplex;
1427static int prt_tumble;
1428static int prt_collate;
1429
1430/*
1431 * Buffers used when generating PostScript output
1432 */
1433static char_u prt_line_buffer[257];
1434static garray_T prt_ps_buffer;
1435
1436# ifdef FEAT_MBYTE
1437static int prt_do_conv;
1438static vimconv_T prt_conv;
1439
1440static int prt_out_mbyte;
1441static int prt_custom_cmap;
1442static char prt_cmap[80];
1443static int prt_use_courier;
1444static int prt_in_ascii;
1445static int prt_half_width;
1446static char *prt_ascii_encoding;
1447static char_u prt_hexchar[] = "0123456789abcdef";
1448# endif
1449
1450 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001451prt_write_file_raw_len(char_u *buffer, int bytes)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001452{
1453 if (!prt_file_error
1454 && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
1455 != (size_t)bytes)
1456 {
1457 EMSG(_("E455: Error writing to PostScript output file"));
1458 prt_file_error = TRUE;
1459 }
1460}
1461
1462 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001463prt_write_file(char_u *buffer)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001464{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001465 prt_write_file_len(buffer, (int)STRLEN(buffer));
Bram Moolenaar81366db2005-07-24 21:16:51 +00001466}
1467
1468 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001469prt_write_file_len(char_u *buffer, int bytes)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001470{
1471#ifdef EBCDIC
1472 ebcdic2ascii(buffer, bytes);
1473#endif
1474 prt_write_file_raw_len(buffer, bytes);
1475}
1476
1477/*
1478 * Write a string.
1479 */
1480 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001481prt_write_string(char *s)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001482{
1483 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
1484 prt_write_file(prt_line_buffer);
1485}
1486
1487/*
1488 * Write an int and a space.
1489 */
1490 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001491prt_write_int(int i)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001492{
1493 sprintf((char *)prt_line_buffer, "%d ", i);
1494 prt_write_file(prt_line_buffer);
1495}
1496
1497/*
1498 * Write a boolean and a space.
1499 */
1500 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001501prt_write_boolean(int b)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001502{
1503 sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
1504 prt_write_file(prt_line_buffer);
1505}
1506
1507/*
1508 * Write PostScript to re-encode and define the font.
1509 */
1510 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001511prt_def_font(
1512 char *new_name,
1513 char *encoding,
1514 int height,
1515 char *font)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001516{
1517 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1518 "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
1519 prt_write_file(prt_line_buffer);
1520#ifdef FEAT_MBYTE
1521 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001522 sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
Bram Moolenaar81366db2005-07-24 21:16:51 +00001523 new_name, height, 500./prt_ps_courier_font.wx, new_name);
1524 else
1525#endif
1526 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1527 "/%s %d /_%s ffs\n", new_name, height, new_name);
1528 prt_write_file(prt_line_buffer);
1529}
1530
1531#ifdef FEAT_MBYTE
1532/*
1533 * Write a line to define the CID font.
1534 */
1535 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001536prt_def_cidfont(char *new_name, int height, char *cidfont)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001537{
1538 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1539 "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
1540 prt_write_file(prt_line_buffer);
1541 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1542 "/%s %d /_%s ffs\n", new_name, height, new_name);
1543 prt_write_file(prt_line_buffer);
1544}
1545
1546/*
1547 * Write a line to define a duplicate of a CID font
1548 */
1549 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001550prt_dup_cidfont(char *original_name, char *new_name)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001551{
1552 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1553 "/%s %s d\n", new_name, original_name);
1554 prt_write_file(prt_line_buffer);
1555}
1556#endif
1557
1558/*
1559 * Convert a real value into an integer and fractional part as integers, with
1560 * the fractional part being in the range [0,10^precision). The fractional part
1561 * is also rounded based on the precision + 1'th fractional digit.
1562 */
1563 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001564prt_real_bits(
1565 double real,
1566 int precision,
1567 int *pinteger,
1568 int *pfraction)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001569{
1570 int i;
1571 int integer;
1572 float fraction;
1573
1574 integer = (int)real;
1575 fraction = (float)(real - integer);
1576 if (real < (double)integer)
1577 fraction = -fraction;
1578 for (i = 0; i < precision; i++)
1579 fraction *= 10.0;
1580
1581 *pinteger = integer;
1582 *pfraction = (int)(fraction + 0.5);
1583}
1584
1585/*
1586 * Write a real and a space. Save bytes if real value has no fractional part!
1587 * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
1588 * what decimal point character to use, but PS always requires a '.'.
1589 */
1590 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001591prt_write_real(double val, int prec)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001592{
1593 int integer;
1594 int fraction;
1595
1596 prt_real_bits(val, prec, &integer, &fraction);
1597 /* Emit integer part */
1598 sprintf((char *)prt_line_buffer, "%d", integer);
1599 prt_write_file(prt_line_buffer);
1600 /* Only emit fraction if necessary */
1601 if (fraction != 0)
1602 {
1603 /* Remove any trailing zeros */
1604 while ((fraction % 10) == 0)
1605 {
1606 prec--;
1607 fraction /= 10;
1608 }
1609 /* Emit fraction left padded with zeros */
1610 sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
1611 prt_write_file(prt_line_buffer);
1612 }
1613 sprintf((char *)prt_line_buffer, " ");
1614 prt_write_file(prt_line_buffer);
1615}
1616
1617/*
1618 * Write a line to define a numeric variable.
1619 */
1620 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001621prt_def_var(char *name, double value, int prec)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001622{
1623 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1624 "/%s ", name);
1625 prt_write_file(prt_line_buffer);
1626 prt_write_real(value, prec);
1627 sprintf((char *)prt_line_buffer, "d\n");
1628 prt_write_file(prt_line_buffer);
1629}
1630
1631/* Convert size from font space to user space at current font scale */
1632#define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0))
1633
1634 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001635prt_flush_buffer(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001636{
1637 if (prt_ps_buffer.ga_len > 0)
1638 {
1639 /* Any background color must be drawn first */
1640 if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
1641 {
1642 int r, g, b;
1643
1644 if (prt_do_moveto)
1645 {
1646 prt_write_real(prt_pos_x_moveto, 2);
1647 prt_write_real(prt_pos_y_moveto, 2);
1648 prt_write_string("m\n");
1649 prt_do_moveto = FALSE;
1650 }
1651
1652 /* Size of rect of background color on which text is printed */
1653 prt_write_real(prt_text_run, 2);
1654 prt_write_real(prt_line_height, 2);
1655
1656 /* Lastly add the color of the background */
1657 r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
1658 g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
1659 b = prt_new_bgcol & 0xff;
1660 prt_write_real(r / 255.0, 3);
1661 prt_write_real(g / 255.0, 3);
1662 prt_write_real(b / 255.0, 3);
1663 prt_write_string("bg\n");
1664 }
1665 /* Draw underlines before the text as it makes it slightly easier to
1666 * find the starting point.
1667 */
1668 if (prt_do_underline)
1669 {
1670 if (prt_do_moveto)
1671 {
1672 prt_write_real(prt_pos_x_moveto, 2);
1673 prt_write_real(prt_pos_y_moveto, 2);
1674 prt_write_string("m\n");
1675 prt_do_moveto = FALSE;
1676 }
1677
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001678 /* Underline length of text run */
Bram Moolenaar81366db2005-07-24 21:16:51 +00001679 prt_write_real(prt_text_run, 2);
1680 prt_write_string("ul\n");
1681 }
1682 /* Draw the text
1683 * Note: we write text out raw - EBCDIC conversion is handled in the
1684 * PostScript world via the font encoding vector. */
1685#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001686 if (prt_out_mbyte)
1687 prt_write_string("<");
1688 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00001689#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001690 prt_write_string("(");
Bram Moolenaar81366db2005-07-24 21:16:51 +00001691 prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
1692#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001693 if (prt_out_mbyte)
1694 prt_write_string(">");
1695 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00001696#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001697 prt_write_string(")");
Bram Moolenaar81366db2005-07-24 21:16:51 +00001698 /* Add a moveto if need be and use the appropriate show procedure */
1699 if (prt_do_moveto)
1700 {
1701 prt_write_real(prt_pos_x_moveto, 2);
1702 prt_write_real(prt_pos_y_moveto, 2);
1703 /* moveto and a show */
1704 prt_write_string("ms\n");
1705 prt_do_moveto = FALSE;
1706 }
1707 else /* Simple show */
1708 prt_write_string("s\n");
1709
1710 ga_clear(&prt_ps_buffer);
1711 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
1712 }
1713}
1714
1715
1716 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001717prt_resource_name(char_u *filename, void *cookie)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001718{
1719 char_u *resource_filename = cookie;
1720
1721 if (STRLEN(filename) >= MAXPATHL)
1722 *resource_filename = NUL;
1723 else
1724 STRCPY(resource_filename, filename);
1725}
1726
1727 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001728prt_find_resource(char *name, struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001729{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001730 char_u *buffer;
1731 int retval;
1732
1733 buffer = alloc(MAXPATHL + 1);
1734 if (buffer == NULL)
1735 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001736
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02001737 vim_strncpy(resource->name, (char_u *)name, 63);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001738 /* Look for named resource file in runtimepath */
1739 STRCPY(buffer, "print");
1740 add_pathsep(buffer);
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02001741 vim_strcat(buffer, (char_u *)name, MAXPATHL);
1742 vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001743 resource->filename[0] = NUL;
Bram Moolenaard9462e32011-04-11 21:35:11 +02001744 retval = (do_in_runtimepath(buffer, FALSE, prt_resource_name,
Bram Moolenaar81366db2005-07-24 21:16:51 +00001745 resource->filename)
1746 && resource->filename[0] != NUL);
Bram Moolenaard9462e32011-04-11 21:35:11 +02001747 vim_free(buffer);
1748 return retval;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001749}
1750
1751/* PS CR and LF characters have platform independent values */
1752#define PSLF (0x0a)
1753#define PSCR (0x0d)
1754
1755/* Static buffer to read initial comments in a resource file, some can have a
1756 * couple of KB of comments! */
1757#define PRT_FILE_BUFFER_LEN (2048)
1758struct prt_resfile_buffer_S
1759{
1760 char_u buffer[PRT_FILE_BUFFER_LEN];
1761 int len;
1762 int line_start;
1763 int line_end;
1764};
1765
1766static struct prt_resfile_buffer_S prt_resfile;
1767
1768 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001769prt_resfile_next_line(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001770{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001771 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001772
1773 /* Move to start of next line and then find end of line */
Bram Moolenaar89d40322006-08-29 15:30:07 +00001774 idx = prt_resfile.line_end + 1;
1775 while (idx < prt_resfile.len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001776 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001777 if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001778 break;
Bram Moolenaar89d40322006-08-29 15:30:07 +00001779 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001780 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001781 prt_resfile.line_start = idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001782
Bram Moolenaar89d40322006-08-29 15:30:07 +00001783 while (idx < prt_resfile.len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001784 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001785 if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001786 break;
Bram Moolenaar89d40322006-08-29 15:30:07 +00001787 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001788 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001789 prt_resfile.line_end = idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001790
Bram Moolenaar89d40322006-08-29 15:30:07 +00001791 return (idx < prt_resfile.len);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001792}
1793
1794 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001795prt_resfile_strncmp(int offset, char *string, int len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001796{
1797 /* Force not equal if string is longer than remainder of line */
1798 if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001799 return 1;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001800
1801 return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001802 string, len);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001803}
1804
1805 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001806prt_resfile_skip_nonws(int offset)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001807{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001808 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001809
Bram Moolenaar89d40322006-08-29 15:30:07 +00001810 idx = prt_resfile.line_start + offset;
1811 while (idx < prt_resfile.line_end)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001812 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001813 if (isspace(prt_resfile.buffer[idx]))
1814 return idx - prt_resfile.line_start;
1815 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001816 }
1817 return -1;
1818}
1819
1820 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001821prt_resfile_skip_ws(int offset)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001822{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001823 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001824
Bram Moolenaar89d40322006-08-29 15:30:07 +00001825 idx = prt_resfile.line_start + offset;
1826 while (idx < prt_resfile.line_end)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001827 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001828 if (!isspace(prt_resfile.buffer[idx]))
1829 return idx - prt_resfile.line_start;
1830 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001831 }
1832 return -1;
1833}
1834
1835/* prt_next_dsc() - returns detail on next DSC comment line found. Returns true
1836 * if a DSC comment is found, else false */
1837 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001838prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001839{
1840 int comment;
1841 int offset;
1842
1843 /* Move to start of next line */
1844 if (!prt_resfile_next_line())
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001845 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001846
1847 /* DSC comments always start %% */
1848 if (prt_resfile_strncmp(0, "%%", 2) != 0)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001849 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001850
1851 /* Find type of DSC comment */
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00001852 for (comment = 0; comment < (int)NUM_ELEMENTS(prt_dsc_table); comment++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001853 if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
1854 prt_dsc_table[comment].len) == 0)
1855 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001856
1857 if (comment != NUM_ELEMENTS(prt_dsc_table))
1858 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001859 /* Return type of comment */
1860 p_dsc_line->type = prt_dsc_table[comment].type;
1861 offset = prt_dsc_table[comment].len;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001862 }
1863 else
1864 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001865 /* Unrecognised DSC comment, skip to ws after comment leader */
1866 p_dsc_line->type = PRT_DSC_MISC_TYPE;
1867 offset = prt_resfile_skip_nonws(0);
1868 if (offset == -1)
1869 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001870 }
1871
1872 /* Skip ws to comment value */
1873 offset = prt_resfile_skip_ws(offset);
1874 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001875 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001876
1877 p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
1878 p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
1879
1880 return TRUE;
1881}
1882
1883/* Improved hand crafted parser to get the type, title, and version number of a
1884 * PS resource file so the file details can be added to the DSC header comments.
1885 */
1886 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001887prt_open_resource(struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001888{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001889 int offset;
1890 int seen_all;
1891 int seen_title;
1892 int seen_version;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001893 FILE *fd_resource;
1894 struct prt_dsc_line_S dsc_line;
1895
1896 fd_resource = mch_fopen((char *)resource->filename, READBIN);
1897 if (fd_resource == NULL)
1898 {
1899 EMSG2(_("E624: Can't open file \"%s\""), resource->filename);
1900 return FALSE;
1901 }
1902 vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN);
1903
1904 /* Parse first line to ensure valid resource file */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001905 prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001906 PRT_FILE_BUFFER_LEN, fd_resource);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001907 if (ferror(fd_resource))
1908 {
1909 EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
1910 resource->filename);
1911 fclose(fd_resource);
1912 return FALSE;
1913 }
Bram Moolenaara9d52e32010-07-31 16:44:19 +02001914 fclose(fd_resource);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001915
1916 prt_resfile.line_end = -1;
1917 prt_resfile.line_start = 0;
1918 if (!prt_resfile_next_line())
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001919 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001920
1921 offset = 0;
1922
1923 if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001924 (int)STRLEN(PRT_RESOURCE_HEADER)) != 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001925 {
1926 EMSG2(_("E618: file \"%s\" is not a PostScript resource file"),
1927 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001928 return FALSE;
1929 }
1930
1931 /* Skip over any version numbers and following ws */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001932 offset += (int)STRLEN(PRT_RESOURCE_HEADER);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001933 offset = prt_resfile_skip_nonws(offset);
1934 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001935 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001936 offset = prt_resfile_skip_ws(offset);
1937 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001938 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001939
1940 if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001941 (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001942 {
1943 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
1944 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001945 return FALSE;
1946 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001947 offset += (int)STRLEN(PRT_RESOURCE_RESOURCE);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001948
1949 /* Decide type of resource in the file */
1950 if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001951 (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001952 resource->type = PRT_RESOURCE_TYPE_PROCSET;
1953 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001954 (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001955 resource->type = PRT_RESOURCE_TYPE_ENCODING;
1956 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001957 (int)STRLEN(PRT_RESOURCE_CMAP)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001958 resource->type = PRT_RESOURCE_TYPE_CMAP;
1959 else
1960 {
1961 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
1962 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001963 return FALSE;
1964 }
1965
1966 /* Look for title and version of resource */
1967 resource->title[0] = '\0';
1968 resource->version[0] = '\0';
1969 seen_title = FALSE;
1970 seen_version = FALSE;
1971 seen_all = FALSE;
1972 while (!seen_all && prt_next_dsc(&dsc_line))
1973 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001974 switch (dsc_line.type)
1975 {
1976 case PRT_DSC_TITLE_TYPE:
1977 vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
1978 seen_title = TRUE;
1979 if (seen_version)
1980 seen_all = TRUE;
1981 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001982
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001983 case PRT_DSC_VERSION_TYPE:
1984 vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
1985 seen_version = TRUE;
1986 if (seen_title)
1987 seen_all = TRUE;
1988 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001989
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001990 case PRT_DSC_ENDCOMMENTS_TYPE:
1991 /* Wont find title or resource after this comment, stop searching */
1992 seen_all = TRUE;
1993 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001994
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001995 case PRT_DSC_MISC_TYPE:
1996 /* Not interested in whatever comment this line had */
1997 break;
1998 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00001999 }
2000
2001 if (!seen_title || !seen_version)
2002 {
2003 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
2004 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002005 return FALSE;
2006 }
2007
Bram Moolenaar81366db2005-07-24 21:16:51 +00002008 return TRUE;
2009}
2010
2011 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002012prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002013{
2014 /* Version number m.n should match, the revision number does not matter */
2015 if (STRNCMP(resource->version, version, STRLEN(version)))
2016 {
2017 EMSG2(_("E621: \"%s\" resource file has wrong version"),
2018 resource->name);
2019 return FALSE;
2020 }
2021
2022 /* Other checks to be added as needed */
2023 return TRUE;
2024}
2025
2026 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002027prt_dsc_start(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002028{
2029 prt_write_string("%!PS-Adobe-3.0\n");
2030}
2031
2032 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002033prt_dsc_noarg(char *comment)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002034{
2035 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2036 "%%%%%s\n", comment);
2037 prt_write_file(prt_line_buffer);
2038}
2039
2040 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002041prt_dsc_textline(char *comment, char *text)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002042{
2043 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2044 "%%%%%s: %s\n", comment, text);
2045 prt_write_file(prt_line_buffer);
2046}
2047
2048 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002049prt_dsc_text(char *comment, char *text)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002050{
2051 /* TODO - should scan 'text' for any chars needing escaping! */
2052 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2053 "%%%%%s: (%s)\n", comment, text);
2054 prt_write_file(prt_line_buffer);
2055}
2056
2057#define prt_dsc_atend(c) prt_dsc_text((c), "atend")
2058
2059 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002060prt_dsc_ints(char *comment, int count, int *ints)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002061{
2062 int i;
2063
2064 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2065 "%%%%%s:", comment);
2066 prt_write_file(prt_line_buffer);
2067
2068 for (i = 0; i < count; i++)
2069 {
2070 sprintf((char *)prt_line_buffer, " %d", ints[i]);
2071 prt_write_file(prt_line_buffer);
2072 }
2073
2074 prt_write_string("\n");
2075}
2076
2077 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002078prt_dsc_resources(
2079 char *comment, /* if NULL add to previous */
2080 char *type,
2081 char *string)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002082{
2083 if (comment != NULL)
2084 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2085 "%%%%%s: %s", comment, type);
2086 else
2087 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2088 "%%%%+ %s", type);
2089 prt_write_file(prt_line_buffer);
2090
2091 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2092 " %s\n", string);
2093 prt_write_file(prt_line_buffer);
2094}
2095
2096 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002097prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002098{
2099 int i;
2100
2101 prt_dsc_resources(resource, "font",
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002102 ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002103 for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002104 if (ps_font->ps_fontname[i] != NULL)
2105 prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002106}
2107
2108 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002109prt_dsc_requirements(
2110 int duplex,
2111 int tumble,
2112 int collate,
2113 int color,
2114 int num_copies)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002115{
2116 /* Only output the comment if we need to.
2117 * Note: tumble is ignored if we are not duplexing
2118 */
2119 if (!(duplex || collate || color || (num_copies > 1)))
2120 return;
2121
2122 sprintf((char *)prt_line_buffer, "%%%%Requirements:");
2123 prt_write_file(prt_line_buffer);
2124
2125 if (duplex)
2126 {
2127 prt_write_string(" duplex");
2128 if (tumble)
2129 prt_write_string("(tumble)");
2130 }
2131 if (collate)
2132 prt_write_string(" collate");
2133 if (color)
2134 prt_write_string(" color");
2135 if (num_copies > 1)
2136 {
2137 prt_write_string(" numcopies(");
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002138 /* Note: no space wanted so don't use prt_write_int() */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002139 sprintf((char *)prt_line_buffer, "%d", num_copies);
2140 prt_write_file(prt_line_buffer);
2141 prt_write_string(")");
2142 }
2143 prt_write_string("\n");
2144}
2145
2146 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002147prt_dsc_docmedia(
2148 char *paper_name,
2149 double width,
2150 double height,
2151 double weight,
2152 char *colour,
2153 char *type)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002154{
2155 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2156 "%%%%DocumentMedia: %s ", paper_name);
2157 prt_write_file(prt_line_buffer);
2158 prt_write_real(width, 2);
2159 prt_write_real(height, 2);
2160 prt_write_real(weight, 2);
2161 if (colour == NULL)
2162 prt_write_string("()");
2163 else
2164 prt_write_string(colour);
2165 prt_write_string(" ");
2166 if (type == NULL)
2167 prt_write_string("()");
2168 else
2169 prt_write_string(type);
2170 prt_write_string("\n");
2171}
2172
2173 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002174mch_print_cleanup(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002175{
2176#ifdef FEAT_MBYTE
2177 if (prt_out_mbyte)
2178 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002179 int i;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002180
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002181 /* Free off all CID font names created, but first clear duplicate
2182 * pointers to the same string (when the same font is used for more than
2183 * one style).
2184 */
2185 for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
2186 {
2187 if (prt_ps_mb_font.ps_fontname[i] != NULL)
2188 vim_free(prt_ps_mb_font.ps_fontname[i]);
2189 prt_ps_mb_font.ps_fontname[i] = NULL;
2190 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002191 }
2192
2193 if (prt_do_conv)
2194 {
2195 convert_setup(&prt_conv, NULL, NULL);
2196 prt_do_conv = FALSE;
2197 }
2198#endif
2199 if (prt_ps_fd != NULL)
2200 {
2201 fclose(prt_ps_fd);
2202 prt_ps_fd = NULL;
2203 prt_file_error = FALSE;
2204 }
2205 if (prt_ps_file_name != NULL)
2206 {
2207 vim_free(prt_ps_file_name);
2208 prt_ps_file_name = NULL;
2209 }
2210}
2211
2212 static float
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002213to_device_units(int idx, double physsize, int def_number)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002214{
2215 float ret;
2216 int u;
2217 int nr;
2218
2219 u = prt_get_unit(idx);
2220 if (u == PRT_UNIT_NONE)
2221 {
2222 u = PRT_UNIT_PERC;
2223 nr = def_number;
2224 }
2225 else
2226 nr = printer_opts[idx].number;
2227
2228 switch (u)
2229 {
2230 case PRT_UNIT_INCH:
2231 ret = (float)(nr * PRT_PS_DEFAULT_DPI);
2232 break;
2233 case PRT_UNIT_MM:
2234 ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
2235 break;
2236 case PRT_UNIT_POINT:
2237 ret = (float)nr;
2238 break;
2239 case PRT_UNIT_PERC:
2240 default:
2241 ret = (float)(physsize * nr) / 100;
2242 break;
2243 }
2244
2245 return ret;
2246}
2247
2248/*
2249 * Calculate margins for given width and height from printoptions settings.
2250 */
2251 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002252prt_page_margins(
2253 double width,
2254 double height,
2255 double *left,
2256 double *right,
2257 double *top,
2258 double *bottom)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002259{
2260 *left = to_device_units(OPT_PRINT_LEFT, width, 10);
2261 *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
2262 *top = height - to_device_units(OPT_PRINT_TOP, height, 5);
2263 *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
2264}
2265
2266 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002267prt_font_metrics(int font_scale)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002268{
2269 prt_line_height = (float)font_scale;
2270 prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
2271}
2272
2273
2274 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002275prt_get_cpl(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002276{
2277 if (prt_use_number())
2278 {
2279 prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
2280#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002281 /* If we are outputting multi-byte characters then line numbers will be
2282 * printed with half width characters
2283 */
2284 if (prt_out_mbyte)
2285 prt_number_width /= 2;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002286#endif
2287 prt_left_margin += prt_number_width;
2288 }
2289 else
2290 prt_number_width = 0.0;
2291
2292 return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
2293}
2294
2295#ifdef FEAT_MBYTE
2296 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002297prt_build_cid_fontname(int font, char_u *name, int name_len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002298{
2299 char *fontname;
2300
2301 fontname = (char *)alloc(name_len + 1);
2302 if (fontname == NULL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002303 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002304 vim_strncpy((char_u *)fontname, name, name_len);
2305 prt_ps_mb_font.ps_fontname[font] = fontname;
2306
2307 return TRUE;
2308}
2309#endif
2310
2311/*
2312 * Get number of lines of text that fit on a page (excluding the header).
2313 */
2314 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002315prt_get_lpp(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002316{
2317 int lpp;
2318
2319 /*
2320 * Calculate offset to lower left corner of background rect based on actual
2321 * font height (based on its bounding box) and the line height, handling the
2322 * case where the font height can exceed the line height.
2323 */
2324 prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
2325 prt_ps_font->bbox_min_y);
2326 if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
2327 {
2328 prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
2329 (1000.0 - (prt_ps_font->bbox_max_y -
2330 prt_ps_font->bbox_min_y)) / 2);
2331 }
2332
2333 /* Get height for topmost line based on background rect offset. */
2334 prt_first_line_height = prt_line_height + prt_bgcol_offset;
2335
2336 /* Calculate lpp */
2337 lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
2338
2339 /* Adjust top margin if there is a header */
2340 prt_top_margin -= prt_line_height * prt_header_height();
2341
2342 return lpp - prt_header_height();
2343}
2344
2345#ifdef FEAT_MBYTE
2346 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002347prt_match_encoding(
2348 char *p_encoding,
2349 struct prt_ps_mbfont_S *p_cmap,
2350 struct prt_ps_encoding_S **pp_mbenc)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002351{
2352 int mbenc;
2353 int enc_len;
2354 struct prt_ps_encoding_S *p_mbenc;
2355
2356 *pp_mbenc = NULL;
2357 /* Look for recognised encoding */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002358 enc_len = (int)STRLEN(p_encoding);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002359 p_mbenc = p_cmap->encodings;
2360 for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
2361 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002362 if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
2363 {
2364 *pp_mbenc = p_mbenc;
2365 return TRUE;
2366 }
2367 p_mbenc++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002368 }
2369 return FALSE;
2370}
2371
2372 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002373prt_match_charset(
2374 char *p_charset,
2375 struct prt_ps_mbfont_S *p_cmap,
2376 struct prt_ps_charset_S **pp_mbchar)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002377{
2378 int mbchar;
2379 int char_len;
2380 struct prt_ps_charset_S *p_mbchar;
2381
2382 /* Look for recognised character set, using default if one is not given */
2383 if (*p_charset == NUL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002384 p_charset = p_cmap->defcs;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002385 char_len = (int)STRLEN(p_charset);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002386 p_mbchar = p_cmap->charsets;
2387 for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
2388 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002389 if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
2390 {
2391 *pp_mbchar = p_mbchar;
2392 return TRUE;
2393 }
2394 p_mbchar++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002395 }
2396 return FALSE;
2397}
2398#endif
2399
Bram Moolenaar81366db2005-07-24 21:16:51 +00002400 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002401mch_print_init(
2402 prt_settings_T *psettings,
2403 char_u *jobname,
2404 int forceit UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002405{
2406 int i;
2407 char *paper_name;
2408 int paper_strlen;
2409 int fontsize;
2410 char_u *p;
2411 double left;
2412 double right;
2413 double top;
2414 double bottom;
2415#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002416 int props;
2417 int cmap = 0;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002418 char_u *p_encoding;
2419 struct prt_ps_encoding_S *p_mbenc;
2420 struct prt_ps_encoding_S *p_mbenc_first;
Bram Moolenaar89d40322006-08-29 15:30:07 +00002421 struct prt_ps_charset_S *p_mbchar = NULL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002422#endif
2423
2424#if 0
2425 /*
2426 * TODO:
2427 * If "forceit" is false: pop up a dialog to select:
2428 * - printer name
2429 * - copies
2430 * - collated/uncollated
2431 * - duplex off/long side/short side
2432 * - paper size
2433 * - portrait/landscape
2434 * - font size
2435 *
2436 * If "forceit" is true: use the default printer and settings
2437 */
2438 if (forceit)
2439 s_pd.Flags |= PD_RETURNDEFAULT;
2440#endif
2441
2442 /*
2443 * Set up font and encoding.
2444 */
2445#ifdef FEAT_MBYTE
2446 p_encoding = enc_skip(p_penc);
2447 if (*p_encoding == NUL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002448 p_encoding = enc_skip(p_enc);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002449
Bram Moolenaar14716812006-05-04 21:54:08 +00002450 /* Look for a multi-byte font that matches the encoding and character set.
2451 * Only look if multi-byte character set is defined, or using multi-byte
2452 * encoding other than Unicode. This is because a Unicode encoding does not
2453 * uniquely identify a CJK character set to use. */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002454 p_mbenc = NULL;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002455 props = enc_canon_props(p_encoding);
Bram Moolenaar14716812006-05-04 21:54:08 +00002456 if (!(props & ENC_8BIT) && ((*p_pmcs != NUL) || !(props & ENC_UNICODE)))
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002457 {
Bram Moolenaarec45c4a2015-04-15 14:27:49 +02002458 int cmap_first = 0;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002459
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002460 p_mbenc_first = NULL;
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00002461 for (cmap = 0; cmap < (int)NUM_ELEMENTS(prt_ps_mbfonts); cmap++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002462 if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
Bram Moolenaar81366db2005-07-24 21:16:51 +00002463 &p_mbenc))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002464 {
2465 if (p_mbenc_first == NULL)
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002466 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002467 p_mbenc_first = p_mbenc;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002468 cmap_first = cmap;
2469 }
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002470 if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
Bram Moolenaar81366db2005-07-24 21:16:51 +00002471 &p_mbchar))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002472 break;
2473 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002474
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002475 /* Use first encoding matched if no charset matched */
2476 if (p_mbchar == NULL && p_mbenc_first != NULL)
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002477 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002478 p_mbenc = p_mbenc_first;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002479 cmap = cmap_first;
2480 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002481 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002482
2483 prt_out_mbyte = (p_mbenc != NULL);
2484 if (prt_out_mbyte)
2485 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002486 /* Build CMap name - will be same for all multi-byte fonts used */
2487 prt_cmap[0] = NUL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002488
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002489 prt_custom_cmap = (p_mbchar == NULL);
2490 if (!prt_custom_cmap)
2491 {
2492 /* Check encoding and character set are compatible */
2493 if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0)
2494 {
2495 EMSG(_("E673: Incompatible multi-byte encoding and character set."));
2496 return FALSE;
2497 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002498
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002499 /* Add charset name if not empty */
2500 if (p_mbchar->cmap_charset != NULL)
2501 {
2502 vim_strncpy((char_u *)prt_cmap,
Bram Moolenaar81366db2005-07-24 21:16:51 +00002503 (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002504 STRCAT(prt_cmap, "-");
2505 }
2506 }
2507 else
2508 {
2509 /* Add custom CMap character set name */
2510 if (*p_pmcs == NUL)
2511 {
2512 EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
2513 return FALSE;
2514 }
2515 vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
2516 STRCAT(prt_cmap, "-");
2517 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002518
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002519 /* CMap name ends with (optional) encoding name and -H for horizontal */
2520 if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002521 + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002522 {
2523 STRCAT(prt_cmap, p_mbenc->cmap_encoding);
2524 STRCAT(prt_cmap, "-");
2525 }
2526 STRCAT(prt_cmap, "H");
Bram Moolenaar81366db2005-07-24 21:16:51 +00002527
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002528 if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
2529 {
2530 EMSG(_("E675: No default font specified for multi-byte printing."));
2531 return FALSE;
2532 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002533
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002534 /* Derive CID font names with fallbacks if not defined */
2535 if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
2536 mbfont_opts[OPT_MBFONT_REGULAR].string,
2537 mbfont_opts[OPT_MBFONT_REGULAR].strlen))
2538 return FALSE;
2539 if (mbfont_opts[OPT_MBFONT_BOLD].present)
2540 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
2541 mbfont_opts[OPT_MBFONT_BOLD].string,
2542 mbfont_opts[OPT_MBFONT_BOLD].strlen))
2543 return FALSE;
2544 if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
2545 if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
2546 mbfont_opts[OPT_MBFONT_OBLIQUE].string,
2547 mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
2548 return FALSE;
2549 if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
2550 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
Bram Moolenaar81366db2005-07-24 21:16:51 +00002551 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
2552 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002553 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002554
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002555 /* Check if need to use Courier for ASCII code range, and if so pick up
2556 * the encoding to use */
2557 prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
2558 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
2559 if (prt_use_courier)
2560 {
2561 /* Use national ASCII variant unless ASCII wanted */
2562 if (mbfont_opts[OPT_MBFONT_ASCII].present &&
2563 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
2564 prt_ascii_encoding = "ascii";
2565 else
2566 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
2567 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002568
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002569 prt_ps_font = &prt_ps_mb_font;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002570 }
2571 else
2572#endif
2573 {
2574#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002575 prt_use_courier = FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002576#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002577 prt_ps_font = &prt_ps_courier_font;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002578 }
2579
2580 /*
2581 * Find the size of the paper and set the margins.
2582 */
2583 prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
2584 || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
2585 if (printer_opts[OPT_PRINT_PAPER].present)
2586 {
2587 paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
2588 paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
2589 }
2590 else
2591 {
2592 paper_name = "A4";
2593 paper_strlen = 2;
2594 }
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00002595 for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002596 if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
2597 && STRNICMP(prt_mediasize[i].name, paper_name,
2598 paper_strlen) == 0)
2599 break;
2600 if (i == PRT_MEDIASIZE_LEN)
2601 i = 0;
2602 prt_media = i;
2603
2604 /*
2605 * Set PS pagesize based on media dimensions and print orientation.
2606 * Note: Media and page sizes have defined meanings in PostScript and should
2607 * be kept distinct. Media is the paper (or transparency, or ...) that is
2608 * printed on, whereas the page size is the area that the PostScript
2609 * interpreter renders into.
2610 */
2611 if (prt_portrait)
2612 {
2613 prt_page_width = prt_mediasize[i].width;
2614 prt_page_height = prt_mediasize[i].height;
2615 }
2616 else
2617 {
2618 prt_page_width = prt_mediasize[i].height;
2619 prt_page_height = prt_mediasize[i].width;
2620 }
2621
2622 /*
2623 * Set PS page margins based on the PS pagesize, not the mediasize - this
2624 * needs to be done before the cpl and lpp are calculated.
2625 */
2626 prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
2627 &bottom);
2628 prt_left_margin = (float)left;
2629 prt_right_margin = (float)right;
2630 prt_top_margin = (float)top;
2631 prt_bottom_margin = (float)bottom;
2632
2633 /*
2634 * Set up the font size.
2635 */
2636 fontsize = PRT_PS_DEFAULT_FONTSIZE;
2637 for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
2638 if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
2639 fontsize = atoi((char *)p + 2);
2640 prt_font_metrics(fontsize);
2641
2642 /*
2643 * Return the number of characters per line, and lines per page for the
2644 * generic print code.
2645 */
2646 psettings->chars_per_line = prt_get_cpl();
2647 psettings->lines_per_page = prt_get_lpp();
2648
2649 /* Catch margin settings that leave no space for output! */
2650 if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
2651 return FAIL;
2652
2653 /*
2654 * Sort out the number of copies to be printed. PS by default will do
2655 * uncollated copies for you, so once we know how many uncollated copies are
2656 * wanted cache it away and lie to the generic code that we only want one
2657 * uncollated copy.
2658 */
2659 psettings->n_collated_copies = 1;
2660 psettings->n_uncollated_copies = 1;
2661 prt_num_copies = 1;
2662 prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
2663 || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
2664 if (prt_collate)
2665 {
2666 /* TODO: Get number of collated copies wanted. */
2667 psettings->n_collated_copies = 1;
2668 }
2669 else
2670 {
2671 /* TODO: Get number of uncollated copies wanted and update the cached
2672 * count.
2673 */
2674 prt_num_copies = 1;
2675 }
2676
2677 psettings->jobname = jobname;
2678
2679 /*
2680 * Set up printer duplex and tumble based on Duplex option setting - default
2681 * is long sided duplex printing (i.e. no tumble).
2682 */
2683 prt_duplex = TRUE;
2684 prt_tumble = FALSE;
2685 psettings->duplex = 1;
2686 if (printer_opts[OPT_PRINT_DUPLEX].present)
2687 {
2688 if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
2689 {
2690 prt_duplex = FALSE;
2691 psettings->duplex = 0;
2692 }
2693 else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
2694 == 0)
2695 prt_tumble = TRUE;
2696 }
2697
2698 /* For now user abort not supported */
2699 psettings->user_abort = 0;
2700
2701 /* If the user didn't specify a file name, use a temp file. */
2702 if (psettings->outfile == NULL)
2703 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +02002704 prt_ps_file_name = vim_tempname('p', TRUE);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002705 if (prt_ps_file_name == NULL)
2706 {
2707 EMSG(_(e_notmp));
2708 return FAIL;
2709 }
2710 prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
2711 }
2712 else
2713 {
2714 p = expand_env_save(psettings->outfile);
2715 if (p != NULL)
2716 {
2717 prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
2718 vim_free(p);
2719 }
2720 }
2721 if (prt_ps_fd == NULL)
2722 {
2723 EMSG(_("E324: Can't open PostScript output file"));
2724 mch_print_cleanup();
2725 return FAIL;
2726 }
2727
2728 prt_bufsiz = psettings->chars_per_line;
2729#ifdef FEAT_MBYTE
2730 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002731 prt_bufsiz *= 2;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002732#endif
2733 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
2734
2735 prt_page_num = 0;
2736
2737 prt_attribute_change = FALSE;
2738 prt_need_moveto = FALSE;
2739 prt_need_font = FALSE;
2740 prt_need_fgcol = FALSE;
2741 prt_need_bgcol = FALSE;
2742 prt_need_underline = FALSE;
2743
2744 prt_file_error = FALSE;
2745
2746 return OK;
2747}
2748
2749 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002750prt_add_resource(struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002751{
2752 FILE* fd_resource;
2753 char_u resource_buffer[512];
2754 size_t bytes_read;
2755
2756 fd_resource = mch_fopen((char *)resource->filename, READBIN);
2757 if (fd_resource == NULL)
2758 {
2759 EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
2760 return FALSE;
2761 }
2762 prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
2763 (char *)resource->title);
2764
2765 prt_dsc_textline("BeginDocument", (char *)resource->filename);
2766
2767 for (;;)
2768 {
2769 bytes_read = fread((char *)resource_buffer, sizeof(char_u),
2770 sizeof(resource_buffer), fd_resource);
2771 if (ferror(fd_resource))
2772 {
2773 EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
2774 resource->filename);
2775 fclose(fd_resource);
2776 return FALSE;
2777 }
2778 if (bytes_read == 0)
2779 break;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002780 prt_write_file_raw_len(resource_buffer, (int)bytes_read);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002781 if (prt_file_error)
2782 {
2783 fclose(fd_resource);
2784 return FALSE;
2785 }
2786 }
2787 fclose(fd_resource);
2788
2789 prt_dsc_noarg("EndDocument");
2790
2791 prt_dsc_noarg("EndResource");
2792
2793 return TRUE;
2794}
2795
2796 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002797mch_print_begin(prt_settings_T *psettings)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002798{
2799 time_t now;
2800 int bbox[4];
2801 char *p_time;
2802 double left;
2803 double right;
2804 double top;
2805 double bottom;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002806 struct prt_ps_resource_S *res_prolog;
2807 struct prt_ps_resource_S *res_encoding;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002808 char buffer[256];
2809 char_u *p_encoding;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002810 char_u *p;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002811#ifdef FEAT_MBYTE
Bram Moolenaard9462e32011-04-11 21:35:11 +02002812 struct prt_ps_resource_S *res_cidfont;
2813 struct prt_ps_resource_S *res_cmap;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002814#endif
Bram Moolenaard9462e32011-04-11 21:35:11 +02002815 int retval = FALSE;
2816
2817 res_prolog = (struct prt_ps_resource_S *)
2818 alloc(sizeof(struct prt_ps_resource_S));
2819 res_encoding = (struct prt_ps_resource_S *)
2820 alloc(sizeof(struct prt_ps_resource_S));
2821#ifdef FEAT_MBYTE
2822 res_cidfont = (struct prt_ps_resource_S *)
2823 alloc(sizeof(struct prt_ps_resource_S));
2824 res_cmap = (struct prt_ps_resource_S *)
2825 alloc(sizeof(struct prt_ps_resource_S));
2826#endif
2827 if (res_prolog == NULL || res_encoding == NULL
2828#ifdef FEAT_MBYTE
2829 || res_cidfont == NULL || res_cmap == NULL
2830#endif
2831 )
2832 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002833
2834 /*
2835 * PS DSC Header comments - no PS code!
2836 */
2837 prt_dsc_start();
2838 prt_dsc_textline("Title", (char *)psettings->jobname);
2839 if (!get_user_name((char_u *)buffer, 256))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002840 STRCPY(buffer, "Unknown");
Bram Moolenaar81366db2005-07-24 21:16:51 +00002841 prt_dsc_textline("For", buffer);
2842 prt_dsc_textline("Creator", VIM_VERSION_LONG);
2843 /* Note: to ensure Clean8bit I don't think we can use LC_TIME */
2844 now = time(NULL);
2845 p_time = ctime(&now);
2846 /* Note: ctime() adds a \n so we have to remove it :-( */
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002847 p = vim_strchr((char_u *)p_time, '\n');
2848 if (p != NULL)
2849 *p = NUL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002850 prt_dsc_textline("CreationDate", p_time);
2851 prt_dsc_textline("DocumentData", "Clean8Bit");
2852 prt_dsc_textline("Orientation", "Portrait");
2853 prt_dsc_atend("Pages");
2854 prt_dsc_textline("PageOrder", "Ascend");
2855 /* The bbox does not change with orientation - it is always in the default
2856 * user coordinate system! We have to recalculate right and bottom
2857 * coordinates based on the font metrics for the bbox to be accurate. */
2858 prt_page_margins(prt_mediasize[prt_media].width,
2859 prt_mediasize[prt_media].height,
2860 &left, &right, &top, &bottom);
2861 bbox[0] = (int)left;
2862 if (prt_portrait)
2863 {
2864 /* In portrait printing the fixed point is the top left corner so we
2865 * derive the bbox from that point. We have the expected cpl chars
2866 * across the media and lpp lines down the media.
2867 */
2868 bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
2869 * prt_line_height);
2870 bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
2871 + 0.5);
2872 bbox[3] = (int)(top + 0.5);
2873 }
2874 else
2875 {
2876 /* In landscape printing the fixed point is the bottom left corner so we
2877 * derive the bbox from that point. We have lpp chars across the media
2878 * and cpl lines up the media.
2879 */
2880 bbox[1] = (int)bottom;
2881 bbox[2] = (int)(left + ((psettings->lines_per_page
2882 + prt_header_height()) * prt_line_height) + 0.5);
2883 bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
2884 + 0.5);
2885 }
2886 prt_dsc_ints("BoundingBox", 4, bbox);
2887 /* The media width and height does not change with landscape printing! */
2888 prt_dsc_docmedia(prt_mediasize[prt_media].name,
2889 prt_mediasize[prt_media].width,
2890 prt_mediasize[prt_media].height,
2891 (double)0, NULL, NULL);
2892 /* Define fonts needed */
2893#ifdef FEAT_MBYTE
2894 if (!prt_out_mbyte || prt_use_courier)
2895#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002896 prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002897#ifdef FEAT_MBYTE
2898 if (prt_out_mbyte)
2899 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002900 prt_dsc_font_resource((prt_use_courier ? NULL
2901 : "DocumentNeededResources"), &prt_ps_mb_font);
2902 if (!prt_custom_cmap)
2903 prt_dsc_resources(NULL, "cmap", prt_cmap);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002904 }
2905#endif
2906
2907 /* Search for external resources VIM supplies */
Bram Moolenaard9462e32011-04-11 21:35:11 +02002908 if (!prt_find_resource("prolog", res_prolog))
Bram Moolenaar81366db2005-07-24 21:16:51 +00002909 {
2910 EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\""));
Bram Moolenaar0a383962014-11-27 17:37:57 +01002911 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002912 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002913 if (!prt_open_resource(res_prolog))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002914 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002915 if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002916 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002917#ifdef FEAT_MBYTE
2918 if (prt_out_mbyte)
2919 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002920 /* Look for required version of multi-byte printing procset */
Bram Moolenaard9462e32011-04-11 21:35:11 +02002921 if (!prt_find_resource("cidfont", res_cidfont))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002922 {
2923 EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
Bram Moolenaar0a383962014-11-27 17:37:57 +01002924 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002925 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002926 if (!prt_open_resource(res_cidfont))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002927 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002928 if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002929 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002930 }
2931#endif
2932
2933 /* Find an encoding to use for printing.
2934 * Check 'printencoding'. If not set or not found, then use 'encoding'. If
2935 * that cannot be found then default to "latin1".
2936 * Note: VIM specific encoding header is always skipped.
2937 */
2938#ifdef FEAT_MBYTE
2939 if (!prt_out_mbyte)
2940 {
2941#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002942 p_encoding = enc_skip(p_penc);
2943 if (*p_encoding == NUL
Bram Moolenaard9462e32011-04-11 21:35:11 +02002944 || !prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002945 {
2946 /* 'printencoding' not set or not supported - find alternate */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002947#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002948 int props;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002949
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002950 p_encoding = enc_skip(p_enc);
2951 props = enc_canon_props(p_encoding);
2952 if (!(props & ENC_8BIT)
Bram Moolenaard9462e32011-04-11 21:35:11 +02002953 || !prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002954 /* 8-bit 'encoding' is not supported */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002955#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002956 {
2957 /* Use latin1 as default printing encoding */
2958 p_encoding = (char_u *)"latin1";
Bram Moolenaard9462e32011-04-11 21:35:11 +02002959 if (!prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002960 {
2961 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
2962 p_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002963 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002964 }
2965 }
2966 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002967 if (!prt_open_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002968 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002969 /* For the moment there are no checks on encoding resource files to
2970 * perform */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002971#ifdef FEAT_MBYTE
2972 }
2973 else
2974 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002975 p_encoding = enc_skip(p_penc);
2976 if (*p_encoding == NUL)
2977 p_encoding = enc_skip(p_enc);
2978 if (prt_use_courier)
2979 {
2980 /* Include ASCII range encoding vector */
Bram Moolenaard9462e32011-04-11 21:35:11 +02002981 if (!prt_find_resource(prt_ascii_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002982 {
2983 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
Bram Moolenaar81366db2005-07-24 21:16:51 +00002984 prt_ascii_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002985 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002986 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002987 if (!prt_open_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002988 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002989 /* For the moment there are no checks on encoding resource files to
2990 * perform */
2991 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002992 }
2993
2994 prt_conv.vc_type = CONV_NONE;
2995 if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002996 /* Set up encoding conversion if required */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002997 if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
2998 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002999 EMSG2(_("E620: Unable to convert to print encoding \"%s\""),
Bram Moolenaar81366db2005-07-24 21:16:51 +00003000 p_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01003001 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003002 }
3003 prt_do_conv = TRUE;
3004 }
3005 prt_do_conv = prt_conv.vc_type != CONV_NONE;
3006
3007 if (prt_out_mbyte && prt_custom_cmap)
3008 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003009 /* Find user supplied CMap */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003010 if (!prt_find_resource(prt_cmap, res_cmap))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003011 {
3012 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
Bram Moolenaar81366db2005-07-24 21:16:51 +00003013 prt_cmap);
Bram Moolenaar0a383962014-11-27 17:37:57 +01003014 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003015 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02003016 if (!prt_open_resource(res_cmap))
Bram Moolenaar0a383962014-11-27 17:37:57 +01003017 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003018 }
3019#endif
3020
3021 /* List resources supplied */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003022 STRCPY(buffer, res_prolog->title);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003023 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02003024 STRCAT(buffer, res_prolog->version);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003025 prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
3026#ifdef FEAT_MBYTE
3027 if (prt_out_mbyte)
3028 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02003029 STRCPY(buffer, res_cidfont->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003030 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02003031 STRCAT(buffer, res_cidfont->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003032 prt_dsc_resources(NULL, "procset", buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003033
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003034 if (prt_custom_cmap)
3035 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02003036 STRCPY(buffer, res_cmap->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003037 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02003038 STRCAT(buffer, res_cmap->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003039 prt_dsc_resources(NULL, "cmap", buffer);
3040 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003041 }
3042 if (!prt_out_mbyte || prt_use_courier)
3043#endif
3044 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02003045 STRCPY(buffer, res_encoding->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003046 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02003047 STRCAT(buffer, res_encoding->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003048 prt_dsc_resources(NULL, "encoding", buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003049 }
3050 prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
3051#ifdef FEAT_SYN_HL
3052 psettings->do_syntax
3053#else
3054 0
3055#endif
3056 , prt_num_copies);
3057 prt_dsc_noarg("EndComments");
3058
3059 /*
3060 * PS Document page defaults
3061 */
3062 prt_dsc_noarg("BeginDefaults");
3063
3064 /* List font resources most likely common to all pages */
3065#ifdef FEAT_MBYTE
3066 if (!prt_out_mbyte || prt_use_courier)
3067#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003068 prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003069#ifdef FEAT_MBYTE
3070 if (prt_out_mbyte)
3071 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003072 prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
3073 &prt_ps_mb_font);
3074 if (!prt_custom_cmap)
3075 prt_dsc_resources(NULL, "cmap", prt_cmap);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003076 }
3077#endif
3078
3079 /* Paper will be used for all pages */
3080 prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
3081
3082 prt_dsc_noarg("EndDefaults");
3083
3084 /*
3085 * PS Document prolog inclusion - all required procsets.
3086 */
3087 prt_dsc_noarg("BeginProlog");
3088
3089 /* Add required procsets - NOTE: order is important! */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003090 if (!prt_add_resource(res_prolog))
Bram Moolenaar0a383962014-11-27 17:37:57 +01003091 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003092#ifdef FEAT_MBYTE
3093 if (prt_out_mbyte)
3094 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003095 /* Add CID font procset, and any user supplied CMap */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003096 if (!prt_add_resource(res_cidfont))
Bram Moolenaar0a383962014-11-27 17:37:57 +01003097 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02003098 if (prt_custom_cmap && !prt_add_resource(res_cmap))
Bram Moolenaar0a383962014-11-27 17:37:57 +01003099 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003100 }
3101#endif
3102
3103#ifdef FEAT_MBYTE
3104 if (!prt_out_mbyte || prt_use_courier)
3105#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003106 /* There will be only one Roman font encoding to be included in the PS
3107 * file. */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003108 if (!prt_add_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01003109 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003110
3111 prt_dsc_noarg("EndProlog");
3112
3113 /*
3114 * PS Document setup - must appear after the prolog
3115 */
3116 prt_dsc_noarg("BeginSetup");
3117
3118 /* Device setup - page size and number of uncollated copies */
3119 prt_write_int((int)prt_mediasize[prt_media].width);
3120 prt_write_int((int)prt_mediasize[prt_media].height);
3121 prt_write_int(0);
3122 prt_write_string("sps\n");
3123 prt_write_int(prt_num_copies);
3124 prt_write_string("nc\n");
3125 prt_write_boolean(prt_duplex);
3126 prt_write_boolean(prt_tumble);
3127 prt_write_string("dt\n");
3128 prt_write_boolean(prt_collate);
3129 prt_write_string("c\n");
3130
3131 /* Font resource inclusion and definition */
3132#ifdef FEAT_MBYTE
3133 if (!prt_out_mbyte || prt_use_courier)
3134 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003135 /* When using Courier for ASCII range when printing multi-byte, need to
3136 * pick up ASCII encoding to use with it. */
3137 if (prt_use_courier)
3138 p_encoding = (char_u *)prt_ascii_encoding;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003139#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003140 prt_dsc_resources("IncludeResource", "font",
3141 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3142 prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
3143 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3144 prt_dsc_resources("IncludeResource", "font",
3145 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3146 prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
3147 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3148 prt_dsc_resources("IncludeResource", "font",
3149 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3150 prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
3151 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3152 prt_dsc_resources("IncludeResource", "font",
3153 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3154 prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
3155 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003156#ifdef FEAT_MBYTE
3157 }
3158 if (prt_out_mbyte)
3159 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003160 /* Define the CID fonts to be used in the job. Typically CJKV fonts do
3161 * not have an italic form being a western style, so where no font is
3162 * defined for these faces VIM falls back to an existing face.
3163 * Note: if using Courier for the ASCII range then the printout will
3164 * have bold/italic/bolditalic regardless of the setting of printmbfont.
3165 */
3166 prt_dsc_resources("IncludeResource", "font",
3167 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3168 if (!prt_custom_cmap)
3169 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3170 prt_def_cidfont("CF0", (int)prt_line_height,
3171 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003172
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003173 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
3174 {
3175 prt_dsc_resources("IncludeResource", "font",
3176 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3177 if (!prt_custom_cmap)
3178 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3179 prt_def_cidfont("CF1", (int)prt_line_height,
3180 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3181 }
3182 else
3183 /* Use ROMAN for BOLD */
3184 prt_dup_cidfont("CF0", "CF1");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003185
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003186 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
3187 {
3188 prt_dsc_resources("IncludeResource", "font",
3189 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3190 if (!prt_custom_cmap)
3191 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3192 prt_def_cidfont("CF2", (int)prt_line_height,
3193 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3194 }
3195 else
3196 /* Use ROMAN for OBLIQUE */
3197 prt_dup_cidfont("CF0", "CF2");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003198
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003199 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
3200 {
3201 prt_dsc_resources("IncludeResource", "font",
3202 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3203 if (!prt_custom_cmap)
3204 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3205 prt_def_cidfont("CF3", (int)prt_line_height,
3206 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3207 }
3208 else
3209 /* Use BOLD for BOLDOBLIQUE */
3210 prt_dup_cidfont("CF1", "CF3");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003211 }
3212#endif
3213
3214 /* Misc constant vars used for underlining and background rects */
3215 prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
3216 prt_ps_font->uline_offset), 2);
3217 prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
3218 prt_ps_font->uline_width), 2);
3219 prt_def_var("BO", prt_bgcol_offset, 2);
3220
3221 prt_dsc_noarg("EndSetup");
3222
3223 /* Fail if any problems writing out to the PS file */
Bram Moolenaard9462e32011-04-11 21:35:11 +02003224 retval = !prt_file_error;
3225
3226theend:
3227 vim_free(res_prolog);
3228 vim_free(res_encoding);
3229#ifdef FEAT_MBYTE
3230 vim_free(res_cidfont);
3231 vim_free(res_cmap);
3232#endif
3233
3234 return retval;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003235}
3236
3237 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003238mch_print_end(prt_settings_T *psettings)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003239{
3240 prt_dsc_noarg("Trailer");
3241
3242 /*
3243 * Output any info we don't know in toto until we finish
3244 */
3245 prt_dsc_ints("Pages", 1, &prt_page_num);
3246
3247 prt_dsc_noarg("EOF");
3248
3249 /* Write CTRL-D to close serial communication link if used.
3250 * NOTHING MUST BE WRITTEN AFTER THIS! */
3251 prt_write_file((char_u *)IF_EB("\004", "\067"));
3252
3253 if (!prt_file_error && psettings->outfile == NULL
3254 && !got_int && !psettings->user_abort)
3255 {
3256 /* Close the file first. */
3257 if (prt_ps_fd != NULL)
3258 {
3259 fclose(prt_ps_fd);
3260 prt_ps_fd = NULL;
3261 }
3262 prt_message((char_u *)_("Sending to printer..."));
3263
3264 /* Not printing to a file: use 'printexpr' to print the file. */
3265 if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
3266 EMSG(_("E365: Failed to print PostScript file"));
3267 else
3268 prt_message((char_u *)_("Print job sent."));
3269 }
3270
3271 mch_print_cleanup();
3272}
3273
3274 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003275mch_print_end_page(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003276{
3277 prt_flush_buffer();
3278
3279 prt_write_string("re sp\n");
3280
3281 prt_dsc_noarg("PageTrailer");
3282
3283 return !prt_file_error;
3284}
3285
Bram Moolenaar81366db2005-07-24 21:16:51 +00003286 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003287mch_print_begin_page(char_u *str UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003288{
3289 int page_num[2];
3290
3291 prt_page_num++;
3292
3293 page_num[0] = page_num[1] = prt_page_num;
3294 prt_dsc_ints("Page", 2, page_num);
3295
3296 prt_dsc_noarg("BeginPageSetup");
3297
3298 prt_write_string("sv\n0 g\n");
3299#ifdef FEAT_MBYTE
3300 prt_in_ascii = !prt_out_mbyte;
3301 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003302 prt_write_string("CF0 sf\n");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003303 else
3304#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003305 prt_write_string("F0 sf\n");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003306 prt_fgcol = PRCOLOR_BLACK;
3307 prt_bgcol = PRCOLOR_WHITE;
3308 prt_font = PRT_PS_FONT_ROMAN;
3309
3310 /* Set up page transformation for landscape printing. */
3311 if (!prt_portrait)
3312 {
3313 prt_write_int(-((int)prt_mediasize[prt_media].width));
3314 prt_write_string("sl\n");
3315 }
3316
3317 prt_dsc_noarg("EndPageSetup");
3318
3319 /* We have reset the font attributes, force setting them again. */
3320 curr_bg = (long_u)0xffffffff;
3321 curr_fg = (long_u)0xffffffff;
3322 curr_bold = MAYBE;
3323
3324 return !prt_file_error;
3325}
3326
3327 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003328mch_print_blank_page(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003329{
3330 return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
3331}
3332
3333static float prt_pos_x = 0;
3334static float prt_pos_y = 0;
3335
3336 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003337mch_print_start_line(int margin, int page_line)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003338{
3339 prt_pos_x = prt_left_margin;
3340 if (margin)
3341 prt_pos_x -= prt_number_width;
3342
3343 prt_pos_y = prt_top_margin - prt_first_line_height -
3344 page_line * prt_line_height;
3345
3346 prt_attribute_change = TRUE;
3347 prt_need_moveto = TRUE;
3348#ifdef FEAT_MBYTE
3349 prt_half_width = FALSE;
3350#endif
3351}
3352
Bram Moolenaar81366db2005-07-24 21:16:51 +00003353 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003354mch_print_text_out(char_u *p, int len UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003355{
3356 int need_break;
3357 char_u ch;
3358 char_u ch_buff[8];
3359 float char_width;
3360 float next_pos;
3361#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003362 int in_ascii;
3363 int half_width;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003364#endif
3365
3366 char_width = prt_char_width;
3367
3368#ifdef FEAT_MBYTE
3369 /* Ideally VIM would create a rearranged CID font to combine a Roman and
3370 * CJKV font to do what VIM is doing here - use a Roman font for characters
Bram Moolenaarb15c8332007-05-10 18:40:02 +00003371 * in the ASCII range, and the original CID font for everything else.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003372 * The problem is that GhostScript still (as of 8.13) does not support
3373 * rearranged fonts even though they have been documented by Adobe for 7
3374 * years! If they ever do, a lot of this code will disappear.
3375 */
3376 if (prt_use_courier)
3377 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003378 in_ascii = (len == 1 && *p < 0x80);
3379 if (prt_in_ascii)
3380 {
3381 if (!in_ascii)
3382 {
3383 /* No longer in ASCII range - need to switch font */
3384 prt_in_ascii = FALSE;
3385 prt_need_font = TRUE;
3386 prt_attribute_change = TRUE;
3387 }
3388 }
3389 else if (in_ascii)
3390 {
3391 /* Now in ASCII range - need to switch font */
3392 prt_in_ascii = TRUE;
3393 prt_need_font = TRUE;
3394 prt_attribute_change = TRUE;
3395 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003396 }
3397 if (prt_out_mbyte)
3398 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003399 half_width = ((*mb_ptr2cells)(p) == 1);
3400 if (half_width)
3401 char_width /= 2;
3402 if (prt_half_width)
3403 {
3404 if (!half_width)
3405 {
3406 prt_half_width = FALSE;
3407 prt_pos_x += prt_char_width/4;
3408 prt_need_moveto = TRUE;
3409 prt_attribute_change = TRUE;
3410 }
3411 }
3412 else if (half_width)
3413 {
3414 prt_half_width = TRUE;
3415 prt_pos_x += prt_char_width/4;
3416 prt_need_moveto = TRUE;
3417 prt_attribute_change = TRUE;
3418 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003419 }
3420#endif
3421
3422 /* Output any required changes to the graphics state, after flushing any
3423 * text buffered so far.
3424 */
3425 if (prt_attribute_change)
3426 {
3427 prt_flush_buffer();
3428 /* Reset count of number of chars that will be printed */
3429 prt_text_run = 0;
3430
3431 if (prt_need_moveto)
3432 {
3433 prt_pos_x_moveto = prt_pos_x;
3434 prt_pos_y_moveto = prt_pos_y;
3435 prt_do_moveto = TRUE;
3436
3437 prt_need_moveto = FALSE;
3438 }
3439 if (prt_need_font)
3440 {
3441#ifdef FEAT_MBYTE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003442 if (!prt_in_ascii)
3443 prt_write_string("CF");
3444 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00003445#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003446 prt_write_string("F");
3447 prt_write_int(prt_font);
3448 prt_write_string("sf\n");
3449 prt_need_font = FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003450 }
3451 if (prt_need_fgcol)
3452 {
3453 int r, g, b;
3454 r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
3455 g = ((unsigned)prt_fgcol & 0xff00) >> 8;
3456 b = prt_fgcol & 0xff;
3457
3458 prt_write_real(r / 255.0, 3);
3459 if (r == g && g == b)
3460 prt_write_string("g\n");
3461 else
3462 {
3463 prt_write_real(g / 255.0, 3);
3464 prt_write_real(b / 255.0, 3);
3465 prt_write_string("r\n");
3466 }
3467 prt_need_fgcol = FALSE;
3468 }
3469
3470 if (prt_bgcol != PRCOLOR_WHITE)
3471 {
3472 prt_new_bgcol = prt_bgcol;
3473 if (prt_need_bgcol)
3474 prt_do_bgcol = TRUE;
3475 }
3476 else
3477 prt_do_bgcol = FALSE;
3478 prt_need_bgcol = FALSE;
3479
3480 if (prt_need_underline)
3481 prt_do_underline = prt_underline;
3482 prt_need_underline = FALSE;
3483
3484 prt_attribute_change = FALSE;
3485 }
3486
3487#ifdef FEAT_MBYTE
3488 if (prt_do_conv)
3489 {
3490 /* Convert from multi-byte to 8-bit encoding */
3491 p = string_convert(&prt_conv, p, &len);
3492 if (p == NULL)
3493 p = (char_u *)"";
3494 }
3495
3496 if (prt_out_mbyte)
3497 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003498 /* Multi-byte character strings are represented more efficiently as hex
3499 * strings when outputting clean 8 bit PS.
3500 */
3501 do
3502 {
3503 ch = prt_hexchar[(unsigned)(*p) >> 4];
3504 ga_append(&prt_ps_buffer, ch);
3505 ch = prt_hexchar[(*p) & 0xf];
3506 ga_append(&prt_ps_buffer, ch);
3507 p++;
3508 }
3509 while (--len);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003510 }
3511 else
3512#endif
3513 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003514 /* Add next character to buffer of characters to output.
3515 * Note: One printed character may require several PS characters to
3516 * represent it, but we only count them as one printed character.
3517 */
3518 ch = *p;
3519 if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
3520 {
3521 /* Convert non-printing characters to either their escape or octal
3522 * sequence, ensures PS sent over a serial line does not interfere
3523 * with the comms protocol. Note: For EBCDIC we need to write out
3524 * the escape sequences as ASCII codes!
Bram Moolenaar81366db2005-07-24 21:16:51 +00003525 * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
3526 */
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003527 ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
3528 switch (ch)
3529 {
3530 case BS: ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
3531 case TAB: ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
3532 case NL: ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
3533 case FF: ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
3534 case CAR: ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
3535 case '(': ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
3536 case ')': ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
3537 case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003538
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003539 default:
3540 sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003541#ifdef EBCDIC
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003542 ebcdic2ascii(ch_buff, 3);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003543#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003544 ga_append(&prt_ps_buffer, ch_buff[0]);
3545 ga_append(&prt_ps_buffer, ch_buff[1]);
3546 ga_append(&prt_ps_buffer, ch_buff[2]);
3547 break;
3548 }
3549 }
3550 else
3551 ga_append(&prt_ps_buffer, ch);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003552 }
3553
3554#ifdef FEAT_MBYTE
3555 /* Need to free any translated characters */
3556 if (prt_do_conv && (*p != NUL))
3557 vim_free(p);
3558#endif
3559
3560 prt_text_run += char_width;
3561 prt_pos_x += char_width;
3562
3563 /* The downside of fp - use relative error on right margin check */
3564 next_pos = prt_pos_x + prt_char_width;
3565 need_break = (next_pos > prt_right_margin) &&
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003566 ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
Bram Moolenaar81366db2005-07-24 21:16:51 +00003567
3568 if (need_break)
3569 prt_flush_buffer();
3570
3571 return need_break;
3572}
3573
3574 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003575mch_print_set_font(int iBold, int iItalic, int iUnderline)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003576{
3577 int font = 0;
3578
3579 if (iBold)
3580 font |= 0x01;
3581 if (iItalic)
3582 font |= 0x02;
3583
3584 if (font != prt_font)
3585 {
3586 prt_font = font;
3587 prt_attribute_change = TRUE;
3588 prt_need_font = TRUE;
3589 }
3590 if (prt_underline != iUnderline)
3591 {
3592 prt_underline = iUnderline;
3593 prt_attribute_change = TRUE;
3594 prt_need_underline = TRUE;
3595 }
3596}
3597
3598 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003599mch_print_set_bg(long_u bgcol)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003600{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003601 prt_bgcol = (int)bgcol;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003602 prt_attribute_change = TRUE;
3603 prt_need_bgcol = TRUE;
3604}
3605
3606 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003607mch_print_set_fg(long_u fgcol)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003608{
3609 if (fgcol != (long_u)prt_fgcol)
3610 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003611 prt_fgcol = (int)fgcol;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003612 prt_attribute_change = TRUE;
3613 prt_need_fgcol = TRUE;
3614 }
3615}
3616
3617# endif /*FEAT_POSTSCRIPT*/
3618#endif /*FEAT_PRINTER*/