blob: 9d114c587e64a34d3900a5e1c7b93615be054e80 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar81366db2005-07-24 21:16:51 +00002 *
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
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100105#if defined(FEAT_POSTSCRIPT)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000106# 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{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100130 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
Bram Moolenaar81366db2005-07-24 21:16:51 +0000136} prt_pos_T;
137
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100138static char *parse_list_options(char_u *option_str, option_table_T *table, int table_size);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000139
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +0100140static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000141
142/*
143 * Parse 'printoptions' and set the flags in "printer_opts".
144 * Returns an error message or NULL;
145 */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100146 char *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100147parse_printoptions(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000148{
149 return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS);
150}
151
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100152#if defined(FEAT_POSTSCRIPT) || defined(PROTO)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000153/*
Bram Moolenaar8a633e32016-04-21 21:10:14 +0200154 * Parse 'printmbfont' and set the flags in "mbfont_opts".
Bram Moolenaar81366db2005-07-24 21:16:51 +0000155 * Returns an error message or NULL;
156 */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100157 char *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100158parse_printmbfont(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000159{
160 return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS);
161}
162#endif
163
164/*
165 * Parse a list of options in the form
166 * option:value,option:value,option:value
167 *
168 * "value" can start with a number which is parsed out, e.g. margin:12mm
169 *
170 * Returns an error message for an illegal option, NULL otherwise.
171 * Only used for the printer at the moment...
172 */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100173 static char *
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100174parse_list_options(
175 char_u *option_str,
176 option_table_T *table,
177 int table_size)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000178{
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200179 option_table_T *old_opts;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100180 char *ret = NULL;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000181 char_u *stringp;
182 char_u *colonp;
183 char_u *commap;
184 char_u *p;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100185 int idx = 0; // init for GCC
Bram Moolenaar81366db2005-07-24 21:16:51 +0000186 int len;
187
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100188 // Save the old values, so that they can be restored in case of an error.
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200189 old_opts = ALLOC_MULT(option_table_T, table_size);
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200190 if (old_opts == NULL)
191 return NULL;
192
Bram Moolenaar81366db2005-07-24 21:16:51 +0000193 for (idx = 0; idx < table_size; ++idx)
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200194 {
195 old_opts[idx] = table[idx];
Bram Moolenaar81366db2005-07-24 21:16:51 +0000196 table[idx].present = FALSE;
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200197 }
Bram Moolenaar81366db2005-07-24 21:16:51 +0000198
199 /*
200 * Repeat for all comma separated parts.
201 */
202 stringp = option_str;
203 while (*stringp)
204 {
205 colonp = vim_strchr(stringp, ':');
206 if (colonp == NULL)
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200207 {
Bram Moolenaar1d423ef2022-01-02 21:26:16 +0000208 ret = e_missing_colon_3;
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200209 break;
210 }
Bram Moolenaar81366db2005-07-24 21:16:51 +0000211 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)
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200222 {
Bram Moolenaar1d423ef2022-01-02 21:26:16 +0000223 ret = e_illegal_component;
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200224 break;
225 }
Bram Moolenaar81366db2005-07-24 21:16:51 +0000226 p = colonp + 1;
227 table[idx].present = TRUE;
228
229 if (table[idx].hasnum)
230 {
231 if (!VIM_ISDIGIT(*p))
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200232 {
Bram Moolenaar1d423ef2022-01-02 21:26:16 +0000233 ret = e_digit_expected_2;
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200234 break;
235 }
Bram Moolenaar81366db2005-07-24 21:16:51 +0000236
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100237 table[idx].number = getdigits(&p); // advances p
Bram Moolenaar81366db2005-07-24 21:16:51 +0000238 }
239
240 table[idx].string = p;
241 table[idx].strlen = (int)(commap - p);
242
243 stringp = commap;
244 if (*stringp == ',')
245 ++stringp;
246 }
247
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200248 if (ret != NULL)
249 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100250 // Restore old options in case of error
Bram Moolenaar4afc7c52016-04-03 14:56:52 +0200251 for (idx = 0; idx < table_size; ++idx)
252 table[idx] = old_opts[idx];
253 }
254 vim_free(old_opts);
255 return ret;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000256}
257
258
259#ifdef FEAT_SYN_HL
260/*
261 * If using a dark background, the colors will probably be too bright to show
262 * up well on white paper, so reduce their brightness.
263 */
264 static long_u
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100265darken_rgb(long_u rgb)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000266{
267 return ((rgb >> 17) << 16)
268 + (((rgb & 0xff00) >> 9) << 8)
269 + ((rgb & 0xff) >> 1);
270}
271
272 static long_u
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100273prt_get_term_color(int colorindex)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000274{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100275 // TODO: Should check for xterm with 88 or 256 colors.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000276 if (t_colors > 8)
277 return cterm_color_16[colorindex % 16];
278 return cterm_color_8[colorindex % 8];
279}
280
281 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100282prt_get_attr(
283 int hl_id,
284 prt_text_attr_T *pattr,
285 int modec)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000286{
287 int colorindex;
288 long_u fg_color;
289 long_u bg_color;
290 char *color;
291
292 pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
293 pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
294 pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL);
295 pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
Bram Moolenaar84f54632022-06-29 18:39:11 +0100296 // TODO: HL_UNDERDOUBLE, HL_UNDERDOTTED, HL_UNDERDASHED
Bram Moolenaar81366db2005-07-24 21:16:51 +0000297
Bram Moolenaar61be73b2016-04-29 22:59:22 +0200298# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a633e32016-04-21 21:10:14 +0200299 if (USE_24BIT)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000300 {
301 bg_color = highlight_gui_color_rgb(hl_id, FALSE);
302 if (bg_color == PRCOLOR_BLACK)
303 bg_color = PRCOLOR_WHITE;
304
305 fg_color = highlight_gui_color_rgb(hl_id, TRUE);
306 }
307 else
308# endif
309 {
310 bg_color = PRCOLOR_WHITE;
311
312 color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
313 if (color == NULL)
314 colorindex = 0;
315 else
316 colorindex = atoi(color);
317
318 if (colorindex >= 0 && colorindex < t_colors)
319 fg_color = prt_get_term_color(colorindex);
320 else
321 fg_color = PRCOLOR_BLACK;
322 }
323
324 if (fg_color == PRCOLOR_WHITE)
325 fg_color = PRCOLOR_BLACK;
326 else if (*p_bg == 'd')
327 fg_color = darken_rgb(fg_color);
328
329 pattr->fg_color = fg_color;
330 pattr->bg_color = bg_color;
331}
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100332#endif // FEAT_SYN_HL
Bram Moolenaar81366db2005-07-24 21:16:51 +0000333
334 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100335prt_set_fg(long_u fg)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000336{
337 if (fg != curr_fg)
338 {
339 curr_fg = fg;
340 mch_print_set_fg(fg);
341 }
342}
343
344 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100345prt_set_bg(long_u bg)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000346{
347 if (bg != curr_bg)
348 {
349 curr_bg = bg;
350 mch_print_set_bg(bg);
351 }
352}
353
354 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100355prt_set_font(int bold, int italic, int underline)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000356{
357 if (curr_bold != bold
358 || curr_italic != italic
359 || curr_underline != underline)
360 {
361 curr_underline = underline;
362 curr_italic = italic;
363 curr_bold = bold;
364 mch_print_set_font(bold, italic, underline);
365 }
366}
367
368/*
369 * Print the line number in the left margin.
370 */
371 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100372prt_line_number(
373 prt_settings_T *psettings,
374 int page_line,
375 linenr_T lnum)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000376{
377 int i;
378 char_u tbuf[20];
379
380 prt_set_fg(psettings->number.fg_color);
381 prt_set_bg(psettings->number.bg_color);
382 prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
383 mch_print_start_line(TRUE, page_line);
384
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100385 // Leave two spaces between the number and the text; depends on
386 // PRINT_NUMBER_WIDTH.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000387 sprintf((char *)tbuf, "%6ld", (long)lnum);
388 for (i = 0; i < 6; i++)
389 (void)mch_print_text_out(&tbuf[i], 1);
390
391#ifdef FEAT_SYN_HL
392 if (psettings->do_syntax)
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100393 // Set colors for next character.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000394 current_syn_id = -1;
395 else
396#endif
397 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100398 // Set colors and font back to normal.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000399 prt_set_fg(PRCOLOR_BLACK);
400 prt_set_bg(PRCOLOR_WHITE);
401 prt_set_font(FALSE, FALSE, FALSE);
402 }
403}
404
Bram Moolenaar81366db2005-07-24 21:16:51 +0000405/*
406 * Get the currently effective header height.
407 */
408 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100409prt_header_height(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000410{
411 if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
412 return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
413 return 2;
414}
415
416/*
417 * Return TRUE if using a line number for printing.
418 */
419 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100420prt_use_number(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000421{
422 return (printer_opts[OPT_PRINT_NUMBER].present
423 && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
424}
425
426/*
427 * Return the unit used in a margin item in 'printoptions'.
428 * Returns PRT_UNIT_NONE if not recognized.
429 */
430 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100431prt_get_unit(int idx)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000432{
433 int u = PRT_UNIT_NONE;
434 int i;
435 static char *(units[4]) = PRT_UNIT_NAMES;
436
437 if (printer_opts[idx].present)
438 for (i = 0; i < 4; ++i)
439 if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
440 {
441 u = i;
442 break;
443 }
444 return u;
445}
446
447/*
448 * Print the page header.
449 */
Bram Moolenaar81366db2005-07-24 21:16:51 +0000450 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100451prt_header(
452 prt_settings_T *psettings,
453 int pagenum,
454 linenr_T lnum UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000455{
456 int width = psettings->chars_per_line;
457 int page_line;
458 char_u *tbuf;
459 char_u *p;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000460 int l;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000461
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100462 // Also use the space for the line number.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000463 if (prt_use_number())
464 width += PRINT_NUMBER_WIDTH;
465
466 tbuf = alloc(width + IOSIZE);
467 if (tbuf == NULL)
468 return;
469
470#ifdef FEAT_STL_OPT
471 if (*p_header != NUL)
472 {
473 linenr_T tmp_lnum, tmp_topline, tmp_botline;
474
475 /*
476 * Need to (temporarily) set current line number and first/last line
477 * number on the 'window'. Since we don't know how long the page is,
478 * set the first and current line number to the top line, and guess
479 * that the page length is 64.
480 */
481 tmp_lnum = curwin->w_cursor.lnum;
482 tmp_topline = curwin->w_topline;
483 tmp_botline = curwin->w_botline;
484 curwin->w_cursor.lnum = lnum;
485 curwin->w_topline = lnum;
486 curwin->w_botline = lnum + 63;
487 printer_page_num = pagenum;
488
Luuk van Baal7b224fd2022-11-07 12:16:51 +0000489 build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE), p_header,
490 (char_u *)"printheader", 0, ' ', width, NULL, NULL);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000491
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100492 // Reset line numbers
Bram Moolenaar81366db2005-07-24 21:16:51 +0000493 curwin->w_cursor.lnum = tmp_lnum;
494 curwin->w_topline = tmp_topline;
495 curwin->w_botline = tmp_botline;
496 }
497 else
498#endif
499 sprintf((char *)tbuf, _("Page %d"), pagenum);
500
501 prt_set_fg(PRCOLOR_BLACK);
502 prt_set_bg(PRCOLOR_WHITE);
503 prt_set_font(TRUE, FALSE, FALSE);
504
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100505 // Use a negative line number to indicate printing in the top margin.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000506 page_line = 0 - prt_header_height();
507 mch_print_start_line(TRUE, page_line);
508 for (p = tbuf; *p != NUL; )
509 {
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100510 if (mch_print_text_out(p, (l = (*mb_ptr2len)(p))))
Bram Moolenaar81366db2005-07-24 21:16:51 +0000511 {
512 ++page_line;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100513 if (page_line >= 0) // out of room in header
Bram Moolenaar81366db2005-07-24 21:16:51 +0000514 break;
515 mch_print_start_line(TRUE, page_line);
516 }
Bram Moolenaar81366db2005-07-24 21:16:51 +0000517 p += l;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000518 }
519
520 vim_free(tbuf);
521
522#ifdef FEAT_SYN_HL
523 if (psettings->do_syntax)
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100524 // Set colors for next character.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000525 current_syn_id = -1;
526 else
527#endif
528 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100529 // Set colors and font back to normal.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000530 prt_set_fg(PRCOLOR_BLACK);
531 prt_set_bg(PRCOLOR_WHITE);
532 prt_set_font(FALSE, FALSE, FALSE);
533 }
534}
535
536/*
537 * Display a print status message.
538 */
539 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100540prt_message(char_u *s)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000541{
542 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
Bram Moolenaar8820b482017-03-16 17:23:31 +0100543 screen_puts(s, (int)Rows - 1, 0, HL_ATTR(HLF_R));
Bram Moolenaar81366db2005-07-24 21:16:51 +0000544 out_flush();
545}
546
547 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100548ex_hardcopy(exarg_T *eap)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000549{
550 linenr_T lnum;
551 int collated_copies, uncollated_copies;
552 prt_settings_T settings;
553 long_u bytes_to_print = 0;
554 int page_line;
555 int jobsplit;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000556
Bram Moolenaara80faa82020-04-12 19:37:17 +0200557 CLEAR_FIELD(settings);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000558 settings.has_color = TRUE;
559
560# ifdef FEAT_POSTSCRIPT
561 if (*eap->arg == '>')
562 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100563 char *errormsg = NULL;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000564
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100565 // Expand things like "%.ps".
Bram Moolenaar81366db2005-07-24 21:16:51 +0000566 if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
567 {
568 if (errormsg != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100569 emsg(errormsg);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000570 return;
571 }
572 settings.outfile = skipwhite(eap->arg + 1);
573 }
574 else if (*eap->arg != NUL)
575 settings.arguments = eap->arg;
576# endif
577
578 /*
579 * Initialise for printing. Ask the user for settings, unless forceit is
580 * set.
581 * The mch_print_init() code should set up margins if applicable. (It may
582 * not be a real printer - for example the engine might generate HTML or
583 * PS.)
584 */
585 if (mch_print_init(&settings,
586 curbuf->b_fname == NULL
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +0100587 ? buf_spname(curbuf)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000588 : curbuf->b_sfname == NULL
589 ? curbuf->b_fname
590 : curbuf->b_sfname,
591 eap->forceit) == FAIL)
592 return;
593
594#ifdef FEAT_SYN_HL
595# ifdef FEAT_GUI
596 if (gui.in_use)
597 settings.modec = 'g';
598 else
599# endif
600 if (t_colors > 1)
601 settings.modec = 'c';
602 else
603 settings.modec = 't';
604
Bram Moolenaar860cae12010-06-05 23:22:07 +0200605 if (!syntax_present(curwin))
Bram Moolenaar81366db2005-07-24 21:16:51 +0000606 settings.do_syntax = FALSE;
607 else if (printer_opts[OPT_PRINT_SYNTAX].present
608 && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
609 settings.do_syntax =
610 (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
611 else
612 settings.do_syntax = settings.has_color;
613#endif
614
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100615 // Set up printing attributes for line numbers
Bram Moolenaar81366db2005-07-24 21:16:51 +0000616 settings.number.fg_color = PRCOLOR_BLACK;
617 settings.number.bg_color = PRCOLOR_WHITE;
618 settings.number.bold = FALSE;
619 settings.number.italic = TRUE;
620 settings.number.underline = FALSE;
621#ifdef FEAT_SYN_HL
622 /*
623 * Syntax highlighting of line numbers.
624 */
625 if (prt_use_number() && settings.do_syntax)
626 {
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000627 int id;
628
Bram Moolenaar81366db2005-07-24 21:16:51 +0000629 id = syn_name2id((char_u *)"LineNr");
630 if (id > 0)
631 id = syn_get_final_id(id);
632
633 prt_get_attr(id, &settings.number, settings.modec);
634 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000635#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000636
637 /*
638 * Estimate the total lines to be printed
639 */
640 for (lnum = eap->line1; lnum <= eap->line2; lnum++)
641 bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
642 if (bytes_to_print == 0)
643 {
Bram Moolenaar32526b32019-01-19 17:43:09 +0100644 msg(_("No text to be printed"));
Bram Moolenaar81366db2005-07-24 21:16:51 +0000645 goto print_fail_no_begin;
646 }
647
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100648 // Set colors and font to normal.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000649 curr_bg = (long_u)0xffffffffL;
650 curr_fg = (long_u)0xffffffffL;
651 curr_italic = MAYBE;
652 curr_bold = MAYBE;
653 curr_underline = MAYBE;
654
655 prt_set_fg(PRCOLOR_BLACK);
656 prt_set_bg(PRCOLOR_WHITE);
657 prt_set_font(FALSE, FALSE, FALSE);
658#ifdef FEAT_SYN_HL
659 current_syn_id = -1;
660#endif
661
662 jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
663 && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
664
665 if (!mch_print_begin(&settings))
666 goto print_fail_no_begin;
667
668 /*
669 * Loop over collated copies: 1 2 3, 1 2 3, ...
670 */
671 page_count = 0;
672 for (collated_copies = 0;
673 collated_copies < settings.n_collated_copies;
674 collated_copies++)
675 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100676 prt_pos_T prtpos; // current print position
677 prt_pos_T page_prtpos; // print position at page start
Bram Moolenaar81366db2005-07-24 21:16:51 +0000678 int side;
679
Bram Moolenaara80faa82020-04-12 19:37:17 +0200680 CLEAR_FIELD(page_prtpos);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000681 page_prtpos.file_line = eap->line1;
682 prtpos = page_prtpos;
683
684 if (jobsplit && collated_copies > 0)
685 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100686 // Splitting jobs: Stop a previous job and start a new one.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000687 mch_print_end(&settings);
688 if (!mch_print_begin(&settings))
689 goto print_fail_no_begin;
690 }
691
692 /*
693 * Loop over all pages in the print job: 1 2 3 ...
694 */
695 for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
696 {
697 /*
698 * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
699 * For duplex: 12 12 12 34 34 34, ...
700 */
701 for (uncollated_copies = 0;
702 uncollated_copies < settings.n_uncollated_copies;
703 uncollated_copies++)
704 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100705 // Set the print position to the start of this page.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000706 prtpos = page_prtpos;
707
708 /*
709 * Do front and rear side of a page.
710 */
711 for (side = 0; side <= settings.duplex; ++side)
712 {
713 /*
714 * Print one page.
715 */
716
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100717 // Check for interrupt character every page.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000718 ui_breakcheck();
719 if (got_int || settings.user_abort)
720 goto print_fail;
721
722 sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
723 page_count + 1 + side,
724 prtpos.bytes_printed > 1000000
725 ? (int)(prtpos.bytes_printed /
726 (bytes_to_print / 100))
727 : (int)((prtpos.bytes_printed * 100)
728 / bytes_to_print));
729 if (!mch_print_begin_page(IObuff))
730 goto print_fail;
731
732 if (settings.n_collated_copies > 1)
733 sprintf((char *)IObuff + STRLEN(IObuff),
734 _(" Copy %d of %d"),
735 collated_copies + 1,
736 settings.n_collated_copies);
737 prt_message(IObuff);
738
739 /*
740 * Output header if required
741 */
742 if (prt_header_height() > 0)
743 prt_header(&settings, page_count + 1 + side,
744 prtpos.file_line);
745
746 for (page_line = 0; page_line < settings.lines_per_page;
747 ++page_line)
748 {
749 prtpos.column = hardcopy_line(&settings,
750 page_line, &prtpos);
751 if (prtpos.column == 0)
752 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100753 // finished a file line
Bram Moolenaar81366db2005-07-24 21:16:51 +0000754 prtpos.bytes_printed +=
755 STRLEN(skipwhite(ml_get(prtpos.file_line)));
756 if (++prtpos.file_line > eap->line2)
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100757 break; // reached the end
Bram Moolenaar81366db2005-07-24 21:16:51 +0000758 }
759 else if (prtpos.ff)
760 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100761 // Line had a formfeed in it - start new page but
762 // stay on the current line
Bram Moolenaar81366db2005-07-24 21:16:51 +0000763 break;
764 }
765 }
766
767 if (!mch_print_end_page())
768 goto print_fail;
769 if (prtpos.file_line > eap->line2)
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100770 break; // reached the end
Bram Moolenaar81366db2005-07-24 21:16:51 +0000771 }
772
773 /*
774 * Extra blank page for duplexing with odd number of pages and
775 * more copies to come.
776 */
777 if (prtpos.file_line > eap->line2 && settings.duplex
778 && side == 0
779 && uncollated_copies + 1 < settings.n_uncollated_copies)
780 {
781 if (!mch_print_blank_page())
782 goto print_fail;
783 }
784 }
785 if (settings.duplex && prtpos.file_line <= eap->line2)
786 ++page_count;
787
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100788 // Remember the position where the next page starts.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000789 page_prtpos = prtpos;
790 }
791
792 vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"),
793 settings.jobname);
794 prt_message(IObuff);
795 }
796
797print_fail:
798 if (got_int || settings.user_abort)
799 {
800 sprintf((char *)IObuff, "%s", _("Printing aborted"));
801 prt_message(IObuff);
802 }
803 mch_print_end(&settings);
804
805print_fail_no_begin:
806 mch_print_cleanup();
807}
808
809/*
810 * Print one page line.
811 * Return the next column to print, or zero if the line is finished.
812 */
813 static colnr_T
Bram Moolenaar68c2f632016-01-30 17:24:07 +0100814hardcopy_line(
815 prt_settings_T *psettings,
816 int page_line,
817 prt_pos_T *ppos)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000818{
819 colnr_T col;
820 char_u *line;
821 int need_break = FALSE;
822 int outputlen;
823 int tab_spaces;
824 long_u print_pos;
825#ifdef FEAT_SYN_HL
826 prt_text_attr_T attr;
827 int id;
828#endif
829
830 if (ppos->column == 0 || ppos->ff)
831 {
832 print_pos = 0;
833 tab_spaces = 0;
834 if (!ppos->ff && prt_use_number())
835 prt_line_number(psettings, page_line, ppos->file_line);
836 ppos->ff = FALSE;
837 }
838 else
839 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100840 // left over from wrap halfway a tab
Bram Moolenaar81366db2005-07-24 21:16:51 +0000841 print_pos = ppos->print_pos;
842 tab_spaces = ppos->lead_spaces;
843 }
844
845 mch_print_start_line(0, page_line);
846 line = ml_get(ppos->file_line);
847
848 /*
849 * Loop over the columns until the end of the file line or right margin.
850 */
851 for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
852 {
853 outputlen = 1;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000854 if (has_mbyte && (outputlen = (*mb_ptr2len)(line + col)) < 1)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000855 outputlen = 1;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000856#ifdef FEAT_SYN_HL
857 /*
858 * syntax highlighting stuff.
859 */
860 if (psettings->do_syntax)
861 {
Bram Moolenaar56cefaf2008-01-12 15:47:10 +0000862 id = syn_get_id(curwin, ppos->file_line, col, 1, NULL, FALSE);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000863 if (id > 0)
864 id = syn_get_final_id(id);
865 else
866 id = 0;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100867 // Get the line again, a multi-line regexp may invalidate it.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000868 line = ml_get(ppos->file_line);
869
870 if (id != current_syn_id)
871 {
872 current_syn_id = id;
873 prt_get_attr(id, &attr, psettings->modec);
874 prt_set_font(attr.bold, attr.italic, attr.underline);
875 prt_set_fg(attr.fg_color);
876 prt_set_bg(attr.bg_color);
877 }
878 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000879#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000880
881 /*
882 * Appropriately expand any tabs to spaces.
883 */
884 if (line[col] == TAB || tab_spaces != 0)
885 {
886 if (tab_spaces == 0)
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200887#ifdef FEAT_VARTABS
888 tab_spaces = tabstop_padding(print_pos, curbuf->b_p_ts,
889 curbuf->b_p_vts_array);
890#else
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000891 tab_spaces = (int)(curbuf->b_p_ts - (print_pos % curbuf->b_p_ts));
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200892#endif
Bram Moolenaar81366db2005-07-24 21:16:51 +0000893
894 while (tab_spaces > 0)
895 {
896 need_break = mch_print_text_out((char_u *)" ", 1);
897 print_pos++;
898 tab_spaces--;
899 if (need_break)
900 break;
901 }
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100902 // Keep the TAB if we didn't finish it.
Bram Moolenaar81366db2005-07-24 21:16:51 +0000903 if (need_break && tab_spaces > 0)
904 break;
905 }
906 else if (line[col] == FF
907 && printer_opts[OPT_PRINT_FORMFEED].present
908 && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
909 == 'y')
910 {
911 ppos->ff = TRUE;
912 need_break = 1;
913 }
914 else
915 {
916 need_break = mch_print_text_out(line + col, outputlen);
Bram Moolenaar81366db2005-07-24 21:16:51 +0000917 if (has_mbyte)
918 print_pos += (*mb_ptr2cells)(line + col);
919 else
Bram Moolenaar81366db2005-07-24 21:16:51 +0000920 print_pos++;
921 }
922 }
923
924 ppos->lead_spaces = tab_spaces;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000925 ppos->print_pos = (int)print_pos;
Bram Moolenaar81366db2005-07-24 21:16:51 +0000926
927 /*
928 * Start next line of file if we clip lines, or have reached end of the
929 * line, unless we are doing a formfeed.
930 */
931 if (!ppos->ff
932 && (line[col] == NUL
933 || (printer_opts[OPT_PRINT_WRAP].present
934 && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
935 == 'n')))
936 return 0;
937 return col;
938}
939
940# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
941
942/*
943 * PS printer stuff.
944 *
945 * Sources of information to help maintain the PS printing code:
946 *
947 * 1. PostScript Language Reference, 3rd Edition,
948 * Addison-Wesley, 1999, ISBN 0-201-37922-8
949 * 2. PostScript Language Program Design,
950 * Addison-Wesley, 1988, ISBN 0-201-14396-8
951 * 3. PostScript Tutorial and Cookbook,
952 * Addison Wesley, 1985, ISBN 0-201-10179-3
953 * 4. PostScript Language Document Structuring Conventions Specification,
954 * version 3.0,
955 * Adobe Technote 5001, 25th September 1992
956 * 5. PostScript Printer Description File Format Specification, Version 4.3,
957 * Adobe technote 5003, 9th February 1996
958 * 6. Adobe Font Metrics File Format Specification, Version 4.1,
959 * Adobe Technote 5007, 7th October 1998
960 * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
961 * Adobe Technote 5014, 8th October 1996
962 * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
963 * Adoboe Technote 5094, 8th September, 2001
964 * 9. CJKV Information Processing, 2nd Edition,
965 * O'Reilly, 2002, ISBN 1-56592-224-7
966 *
967 * Some of these documents can be found in PDF form on Adobe's web site -
968 * http://www.adobe.com
969 */
970
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100971#define PRT_PS_DEFAULT_DPI (72) // Default user space resolution
Bram Moolenaar81366db2005-07-24 21:16:51 +0000972#define PRT_PS_DEFAULT_FONTSIZE (10)
973#define PRT_PS_DEFAULT_BUFFER_SIZE (80)
974
975struct prt_mediasize_S
976{
977 char *name;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100978 float width; // width and height in points for portrait
Bram Moolenaar81366db2005-07-24 21:16:51 +0000979 float height;
980};
981
K.Takataeeec2542021-06-02 13:28:16 +0200982#define PRT_MEDIASIZE_LEN ARRAY_LENGTH(prt_mediasize)
Bram Moolenaar81366db2005-07-24 21:16:51 +0000983
984static struct prt_mediasize_S prt_mediasize[] =
985{
986 {"A4", 595.0, 842.0},
987 {"letter", 612.0, 792.0},
988 {"10x14", 720.0, 1008.0},
989 {"A3", 842.0, 1191.0},
990 {"A5", 420.0, 595.0},
991 {"B4", 729.0, 1032.0},
992 {"B5", 516.0, 729.0},
993 {"executive", 522.0, 756.0},
994 {"folio", 595.0, 935.0},
Bram Moolenaar2ab2e862019-12-04 21:24:53 +0100995 {"ledger", 1224.0, 792.0}, // Yes, it is wider than taller!
Bram Moolenaar81366db2005-07-24 21:16:51 +0000996 {"legal", 612.0, 1008.0},
997 {"quarto", 610.0, 780.0},
998 {"statement", 396.0, 612.0},
999 {"tabloid", 792.0, 1224.0}
1000};
1001
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001002// PS font names, must be in Roman, Bold, Italic, Bold-Italic order
Bram Moolenaar81366db2005-07-24 21:16:51 +00001003struct prt_ps_font_S
1004{
1005 int wx;
1006 int uline_offset;
1007 int uline_width;
1008 int bbox_min_y;
1009 int bbox_max_y;
1010 char *(ps_fontname[4]);
1011};
1012
1013#define PRT_PS_FONT_ROMAN (0)
1014#define PRT_PS_FONT_BOLD (1)
1015#define PRT_PS_FONT_OBLIQUE (2)
1016#define PRT_PS_FONT_BOLDOBLIQUE (3)
1017
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001018// Standard font metrics for Courier family
Bram Moolenaar81366db2005-07-24 21:16:51 +00001019static struct prt_ps_font_S prt_ps_courier_font =
1020{
1021 600,
1022 -100, 50,
1023 -250, 805,
1024 {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
1025};
1026
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001027// Generic font metrics for multi-byte fonts
Bram Moolenaar81366db2005-07-24 21:16:51 +00001028static struct prt_ps_font_S prt_ps_mb_font =
1029{
1030 1000,
1031 -100, 50,
1032 -250, 805,
1033 {NULL, NULL, NULL, NULL}
1034};
Bram Moolenaar81366db2005-07-24 21:16:51 +00001035
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001036// Pointer to current font set being used
Bram Moolenaar81366db2005-07-24 21:16:51 +00001037static struct prt_ps_font_S* prt_ps_font;
1038
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001039// Structures to map user named encoding and mapping to PS equivalents for
1040// building CID font name
Bram Moolenaar81366db2005-07-24 21:16:51 +00001041struct prt_ps_encoding_S
1042{
1043 char *encoding;
1044 char *cmap_encoding;
1045 int needs_charset;
1046};
1047
1048struct prt_ps_charset_S
1049{
1050 char *charset;
1051 char *cmap_charset;
1052 int has_charset;
1053};
1054
Bram Moolenaar81366db2005-07-24 21:16:51 +00001055
1056#define CS_JIS_C_1978 (0x01)
1057#define CS_JIS_X_1983 (0x02)
1058#define CS_JIS_X_1990 (0x04)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001059#define CS_NEC (0x08)
1060#define CS_MSWINDOWS (0x10)
1061#define CS_CP932 (0x20)
1062#define CS_KANJITALK6 (0x40)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001063#define CS_KANJITALK7 (0x80)
1064
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001065// Japanese encodings and charsets
Bram Moolenaar81366db2005-07-24 21:16:51 +00001066static struct prt_ps_encoding_S j_encodings[] =
1067{
1068 {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001069 CS_NEC)},
1070 {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
1071 {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
1072 CS_KANJITALK6|CS_KANJITALK7)},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001073 {"cp932", "RKSJ", CS_JIS_X_1983},
1074 {"ucs-2", "UCS2", CS_JIS_X_1990},
1075 {"utf-8", "UTF8" , CS_JIS_X_1990}
1076};
1077static struct prt_ps_charset_S j_charsets[] =
1078{
1079 {"JIS_C_1978", "78", CS_JIS_C_1978},
1080 {"JIS_X_1983", NULL, CS_JIS_X_1983},
1081 {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001082 {"NEC", "Ext", CS_NEC},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001083 {"MSWINDOWS", "90ms", CS_MSWINDOWS},
1084 {"CP932", "90ms", CS_JIS_X_1983},
1085 {"KANJITALK6", "83pv", CS_KANJITALK6},
1086 {"KANJITALK7", "90pv", CS_KANJITALK7}
1087};
1088
1089#define CS_GB_2312_80 (0x01)
1090#define CS_GBT_12345_90 (0x02)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001091#define CS_GBK2K (0x04)
1092#define CS_SC_MAC (0x08)
1093#define CS_GBT_90_MAC (0x10)
1094#define CS_GBK (0x20)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001095#define CS_SC_ISO10646 (0x40)
1096
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001097// Simplified Chinese encodings and charsets
Bram Moolenaar81366db2005-07-24 21:16:51 +00001098static struct prt_ps_encoding_S sc_encodings[] =
1099{
1100 {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
1101 {"gb18030", NULL, CS_GBK2K},
1102 {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001103 CS_GBT_90_MAC)},
1104 {"gbk", "EUC", CS_GBK},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001105 {"ucs-2", "UCS2", CS_SC_ISO10646},
1106 {"utf-8", "UTF8", CS_SC_ISO10646}
1107};
1108static struct prt_ps_charset_S sc_charsets[] =
1109{
1110 {"GB_2312-80", "GB", CS_GB_2312_80},
1111 {"GBT_12345-90","GBT", CS_GBT_12345_90},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001112 {"MAC", "GBpc", CS_SC_MAC},
1113 {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
1114 {"GBK", "GBK", CS_GBK},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001115 {"GB18030", "GBK2K", CS_GBK2K},
1116 {"ISO10646", "UniGB", CS_SC_ISO10646}
1117};
1118
1119#define CS_CNS_PLANE_1 (0x01)
1120#define CS_CNS_PLANE_2 (0x02)
1121#define CS_CNS_PLANE_1_2 (0x04)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001122#define CS_B5 (0x08)
1123#define CS_ETEN (0x10)
1124#define CS_HK_GCCS (0x20)
1125#define CS_HK_SCS (0x40)
1126#define CS_HK_SCS_ETEN (0x80)
1127#define CS_MTHKL (0x100)
1128#define CS_MTHKS (0x200)
1129#define CS_DLHKL (0x400)
1130#define CS_DLHKS (0x800)
1131#define CS_TC_ISO10646 (0x1000)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001132
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001133// Traditional Chinese encodings and charsets
Bram Moolenaar81366db2005-07-24 21:16:51 +00001134static struct prt_ps_encoding_S tc_encodings[] =
1135{
1136 {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
1137 {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001138 {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
1139 CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
1140 CS_DLHKS)},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001141 {"cp950", "B5", CS_B5},
1142 {"ucs-2", "UCS2", CS_TC_ISO10646},
1143 {"utf-8", "UTF8", CS_TC_ISO10646},
1144 {"utf-16", "UTF16", CS_TC_ISO10646},
1145 {"utf-32", "UTF32", CS_TC_ISO10646}
1146};
1147static struct prt_ps_charset_S tc_charsets[] =
1148{
1149 {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
1150 {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
1151 {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001152 {"BIG5", NULL, CS_B5},
1153 {"CP950", NULL, CS_B5},
1154 {"ETEN", "ETen", CS_ETEN},
1155 {"HK_GCCS", "HKgccs", CS_HK_GCCS},
1156 {"SCS", "HKscs", CS_HK_SCS},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001157 {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
1158 {"MTHKL", "HKm471", CS_MTHKL},
1159 {"MTHKS", "HKm314", CS_MTHKS},
1160 {"DLHKL", "HKdla", CS_DLHKL},
1161 {"DLHKS", "HKdlb", CS_DLHKS},
1162 {"ISO10646", "UniCNS", CS_TC_ISO10646}
1163};
1164
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001165#define CS_KR_X_1992 (0x01)
1166#define CS_KR_MAC (0x02)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001167#define CS_KR_X_1992_MS (0x04)
1168#define CS_KR_ISO10646 (0x08)
1169
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001170// Korean encodings and charsets
Bram Moolenaar81366db2005-07-24 21:16:51 +00001171static struct prt_ps_encoding_S k_encodings[] =
1172{
1173 {"iso-2022-kr", NULL, CS_KR_X_1992},
1174 {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
1175 {"johab", "Johab", CS_KR_X_1992},
1176 {"cp1361", "Johab", CS_KR_X_1992},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001177 {"uhc", "UHC", CS_KR_X_1992_MS},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001178 {"cp949", "UHC", CS_KR_X_1992_MS},
1179 {"ucs-2", "UCS2", CS_KR_ISO10646},
1180 {"utf-8", "UTF8", CS_KR_ISO10646}
1181};
1182static struct prt_ps_charset_S k_charsets[] =
1183{
1184 {"KS_X_1992", "KSC", CS_KR_X_1992},
1185 {"CP1361", "KSC", CS_KR_X_1992},
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001186 {"MAC", "KSCpc", CS_KR_MAC},
Bram Moolenaar81366db2005-07-24 21:16:51 +00001187 {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
1188 {"CP949", "KSCms", CS_KR_X_1992_MS},
1189 {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
1190 {"ISO10646", "UniKS", CS_KR_ISO10646}
1191};
1192
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001193// Collections of encodings and charsets for multi-byte printing
Bram Moolenaar81366db2005-07-24 21:16:51 +00001194struct prt_ps_mbfont_S
1195{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001196 int num_encodings;
1197 struct prt_ps_encoding_S *encodings;
1198 int num_charsets;
1199 struct prt_ps_charset_S *charsets;
1200 char *ascii_enc;
1201 char *defcs;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001202};
1203
1204static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
1205{
1206 {
K.Takataeeec2542021-06-02 13:28:16 +02001207 ARRAY_LENGTH(j_encodings),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001208 j_encodings,
K.Takataeeec2542021-06-02 13:28:16 +02001209 ARRAY_LENGTH(j_charsets),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001210 j_charsets,
1211 "jis_roman",
1212 "JIS_X_1983"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001213 },
1214 {
K.Takataeeec2542021-06-02 13:28:16 +02001215 ARRAY_LENGTH(sc_encodings),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001216 sc_encodings,
K.Takataeeec2542021-06-02 13:28:16 +02001217 ARRAY_LENGTH(sc_charsets),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001218 sc_charsets,
1219 "gb_roman",
1220 "GB_2312-80"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001221 },
1222 {
K.Takataeeec2542021-06-02 13:28:16 +02001223 ARRAY_LENGTH(tc_encodings),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001224 tc_encodings,
K.Takataeeec2542021-06-02 13:28:16 +02001225 ARRAY_LENGTH(tc_charsets),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001226 tc_charsets,
1227 "cns_roman",
1228 "BIG5"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001229 },
1230 {
K.Takataeeec2542021-06-02 13:28:16 +02001231 ARRAY_LENGTH(k_encodings),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001232 k_encodings,
K.Takataeeec2542021-06-02 13:28:16 +02001233 ARRAY_LENGTH(k_charsets),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001234 k_charsets,
1235 "ks_roman",
1236 "KS_X_1992"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001237 }
1238};
Bram Moolenaar81366db2005-07-24 21:16:51 +00001239
1240struct prt_ps_resource_S
1241{
1242 char_u name[64];
1243 char_u filename[MAXPATHL + 1];
1244 int type;
1245 char_u title[256];
1246 char_u version[256];
1247};
1248
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001249// Types of PS resource file currently used
Bram Moolenaar81366db2005-07-24 21:16:51 +00001250#define PRT_RESOURCE_TYPE_PROCSET (0)
1251#define PRT_RESOURCE_TYPE_ENCODING (1)
1252#define PRT_RESOURCE_TYPE_CMAP (2)
1253
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001254// The PS prolog file version number has to match - if the prolog file is
1255// updated, increment the number in the file and here. Version checking was
1256// added as of VIM 6.2.
1257// The CID prolog file version number behaves as per PS prolog.
1258// Table of VIM and prolog versions:
1259//
1260// VIM Prolog CIDProlog
1261// 6.2 1.3
1262// 7.0 1.4 1.0
Bram Moolenaar81366db2005-07-24 21:16:51 +00001263#define PRT_PROLOG_VERSION ((char_u *)"1.4")
1264#define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
1265
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001266// String versions of PS resource types - indexed by constants above so don't
1267// re-order!
Bram Moolenaar81366db2005-07-24 21:16:51 +00001268static char *prt_resource_types[] =
1269{
1270 "procset",
1271 "encoding",
1272 "cmap"
1273};
1274
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001275// Strings to look for in a PS resource file
Bram Moolenaar81366db2005-07-24 21:16:51 +00001276#define PRT_RESOURCE_HEADER "%!PS-Adobe-"
1277#define PRT_RESOURCE_RESOURCE "Resource-"
1278#define PRT_RESOURCE_PROCSET "ProcSet"
1279#define PRT_RESOURCE_ENCODING "Encoding"
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001280#define PRT_RESOURCE_CMAP "CMap"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001281
1282
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001283// Data for table based DSC comment recognition, easy to extend if VIM needs to
1284// read more comments.
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001285#define PRT_DSC_MISC_TYPE (-1)
1286#define PRT_DSC_TITLE_TYPE (1)
1287#define PRT_DSC_VERSION_TYPE (2)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001288#define PRT_DSC_ENDCOMMENTS_TYPE (3)
1289
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001290#define PRT_DSC_TITLE "%%Title:"
1291#define PRT_DSC_VERSION "%%Version:"
1292#define PRT_DSC_ENDCOMMENTS "%%EndComments:"
Bram Moolenaar81366db2005-07-24 21:16:51 +00001293
1294struct prt_dsc_comment_S
1295{
1296 char *string;
1297 int len;
1298 int type;
1299};
1300
1301struct prt_dsc_line_S
1302{
1303 int type;
1304 char_u *string;
1305 int len;
1306};
1307
1308
1309#define SIZEOF_CSTR(s) (sizeof(s) - 1)
1310static struct prt_dsc_comment_S prt_dsc_table[] =
1311{
1312 {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE},
1313 {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
1314 PRT_DSC_VERSION_TYPE},
1315 {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
1316 PRT_DSC_ENDCOMMENTS_TYPE}
1317};
1318
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01001319static void prt_write_file_len(char_u *buffer, int bytes);
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +01001320static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001321
1322/*
1323 * Variables for the output PostScript file.
1324 */
1325static FILE *prt_ps_fd;
1326static int prt_file_error;
1327static char_u *prt_ps_file_name = NULL;
1328
1329/*
1330 * Various offsets and dimensions in default PostScript user space (points).
1331 * Used for text positioning calculations
1332 */
1333static float prt_page_width;
1334static float prt_page_height;
1335static float prt_left_margin;
1336static float prt_right_margin;
1337static float prt_top_margin;
1338static float prt_bottom_margin;
1339static float prt_line_height;
1340static float prt_first_line_height;
1341static float prt_char_width;
1342static float prt_number_width;
1343static float prt_bgcol_offset;
1344static float prt_pos_x_moveto = 0.0;
1345static float prt_pos_y_moveto = 0.0;
1346
1347/*
1348 * Various control variables used to decide when and how to change the
1349 * PostScript graphics state.
1350 */
1351static int prt_need_moveto;
1352static int prt_do_moveto;
1353static int prt_need_font;
1354static int prt_font;
1355static int prt_need_underline;
1356static int prt_underline;
1357static int prt_do_underline;
1358static int prt_need_fgcol;
1359static int prt_fgcol;
1360static int prt_need_bgcol;
1361static int prt_do_bgcol;
1362static int prt_bgcol;
1363static int prt_new_bgcol;
1364static int prt_attribute_change;
1365static float prt_text_run;
1366static int prt_page_num;
1367static int prt_bufsiz;
1368
1369/*
1370 * Variables controlling physical printing.
1371 */
1372static int prt_media;
1373static int prt_portrait;
1374static int prt_num_copies;
1375static int prt_duplex;
1376static int prt_tumble;
1377static int prt_collate;
1378
1379/*
1380 * Buffers used when generating PostScript output
1381 */
1382static char_u prt_line_buffer[257];
1383static garray_T prt_ps_buffer;
1384
Bram Moolenaar81366db2005-07-24 21:16:51 +00001385static int prt_do_conv;
1386static vimconv_T prt_conv;
1387
1388static int prt_out_mbyte;
1389static int prt_custom_cmap;
1390static char prt_cmap[80];
1391static int prt_use_courier;
1392static int prt_in_ascii;
1393static int prt_half_width;
1394static char *prt_ascii_encoding;
1395static char_u prt_hexchar[] = "0123456789abcdef";
Bram Moolenaar81366db2005-07-24 21:16:51 +00001396
1397 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001398prt_write_file_raw_len(char_u *buffer, int bytes)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001399{
1400 if (!prt_file_error
1401 && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
1402 != (size_t)bytes)
1403 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00001404 emsg(_(e_error_writing_to_postscript_output_file));
Bram Moolenaar81366db2005-07-24 21:16:51 +00001405 prt_file_error = TRUE;
1406 }
1407}
1408
1409 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001410prt_write_file(char_u *buffer)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001411{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001412 prt_write_file_len(buffer, (int)STRLEN(buffer));
Bram Moolenaar81366db2005-07-24 21:16:51 +00001413}
1414
1415 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001416prt_write_file_len(char_u *buffer, int bytes)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001417{
Bram Moolenaar81366db2005-07-24 21:16:51 +00001418 prt_write_file_raw_len(buffer, bytes);
1419}
1420
1421/*
1422 * Write a string.
1423 */
1424 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001425prt_write_string(char *s)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001426{
1427 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
1428 prt_write_file(prt_line_buffer);
1429}
1430
1431/*
1432 * Write an int and a space.
1433 */
1434 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001435prt_write_int(int i)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001436{
1437 sprintf((char *)prt_line_buffer, "%d ", i);
1438 prt_write_file(prt_line_buffer);
1439}
1440
1441/*
1442 * Write a boolean and a space.
1443 */
1444 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001445prt_write_boolean(int b)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001446{
1447 sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
1448 prt_write_file(prt_line_buffer);
1449}
1450
1451/*
1452 * Write PostScript to re-encode and define the font.
1453 */
1454 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001455prt_def_font(
1456 char *new_name,
1457 char *encoding,
1458 int height,
1459 char *font)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001460{
1461 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1462 "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
1463 prt_write_file(prt_line_buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001464 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001465 sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
Bram Moolenaar81366db2005-07-24 21:16:51 +00001466 new_name, height, 500./prt_ps_courier_font.wx, new_name);
1467 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00001468 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1469 "/%s %d /_%s ffs\n", new_name, height, new_name);
1470 prt_write_file(prt_line_buffer);
1471}
1472
Bram Moolenaar81366db2005-07-24 21:16:51 +00001473/*
1474 * Write a line to define the CID font.
1475 */
1476 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001477prt_def_cidfont(char *new_name, int height, char *cidfont)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001478{
1479 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1480 "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
1481 prt_write_file(prt_line_buffer);
1482 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1483 "/%s %d /_%s ffs\n", new_name, height, new_name);
1484 prt_write_file(prt_line_buffer);
1485}
1486
1487/*
1488 * Write a line to define a duplicate of a CID font
1489 */
1490 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001491prt_dup_cidfont(char *original_name, char *new_name)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001492{
1493 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1494 "/%s %s d\n", new_name, original_name);
1495 prt_write_file(prt_line_buffer);
1496}
Bram Moolenaar81366db2005-07-24 21:16:51 +00001497
1498/*
1499 * Convert a real value into an integer and fractional part as integers, with
1500 * the fractional part being in the range [0,10^precision). The fractional part
1501 * is also rounded based on the precision + 1'th fractional digit.
1502 */
1503 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001504prt_real_bits(
1505 double real,
1506 int precision,
1507 int *pinteger,
1508 int *pfraction)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001509{
1510 int i;
1511 int integer;
1512 float fraction;
1513
1514 integer = (int)real;
1515 fraction = (float)(real - integer);
1516 if (real < (double)integer)
1517 fraction = -fraction;
1518 for (i = 0; i < precision; i++)
1519 fraction *= 10.0;
1520
1521 *pinteger = integer;
1522 *pfraction = (int)(fraction + 0.5);
1523}
1524
1525/*
1526 * Write a real and a space. Save bytes if real value has no fractional part!
1527 * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
1528 * what decimal point character to use, but PS always requires a '.'.
1529 */
1530 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001531prt_write_real(double val, int prec)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001532{
1533 int integer;
1534 int fraction;
1535
1536 prt_real_bits(val, prec, &integer, &fraction);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001537 // Emit integer part
Bram Moolenaar81366db2005-07-24 21:16:51 +00001538 sprintf((char *)prt_line_buffer, "%d", integer);
1539 prt_write_file(prt_line_buffer);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001540 // Only emit fraction if necessary
Bram Moolenaar81366db2005-07-24 21:16:51 +00001541 if (fraction != 0)
1542 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001543 // Remove any trailing zeros
Bram Moolenaar81366db2005-07-24 21:16:51 +00001544 while ((fraction % 10) == 0)
1545 {
1546 prec--;
1547 fraction /= 10;
1548 }
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001549 // Emit fraction left padded with zeros
Bram Moolenaar81366db2005-07-24 21:16:51 +00001550 sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
1551 prt_write_file(prt_line_buffer);
1552 }
1553 sprintf((char *)prt_line_buffer, " ");
1554 prt_write_file(prt_line_buffer);
1555}
1556
1557/*
1558 * Write a line to define a numeric variable.
1559 */
1560 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001561prt_def_var(char *name, double value, int prec)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001562{
1563 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1564 "/%s ", name);
1565 prt_write_file(prt_line_buffer);
1566 prt_write_real(value, prec);
1567 sprintf((char *)prt_line_buffer, "d\n");
1568 prt_write_file(prt_line_buffer);
1569}
1570
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001571// Convert size from font space to user space at current font scale
Bram Moolenaar81366db2005-07-24 21:16:51 +00001572#define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0))
1573
1574 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001575prt_flush_buffer(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001576{
1577 if (prt_ps_buffer.ga_len > 0)
1578 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001579 // Any background color must be drawn first
Bram Moolenaar81366db2005-07-24 21:16:51 +00001580 if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
1581 {
1582 int r, g, b;
1583
1584 if (prt_do_moveto)
1585 {
1586 prt_write_real(prt_pos_x_moveto, 2);
1587 prt_write_real(prt_pos_y_moveto, 2);
1588 prt_write_string("m\n");
1589 prt_do_moveto = FALSE;
1590 }
1591
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001592 // Size of rect of background color on which text is printed
Bram Moolenaar81366db2005-07-24 21:16:51 +00001593 prt_write_real(prt_text_run, 2);
1594 prt_write_real(prt_line_height, 2);
1595
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001596 // Lastly add the color of the background
Bram Moolenaar81366db2005-07-24 21:16:51 +00001597 r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
1598 g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
1599 b = prt_new_bgcol & 0xff;
1600 prt_write_real(r / 255.0, 3);
1601 prt_write_real(g / 255.0, 3);
1602 prt_write_real(b / 255.0, 3);
1603 prt_write_string("bg\n");
1604 }
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001605 // Draw underlines before the text as it makes it slightly easier to
1606 // find the starting point.
Bram Moolenaar81366db2005-07-24 21:16:51 +00001607 if (prt_do_underline)
1608 {
1609 if (prt_do_moveto)
1610 {
1611 prt_write_real(prt_pos_x_moveto, 2);
1612 prt_write_real(prt_pos_y_moveto, 2);
1613 prt_write_string("m\n");
1614 prt_do_moveto = FALSE;
1615 }
1616
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001617 // Underline length of text run
Bram Moolenaar81366db2005-07-24 21:16:51 +00001618 prt_write_real(prt_text_run, 2);
1619 prt_write_string("ul\n");
1620 }
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001621 // Draw the text
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001622 if (prt_out_mbyte)
1623 prt_write_string("<");
1624 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001625 prt_write_string("(");
Bram Moolenaar81366db2005-07-24 21:16:51 +00001626 prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001627 if (prt_out_mbyte)
1628 prt_write_string(">");
1629 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001630 prt_write_string(")");
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001631 // Add a moveto if need be and use the appropriate show procedure
Bram Moolenaar81366db2005-07-24 21:16:51 +00001632 if (prt_do_moveto)
1633 {
1634 prt_write_real(prt_pos_x_moveto, 2);
1635 prt_write_real(prt_pos_y_moveto, 2);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001636 // moveto and a show
Bram Moolenaar81366db2005-07-24 21:16:51 +00001637 prt_write_string("ms\n");
1638 prt_do_moveto = FALSE;
1639 }
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001640 else // Simple show
Bram Moolenaar81366db2005-07-24 21:16:51 +00001641 prt_write_string("s\n");
1642
1643 ga_clear(&prt_ps_buffer);
Bram Moolenaar04935fb2022-01-08 16:19:22 +00001644 ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001645 }
1646}
1647
1648
1649 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001650prt_resource_name(char_u *filename, void *cookie)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001651{
1652 char_u *resource_filename = cookie;
1653
1654 if (STRLEN(filename) >= MAXPATHL)
1655 *resource_filename = NUL;
1656 else
1657 STRCPY(resource_filename, filename);
1658}
1659
1660 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001661prt_find_resource(char *name, struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001662{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001663 char_u *buffer;
1664 int retval;
1665
1666 buffer = alloc(MAXPATHL + 1);
1667 if (buffer == NULL)
1668 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001669
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02001670 vim_strncpy(resource->name, (char_u *)name, 63);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001671 // Look for named resource file in runtimepath
Bram Moolenaar81366db2005-07-24 21:16:51 +00001672 STRCPY(buffer, "print");
1673 add_pathsep(buffer);
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02001674 vim_strcat(buffer, (char_u *)name, MAXPATHL);
1675 vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001676 resource->filename[0] = NUL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01001677 retval = (do_in_runtimepath(buffer, 0, prt_resource_name,
Bram Moolenaar81366db2005-07-24 21:16:51 +00001678 resource->filename)
1679 && resource->filename[0] != NUL);
Bram Moolenaard9462e32011-04-11 21:35:11 +02001680 vim_free(buffer);
1681 return retval;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001682}
1683
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001684// PS CR and LF characters have platform independent values
Bram Moolenaar81366db2005-07-24 21:16:51 +00001685#define PSLF (0x0a)
1686#define PSCR (0x0d)
1687
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001688// Static buffer to read initial comments in a resource file, some can have a
1689// couple of KB of comments!
Bram Moolenaar81366db2005-07-24 21:16:51 +00001690#define PRT_FILE_BUFFER_LEN (2048)
1691struct prt_resfile_buffer_S
1692{
1693 char_u buffer[PRT_FILE_BUFFER_LEN];
1694 int len;
1695 int line_start;
1696 int line_end;
1697};
1698
1699static struct prt_resfile_buffer_S prt_resfile;
1700
1701 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001702prt_resfile_next_line(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001703{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001704 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001705
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001706 // Move to start of next line and then find end of line
Bram Moolenaar89d40322006-08-29 15:30:07 +00001707 idx = prt_resfile.line_end + 1;
1708 while (idx < prt_resfile.len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001709 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001710 if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001711 break;
Bram Moolenaar89d40322006-08-29 15:30:07 +00001712 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001713 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001714 prt_resfile.line_start = idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001715
Bram Moolenaar89d40322006-08-29 15:30:07 +00001716 while (idx < prt_resfile.len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001717 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001718 if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001719 break;
Bram Moolenaar89d40322006-08-29 15:30:07 +00001720 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001721 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00001722 prt_resfile.line_end = idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001723
Bram Moolenaar89d40322006-08-29 15:30:07 +00001724 return (idx < prt_resfile.len);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001725}
1726
1727 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001728prt_resfile_strncmp(int offset, char *string, int len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001729{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001730 // Force not equal if string is longer than remainder of line
Bram Moolenaar81366db2005-07-24 21:16:51 +00001731 if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001732 return 1;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001733
1734 return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001735 string, len);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001736}
1737
1738 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001739prt_resfile_skip_nonws(int offset)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001740{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001741 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001742
Bram Moolenaar89d40322006-08-29 15:30:07 +00001743 idx = prt_resfile.line_start + offset;
1744 while (idx < prt_resfile.line_end)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001745 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001746 if (isspace(prt_resfile.buffer[idx]))
1747 return idx - prt_resfile.line_start;
1748 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001749 }
1750 return -1;
1751}
1752
1753 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001754prt_resfile_skip_ws(int offset)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001755{
Bram Moolenaar89d40322006-08-29 15:30:07 +00001756 int idx;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001757
Bram Moolenaar89d40322006-08-29 15:30:07 +00001758 idx = prt_resfile.line_start + offset;
1759 while (idx < prt_resfile.line_end)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001760 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00001761 if (!isspace(prt_resfile.buffer[idx]))
1762 return idx - prt_resfile.line_start;
1763 idx++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001764 }
1765 return -1;
1766}
1767
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001768// prt_next_dsc() - returns detail on next DSC comment line found. Returns true
1769// if a DSC comment is found, else false
Bram Moolenaar81366db2005-07-24 21:16:51 +00001770 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001771prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001772{
1773 int comment;
1774 int offset;
1775
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001776 // Move to start of next line
Bram Moolenaar81366db2005-07-24 21:16:51 +00001777 if (!prt_resfile_next_line())
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001778 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001779
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001780 // DSC comments always start %%
Bram Moolenaar81366db2005-07-24 21:16:51 +00001781 if (prt_resfile_strncmp(0, "%%", 2) != 0)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001782 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001783
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001784 // Find type of DSC comment
K.Takataeeec2542021-06-02 13:28:16 +02001785 for (comment = 0; comment < (int)ARRAY_LENGTH(prt_dsc_table); comment++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001786 if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
1787 prt_dsc_table[comment].len) == 0)
1788 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001789
K.Takataeeec2542021-06-02 13:28:16 +02001790 if (comment != ARRAY_LENGTH(prt_dsc_table))
Bram Moolenaar81366db2005-07-24 21:16:51 +00001791 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001792 // Return type of comment
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001793 p_dsc_line->type = prt_dsc_table[comment].type;
1794 offset = prt_dsc_table[comment].len;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001795 }
1796 else
1797 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001798 // Unrecognised DSC comment, skip to ws after comment leader
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001799 p_dsc_line->type = PRT_DSC_MISC_TYPE;
1800 offset = prt_resfile_skip_nonws(0);
1801 if (offset == -1)
1802 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001803 }
1804
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001805 // Skip ws to comment value
Bram Moolenaar81366db2005-07-24 21:16:51 +00001806 offset = prt_resfile_skip_ws(offset);
1807 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001808 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001809
1810 p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
1811 p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
1812
1813 return TRUE;
1814}
1815
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001816/*
1817 * Improved hand crafted parser to get the type, title, and version number of a
Bram Moolenaar81366db2005-07-24 21:16:51 +00001818 * PS resource file so the file details can be added to the DSC header comments.
1819 */
1820 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001821prt_open_resource(struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001822{
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001823 int offset;
1824 int seen_all;
1825 int seen_title;
1826 int seen_version;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001827 FILE *fd_resource;
1828 struct prt_dsc_line_S dsc_line;
1829
1830 fd_resource = mch_fopen((char *)resource->filename, READBIN);
1831 if (fd_resource == NULL)
1832 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001833 semsg(_(e_cant_open_file_str_3), resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001834 return FALSE;
1835 }
Bram Moolenaara80faa82020-04-12 19:37:17 +02001836 CLEAR_FIELD(prt_resfile.buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001837
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001838 // Parse first line to ensure valid resource file
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001839 prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001840 PRT_FILE_BUFFER_LEN, fd_resource);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001841 if (ferror(fd_resource))
1842 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00001843 semsg(_(e_cant_read_postscript_resource_file_str),
Bram Moolenaar81366db2005-07-24 21:16:51 +00001844 resource->filename);
1845 fclose(fd_resource);
1846 return FALSE;
1847 }
Bram Moolenaara9d52e32010-07-31 16:44:19 +02001848 fclose(fd_resource);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001849
1850 prt_resfile.line_end = -1;
1851 prt_resfile.line_start = 0;
1852 if (!prt_resfile_next_line())
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001853 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001854
1855 offset = 0;
1856
1857 if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001858 (int)STRLEN(PRT_RESOURCE_HEADER)) != 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001859 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001860 semsg(_(e_file_str_is_not_postscript_resource_file),
1861 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001862 return FALSE;
1863 }
1864
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001865 // Skip over any version numbers and following ws
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001866 offset += (int)STRLEN(PRT_RESOURCE_HEADER);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001867 offset = prt_resfile_skip_nonws(offset);
1868 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001869 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001870 offset = prt_resfile_skip_ws(offset);
1871 if (offset == -1)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001872 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001873
1874 if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001875 (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001876 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001877 semsg(_(e_file_str_is_not_supported_postscript_resource_file),
1878 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001879 return FALSE;
1880 }
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001881 offset += (int)STRLEN(PRT_RESOURCE_RESOURCE);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001882
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001883 // Decide type of resource in the file
Bram Moolenaar81366db2005-07-24 21:16:51 +00001884 if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001885 (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001886 resource->type = PRT_RESOURCE_TYPE_PROCSET;
1887 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001888 (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001889 resource->type = PRT_RESOURCE_TYPE_ENCODING;
1890 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001891 (int)STRLEN(PRT_RESOURCE_CMAP)) == 0)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001892 resource->type = PRT_RESOURCE_TYPE_CMAP;
1893 else
1894 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001895 semsg(_(e_file_str_is_not_supported_postscript_resource_file),
1896 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001897 return FALSE;
1898 }
1899
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001900 // Look for title and version of resource
Bram Moolenaar81366db2005-07-24 21:16:51 +00001901 resource->title[0] = '\0';
1902 resource->version[0] = '\0';
1903 seen_title = FALSE;
1904 seen_version = FALSE;
1905 seen_all = FALSE;
1906 while (!seen_all && prt_next_dsc(&dsc_line))
1907 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001908 switch (dsc_line.type)
1909 {
1910 case PRT_DSC_TITLE_TYPE:
1911 vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
1912 seen_title = TRUE;
1913 if (seen_version)
1914 seen_all = TRUE;
1915 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001916
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001917 case PRT_DSC_VERSION_TYPE:
1918 vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
1919 seen_version = TRUE;
1920 if (seen_title)
1921 seen_all = TRUE;
1922 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001923
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001924 case PRT_DSC_ENDCOMMENTS_TYPE:
=?UTF-8?q?Dundar=20G=C3=B6c?=dfa5e462021-10-02 11:26:51 +01001925 // Won't find title or resource after this comment, stop searching
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001926 seen_all = TRUE;
1927 break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00001928
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001929 case PRT_DSC_MISC_TYPE:
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001930 // Not interested in whatever comment this line had
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001931 break;
1932 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00001933 }
1934
1935 if (!seen_title || !seen_version)
1936 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001937 semsg(_(e_file_str_is_not_supported_postscript_resource_file),
1938 resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00001939 return FALSE;
1940 }
1941
Bram Moolenaar81366db2005-07-24 21:16:51 +00001942 return TRUE;
1943}
1944
1945 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001946prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001947{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001948 // Version number m.n should match, the revision number does not matter
Bram Moolenaar81366db2005-07-24 21:16:51 +00001949 if (STRNCMP(resource->version, version, STRLEN(version)))
1950 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00001951 semsg(_(e_str_resource_file_has_wrong_version),
Bram Moolenaar81366db2005-07-24 21:16:51 +00001952 resource->name);
1953 return FALSE;
1954 }
1955
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001956 // Other checks to be added as needed
Bram Moolenaar81366db2005-07-24 21:16:51 +00001957 return TRUE;
1958}
1959
1960 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001961prt_dsc_start(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001962{
1963 prt_write_string("%!PS-Adobe-3.0\n");
1964}
1965
1966 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001967prt_dsc_noarg(char *comment)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001968{
1969 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1970 "%%%%%s\n", comment);
1971 prt_write_file(prt_line_buffer);
1972}
1973
1974 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001975prt_dsc_textline(char *comment, char *text)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001976{
1977 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1978 "%%%%%s: %s\n", comment, text);
1979 prt_write_file(prt_line_buffer);
1980}
1981
1982 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001983prt_dsc_text(char *comment, char *text)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001984{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01001985 // TODO - should scan 'text' for any chars needing escaping!
Bram Moolenaar81366db2005-07-24 21:16:51 +00001986 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1987 "%%%%%s: (%s)\n", comment, text);
1988 prt_write_file(prt_line_buffer);
1989}
1990
1991#define prt_dsc_atend(c) prt_dsc_text((c), "atend")
1992
1993 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01001994prt_dsc_ints(char *comment, int count, int *ints)
Bram Moolenaar81366db2005-07-24 21:16:51 +00001995{
1996 int i;
1997
1998 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1999 "%%%%%s:", comment);
2000 prt_write_file(prt_line_buffer);
2001
2002 for (i = 0; i < count; i++)
2003 {
2004 sprintf((char *)prt_line_buffer, " %d", ints[i]);
2005 prt_write_file(prt_line_buffer);
2006 }
2007
2008 prt_write_string("\n");
2009}
2010
2011 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002012prt_dsc_resources(
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002013 char *comment, // if NULL add to previous
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002014 char *type,
2015 char *string)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002016{
2017 if (comment != NULL)
2018 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2019 "%%%%%s: %s", comment, type);
2020 else
2021 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2022 "%%%%+ %s", type);
2023 prt_write_file(prt_line_buffer);
2024
2025 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2026 " %s\n", string);
2027 prt_write_file(prt_line_buffer);
2028}
2029
2030 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002031prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002032{
2033 int i;
2034
2035 prt_dsc_resources(resource, "font",
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002036 ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002037 for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002038 if (ps_font->ps_fontname[i] != NULL)
2039 prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002040}
2041
2042 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002043prt_dsc_requirements(
2044 int duplex,
2045 int tumble,
2046 int collate,
2047 int color,
2048 int num_copies)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002049{
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002050 // Only output the comment if we need to.
2051 // Note: tumble is ignored if we are not duplexing
Bram Moolenaar81366db2005-07-24 21:16:51 +00002052 if (!(duplex || collate || color || (num_copies > 1)))
2053 return;
2054
2055 sprintf((char *)prt_line_buffer, "%%%%Requirements:");
2056 prt_write_file(prt_line_buffer);
2057
2058 if (duplex)
2059 {
2060 prt_write_string(" duplex");
2061 if (tumble)
2062 prt_write_string("(tumble)");
2063 }
2064 if (collate)
2065 prt_write_string(" collate");
2066 if (color)
2067 prt_write_string(" color");
2068 if (num_copies > 1)
2069 {
2070 prt_write_string(" numcopies(");
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002071 // Note: no space wanted so don't use prt_write_int()
Bram Moolenaar81366db2005-07-24 21:16:51 +00002072 sprintf((char *)prt_line_buffer, "%d", num_copies);
2073 prt_write_file(prt_line_buffer);
2074 prt_write_string(")");
2075 }
2076 prt_write_string("\n");
2077}
2078
2079 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002080prt_dsc_docmedia(
2081 char *paper_name,
2082 double width,
2083 double height,
2084 double weight,
2085 char *colour,
2086 char *type)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002087{
2088 vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2089 "%%%%DocumentMedia: %s ", paper_name);
2090 prt_write_file(prt_line_buffer);
2091 prt_write_real(width, 2);
2092 prt_write_real(height, 2);
2093 prt_write_real(weight, 2);
2094 if (colour == NULL)
2095 prt_write_string("()");
2096 else
2097 prt_write_string(colour);
2098 prt_write_string(" ");
2099 if (type == NULL)
2100 prt_write_string("()");
2101 else
2102 prt_write_string(type);
2103 prt_write_string("\n");
2104}
2105
2106 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002107mch_print_cleanup(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002108{
Bram Moolenaar81366db2005-07-24 21:16:51 +00002109 if (prt_out_mbyte)
2110 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002111 int i;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002112
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002113 // Free off all CID font names created, but first clear duplicate
2114 // pointers to the same string (when the same font is used for more than
2115 // one style).
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002116 for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
2117 {
2118 if (prt_ps_mb_font.ps_fontname[i] != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01002119 VIM_CLEAR(prt_ps_mb_font.ps_fontname[i]);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002120 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002121 }
2122
2123 if (prt_do_conv)
2124 {
2125 convert_setup(&prt_conv, NULL, NULL);
2126 prt_do_conv = FALSE;
2127 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002128 if (prt_ps_fd != NULL)
2129 {
2130 fclose(prt_ps_fd);
2131 prt_ps_fd = NULL;
2132 prt_file_error = FALSE;
2133 }
2134 if (prt_ps_file_name != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01002135 VIM_CLEAR(prt_ps_file_name);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002136}
2137
2138 static float
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002139to_device_units(int idx, double physsize, int def_number)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002140{
2141 float ret;
2142 int u;
2143 int nr;
2144
2145 u = prt_get_unit(idx);
2146 if (u == PRT_UNIT_NONE)
2147 {
2148 u = PRT_UNIT_PERC;
2149 nr = def_number;
2150 }
2151 else
2152 nr = printer_opts[idx].number;
2153
2154 switch (u)
2155 {
2156 case PRT_UNIT_INCH:
2157 ret = (float)(nr * PRT_PS_DEFAULT_DPI);
2158 break;
2159 case PRT_UNIT_MM:
2160 ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
2161 break;
2162 case PRT_UNIT_POINT:
2163 ret = (float)nr;
2164 break;
2165 case PRT_UNIT_PERC:
2166 default:
2167 ret = (float)(physsize * nr) / 100;
2168 break;
2169 }
2170
2171 return ret;
2172}
2173
2174/*
2175 * Calculate margins for given width and height from printoptions settings.
2176 */
2177 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002178prt_page_margins(
2179 double width,
2180 double height,
2181 double *left,
2182 double *right,
2183 double *top,
2184 double *bottom)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002185{
2186 *left = to_device_units(OPT_PRINT_LEFT, width, 10);
2187 *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
2188 *top = height - to_device_units(OPT_PRINT_TOP, height, 5);
2189 *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
2190}
2191
2192 static void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002193prt_font_metrics(int font_scale)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002194{
2195 prt_line_height = (float)font_scale;
2196 prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
2197}
2198
2199
2200 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002201prt_get_cpl(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002202{
2203 if (prt_use_number())
2204 {
2205 prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002206 // If we are outputting multi-byte characters then line numbers will be
2207 // printed with half width characters
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002208 if (prt_out_mbyte)
2209 prt_number_width /= 2;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002210 prt_left_margin += prt_number_width;
2211 }
2212 else
2213 prt_number_width = 0.0;
2214
2215 return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
2216}
2217
Bram Moolenaar81366db2005-07-24 21:16:51 +00002218 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002219prt_build_cid_fontname(int font, char_u *name, int name_len)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002220{
2221 char *fontname;
2222
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002223 fontname = alloc(name_len + 1);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002224 if (fontname == NULL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002225 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002226 vim_strncpy((char_u *)fontname, name, name_len);
2227 prt_ps_mb_font.ps_fontname[font] = fontname;
2228
2229 return TRUE;
2230}
Bram Moolenaar81366db2005-07-24 21:16:51 +00002231
2232/*
2233 * Get number of lines of text that fit on a page (excluding the header).
2234 */
2235 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002236prt_get_lpp(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002237{
2238 int lpp;
2239
2240 /*
2241 * Calculate offset to lower left corner of background rect based on actual
2242 * font height (based on its bounding box) and the line height, handling the
2243 * case where the font height can exceed the line height.
2244 */
2245 prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
2246 prt_ps_font->bbox_min_y);
2247 if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
2248 {
2249 prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
2250 (1000.0 - (prt_ps_font->bbox_max_y -
2251 prt_ps_font->bbox_min_y)) / 2);
2252 }
2253
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002254 // Get height for topmost line based on background rect offset.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002255 prt_first_line_height = prt_line_height + prt_bgcol_offset;
2256
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002257 // Calculate lpp
Bram Moolenaar81366db2005-07-24 21:16:51 +00002258 lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
2259
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002260 // Adjust top margin if there is a header
Bram Moolenaar81366db2005-07-24 21:16:51 +00002261 prt_top_margin -= prt_line_height * prt_header_height();
2262
2263 return lpp - prt_header_height();
2264}
2265
Bram Moolenaar81366db2005-07-24 21:16:51 +00002266 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002267prt_match_encoding(
2268 char *p_encoding,
2269 struct prt_ps_mbfont_S *p_cmap,
2270 struct prt_ps_encoding_S **pp_mbenc)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002271{
2272 int mbenc;
2273 int enc_len;
2274 struct prt_ps_encoding_S *p_mbenc;
2275
2276 *pp_mbenc = NULL;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002277 // Look for recognised encoding
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002278 enc_len = (int)STRLEN(p_encoding);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002279 p_mbenc = p_cmap->encodings;
2280 for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
2281 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002282 if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
2283 {
2284 *pp_mbenc = p_mbenc;
2285 return TRUE;
2286 }
2287 p_mbenc++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002288 }
2289 return FALSE;
2290}
2291
2292 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002293prt_match_charset(
2294 char *p_charset,
2295 struct prt_ps_mbfont_S *p_cmap,
2296 struct prt_ps_charset_S **pp_mbchar)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002297{
2298 int mbchar;
2299 int char_len;
2300 struct prt_ps_charset_S *p_mbchar;
2301
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002302 // Look for recognised character set, using default if one is not given
Bram Moolenaar81366db2005-07-24 21:16:51 +00002303 if (*p_charset == NUL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002304 p_charset = p_cmap->defcs;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002305 char_len = (int)STRLEN(p_charset);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002306 p_mbchar = p_cmap->charsets;
2307 for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
2308 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002309 if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
2310 {
2311 *pp_mbchar = p_mbchar;
2312 return TRUE;
2313 }
2314 p_mbchar++;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002315 }
2316 return FALSE;
2317}
Bram Moolenaar81366db2005-07-24 21:16:51 +00002318
Bram Moolenaar81366db2005-07-24 21:16:51 +00002319 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002320mch_print_init(
2321 prt_settings_T *psettings,
2322 char_u *jobname,
2323 int forceit UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002324{
2325 int i;
2326 char *paper_name;
2327 int paper_strlen;
2328 int fontsize;
2329 char_u *p;
2330 double left;
2331 double right;
2332 double top;
2333 double bottom;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002334 int props;
2335 int cmap = 0;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002336 char_u *p_encoding;
2337 struct prt_ps_encoding_S *p_mbenc;
2338 struct prt_ps_encoding_S *p_mbenc_first;
Bram Moolenaar89d40322006-08-29 15:30:07 +00002339 struct prt_ps_charset_S *p_mbchar = NULL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002340
2341#if 0
2342 /*
2343 * TODO:
2344 * If "forceit" is false: pop up a dialog to select:
2345 * - printer name
2346 * - copies
2347 * - collated/uncollated
2348 * - duplex off/long side/short side
2349 * - paper size
2350 * - portrait/landscape
2351 * - font size
2352 *
2353 * If "forceit" is true: use the default printer and settings
2354 */
2355 if (forceit)
2356 s_pd.Flags |= PD_RETURNDEFAULT;
2357#endif
2358
2359 /*
2360 * Set up font and encoding.
2361 */
Bram Moolenaar81366db2005-07-24 21:16:51 +00002362 p_encoding = enc_skip(p_penc);
2363 if (*p_encoding == NUL)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002364 p_encoding = enc_skip(p_enc);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002365
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002366 // Look for a multi-byte font that matches the encoding and character set.
2367 // Only look if multi-byte character set is defined, or using multi-byte
2368 // encoding other than Unicode. This is because a Unicode encoding does not
2369 // uniquely identify a CJK character set to use.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002370 p_mbenc = NULL;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002371 props = enc_canon_props(p_encoding);
Bram Moolenaar14716812006-05-04 21:54:08 +00002372 if (!(props & ENC_8BIT) && ((*p_pmcs != NUL) || !(props & ENC_UNICODE)))
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002373 {
Bram Moolenaarec45c4a2015-04-15 14:27:49 +02002374 int cmap_first = 0;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002375
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002376 p_mbenc_first = NULL;
K.Takataeeec2542021-06-02 13:28:16 +02002377 for (cmap = 0; cmap < (int)ARRAY_LENGTH(prt_ps_mbfonts); cmap++)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002378 if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
Bram Moolenaar81366db2005-07-24 21:16:51 +00002379 &p_mbenc))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002380 {
2381 if (p_mbenc_first == NULL)
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002382 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002383 p_mbenc_first = p_mbenc;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002384 cmap_first = cmap;
2385 }
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002386 if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
Bram Moolenaar81366db2005-07-24 21:16:51 +00002387 &p_mbchar))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002388 break;
2389 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002390
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002391 // Use first encoding matched if no charset matched
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002392 if (p_mbchar == NULL && p_mbenc_first != NULL)
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002393 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002394 p_mbenc = p_mbenc_first;
Bram Moolenaar7c94ce92015-04-13 14:45:27 +02002395 cmap = cmap_first;
2396 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002397 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002398
2399 prt_out_mbyte = (p_mbenc != NULL);
2400 if (prt_out_mbyte)
2401 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002402 // Build CMap name - will be same for all multi-byte fonts used
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002403 prt_cmap[0] = NUL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002404
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002405 prt_custom_cmap = (p_mbchar == NULL);
2406 if (!prt_custom_cmap)
2407 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002408 // Check encoding and character set are compatible
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002409 if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0)
2410 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00002411 emsg(_(e_incompatible_multi_byte_encoding_and_character_set));
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002412 return FALSE;
2413 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002414
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002415 // Add charset name if not empty
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002416 if (p_mbchar->cmap_charset != NULL)
2417 {
2418 vim_strncpy((char_u *)prt_cmap,
Bram Moolenaar81366db2005-07-24 21:16:51 +00002419 (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002420 STRCAT(prt_cmap, "-");
2421 }
2422 }
2423 else
2424 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002425 // Add custom CMap character set name
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002426 if (*p_pmcs == NUL)
2427 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00002428 emsg(_(e_printmbcharset_cannot_be_empty_with_multi_byte_encoding));
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002429 return FALSE;
2430 }
2431 vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
2432 STRCAT(prt_cmap, "-");
2433 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002434
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002435 // CMap name ends with (optional) encoding name and -H for horizontal
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002436 if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002437 + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002438 {
2439 STRCAT(prt_cmap, p_mbenc->cmap_encoding);
2440 STRCAT(prt_cmap, "-");
2441 }
2442 STRCAT(prt_cmap, "H");
Bram Moolenaar81366db2005-07-24 21:16:51 +00002443
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002444 if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
2445 {
Bram Moolenaara6f79292022-01-04 21:30:47 +00002446 emsg(_(e_no_default_font_specified_for_multi_byte_printing));
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002447 return FALSE;
2448 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002449
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002450 // Derive CID font names with fallbacks if not defined
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002451 if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
2452 mbfont_opts[OPT_MBFONT_REGULAR].string,
2453 mbfont_opts[OPT_MBFONT_REGULAR].strlen))
2454 return FALSE;
2455 if (mbfont_opts[OPT_MBFONT_BOLD].present)
2456 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
2457 mbfont_opts[OPT_MBFONT_BOLD].string,
2458 mbfont_opts[OPT_MBFONT_BOLD].strlen))
2459 return FALSE;
2460 if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
2461 if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
2462 mbfont_opts[OPT_MBFONT_OBLIQUE].string,
2463 mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
2464 return FALSE;
2465 if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
2466 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
Bram Moolenaar81366db2005-07-24 21:16:51 +00002467 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
2468 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002469 return FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002470
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002471 // Check if need to use Courier for ASCII code range, and if so pick up
2472 // the encoding to use
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002473 prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
2474 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
2475 if (prt_use_courier)
2476 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002477 // Use national ASCII variant unless ASCII wanted
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002478 if (mbfont_opts[OPT_MBFONT_ASCII].present &&
2479 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
2480 prt_ascii_encoding = "ascii";
2481 else
2482 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
2483 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002484
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002485 prt_ps_font = &prt_ps_mb_font;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002486 }
2487 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00002488 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002489 prt_use_courier = FALSE;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002490 prt_ps_font = &prt_ps_courier_font;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002491 }
2492
2493 /*
2494 * Find the size of the paper and set the margins.
2495 */
2496 prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
2497 || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
2498 if (printer_opts[OPT_PRINT_PAPER].present)
2499 {
2500 paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
2501 paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
2502 }
2503 else
2504 {
2505 paper_name = "A4";
2506 paper_strlen = 2;
2507 }
Bram Moolenaaraf0167f2009-05-16 15:31:32 +00002508 for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002509 if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
2510 && STRNICMP(prt_mediasize[i].name, paper_name,
2511 paper_strlen) == 0)
2512 break;
2513 if (i == PRT_MEDIASIZE_LEN)
2514 i = 0;
2515 prt_media = i;
2516
2517 /*
2518 * Set PS pagesize based on media dimensions and print orientation.
2519 * Note: Media and page sizes have defined meanings in PostScript and should
2520 * be kept distinct. Media is the paper (or transparency, or ...) that is
2521 * printed on, whereas the page size is the area that the PostScript
2522 * interpreter renders into.
2523 */
2524 if (prt_portrait)
2525 {
2526 prt_page_width = prt_mediasize[i].width;
2527 prt_page_height = prt_mediasize[i].height;
2528 }
2529 else
2530 {
2531 prt_page_width = prt_mediasize[i].height;
2532 prt_page_height = prt_mediasize[i].width;
2533 }
2534
2535 /*
2536 * Set PS page margins based on the PS pagesize, not the mediasize - this
2537 * needs to be done before the cpl and lpp are calculated.
2538 */
2539 prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
2540 &bottom);
2541 prt_left_margin = (float)left;
2542 prt_right_margin = (float)right;
2543 prt_top_margin = (float)top;
2544 prt_bottom_margin = (float)bottom;
2545
2546 /*
2547 * Set up the font size.
2548 */
2549 fontsize = PRT_PS_DEFAULT_FONTSIZE;
2550 for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
2551 if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
2552 fontsize = atoi((char *)p + 2);
2553 prt_font_metrics(fontsize);
2554
2555 /*
2556 * Return the number of characters per line, and lines per page for the
2557 * generic print code.
2558 */
2559 psettings->chars_per_line = prt_get_cpl();
2560 psettings->lines_per_page = prt_get_lpp();
2561
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002562 // Catch margin settings that leave no space for output!
Bram Moolenaar81366db2005-07-24 21:16:51 +00002563 if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
2564 return FAIL;
2565
2566 /*
2567 * Sort out the number of copies to be printed. PS by default will do
2568 * uncollated copies for you, so once we know how many uncollated copies are
2569 * wanted cache it away and lie to the generic code that we only want one
2570 * uncollated copy.
2571 */
2572 psettings->n_collated_copies = 1;
2573 psettings->n_uncollated_copies = 1;
2574 prt_num_copies = 1;
2575 prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
2576 || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
2577 if (prt_collate)
2578 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002579 // TODO: Get number of collated copies wanted.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002580 psettings->n_collated_copies = 1;
2581 }
2582 else
2583 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002584 // TODO: Get number of uncollated copies wanted and update the cached
2585 // count.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002586 prt_num_copies = 1;
2587 }
2588
2589 psettings->jobname = jobname;
2590
2591 /*
2592 * Set up printer duplex and tumble based on Duplex option setting - default
2593 * is long sided duplex printing (i.e. no tumble).
2594 */
2595 prt_duplex = TRUE;
2596 prt_tumble = FALSE;
2597 psettings->duplex = 1;
2598 if (printer_opts[OPT_PRINT_DUPLEX].present)
2599 {
2600 if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
2601 {
2602 prt_duplex = FALSE;
2603 psettings->duplex = 0;
2604 }
2605 else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
2606 == 0)
2607 prt_tumble = TRUE;
2608 }
2609
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002610 // For now user abort not supported
Bram Moolenaar81366db2005-07-24 21:16:51 +00002611 psettings->user_abort = 0;
2612
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002613 // If the user didn't specify a file name, use a temp file.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002614 if (psettings->outfile == NULL)
2615 {
Bram Moolenaare5c421c2015-03-31 13:33:08 +02002616 prt_ps_file_name = vim_tempname('p', TRUE);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002617 if (prt_ps_file_name == NULL)
2618 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00002619 emsg(_(e_cant_get_temp_file_name));
Bram Moolenaar81366db2005-07-24 21:16:51 +00002620 return FAIL;
2621 }
2622 prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
2623 }
2624 else
2625 {
2626 p = expand_env_save(psettings->outfile);
2627 if (p != NULL)
2628 {
2629 prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
2630 vim_free(p);
2631 }
2632 }
2633 if (prt_ps_fd == NULL)
2634 {
Bram Moolenaareaaac012022-01-02 17:00:40 +00002635 emsg(_(e_cant_open_postscript_output_file));
Bram Moolenaar81366db2005-07-24 21:16:51 +00002636 mch_print_cleanup();
2637 return FAIL;
2638 }
2639
2640 prt_bufsiz = psettings->chars_per_line;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002641 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002642 prt_bufsiz *= 2;
Bram Moolenaar04935fb2022-01-08 16:19:22 +00002643 ga_init2(&prt_ps_buffer, sizeof(char), prt_bufsiz);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002644
2645 prt_page_num = 0;
2646
2647 prt_attribute_change = FALSE;
2648 prt_need_moveto = FALSE;
2649 prt_need_font = FALSE;
2650 prt_need_fgcol = FALSE;
2651 prt_need_bgcol = FALSE;
2652 prt_need_underline = FALSE;
2653
2654 prt_file_error = FALSE;
2655
2656 return OK;
2657}
2658
2659 static int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002660prt_add_resource(struct prt_ps_resource_S *resource)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002661{
2662 FILE* fd_resource;
2663 char_u resource_buffer[512];
2664 size_t bytes_read;
2665
2666 fd_resource = mch_fopen((char *)resource->filename, READBIN);
2667 if (fd_resource == NULL)
2668 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002669 semsg(_(e_cant_open_file_str_2), resource->filename);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002670 return FALSE;
2671 }
2672 prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
2673 (char *)resource->title);
2674
2675 prt_dsc_textline("BeginDocument", (char *)resource->filename);
2676
2677 for (;;)
2678 {
2679 bytes_read = fread((char *)resource_buffer, sizeof(char_u),
2680 sizeof(resource_buffer), fd_resource);
2681 if (ferror(fd_resource))
2682 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002683 semsg(_(e_cant_read_postscript_resource_file_str),
Bram Moolenaar81366db2005-07-24 21:16:51 +00002684 resource->filename);
2685 fclose(fd_resource);
2686 return FALSE;
2687 }
2688 if (bytes_read == 0)
2689 break;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002690 prt_write_file_raw_len(resource_buffer, (int)bytes_read);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002691 if (prt_file_error)
2692 {
2693 fclose(fd_resource);
2694 return FALSE;
2695 }
2696 }
2697 fclose(fd_resource);
2698
2699 prt_dsc_noarg("EndDocument");
2700
2701 prt_dsc_noarg("EndResource");
2702
2703 return TRUE;
2704}
2705
2706 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01002707mch_print_begin(prt_settings_T *psettings)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002708{
Bram Moolenaar81366db2005-07-24 21:16:51 +00002709 int bbox[4];
Bram Moolenaar81366db2005-07-24 21:16:51 +00002710 double left;
2711 double right;
2712 double top;
2713 double bottom;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002714 struct prt_ps_resource_S *res_prolog;
2715 struct prt_ps_resource_S *res_encoding;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002716 char buffer[256];
2717 char_u *p_encoding;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002718 struct prt_ps_resource_S *res_cidfont;
2719 struct prt_ps_resource_S *res_cmap;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002720 int retval = FALSE;
2721
2722 res_prolog = (struct prt_ps_resource_S *)
2723 alloc(sizeof(struct prt_ps_resource_S));
2724 res_encoding = (struct prt_ps_resource_S *)
2725 alloc(sizeof(struct prt_ps_resource_S));
Bram Moolenaard9462e32011-04-11 21:35:11 +02002726 res_cidfont = (struct prt_ps_resource_S *)
2727 alloc(sizeof(struct prt_ps_resource_S));
2728 res_cmap = (struct prt_ps_resource_S *)
2729 alloc(sizeof(struct prt_ps_resource_S));
Bram Moolenaard9462e32011-04-11 21:35:11 +02002730 if (res_prolog == NULL || res_encoding == NULL
Bram Moolenaarfc3abf42019-01-24 15:54:21 +01002731 || res_cidfont == NULL || res_cmap == NULL)
Bram Moolenaard9462e32011-04-11 21:35:11 +02002732 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002733
2734 /*
2735 * PS DSC Header comments - no PS code!
2736 */
2737 prt_dsc_start();
2738 prt_dsc_textline("Title", (char *)psettings->jobname);
2739 if (!get_user_name((char_u *)buffer, 256))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002740 STRCPY(buffer, "Unknown");
Bram Moolenaar81366db2005-07-24 21:16:51 +00002741 prt_dsc_textline("For", buffer);
2742 prt_dsc_textline("Creator", VIM_VERSION_LONG);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002743 // Note: to ensure Clean8bit I don't think we can use LC_TIME
Bram Moolenaar63d25552019-05-10 21:28:38 +02002744
2745 prt_dsc_textline("CreationDate", get_ctime(time(NULL), FALSE));
Bram Moolenaar81366db2005-07-24 21:16:51 +00002746 prt_dsc_textline("DocumentData", "Clean8Bit");
2747 prt_dsc_textline("Orientation", "Portrait");
2748 prt_dsc_atend("Pages");
2749 prt_dsc_textline("PageOrder", "Ascend");
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002750 // The bbox does not change with orientation - it is always in the default
2751 // user coordinate system! We have to recalculate right and bottom
2752 // coordinates based on the font metrics for the bbox to be accurate.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002753 prt_page_margins(prt_mediasize[prt_media].width,
2754 prt_mediasize[prt_media].height,
2755 &left, &right, &top, &bottom);
2756 bbox[0] = (int)left;
2757 if (prt_portrait)
2758 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002759 // In portrait printing the fixed point is the top left corner so we
2760 // derive the bbox from that point. We have the expected cpl chars
2761 // across the media and lpp lines down the media.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002762 bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
=?UTF-8?q?Dundar=20G=C3=B6c?=d5cec1f2022-01-29 15:19:23 +00002763 * (double)prt_line_height);
2764 bbox[2] = (int)(left + psettings->chars_per_line
2765 * (double)prt_char_width + 0.5);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002766 bbox[3] = (int)(top + 0.5);
2767 }
2768 else
2769 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002770 // In landscape printing the fixed point is the bottom left corner so we
2771 // derive the bbox from that point. We have lpp chars across the media
2772 // and cpl lines up the media.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002773 bbox[1] = (int)bottom;
2774 bbox[2] = (int)(left + ((psettings->lines_per_page
2775 + prt_header_height()) * prt_line_height) + 0.5);
=?UTF-8?q?Dundar=20G=C3=B6c?=d5cec1f2022-01-29 15:19:23 +00002776 bbox[3] = (int)(bottom + psettings->chars_per_line
2777 * (double)prt_char_width + 0.5);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002778 }
2779 prt_dsc_ints("BoundingBox", 4, bbox);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002780 // The media width and height does not change with landscape printing!
Bram Moolenaar81366db2005-07-24 21:16:51 +00002781 prt_dsc_docmedia(prt_mediasize[prt_media].name,
2782 prt_mediasize[prt_media].width,
2783 prt_mediasize[prt_media].height,
2784 (double)0, NULL, NULL);
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002785 // Define fonts needed
Bram Moolenaar81366db2005-07-24 21:16:51 +00002786 if (!prt_out_mbyte || prt_use_courier)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002787 prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002788 if (prt_out_mbyte)
2789 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002790 prt_dsc_font_resource((prt_use_courier ? NULL
=?UTF-8?q?Dundar=20G=C3=B6c?=d5cec1f2022-01-29 15:19:23 +00002791 : "DocumentNeededResources"), &prt_ps_mb_font);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002792 if (!prt_custom_cmap)
2793 prt_dsc_resources(NULL, "cmap", prt_cmap);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002794 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002795
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002796 // Search for external resources VIM supplies
Bram Moolenaard9462e32011-04-11 21:35:11 +02002797 if (!prt_find_resource("prolog", res_prolog))
Bram Moolenaar81366db2005-07-24 21:16:51 +00002798 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002799 semsg(_(e_cant_find_postscript_resource_file_str_ps), "prolog");
Bram Moolenaar0a383962014-11-27 17:37:57 +01002800 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002801 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002802 if (!prt_open_resource(res_prolog))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002803 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002804 if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002805 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002806 if (prt_out_mbyte)
2807 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002808 // Look for required version of multi-byte printing procset
Bram Moolenaard9462e32011-04-11 21:35:11 +02002809 if (!prt_find_resource("cidfont", res_cidfont))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002810 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002811 semsg(_(e_cant_find_postscript_resource_file_str_ps), "cidfont");
Bram Moolenaar0a383962014-11-27 17:37:57 +01002812 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002813 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002814 if (!prt_open_resource(res_cidfont))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002815 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002816 if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002817 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002818 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002819
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002820 // Find an encoding to use for printing.
2821 // Check 'printencoding'. If not set or not found, then use 'encoding'. If
2822 // that cannot be found then default to "latin1".
2823 // Note: VIM specific encoding header is always skipped.
Bram Moolenaar81366db2005-07-24 21:16:51 +00002824 if (!prt_out_mbyte)
2825 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002826 p_encoding = enc_skip(p_penc);
2827 if (*p_encoding == NUL
Bram Moolenaard9462e32011-04-11 21:35:11 +02002828 || !prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002829 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002830 // 'printencoding' not set or not supported - find alternate
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002831 int props;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002832
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002833 p_encoding = enc_skip(p_enc);
2834 props = enc_canon_props(p_encoding);
2835 if (!(props & ENC_8BIT)
Bram Moolenaard9462e32011-04-11 21:35:11 +02002836 || !prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002837 // 8-bit 'encoding' is not supported
2838 {
2839 // Use latin1 as default printing encoding
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002840 p_encoding = (char_u *)"latin1";
Bram Moolenaard9462e32011-04-11 21:35:11 +02002841 if (!prt_find_resource((char *)p_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002842 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002843 semsg(_(e_cant_find_postscript_resource_file_str_ps),
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002844 p_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002845 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002846 }
2847 }
2848 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002849 if (!prt_open_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002850 goto theend;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002851 // For the moment there are no checks on encoding resource files to
2852 // perform
Bram Moolenaar81366db2005-07-24 21:16:51 +00002853 }
2854 else
2855 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002856 p_encoding = enc_skip(p_penc);
2857 if (*p_encoding == NUL)
2858 p_encoding = enc_skip(p_enc);
2859 if (prt_use_courier)
2860 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002861 // Include ASCII range encoding vector
Bram Moolenaard9462e32011-04-11 21:35:11 +02002862 if (!prt_find_resource(prt_ascii_encoding, res_encoding))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002863 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002864 semsg(_(e_cant_find_postscript_resource_file_str_ps),
Bram Moolenaar81366db2005-07-24 21:16:51 +00002865 prt_ascii_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002866 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002867 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002868 if (!prt_open_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002869 goto theend;
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002870 // For the moment there are no checks on encoding resource files to
2871 // perform
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002872 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002873 }
2874
2875 prt_conv.vc_type = CONV_NONE;
Bram Moolenaard88be5b2022-01-04 19:57:55 +00002876 if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT))
2877 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002878 // Set up encoding conversion if required
Bram Moolenaar81366db2005-07-24 21:16:51 +00002879 if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
2880 {
Bram Moolenaard88be5b2022-01-04 19:57:55 +00002881 semsg(_(e_unable_to_convert_to_print_encoding_str), p_encoding);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002882 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002883 }
2884 prt_do_conv = TRUE;
2885 }
2886 prt_do_conv = prt_conv.vc_type != CONV_NONE;
2887
2888 if (prt_out_mbyte && prt_custom_cmap)
2889 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002890 // Find user supplied CMap
Bram Moolenaard9462e32011-04-11 21:35:11 +02002891 if (!prt_find_resource(prt_cmap, res_cmap))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002892 {
Bram Moolenaarb09feaa2022-01-02 20:20:45 +00002893 semsg(_(e_cant_find_postscript_resource_file_str_ps), prt_cmap);
Bram Moolenaar0a383962014-11-27 17:37:57 +01002894 goto theend;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002895 }
Bram Moolenaard9462e32011-04-11 21:35:11 +02002896 if (!prt_open_resource(res_cmap))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002897 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002898 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002899
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002900 // List resources supplied
Bram Moolenaard9462e32011-04-11 21:35:11 +02002901 STRCPY(buffer, res_prolog->title);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002902 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02002903 STRCAT(buffer, res_prolog->version);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002904 prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002905 if (prt_out_mbyte)
2906 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002907 STRCPY(buffer, res_cidfont->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002908 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02002909 STRCAT(buffer, res_cidfont->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002910 prt_dsc_resources(NULL, "procset", buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002911
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002912 if (prt_custom_cmap)
2913 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002914 STRCPY(buffer, res_cmap->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002915 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02002916 STRCAT(buffer, res_cmap->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002917 prt_dsc_resources(NULL, "cmap", buffer);
2918 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002919 }
2920 if (!prt_out_mbyte || prt_use_courier)
Bram Moolenaar81366db2005-07-24 21:16:51 +00002921 {
Bram Moolenaard9462e32011-04-11 21:35:11 +02002922 STRCPY(buffer, res_encoding->title);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002923 STRCAT(buffer, " ");
Bram Moolenaard9462e32011-04-11 21:35:11 +02002924 STRCAT(buffer, res_encoding->version);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002925 prt_dsc_resources(NULL, "encoding", buffer);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002926 }
2927 prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
2928#ifdef FEAT_SYN_HL
2929 psettings->do_syntax
2930#else
2931 0
2932#endif
2933 , prt_num_copies);
2934 prt_dsc_noarg("EndComments");
2935
2936 /*
2937 * PS Document page defaults
2938 */
2939 prt_dsc_noarg("BeginDefaults");
2940
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002941 // List font resources most likely common to all pages
Bram Moolenaar81366db2005-07-24 21:16:51 +00002942 if (!prt_out_mbyte || prt_use_courier)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002943 prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002944 if (prt_out_mbyte)
2945 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002946 prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
2947 &prt_ps_mb_font);
2948 if (!prt_custom_cmap)
2949 prt_dsc_resources(NULL, "cmap", prt_cmap);
Bram Moolenaar81366db2005-07-24 21:16:51 +00002950 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002951
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002952 // Paper will be used for all pages
Bram Moolenaar81366db2005-07-24 21:16:51 +00002953 prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
2954
2955 prt_dsc_noarg("EndDefaults");
2956
2957 /*
2958 * PS Document prolog inclusion - all required procsets.
2959 */
2960 prt_dsc_noarg("BeginProlog");
2961
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002962 // Add required procsets - NOTE: order is important!
Bram Moolenaard9462e32011-04-11 21:35:11 +02002963 if (!prt_add_resource(res_prolog))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002964 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002965 if (prt_out_mbyte)
2966 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002967 // Add CID font procset, and any user supplied CMap
Bram Moolenaard9462e32011-04-11 21:35:11 +02002968 if (!prt_add_resource(res_cidfont))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002969 goto theend;
Bram Moolenaard9462e32011-04-11 21:35:11 +02002970 if (prt_custom_cmap && !prt_add_resource(res_cmap))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002971 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002972 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00002973
Bram Moolenaar81366db2005-07-24 21:16:51 +00002974 if (!prt_out_mbyte || prt_use_courier)
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002975 // There will be only one Roman font encoding to be included in the PS
2976 // file.
Bram Moolenaard9462e32011-04-11 21:35:11 +02002977 if (!prt_add_resource(res_encoding))
Bram Moolenaar0a383962014-11-27 17:37:57 +01002978 goto theend;
Bram Moolenaar81366db2005-07-24 21:16:51 +00002979
2980 prt_dsc_noarg("EndProlog");
2981
2982 /*
2983 * PS Document setup - must appear after the prolog
2984 */
2985 prt_dsc_noarg("BeginSetup");
2986
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01002987 // Device setup - page size and number of uncollated copies
Bram Moolenaar81366db2005-07-24 21:16:51 +00002988 prt_write_int((int)prt_mediasize[prt_media].width);
2989 prt_write_int((int)prt_mediasize[prt_media].height);
2990 prt_write_int(0);
2991 prt_write_string("sps\n");
2992 prt_write_int(prt_num_copies);
2993 prt_write_string("nc\n");
2994 prt_write_boolean(prt_duplex);
2995 prt_write_boolean(prt_tumble);
2996 prt_write_string("dt\n");
2997 prt_write_boolean(prt_collate);
2998 prt_write_string("c\n");
2999
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003000 // Font resource inclusion and definition
Bram Moolenaar81366db2005-07-24 21:16:51 +00003001 if (!prt_out_mbyte || prt_use_courier)
3002 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003003 // When using Courier for ASCII range when printing multi-byte, need to
3004 // pick up ASCII encoding to use with it.
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003005 if (prt_use_courier)
3006 p_encoding = (char_u *)prt_ascii_encoding;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003007 prt_dsc_resources("IncludeResource", "font",
3008 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3009 prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
3010 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3011 prt_dsc_resources("IncludeResource", "font",
3012 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3013 prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
3014 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3015 prt_dsc_resources("IncludeResource", "font",
3016 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3017 prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
3018 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3019 prt_dsc_resources("IncludeResource", "font",
3020 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3021 prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
3022 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003023 }
3024 if (prt_out_mbyte)
3025 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003026 // Define the CID fonts to be used in the job. Typically CJKV fonts do
3027 // not have an italic form being a western style, so where no font is
3028 // defined for these faces VIM falls back to an existing face.
3029 // Note: if using Courier for the ASCII range then the printout will
3030 // have bold/italic/bolditalic regardless of the setting of printmbfont.
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003031 prt_dsc_resources("IncludeResource", "font",
3032 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3033 if (!prt_custom_cmap)
3034 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3035 prt_def_cidfont("CF0", (int)prt_line_height,
3036 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003037
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003038 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
3039 {
3040 prt_dsc_resources("IncludeResource", "font",
3041 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3042 if (!prt_custom_cmap)
3043 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3044 prt_def_cidfont("CF1", (int)prt_line_height,
3045 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3046 }
3047 else
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003048 // Use ROMAN for BOLD
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003049 prt_dup_cidfont("CF0", "CF1");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003050
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003051 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
3052 {
3053 prt_dsc_resources("IncludeResource", "font",
3054 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3055 if (!prt_custom_cmap)
3056 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3057 prt_def_cidfont("CF2", (int)prt_line_height,
3058 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3059 }
3060 else
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003061 // Use ROMAN for OBLIQUE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003062 prt_dup_cidfont("CF0", "CF2");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003063
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003064 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
3065 {
3066 prt_dsc_resources("IncludeResource", "font",
3067 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3068 if (!prt_custom_cmap)
3069 prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3070 prt_def_cidfont("CF3", (int)prt_line_height,
3071 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3072 }
3073 else
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003074 // Use BOLD for BOLDOBLIQUE
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003075 prt_dup_cidfont("CF1", "CF3");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003076 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003077
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003078 // Misc constant vars used for underlining and background rects
Bram Moolenaar81366db2005-07-24 21:16:51 +00003079 prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
3080 prt_ps_font->uline_offset), 2);
3081 prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
3082 prt_ps_font->uline_width), 2);
3083 prt_def_var("BO", prt_bgcol_offset, 2);
3084
3085 prt_dsc_noarg("EndSetup");
3086
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003087 // Fail if any problems writing out to the PS file
Bram Moolenaard9462e32011-04-11 21:35:11 +02003088 retval = !prt_file_error;
3089
3090theend:
3091 vim_free(res_prolog);
3092 vim_free(res_encoding);
Bram Moolenaard9462e32011-04-11 21:35:11 +02003093 vim_free(res_cidfont);
3094 vim_free(res_cmap);
Bram Moolenaard9462e32011-04-11 21:35:11 +02003095
3096 return retval;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003097}
3098
3099 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003100mch_print_end(prt_settings_T *psettings)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003101{
3102 prt_dsc_noarg("Trailer");
3103
3104 /*
3105 * Output any info we don't know in toto until we finish
3106 */
3107 prt_dsc_ints("Pages", 1, &prt_page_num);
3108
3109 prt_dsc_noarg("EOF");
3110
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003111 // Write CTRL-D to close serial communication link if used.
3112 // NOTHING MUST BE WRITTEN AFTER THIS!
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003113 prt_write_file((char_u *)"\004");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003114
3115 if (!prt_file_error && psettings->outfile == NULL
3116 && !got_int && !psettings->user_abort)
3117 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003118 // Close the file first.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003119 if (prt_ps_fd != NULL)
3120 {
3121 fclose(prt_ps_fd);
3122 prt_ps_fd = NULL;
3123 }
3124 prt_message((char_u *)_("Sending to printer..."));
3125
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003126 // Not printing to a file: use 'printexpr' to print the file.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003127 if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
Bram Moolenaarac78dd42022-01-02 19:25:26 +00003128 emsg(_(e_failed_to_print_postscript_file));
Bram Moolenaar81366db2005-07-24 21:16:51 +00003129 else
3130 prt_message((char_u *)_("Print job sent."));
3131 }
3132
3133 mch_print_cleanup();
3134}
3135
3136 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003137mch_print_end_page(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003138{
3139 prt_flush_buffer();
3140
3141 prt_write_string("re sp\n");
3142
3143 prt_dsc_noarg("PageTrailer");
3144
3145 return !prt_file_error;
3146}
3147
Bram Moolenaar81366db2005-07-24 21:16:51 +00003148 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003149mch_print_begin_page(char_u *str UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003150{
3151 int page_num[2];
3152
3153 prt_page_num++;
3154
3155 page_num[0] = page_num[1] = prt_page_num;
3156 prt_dsc_ints("Page", 2, page_num);
3157
3158 prt_dsc_noarg("BeginPageSetup");
3159
3160 prt_write_string("sv\n0 g\n");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003161 prt_in_ascii = !prt_out_mbyte;
3162 if (prt_out_mbyte)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003163 prt_write_string("CF0 sf\n");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003164 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003165 prt_write_string("F0 sf\n");
Bram Moolenaar81366db2005-07-24 21:16:51 +00003166 prt_fgcol = PRCOLOR_BLACK;
3167 prt_bgcol = PRCOLOR_WHITE;
3168 prt_font = PRT_PS_FONT_ROMAN;
3169
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003170 // Set up page transformation for landscape printing.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003171 if (!prt_portrait)
3172 {
3173 prt_write_int(-((int)prt_mediasize[prt_media].width));
3174 prt_write_string("sl\n");
3175 }
3176
3177 prt_dsc_noarg("EndPageSetup");
3178
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003179 // We have reset the font attributes, force setting them again.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003180 curr_bg = (long_u)0xffffffff;
3181 curr_fg = (long_u)0xffffffff;
3182 curr_bold = MAYBE;
3183
3184 return !prt_file_error;
3185}
3186
3187 int
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003188mch_print_blank_page(void)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003189{
3190 return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
3191}
3192
3193static float prt_pos_x = 0;
3194static float prt_pos_y = 0;
3195
3196 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003197mch_print_start_line(int margin, int page_line)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003198{
3199 prt_pos_x = prt_left_margin;
3200 if (margin)
3201 prt_pos_x -= prt_number_width;
3202
3203 prt_pos_y = prt_top_margin - prt_first_line_height -
3204 page_line * prt_line_height;
3205
3206 prt_attribute_change = TRUE;
3207 prt_need_moveto = TRUE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003208 prt_half_width = FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003209}
3210
Bram Moolenaar81366db2005-07-24 21:16:51 +00003211 int
Bram Moolenaar43dee182018-06-16 14:44:11 +02003212mch_print_text_out(char_u *textp, int len UNUSED)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003213{
Bram Moolenaar43dee182018-06-16 14:44:11 +02003214 char_u *p = textp;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003215 int need_break;
3216 char_u ch;
3217 char_u ch_buff[8];
3218 float char_width;
3219 float next_pos;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003220 int in_ascii;
3221 int half_width;
Bram Moolenaarcdd09aa2018-02-11 15:38:40 +01003222 char_u *tofree = NULL;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003223
3224 char_width = prt_char_width;
3225
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003226 // Ideally VIM would create a rearranged CID font to combine a Roman and
3227 // CJKV font to do what VIM is doing here - use a Roman font for characters
3228 // in the ASCII range, and the original CID font for everything else.
3229 // The problem is that GhostScript still (as of 8.13) does not support
3230 // rearranged fonts even though they have been documented by Adobe for 7
3231 // years! If they ever do, a lot of this code will disappear.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003232 if (prt_use_courier)
3233 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003234 in_ascii = (len == 1 && *p < 0x80);
3235 if (prt_in_ascii)
3236 {
3237 if (!in_ascii)
3238 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003239 // No longer in ASCII range - need to switch font
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003240 prt_in_ascii = FALSE;
3241 prt_need_font = TRUE;
3242 prt_attribute_change = TRUE;
3243 }
3244 }
3245 else if (in_ascii)
3246 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003247 // Now in ASCII range - need to switch font
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003248 prt_in_ascii = TRUE;
3249 prt_need_font = TRUE;
3250 prt_attribute_change = TRUE;
3251 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003252 }
3253 if (prt_out_mbyte)
3254 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003255 half_width = ((*mb_ptr2cells)(p) == 1);
3256 if (half_width)
3257 char_width /= 2;
3258 if (prt_half_width)
3259 {
3260 if (!half_width)
3261 {
3262 prt_half_width = FALSE;
3263 prt_pos_x += prt_char_width/4;
3264 prt_need_moveto = TRUE;
3265 prt_attribute_change = TRUE;
3266 }
3267 }
3268 else if (half_width)
3269 {
3270 prt_half_width = TRUE;
3271 prt_pos_x += prt_char_width/4;
3272 prt_need_moveto = TRUE;
3273 prt_attribute_change = TRUE;
3274 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003275 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003276
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003277 // Output any required changes to the graphics state, after flushing any
3278 // text buffered so far.
Bram Moolenaar81366db2005-07-24 21:16:51 +00003279 if (prt_attribute_change)
3280 {
3281 prt_flush_buffer();
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003282 // Reset count of number of chars that will be printed
Bram Moolenaar81366db2005-07-24 21:16:51 +00003283 prt_text_run = 0;
3284
3285 if (prt_need_moveto)
3286 {
3287 prt_pos_x_moveto = prt_pos_x;
3288 prt_pos_y_moveto = prt_pos_y;
3289 prt_do_moveto = TRUE;
3290
3291 prt_need_moveto = FALSE;
3292 }
3293 if (prt_need_font)
3294 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003295 if (!prt_in_ascii)
3296 prt_write_string("CF");
3297 else
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003298 prt_write_string("F");
3299 prt_write_int(prt_font);
3300 prt_write_string("sf\n");
3301 prt_need_font = FALSE;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003302 }
3303 if (prt_need_fgcol)
3304 {
3305 int r, g, b;
3306 r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
3307 g = ((unsigned)prt_fgcol & 0xff00) >> 8;
3308 b = prt_fgcol & 0xff;
3309
3310 prt_write_real(r / 255.0, 3);
3311 if (r == g && g == b)
3312 prt_write_string("g\n");
3313 else
3314 {
3315 prt_write_real(g / 255.0, 3);
3316 prt_write_real(b / 255.0, 3);
3317 prt_write_string("r\n");
3318 }
3319 prt_need_fgcol = FALSE;
3320 }
3321
3322 if (prt_bgcol != PRCOLOR_WHITE)
3323 {
3324 prt_new_bgcol = prt_bgcol;
3325 if (prt_need_bgcol)
3326 prt_do_bgcol = TRUE;
3327 }
3328 else
3329 prt_do_bgcol = FALSE;
3330 prt_need_bgcol = FALSE;
3331
3332 if (prt_need_underline)
3333 prt_do_underline = prt_underline;
3334 prt_need_underline = FALSE;
3335
3336 prt_attribute_change = FALSE;
3337 }
3338
Bram Moolenaar81366db2005-07-24 21:16:51 +00003339 if (prt_do_conv)
Bram Moolenaar43dee182018-06-16 14:44:11 +02003340 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003341 // Convert from multi-byte to 8-bit encoding
Bram Moolenaarcdd09aa2018-02-11 15:38:40 +01003342 tofree = p = string_convert(&prt_conv, p, &len);
Bram Moolenaar43dee182018-06-16 14:44:11 +02003343 if (p == NULL)
3344 {
3345 p = (char_u *)"";
3346 len = 0;
3347 }
3348 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003349
3350 if (prt_out_mbyte)
3351 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003352 // Multi-byte character strings are represented more efficiently as hex
3353 // strings when outputting clean 8 bit PS.
Bram Moolenaarcdd09aa2018-02-11 15:38:40 +01003354 while (len-- > 0)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003355 {
3356 ch = prt_hexchar[(unsigned)(*p) >> 4];
3357 ga_append(&prt_ps_buffer, ch);
3358 ch = prt_hexchar[(*p) & 0xf];
3359 ga_append(&prt_ps_buffer, ch);
3360 p++;
3361 }
Bram Moolenaar81366db2005-07-24 21:16:51 +00003362 }
3363 else
Bram Moolenaar81366db2005-07-24 21:16:51 +00003364 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003365 // Add next character to buffer of characters to output.
3366 // Note: One printed character may require several PS characters to
3367 // represent it, but we only count them as one printed character.
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003368 ch = *p;
3369 if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
3370 {
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003371 // Convert non-printing characters to either their escape or octal
3372 // sequence, ensures PS sent over a serial line does not interfere
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003373 // with the comms protocol.
3374 ga_append(&prt_ps_buffer, '\\');
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003375 switch (ch)
3376 {
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003377 case BS: ga_append(&prt_ps_buffer, 'b'); break;
3378 case TAB: ga_append(&prt_ps_buffer, 't'); break;
3379 case NL: ga_append(&prt_ps_buffer, 'n'); break;
3380 case FF: ga_append(&prt_ps_buffer, 'f'); break;
3381 case CAR: ga_append(&prt_ps_buffer, 'r'); break;
3382 case '(': ga_append(&prt_ps_buffer, '('); break;
3383 case ')': ga_append(&prt_ps_buffer, ')'); break;
3384 case '\\': ga_append(&prt_ps_buffer, '\\'); break;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003385
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003386 default:
3387 sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003388 ga_append(&prt_ps_buffer, ch_buff[0]);
3389 ga_append(&prt_ps_buffer, ch_buff[1]);
3390 ga_append(&prt_ps_buffer, ch_buff[2]);
3391 break;
3392 }
3393 }
3394 else
3395 ga_append(&prt_ps_buffer, ch);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003396 }
3397
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003398 // Need to free any translated characters
Bram Moolenaarcdd09aa2018-02-11 15:38:40 +01003399 vim_free(tofree);
Bram Moolenaar81366db2005-07-24 21:16:51 +00003400
3401 prt_text_run += char_width;
3402 prt_pos_x += char_width;
3403
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003404 // The downside of fp - use relative error on right margin check
Bram Moolenaar81366db2005-07-24 21:16:51 +00003405 next_pos = prt_pos_x + prt_char_width;
3406 need_break = (next_pos > prt_right_margin) &&
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00003407 ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
Bram Moolenaar81366db2005-07-24 21:16:51 +00003408
3409 if (need_break)
3410 prt_flush_buffer();
3411
3412 return need_break;
3413}
3414
3415 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003416mch_print_set_font(int iBold, int iItalic, int iUnderline)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003417{
3418 int font = 0;
3419
3420 if (iBold)
3421 font |= 0x01;
3422 if (iItalic)
3423 font |= 0x02;
3424
3425 if (font != prt_font)
3426 {
3427 prt_font = font;
3428 prt_attribute_change = TRUE;
3429 prt_need_font = TRUE;
3430 }
3431 if (prt_underline != iUnderline)
3432 {
3433 prt_underline = iUnderline;
3434 prt_attribute_change = TRUE;
3435 prt_need_underline = TRUE;
3436 }
3437}
3438
3439 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003440mch_print_set_bg(long_u bgcol)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003441{
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003442 prt_bgcol = (int)bgcol;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003443 prt_attribute_change = TRUE;
3444 prt_need_bgcol = TRUE;
3445}
3446
3447 void
Bram Moolenaar68c2f632016-01-30 17:24:07 +01003448mch_print_set_fg(long_u fgcol)
Bram Moolenaar81366db2005-07-24 21:16:51 +00003449{
3450 if (fgcol != (long_u)prt_fgcol)
3451 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003452 prt_fgcol = (int)fgcol;
Bram Moolenaar81366db2005-07-24 21:16:51 +00003453 prt_attribute_change = TRUE;
3454 prt_need_fgcol = TRUE;
3455 }
3456}
3457
Bram Moolenaar2ab2e862019-12-04 21:24:53 +01003458# endif //FEAT_POSTSCRIPT
3459#endif //FEAT_PRINTER